0

Take the following class:

class Automator
  def fill_specific_form(fields)
    fields.each_pair do |key, value|
      puts "Setting '#{key}' to '#{value}'"
    end
  end
end

a = Automator.new
a.fill_specific_form :first_name => "Mads", :last_name => "Mobæk"

# => Setting 'first_name' to 'Mads'
# => Setting 'last_name' to 'Mobæk'

Is it possible to do the same without a hash? Since all parameters are required, I want a method with the following signature:

fill_specific_form(first_name, last_name)

In my mind this would be possible by having the method body reflect and iterate over its parameters, thus achieving the same result.

How would you implement this? Does a pattern/idiom for this exist already? Two obvious benefits would be parameter information in IDEs and not having to check if all hash keys are supplied.

What I want to avoid is:

puts "Setting first_name to #{first_name}"
puts "Setting last_name to #{last_name}"
# and so on
2

3 Answers 3

3

If you set no other local variables inside the method, local_variables will give you a list of the method's parameter names (if you do set other variables you can just call local_variables first thing and remember the result). So you can do what you want with local_variables+eval:

class Automator
  def fill_specific_form(first_name, last_name)
    local_variables.each do |var|
      puts "Setting #{var} to #{eval var.to_s}"
    end
  end
end

Automator.new().fill_specific_form("Mads", "Mobaek")

Be however advised that this is pure evil.

And at least for your example

puts "Setting first_name to #{first_name}"
puts "Setting last_name to #{last_name}"

seems much more sensible.

You could also do fields = {:first_name => first_name, :last_name => last_name} at the beginning of the method and then go with your fields.each_pair code.

Sign up to request clarification or add additional context in comments.

4 Comments

Pure evil is not intended and not what I want. Just curious if there was a way to do this. I will test your suggestions and get back to you
fields = {:first_name => first_name, :last_name => last_name} is what I want. Thank you.
I tried with Ruby 1.9.3, and you have to do #{eval var.to_s} to get it to work, otherwise you get a TypeError: can't convert Symbol into String
@JavidJamae Yes, they've changed local_variables from an array of strings to an array of symbols in 1.9.
0

I don't quite understand. Do you want to receive all parameters within a single array?

def fill_specific_form *args
    #Process args
end

1 Comment

Not quite. This only gets the values passed. By using explicit parameter names matching the name of a form element, I could then set name = value. See sepp2k's answer
0

To reflect on a method's (or Proc's) parameters, you can use Proc#parameters, Method#parameters or UnboundMethod#parameters:

->(m1, o1=nil, *s, m2, &b){}.parameters
# => [[:req, :m1], [:opt, :o1], [:rest, :s], [:req, :m2], [:block, :b]]

However, in your case, I don't see why you need reflection, since you already know the names of the parameters anyway.

2 Comments

Is this new in 1.9.2? This doesn't work for me in 1.8.7 or 1.9.1.
@sepp2k: Yes, Proc#parameters is new in 1.9.2.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.