One thing I love about ruby is that mostly it is a very readable language (which is great for self-documenting code)
However, inspired by this question: Ruby Code explained
and the description of how ||=
works in ruby, I was thinking about the ruby idioms I don't use, as frankly, I don't fully grok them.
So my question is, similar to the example from the referenced question, what common, but not obvious, ruby idioms do I need to be aware of to be a truly proficient ruby programmer?
By the way, from the referenced question
a ||= b
is equivalent to
if a == nil || a == false
a = b
end
(Thanks to Ian Terrell for the correction)
Edit: It turns out this point is not totally uncontroversial. The correct expansion is in fact
(a || (a = (b)))
See these links for why:
Thanks to Jörg W Mittag for pointing this out.
The magic if clause that lets the same file serve as a library or a script:
if __FILE__ == $0
# this library may be run as a standalone script
end
Packing and unpacking arrays:
# put the first two words in a and b and the rest in arr
a,b,*arr = *%w{a dog was following me, but then he decided to chase bob}
# this holds for method definitions to
def catall(first, *rest)
rest.map { |word| first + word }
end
catall( 'franken', 'stein', 'berry', 'sense' ) #=> [ 'frankenstein', 'frankenberry', 'frankensense' ]
The syntatical sugar for hashes as method arguments
this(:is => :the, :same => :as)
this({:is => :the, :same => :as})
Hash initializers:
# this
animals = Hash.new { [] }
animals[:dogs] << :Scooby
animals[:dogs] << :Scrappy
animals[:dogs] << :DynoMutt
animals[:squirrels] << :Rocket
animals[:squirrels] << :Secret
animals #=> {}
# is not the same as this
animals = Hash.new { |_animals, type| _animals[type] = [] }
animals[:dogs] << :Scooby
animals[:dogs] << :Scrappy
animals[:dogs] << :DynoMutt
animals[:squirrels] << :Rocket
animals[:squirrels] << :Secret
animals #=> {:squirrels=>[:Rocket, :Secret], :dogs=>[:Scooby, :Scrappy, :DynoMutt]}
metaclass syntax
x = Array.new
y = Array.new
class << x
# this acts like a class definition, but only applies to x
def custom_method
:pow
end
end
x.custom_method #=> :pow
y.custom_method # raises NoMethodError
class instance variables
class Ticket
@remaining = 3
def self.new
if @remaining > 0
@remaining -= 1
super
else
"IOU"
end
end
end
Ticket.new #=> Ticket
Ticket.new #=> Ticket
Ticket.new #=> Ticket
Ticket.new #=> "IOU"
Blocks, procs, and lambdas. Live and breathe them.
# know how to pack them into an object
block = lambda { |e| puts e }
# unpack them for a method
%w{ and then what? }.each(&block)
# create them as needed
%w{ I saw a ghost! }.each { |w| puts w.upcase }
# and from the method side, how to call them
def ok
yield :ok
end
# or pack them into a block to give to someone else
def ok_dokey_ok(&block)
ok(&block)
block[:dokey] # same as block.call(:dokey)
ok(&block)
end
# know where the parentheses go when a method takes arguments and a block.
%w{ a bunch of words }.inject(0) { |size,w| size + 1 } #=> 4
pusher = lambda { |array, word| array.unshift(word) }
%w{ eat more fish }.inject([], &pusher) #=> ['fish', 'more', 'eat' ]