Cool ruby tricks
Here are a few ruby tricks I’ve collected over the years. They’ve all been tested with ruby 2.5.
Dynamically prefilled array
You’ve probably used:
Array.new(4)
=> [nil, nil, nil, nil]
or even:
Array.new(4, '*')
=> ["*", "*", "*", "*"]
But did you know you can dynamically prefill an array:
Array.new(4) { rand 42 }
=> [33, 14, 13, 18]
or even use the element index to fill the array:
Array.new(4) { |index| 2**index }
=> [1, 2, 4, 8]
Create a new hash from an array
If you have an array:
arr = [:key_1, 'value 1', :key_2, 'value 2']
you can create a hash from this array by doing:
Hash[*arr]
=> {:key_1=>"value 1", :key_2=>"value 2"}
Of course, if you have an array of arrays like: [[:key_1, 'value 1'], [:key_2, 'value 2']]
in ruby 2.1+, you can convert it to a hash with:
[[:key_1, 'value 1'], [:key_2, 'value 2']].to_h
=> {:key_1=>"value 1", :key_2=>"value 2"}
Boolean operator with non-Boolean variables
var_1 ||= 'foo'
assigns 'foo'
to var_1
if var_1
had a “falsy” value, but do you know what var_1 &&= 'bar'
does?
var_1 &&= 'bar'
=> nil
var_1 = 'foo'
=> "foo"
var_1 &&= 'bar'
=> "bar"
It’s the opposite! It assigns a new value to var_1
if it had a “truthy” value.
A more useful example is:
var_1 = 'foo'
var_1 &&= var_1 + 'bar'
=> "foobar"
which is equivalent to var_1 = var_1 + 'bar' if var_1
Quick HTTP server
Python is known to be able to start an HTTP server in one line (e.g.: python -m http.server 8000
). Well, you can do the same in ruby:
ruby -run -e httpd . -p 8000
This starts an HTTP WEBrick server on port 8000. It serves the files in the current directory and sub-directories and you can monitor the HTTP requests from the command line.
Source: @n0kada and @tenderlove on Twitter.
Hash#fetch
If you have a hash h = { key_1: 'value 1', key_2: 'value 2' }
, you can access 'value 2'
by calling h.fetch(:key_2)
, but obviously you could simply call h[:key_2]
. However, another use of Hash#fetch
is how to treat missing keys by passing a block to it:
h[:key_3]
=> nil
h.fetch(:key_3) { |key| "#{key} is missing" }
=> "key_3 is missing"
Unitary operation on a list
This one is a bit niche and not quite as readable:
[0, 1, -2, 8, -42].map(&:-@)
=> [0, -1, 2, -8, 42]
[true, false, true, true, false].map(&:!@)
=> [false, true, false, false, true]
works too. You got the idea.
More common tricks
Extract nested hash values
{ a: { b: { c: 'value' } } }.dig(:a, :b, :c)
=> "value"
{ a: { b: { c: 'value' } } }.dig(:a, :missing, :c)
=> nil
Extract a value in a String with a regex
"Lorem ispum 'value 1' dolor sit amet"[/'.+'/]
=> "'value 1'"
Safe navigation operator
Added in ruby 2.3, it safeguards against the following:
var_1 = nil
var_1.length
# raises NoMethodError (undefined method `length' for nil:NilClass)
var_1&.length
=> nil
You can also “navigate” safely with it:
var_1 = nil
var_1&.length&.to_s
=> nil
Underscore
I use that one with ruby REPLs a lot.
Let’s say you run the following in IRB:
BlackBox.compute
=> 42
You didn’t save the return value. Instead of having to recompute the value with var_1 = BlackBox.compute
, you can simply use the underscore variable _
:
BlackBox.compute
=> 42
var_1 = _
=> 42
_
contains the last return value.