Seven Ruby Tricks for the Curious Developer

Alexey Nikolaev

Software Developer @ Smartly.io

Engineering

I want to share some of Ruby tricks with you that I have collected over the past few years. I hope that I’ll be able to add a few bits of new knowledge to your current Ruby toolkit.

I dare you try to solve these seven challenges without any documentation or irb at first. All code in this blog post is intended to be run using Ruby 2.5.0 or  a more recent version.

0. ?!

To warm up, you can try to guess whether this Ruby code is valid or not — 

?!

You may think this is one of these mysterious global variables in Ruby, but actually this is something quite different.

If you type this code 

?!

in irb it returns

"!"

“?” is Ruby literal that was used as a method to get ASCII code for character prior to Ruby 1.9, in the newer version of Ruby this literal converts a character to a string.

This is the quickest way in Ruby to create a one character string, and it can be used for example like this:

`[*?a..?z]`


1. IIFE

IIFE stands for Immediately-invoked function expression, which is a popular pattern from Javascript world. It might also come very handy in Ruby.

The closest example looks like this:

(->{ puts "Hey, I'm IIFE" }).()

Admittedly, his code doesn’t look very useful. However, immediately-invoked method can be more valuable in other ways.

You might know that method definition returns method name as a symbol, and it means that we can use it like this:

send def execute_right_now
  puts "That's nice!"
end

So, basically every method that accepts the method name as an argument can be rewritten as:

some_method def another_method; end

For example, in Rails, it can be used to define a helper method in the controller:

class RailsController 
  helper_method def current_user
    User.current
  end
end

It looks a bit unorthodox—but it’s a trick!


2. Continue method execution after the return statement

We tend to think that the return keyword always returns control back to the context of the method call, but actually we can still continue method execution if we want to. Here’s how: "ensure"block will be called just after "return" statement:

send def escape
  return "I want to return"
ensure 
  puts "print this text first"
end

Output looks like this:

print this text first
=> "I want to return"

It’s also possible to add a second return keyword to the ensure block and override the returned value:

send def escape
  return "I want to return"
ensure 
  return "I want to finally get out"
end

=> "I want to finally get out"


3. How to return more than one value from the method without explicitly wrapping it into a data structure?

It’s a pretty simple question, but as  developers we rarely think of how much of syntactic sugar in Ruby goes unnoticed. 

As an example, imagine that you have a method “authorize”  that should return a status and some message with it. How would you write this method without wrapping it into an array like this “[status, message]”.

The solution is really easy, you just need to add an explicit “return” and pass multiple arguments to it separated by a comma:

status, reason = send def authorize
  response = do_request   
  if response.success?
    return :ok, response.body
  else
    return :error, response.error
  end
end

Internally Ruby wraps these values into an array anyway, so for developers it works in the same way if you do this:

return [:ok, response.body]
# or 
[:ok, response.body]


4. Create infinitely recursive lambda

Imagine that we want to have lambda that will return the same lambda after every call.

For example:

go_deeper.call.call.call.call.call.call.call.call

You can try to implement it yourself. Your code will look like this:

(go_deeper = -> { puts "deeper"; go_deeper }).call.call.call.call.call

It doesn’t do anything useful (yet), but it’s important to understand how the simplest implementations work in order to do something useful.


5. Infinitely nested Hash!

I guess you already know this Ruby snippet for Hash with default value:

h = Hash.new {|h, k| h[k] = Hash.new }

In this example, it returns a new hash for any given key, but it’s only one level deep which is not enough if need data structure with arbitrary deepness.

Hash instance has /#default_proc method that returns block passed to this hash initially which allows us to create hashes recursively.

h = Hash.new {|h, k| h[k] = Hash.new(&h.default_proc) }
h[:this][:is][:really] = 'Amazing!'; h
=> {:this=>{:is=>{:really=>"Amazing!"}}}

This pattern can be easily implemented for any data structure and may be useful, for example, to store parsed XML documents or create Tree-like structures.


6. Pass block to a method without explicitly capturing it to a variable

This is my favorite trick in the list and it took me some time to figure out how it actually works. I found it in the source of one popular ruby gem called Faraday. It uses this code to build a connection object for request and passes block to the builder:

def new(url = nil, options = nil)
  block = block_given? ? Proc.new : nil
  options = options ? default_connection_options.merge(options) : default_connection_options
  Faraday::Connection.new(url, options, &block)
end

And it should be used like this:

conn = Faraday.new(:url => 'http://sushi.com') do |faraday|
  faraday.request  :url_encoded             # form-encode POST params
  faraday.response :logger                  # log requests to STDOUT
  faraday.adapter  Faraday.default_adapter  # make requests with Net::HTTP
end

As you can see, `Faraday::Connection` expects to receive a block as a parameter for constructor, but the parent method doesn’t contain any reference to the block, and instead it creates `Proc.new` and assigns it to the block variable :|. Here’s how it works.

Proc.new

Creates a new Proc object, bound to the current context. Proc::new may be called without a block only within a method with an attached block, in which case that block is converted to the Proc object.

From Ruby docs: Class: Proc (Ruby 2.5.0)

This means Proc.new implicitly captures the block if it’s given to the method.

But why this code was written this way seven years ago? It would be much easier just to add &block to the method signature and then pass it to the child method. For sure, this advanced technique exists for a reason—and that reason is performance.

Proc creation is considered an expensive operation in Ruby and when you pass &block as a parameter to a method, it always creates a new Proc, even if doesn’t pass the actual block.

So, for the sake of performance, you can check if a block is given, and then capture the block with Proc.new. This definitely decreases the readability of the code, but don’t rush to refactor your code just yet. Ruby 2.5 comes to the rescue and there is no need for this kind of optimization anymore!

You can read more about what changed in Ruby 2.5 here:

Lazy Proc allocation for block parameters

And here you can see benchmarks results:

Ruby benchmark 2.4 vs 2.5: Lazy Proc allocation for block parameters  · GitHub


That's all for now, folks!

I hope these tricks were useful for you and now you feel that you know a bit more about Ruby.

Like most professional developers, I usually try to avoid using any tricks in my own code to keep it simple and follow the principle of least surprise. Still, knowing these underlying details always helps to read and understand the code.

What are your favorite tricks and tips in Ruby? Share them in the comments!

Alexey Nikolaev Alexey Nikolaev

Software Developer @ Smartly.io