module Functional::Protocol

Protocols provide a polymorphism and method-dispatch mechanism that exchews stong typing and embraces the dynamic duck typing of Ruby. Rather than interrogate a module, class, or object for its type and ancestry, protocols allow modules, classes, and methods to be interrogated based on their behavior. It is a logical extension of the ‘respond_to?` method, but vastly more powerful.

{include:file:doc/protocol.md}

Public Class Methods

Satisfy!(target, *protocols) click to toggle source

Does the given module/class/object fully satisfy the given protocol(s)? Raises a {Functional::ProtocolError} on failure.

@param [Object] target the method/class/object to interrogate @param [Symbol] protocols one or more protocols to check against the target @return [Symbol] the target

@raise [Functional::ProtocolError] when one or more protocols are not satisfied @raise [ArgumentError] when no protocols given

# File lib/functional/protocol.rb, line 87
def Satisfy!(target, *protocols)
  Protocol::Satisfy?(target, *protocols) or
    Protocol.error(target, 'does not', *protocols)
  target
end
Satisfy?(target, *protocols) click to toggle source

Does the given module/class/object fully satisfy the given protocol(s)?

@param [Object] target the method/class/object to interrogate @param [Symbol] protocols one or more protocols to check against the target @return [Boolean] true if the target satisfies all given protocols else false

@raise [ArgumentError] when no protocols given

# File lib/functional/protocol.rb, line 72
def Satisfy?(target, *protocols)
  raise ArgumentError.new('no protocols given') if protocols.empty?
  protocols.all?{|protocol| Protocol.satisfies?(target, protocol.to_sym) }
end
Specified!(*protocols) click to toggle source

Have the given protocols been specified? Raises a {Functional::ProtocolError} on failure.

@param [Symbol] protocols the list of protocols to check @return [Boolean] true if all given protocols have been specified

@raise [Functional::ProtocolError] if one or more of the given protocols have

not been specified

@raise [ArgumentError] when no protocols are given

# File lib/functional/protocol.rb, line 115
def Specified!(*protocols)
  raise ArgumentError.new('no protocols given') if protocols.empty?
  (unspecified = Protocol.unspecified(*protocols)).empty? or
    raise ProtocolError.new("The following protocols are unspecified: :#{unspecified.join('; :')}.")
end
Specified?(*protocols) click to toggle source

Have the given protocols been specified?

@param [Symbol] protocols the list of protocols to check @return [Boolean] true if all given protocols have been specified else false

@raise [ArgumentError] when no protocols are given

# File lib/functional/protocol.rb, line 100
def Specified?(*protocols)
  raise ArgumentError.new('no protocols given') if protocols.empty?
  Protocol.unspecified(*protocols).empty?
end

Private Class Methods

error(target, message, *protocols) click to toggle source

Raise a {Functional::ProtocolError} formatted with the given data.

@param [Object] target the object that was being interrogated @param [String] message the message fragment to inject into the error @param [Symbol] protocols list of protocols that were being checked against the target

@raise [Functional::ProtocolError] the formatted exception object

# File lib/functional/protocol.rb, line 151
def self.error(target, message, *protocols)
  target = target.class unless target.is_a?(Module)
  raise ProtocolError,
    "Value (#{target.class}) '#{target}' #{message} behave as all of: :#{protocols.join('; :')}."
end
satisfies?(target, protocol) click to toggle source

Does the target satisfy the given protocol?

@param [Object] target the module/class/object to check @param [Symbol] protocol the protocol to check against the target @return [Boolean] true if the target satisfies the protocol else false

# File lib/functional/protocol.rb, line 129
def self.satisfies?(target, protocol)
  info = @@info[protocol]
  return info && info.satisfies?(target)
end
unspecified(*protocols) click to toggle source

Reduces a list of protocols to a list of unspecified protocols.

@param [Symbol] protocols the list of protocols to check @return [Array] zero or more unspecified protocols

# File lib/functional/protocol.rb, line 138
def self.unspecified(*protocols)
  protocols.drop_while do |protocol|
    @@info.has_key? protocol.to_sym
  end
end

Private Instance Methods

Satisfy!(target, *protocols) click to toggle source

Does the given module/class/object fully satisfy the given protocol(s)? Raises a {Functional::ProtocolError} on failure.

@param [Object] target the method/class/object to interrogate @param [Symbol] protocols one or more protocols to check against the target @return [Symbol] the target

@raise [Functional::ProtocolError] when one or more protocols are not satisfied @raise [ArgumentError] when no protocols given

# File lib/functional/protocol.rb, line 87
def Satisfy!(target, *protocols)
  Protocol::Satisfy?(target, *protocols) or
    Protocol.error(target, 'does not', *protocols)
  target
end
Satisfy?(target, *protocols) click to toggle source

Does the given module/class/object fully satisfy the given protocol(s)?

@param [Object] target the method/class/object to interrogate @param [Symbol] protocols one or more protocols to check against the target @return [Boolean] true if the target satisfies all given protocols else false

@raise [ArgumentError] when no protocols given

# File lib/functional/protocol.rb, line 72
def Satisfy?(target, *protocols)
  raise ArgumentError.new('no protocols given') if protocols.empty?
  protocols.all?{|protocol| Protocol.satisfies?(target, protocol.to_sym) }
end
Specified!(*protocols) click to toggle source

Have the given protocols been specified? Raises a {Functional::ProtocolError} on failure.

@param [Symbol] protocols the list of protocols to check @return [Boolean] true if all given protocols have been specified

@raise [Functional::ProtocolError] if one or more of the given protocols have

not been specified

@raise [ArgumentError] when no protocols are given

# File lib/functional/protocol.rb, line 115
def Specified!(*protocols)
  raise ArgumentError.new('no protocols given') if protocols.empty?
  (unspecified = Protocol.unspecified(*protocols)).empty? or
    raise ProtocolError.new("The following protocols are unspecified: :#{unspecified.join('; :')}.")
end
Specified?(*protocols) click to toggle source

Have the given protocols been specified?

@param [Symbol] protocols the list of protocols to check @return [Boolean] true if all given protocols have been specified else false

@raise [ArgumentError] when no protocols are given

# File lib/functional/protocol.rb, line 100
def Specified?(*protocols)
  raise ArgumentError.new('no protocols given') if protocols.empty?
  Protocol.unspecified(*protocols).empty?
end