lib/protocol/protocol_module.rb in protocol-1.0.1 vs lib/protocol/protocol_module.rb in protocol-2.0.0
- old
+ new
@@ -1,18 +1,15 @@
module Protocol
# A ProtocolModule object
class ProtocolModule < Module
# Creates an new ProtocolModule instance.
def initialize(&block)
- @descriptor = Descriptor.new(self)
- @mode = :error
- module_eval(&block)
+ @descriptor = Descriptor.new(self)
+ @implementation = false
+ block and module_eval(&block)
end
- # The current check mode :none, :warning, or :error (the default).
- attr_reader :mode
-
# Returns all the protocol descriptions to check against as an Array.
def descriptors
descriptors = []
protocols.each do |a|
descriptors << a.instance_variable_get(:@descriptor)
@@ -28,11 +25,10 @@
# Concatenates the protocol as Ruby code to the +result+ string and return
# it. At the moment this method only supports method signatures with
# generic argument names.
def to_ruby(result = '')
result << "#{name} = Protocol do"
- first = true
if messages.empty?
result << "\n"
else
messages.each do |m|
result << "\n"
@@ -127,43 +123,42 @@
# #<FooProtocol: bar(2&), baz(3), foo(-1)>
def inspect
"#<#{name}: #{messages.map { |m| m.shortcut } * ', '}>"
end
- # Check the conformity of +object+ recursively. This method returns either
- # false OR true, if +mode+ is :none or :warning, or raises an
- # CheckFailed, if +mode+ was :error.
- def check(object, mode = @mode)
+ # Check the conformity of +object+ recursively and raise an exception if it
+ # doesn't.
+ def check!(object)
checked = {}
- result = true
errors = CheckFailed.new
each do |message|
begin
message.check(object, checked)
rescue CheckError => e
- case mode
- when :error
- errors << e
- when :warning
- warn e.to_s
- result = false
- when :none
- result = false
- end
+ errors << e
end
end
- raise errors unless errors.empty?
- result
+ errors.empty? or raise errors
+ true
end
- alias =~ check
+ alias =~ check!
+ # Check the conformity of +object+ recursively and return true iff it does.
+ def check(object)
+ check!(object)
+ rescue CheckFailed
+ false
+ else
+ true
+ end
+
# Return all messages for whick a check failed.
def check_failures(object)
- check object
+ check!(object)
rescue CheckFailed => e
- return e.errors.map { |e| e.protocol_message }
+ e.errors.map { |e| e.protocol_message }
end
# This callback is called, when a module, that was extended with Protocol,
# is included (via Modul#include/via Class#conform_to) into some other
# module/class.
@@ -171,36 +166,23 @@
# are collected and the given class is checked for conformance to the
# protocol. +modul+ isn't a Class and only a Module, it is extended with
# the Protocol
# module.
def included(modul)
- super
- if modul.is_a? Class and @mode == :error or @mode == :warning
- $DEBUG and warn "#{name} is checking class #{modul}"
- check modul
+ result = super
+ if modul.is_a? Class
+ check! modul
end
+ result
end
def extend_object(object)
result = super
- if @mode == :error or @mode == :warning
- $DEBUG and warn "#{name} is checking class #{object}"
- check object
- end
+ check! object
result
end
- # Sets the check mode to +id+. +id+ should be one of :none, :warning, or
- # :error. The mode to use while doing a conformity check is always the root
- # module, that is, the modes of the included modules aren't important for
- # the check.
- def check_failure(mode)
- CHECK_MODES.include?(mode) or
- raise ArgumentError, "illegal check mode #{mode}"
- @mode = mode
- end
-
# This method defines one of the messages, the protocol in question
# consists of: The messages which the class, that conforms to this
# protocol, should understand and respond to. An example shows best
# which +message+descriptions_ are allowed:
#
@@ -224,16 +206,16 @@
parser = MethodParser.new(real_module, methodname)
Message.new(self, methodname, method.arity, parser.block_arg?)
end
private :parse_instance_method_signature
- # Inherit a method signature from an instance method named +methodname+ of
+ # Infer a method signature from an instance method named +methodname+ of
# +modul+. This means that this protocol should understand these instance
# methods with their arity and block expectation. Note that automatic
# detection of blocks does not work for Ruby methods defined in C. You can
# set the +block_expected+ argument if you want to do this manually.
- def inherit(modul, methodname, block_expected = nil)
+ def infer(modul, methodname = modul.public_instance_methods(false), block_expected = nil)
Module === modul or
raise TypeError, "expected Module not #{modul.class} as modul argument"
methodnames = methodname.respond_to?(:to_ary) ?
methodname.to_ary :
[ methodname ]
@@ -252,10 +234,10 @@
end
# Return true, if the ProtocolModule is currently in implementation mode.
# Otherwise return false.
def implementation?
- !!@implementation
+ @implementation
end
# Switch to specification mode. Defined methods are added to the protocol
# description in order to be checked against in later conformance tests.
def specification