O Ampersand! my Ampersand! great op'rator indeed,
From boolean to bitwise ANDs, you're just the char I need,
Make procs from plain old Ruby blocks, cast symbols to_proc too,
Safe nil val' checks, set intersects, there's nothing you can't do;

O Ampersand! my Ampersand! you're mighty small but strong,
You make my code more elegant, I'm glad you've come along!

Boolean AND

Only used between boolean or nil operands:

true & true    # => true
true & false   # => false
false & false  # => false
nil & true     # => false

Bitwise AND

Only used between integer operands:

20 & 7  # => 4

###########################
# Binary conversions below:
###########################

20.to_s(2)  # => 10100
7.to_s(2)   # =>   111
4.to_s(2)   # =>   100

Logical AND

Used between any two objects:

Object.new && true  # => true
true && nil         # => false

Not to be confused with and. What's the difference?

Set intersection

[1, 2, 3, 4] & [3, 4, 5, 6]  # => [3, 4]

Nil-safe navigation

object&.foo&.bar

This is syntactic sugar for:

object && object.foo && object.foo.bar

Procs as blocks

def foo(array)
  array.each { |x| yield x }
end

my_array = [1, 2, 3]
my_proc = Proc.new { |x| puts x }

foo(my_array, &my_proc)

Here, foo's definition specifies one parameter (array) and uses the yield keyword, so an implicit block is required. However, the foo call in the last line passes in two arguments and no block! This works because the & prefix tells Ruby to expect a Proc and convert it from an argument to a block.

Blocks as procs

Normally, Ruby blocks passed to methods are anonymous (implicit). We can change that – i.e. reference a block inside a method via an explicit name – by using the & to convert the block to a Proc:

def foo(&block)
  block.call
end

foo { puts "Hello world!" }
def foo(arg1, &arg2)
  puts arg1
  arg2.call
end

foo("arg1") { puts "arg2 block" }

Even though explicit blocks have Proc#call available to them, they're also still callable via yield too:

def foo(&block)
  yield
end

foo { puts "Hello world!" }

Symbols as blocks

["foo", "bar"].map(&:upcase)    # => ["FOO", "BAR"]
[1, 2, 3, 4, 5].select(&:odd?)  # => [1, 3, 5]

Expanding on the previous sections, the above examples work because the Symbol#to_proc method is called when Ruby sees the & and receives a Symbol instead of the expected Proc. Symbol#to_proc then returns a proc that sends the method represented by that symbol to its calling object. Its actual implementation is written in C, but a Ruby implementation might look like this:

class Symbol
  def to_proc
    Proc.new { |obj, *args| obj.send(self, *args) }
  end
end

We can use substitution to show how this shorthand finally transforms back into the more familiar block syntax:

["foo", "bar"].map(&:upcase)
["foo", "bar"].map(&:upcase.to_proc)
["foo", "bar"].map(&Proc.new { |obj| obj.send(:upcase) })
["foo", "bar"].map(&Proc.new { |obj| obj.upcase })
["foo", "bar"].map { |obj| obj.upcase }

Keep in mind that this shorthand only works for functions with no arguments. That said, one blogger implemented a version that could accept arguments!