module EnumStateMachine::EvalHelpers

Provides a set of helper methods for evaluating methods within the context of an object.

Public Instance Methods

evaluate_method(object, method, *args, &block) click to toggle source

Evaluates one of several different types of methods within the context of the given object. Methods can be one of the following types:

  • Symbol

  • Method / Proc

  • String

Examples

Below are examples of the various ways that a method can be evaluated on an object:

class Person
  def initialize(name)
    @name = name
  end

  def name
    @name
  end
end

class PersonCallback
  def self.run(person)
    person.name
  end
end

person = Person.new('John Smith')

evaluate_method(person, :name)                            # => "John Smith"
evaluate_method(person, PersonCallback.method(:run))      # => "John Smith"
evaluate_method(person, Proc.new {|person| person.name})  # => "John Smith"
evaluate_method(person, lambda {|person| person.name})    # => "John Smith"
evaluate_method(person, '@name')                          # => "John Smith"

Additional arguments

Additional arguments can be passed to the methods being evaluated. If the method defines additional arguments other than the object context, then all arguments are required.

For example,

person = Person.new('John Smith')

evaluate_method(person, lambda {|person| person.name}, 21)                              # => "John Smith"
evaluate_method(person, lambda {|person, age| "#{person.name} is #{age}"}, 21)          # => "John Smith is 21"
evaluate_method(person, lambda {|person, age| "#{person.name} is #{age}"}, 21, 'male')  # => ArgumentError: wrong number of arguments (3 for 2)
   # File lib/enum_state_machine/eval_helpers.rb
53 def evaluate_method(object, method, *args, &block)
54   case method
55     when Symbol
56       klass = (class << object; self; end)
57       args = [] if (klass.method_defined?(method) || klass.private_method_defined?(method)) && object.method(method).arity == 0
58       object.send(method, *args, &block)
59     when Proc, Method
60       args.unshift(object)
61       arity = method.arity
62       
63       # Procs don't support blocks in < Ruby 1.9, so it's tacked on as an
64       # argument for consistency across versions of Ruby
65       if block_given? && Proc === method && arity != 0
66         if [1, 2].include?(arity)
67           # Force the block to be either the only argument or the 2nd one
68           # after the object (may mean additional arguments get discarded)
69           args = args[0, arity - 1] + [block]
70         else
71           # Tack the block to the end of the args
72           args << block
73         end
74       else
75         # These method types are only called with 0, 1, or n arguments
76         args = args[0, arity] if [0, 1].include?(arity)
77       end
78       
79       method.is_a?(Proc) ? method.call(*args) : method.call(*args, &block)
80     when String
81       eval(method, object.instance_eval {binding}, &block)
82     else
83       raise ArgumentError, 'Methods must be a symbol denoting the method to call, a block to be invoked, or a string to be evaluated'
84   end
85 end