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