1

https://github.com/activeadmin/activeadmin/blob/1c85c5654a2ce1d43d4c64d98b928ff133d46406/lib/active_admin.rb#L95

What does the & (prefixed to ActiveAdmin) in this code mean?

def before_load(&block)
  ActiveSupport::Notifications.subscribe(
    ActiveAdmin::Application::BeforeLoadEvent,     
    &ActiveAdmin::Event.wrap_block_for_active_support_notifications(block)
  )
end
spickermann
  • 100,941
  • 9
  • 101
  • 131
kissrobber
  • 567
  • 4
  • 12

3 Answers3

4

In functions & 'splats' blocks (also calls to_proc on it), similar to * for regular parameters.

That is somewhat equivalent to

def before_load(&block) # this binds provided block into block variable
  ActiveSupport::Notifications.subscribe(ActiveAdmin::Application::BeforeLoadEvent){|some_params_maybe|
    ActiveAdmin::Event.wrap_block_for_active_support_notifications(block).call(some_params_maybe)
  }
end
Vasfed
  • 18,013
  • 10
  • 47
  • 53
  • The important thing here is you don't have to know or care how many arguments that block needs. – tadman May 06 '16 at 19:57
2

usually & calls to_proc method of the object, such as gets.split.map(&:to_i) is used to read line of integers, which is the same as map { |e| e.to_i }

In method arguments, it appears in the last arguments, meaning the code block you passed to, check the following code for details.

def g
    puts yield "g"
end

def h(block)
    puts block.call "h"
end

def f(&block)
    puts block.class        # => Proc
    puts block.call "f"     # => hello f
    g &block                # => hello g       passed as code block
    h block                 # => hello h       passed as proc
end

f { |x| "hello " + x }
delta
  • 3,778
  • 15
  • 22
1

Following article provides a good explanation on the use of '&' in Ruby:

The Implicit Block Methods in Ruby can take arguments in all sorts of interesting ways. One case that’s especially interesting is when a Ruby method takes a block.

In fact, all Ruby methods can implicitly take a block, without needing to specify this in the parameter list or having to use the block within the method body e.g.:

def hello
end

hello do
  puts "hello"
end

This will execute without any trouble but nothing will be printed out as we’re not executing the block that we’re passing in. We can – of course – easily execute the block by yielding to it:

def hello
  yield if block_given?
end

hello do
  puts "hello"
end

This time we get some output:

hello

We yielded to the block inside the method, but the fact that the method takes a block is still implicit.

It gets even more interesting since Ruby allows to pass any object to a method and have the method attempt to use this object as its block. If we put an ampersand in front of the last parameter to a method, Ruby will try to treat this parameter as the method’s block. If the parameter is already a Proc object, Ruby will simply associate it with the method as its block.

  def hello
      yield if block_given?
    end

    blah = -> {puts "lambda"}

hello(&blah)
lambda

If the parameter is not a Proc, Ruby will try to convert it into one (by calling to_proc on it) before associating it with the method as its block.

def hello
  yield if block_given?
end

class FooBar
  def to_proc
    -> {puts 'converted lambda'}
  end
end

hello(&FooBar.new)
converted lambda

All of this seems pretty clear, but what if I want to take a block that was associated with a method and pass it to another method? We need a way to refer to our block.

The Explicit Block When we write our method definition, we can explicitly state that we expect this method to possibly take a block. Confusingly, Ruby uses the ampersand for this as well:

def hello(&block)
  yield if block_given?
end

hello do
  puts "hello"
end

Defining our method this way, gives us a name by which we can refer to our block within the method body. And since our block is a Proc object, instead of yielding to it, we can call it:

def hello(&block)
  block.call if block_given?
end

hello do
  puts "hello"
end

I prefer block.call instead of yield, it makes things clearer. Of course, when we define our method we don’t have to use the name ‘block’, we can do:

def hello(&foo)
  foo.call if block_given?
end

hello do
  puts "hello"
end

Having said that; ‘block’ is a good convention.

Nirupa
  • 787
  • 1
  • 8
  • 20