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.