How to Require a Block in Ruby

How to require a block in Ruby?

Simply by using yield.

If you include yield in a method, and a block is not given, it throws an error.

Put this in a file and run it:

def needs_block
yield
end

needs_block

It will throw an error like this:

LocalJumpError: no block given
from (irb):14:in `needs_block'
from (irb):16

Ruby - Why use a Block as a parameter?

  1. You'd call it like this:

    print reverser { "Hello" }

Or if your block is several lines long then like this:

print reverser do
"Hello"
end

  1. Blocks are close to what anonymous functions are in other languages.

Map is a good example.
What map does is it takes an array and maps (transforms) every element according to whatever rules you need.

These mapping rules must be a code. That means, it can't be a string or number or something, it has to be a function. Block is used here as function which you can write using minimal code.

So in your example you have this:

words.map { |word| word.reverse }.join(" ")

If you couldn't pass block to map then you'd have to define that function and pass it somewhere - and name that function. That is just not efficient.

Lets change this block to work so that it reverses word only if it starts with capital letter.

words.map do |word| 
if word[0] =~ /[A-Z]/
word.reverse
else
word
end.join(" ")

Without blocks you'd need to define that function, which you do not need in any other places and call that. That's just not efficient.
This is what it would look like

def reverse_if_starts_with_capital_letter(word)
if word[0] =~ /[A-Z]/
word.reverse
else
word
end
end

# not sure if this syntax would work, just demonstrates idea
words.map(&reverse_if_starts_with_capital_letter)

Separating Ruby Code which requires a block with Partials

Sounds like you're in a very sticky situation. This is what I think you've got from your description:

#partial_1
<% form_tag (:model_name) do %>

#partial_2
<% form_contents %>
<% end %>

#controller
@model = Model.load
render(partial1 << partial2)

You may have to correct me if I'm wrong, but is it possible instead to do this?

#controller
@model = Model.load
render(partial_1)

#partial_1
<% form_tag ... %>
<% render(partial_2) %>
<% end %>

#partial_2
<% all the form guts %>

If you're using straight ruby you're probably using the ERB library and you are binding every time, which should keep the variables live all the way through.

how to require my library in chef ruby_block

Depending on load order, you might be including your module into an anonymous Ruby class instead of what you think.

If you want to use your method in a recipe, do this at the top of your recipe:

include AppHelper

You could alternatively use :send at the end of your library:

Chef::Recipe.send(:include, AppHelper)

This is different because it will raise an exception if Chef::Recipe is not defined (whereas you are creating a new class if it doesn't exist).

That's all you should need to do unless you want to use the helper in not_if and only_if guards. Then you need to include the helper in the resource:

Chef::Resource.send(:include, AppHelper)

Okay, now that I explained all of that, it won't actually help you. The Ruby Block provider simply calls the block - it doesn't instance eval it. So including the helper in the resource doesn't do anything.

So, you'll need to use a singleton object in this instance (it's the only solution I can reliably think of). The way you've defined your method, you can call it directly from the global namespace:

AppHelper.find_gem('...')

So:

ruby_block "find gem" do
block do
gem_bin = AppHelper.find_gem('...')
end
end

Ruby - Passing Blocks To Methods

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


Related Topics



Leave a reply



Submit