stupid ruby tricks

Nick Quaranto

Over the past few months of slinging Ruby here at thoughtbot, I’ve picked up quite a few stupid ruby tricks smart ruby techniques that really help out your code. If you’ve got your own, feel free to leave a comment.

Destructuring yielded arrays

def touch_down
  yield [3, 7]
  puts "touchdown!"
end

touch_down do |(first_down, second_down)|
  puts "#{first_down} yards on the run"
  puts "#{second_down} yards passed"
end

=> "3 yards on the run"
=> "7 yards passed"
=> "touchdown!"

At first glance, this barely looks like valid Ruby. But somehow, it just makes sense: it splits up the array. If you’re going to pull out the values of the array inside of the block, why not just do it when you’re defining the block-level variables? This doesn’t seem to work nicely (in 1.8.7 at least) for Hashes, though.

Pulling out elements of an array

>> args = [1, 2, 3]
>> first, *rest = args

>> first
=> 1

>> rest
=> [2, 3]

I knew about splitting up arrays before into individual arguments, but I didn’t know that you could easily get an array of the rest. Perhaps this is Lisp inspired?

The Hash#fetch method

>> items = { :apples => 2, :oranges => 3 }
=> items = {:apples=>2, :oranges=>3}

>> items.fetch(:apples)
=> 2

>> items.fetch(:bananas) { |key| "We don't carry #{key}!"}
=> We don't carry bananas!

This is just a nice little way to provide some default behavior that might be nicer than checking if the value exists in the hash first.

The Hash#new method with a block

>> smash = Hash.new { |hash, key| hash[key] = "a #{key} just got SMASHED!" }
=> {}

>> smash[:plum] = "cannot smash."
=> {:plum=>"cannot smash."}

>> smash[:watermelon]
=> {:plum=>"cannot smash.", :watermelon=>"a watermelon just got SMASHED!"}

This is a really neat way to cache unknown values for Hashes (read: memoization!) I also heard it’s awesome for implementing a Fibonacci sequence.

The Array#sort_by method

>> cars = %w[beetle volt camry]
=> ["beetle", "volt", "camry"]

>> cars.sort_by { |car| car.size }
=> ["volt", "camry", "beetle"]

So, Array#sort_by sorts based on the return value of the block. It’s like a built in #map and #sort that rules even more with some Symbol#to_proc magic.

The String#present? method

>> "brain".present?
=> true

>> "".present?
=> false

I’m sure most Rails developers know about blank? from ActiveSupport, but what about present?. Yeah, it blew my mind too. I like being as positive as possible in conditionals, so toss out those !something.blank? calls today and start using this.

About thoughtbot

We've been helping engineering teams deliver exceptional products for over 20 years. Our designers, developers, and product managers work closely with teams to solve your toughest software challenges through collaborative design and development. Learn more about us.