user3712482
user3712482

Reputation: 113

How to determine how Ruby method arguments will be bound without calling the method

Because there are a few different kinds of method parameters in Ruby (required, default, keyword, variable length...), sometimes determining how actual arguments will be bound to formal parameters can be tricky.

I'm wondering if there's a way to determine what this binding will be without actually calling the method. For example, for the following method A#foo:

class A
   def foo(a, *b, c)
      ...
   end
end

I would like a method like determine_binding that we can use as follows:

A.instance_method(:foo).determine_binding(1,2,3,4,5) ## returns { a: 1, b: [2,3,4], c: 5 }

That is, determine_binding takes a list of arguments and determines the formal binding to foo's parameters, without actually having to call foo. Is there something like this (or similar) in Ruby?

Upvotes: 1

Views: 175

Answers (2)

Josh Brody
Josh Brody

Reputation: 5363

So close. You're looking for Method#parameters

A.instance_method(:foo).parameters => [[:req, :a], [:rest, :b], [:req, :c]]

See the "Method" documentation for more information.

Upvotes: 2

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

You might go with a tiny DSL for that purpose.

module Watcher
  def self.prepended(base)
    base.instance_methods(false).map do |m|
      mthd = base.instance_method(m)
      names = mthd.parameters.map(&:last).map(&:to_s)
      values = names.join(", ")
      params =
        mthd.parameters.map do |type, name|
          case type
          when :req then name.to_s
          when :rest then "*#{name}"
          when :keyrest then "**#{name}"
          when :block then "&#{name}"
          end
        end.join(", ")
      base.class_eval """
        def #{m}(#{params})
          #{names}.zip([#{values}]).to_h
        end
      """
    end
  end
end

class A; def zoo(a, *b, c); 42; end; end
A.new.zoo(1,2,3,4,5)
#⇒ 42

A.prepend Watcher
A.new.zoo(1,2,3,4,5)
#⇒ {"a"=>1, "b"=>[2, 3, 4], "c"=>5}

Upvotes: 3

Related Questions