Secrets of the Standard Library - Paul Battley
None of these things are actually secrets, but Paul pointed out that he's been programming Ruby for quite some time, and only discovered some of the following relatively recently.
Diving straight in, what have we got...
Forwardable
Let's say we have an event, represented as an ActiveRecord
object...
class Event < ActiveRecord::Base
belongs_to :opportunity
end
...and an Opportunity
. If an Event
has an Opportunity
and an Opportunity
has an Organization
, you'll get the following methods on your objects:
opportunity.organization
event.opportunity
That means you could call:
event.opportunity.organization
Hold on though, it's bad form. We've just violated the law of Demeter (the gist of which is that you can play with your friends, but you shouldn't mess with your friends' friends). You could write a wrapper method on the Event class that would return organization for you, or you could use forwardable
:
require "forwardable"
class Event < ActiveRecord:: Base
extend Forwardable
belongs_to :opportunity
def_delegators :opportunity, :organization
def_delegator :opportunity, :organization, :opporunity_organization
end
open
You can use open
to open a file, or (if you require open-uri
) you can grab stuff off the net:
sample = open("http://google.co.uk") do |f|
puts f.read(1024)
end
You can also use open
to send all the output of your program through less
:
open("|less", "w") do |f|
80.times do |i|
f.puts "Line #{i}"
end
end
Here's a neat trick; use a pager if your program is used interactively:
if STDOUT.tty?
$stdout = open("|less", "w")
end
# send stuff to STDOUT
$stdout.close
Array#assoc and rassoc
These methods are handy for looking up stuff inside nested data structures:
data = [["cat", "kitten", "feline"],
["dog", "puppy", "caine"],
["bear", "cub", "ursine"]]
data.assoc("dog") # -> ["dog", "puppy", "caine"]
data.rassoc("kitten") # -> ["cat", "kitten", "feline"]
pack/unpack
unpack works on a string. You can do really clever stuff, such as reading a QT/MPEG4 atom header:
length, name = @io.read(8).unpack("Na4")
"N" means that you should read 4 bytes in big endian order. "a" Means you should read ascii text. 4 means you should read 4 of thing represented by the previous character.
You can pack it all back up again to produce binary output:
header = [1234, "moov"].pack("Na4")
You can also do unicode:
codepoints = "string".unpack("U*")
=> [115, 116, 114, 105, 110, 103]
The asterisk means "any number of", so you get any number of code points back from your string.
So if you know a code point you can get the right character, without knowing how to type it on your keyboard:
em_dash = [0x2014].pack("U") # emdash, apparently
Set
A set only keeps one copy of everything that you put in it, so it's a great way to track unique items. I liked this code for finding the set of vowel sequences that occur in a list of words:
This should come as no surprise, but you can also run set operations on your set objects:
require "set"
a = Set.new([:a, :b, :c])
b = Set.new([:a, :b])
a | b # union of the two sets
a & b # intersection (i.e. which items occur in both)
Soap (yuk)
If you have to do SOAP you want to do it in a way that makes it as easy as possible. It's pretty straightforward with the soap/wsdlDriver
in the standard library.
pp
pp
stands for "pretty print". It's a nice way to get a clean dump of a data structure in irb
.
Cool stuff. I need to spend some time getting my head around pack/unpack
...
More talks from Ruby Manor
- Browser Level Testing - Martin Kleppmann
- Data Visualisation with Ruby - Chris Lowis
- Denormalising Your Rails Application - Dan Lucraft
- gem that - James Adam
- Introduction to Rango - Jakub Šťastný
- Ruby and Cocoa - James Mead
- RubyGoLightly - Eleanor McHugh
- Short Order Ruby - Ben Griffiths
- Testing Third Party HTTP APIs - Richard Livsey and Bartosz Blimke
- The Joy of Painting with Ruby - Jason Cale
- Ruby Manor 2008 morning session and afternoon session