Chris Bunch
Chris Bunch

Reputation: 89823

Ruby - Passing Blocks To Methods

I'm trying to do Ruby password input with the Highline gem and since I have the user input the password twice, I'd like to eliminate the duplication on the blocks I'm passing in. For example, a simple version of what I'm doing right now is:

new_pass = ask("Enter your new password: ") { |prompt| prompt.echo = false }
verify_pass = ask("Enter again to verify: ") { |prompt| prompt.echo = false }

And what I'd like to change it to is something like this:

foo = Proc.new { |prompt| prompt.echo = false }
new_pass = ask("Enter your new password: ") foo
verify_pass = ask("Enter again to verify: ") foo

Which unfortunately doesn't work. What's the correct way to do this?

Upvotes: 43

Views: 46052

Answers (5)

David Nehme
David Nehme

Reputation: 21572

foo = Proc.new { |prompt| prompt.echo = false }
new_pass = ask("Enter your new password: ") {|x| foo.call(x)}
verify_pass = ask("Enter again to verify: ") {|x| foo.call(x)}

Upvotes: 4

Adam Byrtek
Adam Byrtek

Reputation: 12202

The code by David will work fine, but this is an easier and shorter solution:

foo = Proc.new { |prompt| prompt.echo = false }
new_pass = ask("Enter your new password: ", &foo)
verify_pass = ask("Enter again to verify: ", &foo)

You can also use an ampersand to assign a block to a variable when defining a method:

def ask(msg, &block)
  puts block.inspect
end

Upvotes: 74

jspooner
jspooner

Reputation: 11315

Here is an example that will prefix the index with the yield method and append the index with the call method.

class Array
  def alter_each!
    self.each_with_index do |n, i|
      self[i] = yield(n,i)
    end
  end
  def modify_each!(add_one = true, &block)
    self.each_with_index do |n, i|
      j = (add_one) ? (i + 1) : i
      self[i] = block.call(n,j)
    end
  end
end

a = ["dog", "cat", "cow"]

a.alter_each! do |n, i|
  "#{i}_#{n}"
end

a.modify_each! false do |n,i|
  "#{n}_#{i}"
end

puts a

Upvotes: 2

Honza
Honza

Reputation: 4409

This is how you should do it, clean and simple:

def ask(question)
    yield(question)
end

proc = Proc.new { |question| puts question }
new_pass = ask("Enter your new password: ", &proc)
verify_pass = ask("Enter again to verify: ", &proc)

Upvotes: 13

Lucas Oman
Lucas Oman

Reputation: 15872

I don't think the language supports a construct like this. The only way I can see to generalize this in any way is:

def foo(prompt)
  prompt.echo = false
end
new_pass = ask("Enter your new password: ") { |prompt| foo(prompt) }
verify_pass = ask("Enter again to verify: ") { |prompt| foo(prompt) }

It doesn't really shorten the code, though it does remove some duplication--if you wanted to do more than set prompt.echo to false, you'd only have to add code in one place.

Upvotes: -2

Related Questions