Module StateMachine::EvalHelpers
In: lib/state_machine/eval_helpers.rb

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

Methods

Public Instance methods

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)

[Source]

    # File lib/state_machine/eval_helpers.rb, line 53
53:     def evaluate_method(object, method, *args, &block)
54:       case method
55:         when Symbol
56:           object.method(method).arity == 0 ? object.send(method, &block) : object.send(method, *args, &block)
57:         when Proc, Method
58:           args.unshift(object)
59:           arity = method.arity
60:           limit = [0, 1].include?(arity) ? arity : args.length
61:           
62:           # Procs don't support blocks in < Ruby 1.8.6, so it's tacked on as an
63:           # argument for consistency across versions of Ruby (even though 1.9
64:           # supports yielding within blocks)
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:               limit = arity
70:               args.insert(limit - 1, block)
71:             else
72:               # Tack the block to the end of the args
73:               limit += 1 unless limit < 0
74:               args.push(block)
75:             end
76:           end
77:           
78:           method.call(*args[0, limit], &block)
79:         when String
80:           eval(method, object.instance_eval {binding}, &block)
81:         else
82:           raise ArgumentError, 'Methods must be a symbol denoting the method to call, a block to be invoked, or a string to be evaluated'
83:         end
84:     end

[Validate]