Using the Ruby block shortcut with arguments

Updated . Posted . Visible to the public.

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

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.

Dominik Schöler
Last edit
Dominik Schöler
License
Source code in this card is licensed under the MIT License.
Posted by Dominik Schöler to makandra dev (2018-06-08 12:37)