Read more

Using the Ruby block shortcut with arguments

Dominik Schöler
June 08, 2018Software engineer at makandra GmbH

Ruby has this handy block shortcut map(&:to_i) for map { |x| x.to_i }. However, it is limited to argument-less method invocations.

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

To call a method with an argument, you usually need to use the full block form. A common and annoying case is retrieving values from a list of hashes (imagine using a JSON API):

users = [ { name: 'Dominik', color: 'blue' }, { name: 'Stefan', color: 'red'} ]
names = users.collect do |user|
  user[:name]
end

If you're using Rails 5+, this example is covered by Enumerable#pluck (users.pluck(:name)). But with a little extension, you can have this for any method:

Block shortcut with arguments

By defining Symbol#with, you can start passing arguments to the short block form. (Ruby 2.7+ syntax)

class Symbol

  def with(...)
    ->(caller, *rest) {
      caller.send(self, *rest, ...)
    }
  end
  
end

Using Array#dig Show archive.org snapshot and Hash#dig Show archive.org snapshot , we can now do this:

users = [ { name: 'Dominik', color: 'blue' }, { name: 'Stefan', color: 'red'} ]
names = users.collect &:dig.with(:name)

Note that this example is very well suited for working with JSON, where you're usually collecting values at a certain path through the JSON data structure. This is what #dig was designed for. Example: projects.collect &:dig.with(:company, :tags, 0, :name) will call project[:company][:tags][0][:name] for each project and collect the results.


Credits to the linked StackOverflow question.

Posted by Dominik Schöler to makandra dev (2018-06-08 14:37)