class Functional::ProtocolInfo
An immutable object describing a single protocol and capable of building itself from a block. Used by {Functional#SpecifyProtocol}.
@see Functional::Protocol
Constants
- Info
Data structure for encapsulating the protocol info data. @!visibility private
Attributes
The symbolic name of the protocol
Public Class Methods
Process a protocol specification block and build a new object.
@param [Symbol] name the symbolic name of the protocol @yield self to the given specification block @return [Functional::ProtocolInfo] the new info object, frozen
@raise [ArgumentError] when name is nil or an empty string @raise [ArgumentError] when no block given
# File lib/functional/protocol_info.rb, line 22 def initialize(name, &specification) raise ArgumentError.new('no block given') unless block_given? raise ArgumentError.new('no name given') if name.nil? || name.empty? super @name = name.to_sym @info = Info.new({}, {}, []) self.instance_eval(&specification) @info.each_pair{|col, _| col.freeze} @info.freeze ensure_ivar_visibility! self.freeze end
Public Instance Methods
The class methods expected by this protocol.
@return [Hash] a frozen hash of all class method names and their
expected arity for this protocol
# File lib/functional/protocol_info.rb, line 47 def class_methods @info.class_methods end
The constants expected by this protocol.
@return [Array] a frozen list of the constants expected by this protocol
# File lib/functional/protocol_info.rb, line 54 def constants @info.constants end
The instance methods expected by this protocol.
@return [Hash] a frozen hash of all instance method names and their
expected arity for this protocol
# File lib/functional/protocol_info.rb, line 39 def instance_methods @info.instance_methods end
Does the given module/class/object satisfy this protocol?
@return [Boolean] true if the target satisfies this protocol else false
# File lib/functional/protocol_info.rb, line 61 def satisfies?(target) satisfies_constants?(target) && satisfies_instance_methods?(target) && satisfies_class_methods?(target) end
Private Instance Methods
Specify an instance accessor attribute.
@param [Symbol] name the name of the attribute
# File lib/functional/protocol_info.rb, line 164 def attr_accessor(name) attr_reader(name) attr_writer(name) end
Specify an instance reader attribute.
@param [Symbol] name the name of the attribute
# File lib/functional/protocol_info.rb, line 150 def attr_reader(name) instance_method(name, 0) end
Specify an instance writer attribute.
@param [Symbol] name the name of the attribute
# File lib/functional/protocol_info.rb, line 157 def attr_writer(name) instance_method("#{name}=".to_sym, 1) end
Does the given method have the expected arity? Returns true if the arity of the method is ‘-1` (variable length argument list with no required arguments), when expected is `nil` (indicating any arity is acceptable), or the arity of the method exactly matches the expected arity.
@param [Method] method the method object to interrogate @param [Fixnum] expected the expected arity @return [Boolean] true when an acceptable match else false
@see www.ruby-doc.org/core-2.1.2/Method.html#method-i-arity Method#arity
# File lib/functional/protocol_info.rb, line 121 def check_arity?(method, expected) arity = method.arity expected.nil? || arity == -1 || expected == arity end
Specify a class accessor attribute.
@param [Symbol] name the name of the attribute
# File lib/functional/protocol_info.rb, line 186 def class_attr_accessor(name) class_attr_reader(name) class_attr_writer(name) end
Specify a class reader attribute.
@param [Symbol] name the name of the attribute
# File lib/functional/protocol_info.rb, line 172 def class_attr_reader(name) class_method(name, 0) end
Specify a class writer attribute.
@param [Symbol] name the name of the attribute
# File lib/functional/protocol_info.rb, line 179 def class_attr_writer(name) class_method("#{name}=".to_sym, 1) end
Specify a class method.
@param [Symbol] name the name of the method @param [Fixnum] arity the required arity
# File lib/functional/protocol_info.rb, line 142 def class_method(name, arity = nil) arity = arity.to_i unless arity.nil? @info.class_methods[name.to_sym] = arity end
Specify a constant.
@param [Symbol] name the name of the constant
# File lib/functional/protocol_info.rb, line 194 def constant(name) @info.constants << name.to_sym end
Specify an instance method.
@param [Symbol] name the name of the method @param [Fixnum] arity the required arity
# File lib/functional/protocol_info.rb, line 133 def instance_method(name, arity = nil) arity = arity.to_i unless arity.nil? @info.instance_methods[name.to_sym] = arity end
Does the target satisfy the class methods expected by this protocol?
@param [target] target the module/class/object to interrogate @return [Boolean] true when satisfied else false
# File lib/functional/protocol_info.rb, line 101 def satisfies_class_methods?(target) clazz = target.is_a?(Module) ? target : target.class @info.class_methods.all? do |method, arity| break false unless clazz.respond_to? method method = clazz.method(method) check_arity?(method, arity) end end
Does the target satisfy the constants expected by this protocol?
@param [target] target the module/class/object to interrogate @return [Boolean] true when satisfied else false
# File lib/functional/protocol_info.rb, line 77 def satisfies_constants?(target) clazz = target.is_a?(Module) ? target : target.class @info.constants.all?{|constant| clazz.const_defined?(constant) } end
Does the target satisfy the instance methods expected by this protocol?
@param [target] target the module/class/object to interrogate @return [Boolean] true when satisfied else false
# File lib/functional/protocol_info.rb, line 86 def satisfies_instance_methods?(target) @info.instance_methods.all? do |method, arity| if target.is_a? Module target.method_defined?(method) && check_arity?(target.instance_method(method), arity) else target.respond_to?(method) && check_arity?(target.method(method), arity) end end end