Categories
Uncategorized

Enumerating Enumerable: Enumerable#find_all / Enumerable#select

Enumerating Enumerable

We’re at lucky number 13 — the thirteenth article in the Enumerating Enumerable series, which covers the methods of Ruby’s Enumerable module. I started this series after being disappointed with the documentation at Ruby-Doc.org.

In this article, I’m covering the find_all — a.k.a. select — method.

In case you missed any of the previous articles, they’re listed and linked below:

  1. all?
  2. any?
  3. collect / map
  4. count
  5. cycle
  6. detect / find
  7. drop
  8. drop_while
  9. each_cons
  10. each_slice
  11. each_with_index
  12. entries / to_a

Enumerable#find_all / Enumerable#select Quick Summary

Graphic representation of the \"find_all\" / \"select\" method in Ruby\'s \"Enumerable\" module

In the simplest possible terms Which items in the collection meet the given criteria?
Ruby version 1.8 and 1.9
Expects A block containing the criteria.
Returns An array containing the items in the collection that meet the given criteria. If no items in the collection meet the given criteria, this is an empty array.
RubyDoc.org’s entry Enumerable#find_all / Enumerable#select

Enumerable#find_all / Enumerable#select and Arrays

When used on an array, find_all and its synonym select passes each item from the array to the block, returning an array containing only those elements in the original array for which the block returns a value that doesn’t evaluate to false.

If no item in the array causes the block to return a value that doesn’t evaluate to false, find_all/select returns an empty array.

In the examples that follow (which are based on my examples for the detect/find method), I’ll be using the find_all method. select does exactly the same thing; it’s just that I prefer find_all.

# Once again,  I shall establish my "old fart" credentials
classic_rock_bands = ["AC/DC", "Black Sabbath", "Queen", \
"Ted Nugent and the Amboy Dukes", "Scorpions", "Van Halen"]
=> ["AC/DC", "Black Sabbath", "Queen", "Ted Nugent and the Amboy Dukes",
"Scorpions", "Van Halen"]

# Of the bands in the array, which ones have
# a name longer than 8 characters?
classic_rock_bands.find_all {|band| band.length > 8}
=> ["Black Sabbath", "Ted Nugent and the Amboy Dukes", "Scorpions", "Van Halen"]

# Which ones have a name exactly 5 characters long?
classic_rock_bands.find_all {|band| band.length == 5}
=> ["AC/DC", "Queen"]

# If no band in the array meets the criteria,
# find_all returns an empty array.
# Which ones have names shorter than 5 characters?
classic_rock_bands.find_all {|band| band.length < 5}
=> []

Enumerable#find_all / Enumerable#select and Hashes

When used on a hash, find_all/select passes each key/value pair in the hash to the block, which you can “catch” as either:

  1. A two-element array, with the key as element 0 and its corresponding value as element 1, or
  2. Two separate items, with the key as the first item and its corresponding value as the second item.

As with arrays, find_all/select passes each item from the hash to the block, returning an array containing only those items in the original array for which the block returns a value that doesn’t evaluate to false.

Note that each item in the result array is a two-element array corresponding to an item from the original hash. In this array, element 0 contains the key and element 1 contains the corresponding value.

If no item in the hash causes the block to return a value that doesn’t evaluate to false, find_all/select returns an empty array.

years_founded = {"AC/DC" => 1973, \
                 "Black Sabbath" => 1968, \
                 "Queen" => 1970, \
                 "Ted Nugent and the Amboy Dukes" => 1967, \
                 "Scorpions" => 1965, \
                 "Van Halen" => 1972}
=> {"AC/DC"=>1973, "Black Sabbath"=>1968, "Queen"=>1970,
"Ted Nugent and the Amboy Dukes"=>1967, "Scorpions"=>1965, "Van Halen"=>1972}

# Ruby 1.9 preserves hash order so that hashes keep the order in which
# you defined them, while Ruby 1.8 puts them in some mysterious order.
# All these examples are in Ruby 1.9

# Which bands were founded in 1970 or later?
years_founded.find_all {|band| band[1] >= 1970}
=> [["AC/DC", 1973], ["Queen", 1970], ["Van Halen", 1972]]

# Here's another way of phrasing it:
years_founded.find_all {|band, year_founded| year_founded >= 1970}
=> [["AC/DC", 1973], ["Queen", 1970], ["Van Halen", 1972]]

# Which bands were founded after 1980?
years_founded.find_all {|band, year_founded| year_founded > 1980}
=> []

Categories
Uncategorized

Sayonara, Cassettes

Pictured below is the death spasm of a recording format: the compact cassette (a.k.a. “cassette tape”), sitting on the bargain shelf at a drugstore somewhere in the U.S., its price reduced so that it’s one of the cheapest items in the store. Even gum is probably more expensive:

Maxell cassette tapes on sale
Photo courtesy of Miss Fipi Lele.

Here’s another death spasm: an invitation for a farewell party for the cassette held by the book publishing company Hachette, pictured below. Audiobooks were the cassette’s last domain, but in the age of the iPod and phones that double as MP3 players, they had become obsolete:

Hachette\'s invitation to a farewell party for the compact cassette
Image from the New York Times.
Click it to see the source story.


In the first half of the 1980s, the music formats available to a teenager were vinyl records and cassette tape (formally known in the industry as “compact cassette”). CDs hit the market in late 1982, but the first pressings were mostly of classical music and cost anywhere from $20 – $35, well out of the reach of most teenagers (remember, these are 1980s dollars!).

Vinyl was far cheaper: if you were smart and shopped downtown (as opposed to the record stores in the malls, where the prices were $2 – $5 higher), domestic albums sold for about $8 – $12 and imports, special releases and double albums went for about $12 – $18. They didn’t have the signal-to-noise ratio that CDs had, but on a good turntable on a half-decent sound system, you got better sound than a lot of downsampled MP3s playing on the budget speakers that came free with your computer.

Diagram showing the internals of a compact cassette
The internals of a compact cassette.

At the bottom of the hi-fi spectrum is the compact cassette. A clunky storage medium, it was often “hissy”, with a signal-to-noise ratio equivalent to listening to a jazz band in a small club while sitting near the air conditioner. The tape was prone to stretching from the stresses involved in both normal playback and more so with fast-forwarding and rewinding, especially in the case of the C120 (120 minute) cassette, whose tape had to be made thinner so that its reel would still fit inside the shell. Finally, there was its mechanical nature: it had actual moving parts whose quality would have a direct impact on your sound. A cheap shell, a wobbly reel, a misaligned guide roller or any combination thereof could make it sound worse.

In spite of all these disadvantages, it became an incredibly popular format. Cassettes were portable and handled jostling well, which made them perfect for car audio and the Walkman. They also represented the first time that most people could create what we now take for granted in the age of digital audio: the customized playlist in the form of the mix tape. If you were dating in the ’80s, making a mix tape was an important courtship ritual:

\"Breakup Girl\" on mix tapes
From the Breakup Girl comic, Mixed Messages.
Click the image to read the full comic.

Mix tapes didn’t make everyone happy: the record companies became quite concerned about people passing around copies of their music or making copies of their music for their car or Walkman and put up some campaigns to stop home taping, including the infamous “Home Taping is Killing Music” promotion:

Home taping is killing music
History proved this was a lie.

By the way, it turned out to be a lie, as the music industry boomed as home taping blossomed, and home taping for personal use is not illegal; it’s fair use.

For a while, sales of albums in cassette form surpassed those on vinyl or CD. The lesson to be learned from this is the same one that the MP3 format taught us: in spite of what the audiophiles will tell you, versatility and convenience trumps sound quality.

In the days before MP3s and MySpace, before CD-burning was available to the masses, the cassette was the only economical way for a small band to get their music into their audience’s hands. A number of bands got their start this way; one famous local example was the Barenaked Ladies’ “Yellow Tape”, pictured below, which many fans say featured better performances than those on the CD that followed after they got the record deal:

The Barenaked Ladies\' \"Yellow Tape\"
Now a collector’s item.

Finally there’s a way I used cassettes that you may have never encountered: as a storage medium for computer data. Back in the late 70s and early 80s, before 5 1/4″ floppy drives became cheap and ubiquitous, it was the preferred way to store your home computer’s programs and data. Even the original IBM PC used them:

Commodore \"datasette\" cassette recorder and \"computer\" cassettes
Slow but reliable: cassette tapes as computer data storage medium. Some synthesizers of the era also used cassette tape for data storage.

(Somewhere in my parents’ basement sits a pile of cassettes holding my high school programming assignments written on Waterloo Structured BASIC for the Commodore PET. I’m curious to see what the programs I wrote back then look like.)


I don’t miss the cassette: I rather like a world where my music is in digital form and moves frictionlessly from my iPod to my computer to my USB key and across the net (and sometimes onto my camera chip when there’s no other place to store it). I haven’t owned a cassette player in about 8 years — come to think of it, I don’t even own a stand-alone CD Player anymore. Still, I feel I should pay tribute to that clunky mechanical piece of tech that served me so well in my youth.

Maybe I’ll pick up that USB key that comes in mix tape-inspired packaging:

\"Mix Tape\" USB key

Categories
Uncategorized

Triumph the Insult Comic Dog at Comic Con 2008

Oh, the things that happen when Triumph the Insult Comic Dog gets set loose on Comic Con 2008! Notable encounters in the clip below include a run-in with PvP comic artist Scott Kurtz and one segment where a nerd with a puppet takes a page from Batman’s book and turns the tables on Triumph by harnessing the power of the uncomfortable silence:

For old times’ sake, here’s the classic video where Triumph takes on the lineup outside the premiere of Attack of the Clones:

Categories
Uncategorized

Enumerating Enumerable: Enumerable#entries / Enumerable#to_a

Enumerating Enumerable

We’re at the dirty dozen now — this is the twelfth entry in Enumerating Enumerable, my series of articles on the methods in that Ruby workhorse, the Enumerable module. In this article, I cover the entries method, also known as the to_a method. I myself prefer to_a to entries, as its meaning is more obvious.

In case you missed any of the previous articles, they're listed and linked below:

  1. all?
  2. any?
  3. collect / map
  4. count
  5. cycle
  6. detect / find
  7. drop
  8. drop_while
  9. each_cons
  10. each_slice
  11. each_with_index

Enumerable#entries / Enumerable#to_a Quick Summary

In the simplest possible terms Turns any collection into an array.
Ruby version 1.8 and 1.9
Expects Nothing.
Returns An array containing the collection's items.
RubyDoc.org's entry Enumerable#entries / Enumerable#to_a

Enumerable#entries / Enumerable#to_a and Arrays

Converting arrays into arrays isn't terribly useful, but it is possible. Note that the array returned is the same object as the original array!

names = ["alice", "bob", "carol"]
=> ["alice", "bob", "carol"]

new_names = names.to_a
=> ["alice", "bob", "carol"]

# Let's make a change to new_names
new_names[1] = "billy"
=> "billy"

new_names
=> ["alice", "billy", "carol"]

# entries / to_a, when used on an array returns the same object
# as the original array -- names and new_names are the same array!
names
=> ["alice", "billy", "carol"]

Enumerable#entries / Enumerable#to_a and Ranges

entries / to_a converts ranges into ascending-order arrays:

(1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

 ("aa".."az").to_a
=> ["aa", "ab", "ac", "ad", "ae", "af", "ag", "ah", "ai", "aj", "ak", "al",
"am", "an", "ao", "ap", "aq", "ar", "as", "at", "au", "av", "aw", "ax", "ay", "az"]

Enumerable#entries / Enumerable#to_a and Hashes

When used on a hash, entries / to_a creates an array made up of the items in the hash, converting each hash item into a two-element array, where the first element is the key and the second element is the corresponding value.

names = {:sender => "Alice", :receiver => "Bob", :man_in_the_middle => "Carol"}
=> {:sender=>"Alice", :receiver=>"Bob", :man_in_the_middle=>"Carol"}

names.to_a
=> [[:sender, "Alice"], [:receiver, "Bob"], [:man_in_the_middle, "Carol"]]

Categories
Uncategorized

Build Status Interfaces

Having a continuous integration system is nice, but what’s even nicer is if that system has a really clear way of telling you whether the build is working. Last.fm weren’t happy with build status messages on the command line and went the extra mile to set up these illuminated bears:

Last.fm\'s red, yellow and green \"build bears\"

Last.fm’s Adrian Woodhead writes:

These 3 bears sit in a prominent position and watch our developer’s every move. When things are good we have a green bear gently glowing and purring, when changes are being processed a yellow bear joins the party, and if the build gets broken the growling evil red bear makes an appearance. The developer who broke things usually goes a similar shade of red while frantically trying to fix whatever was broken while the others chortle in the background.

I’ve been meaning to get back into a little hardware hacking (something I haven’t done since I was a teen) and learn how to build computer-driven gizmos like Last.fm’s bears. In the meantime, I’ll have to satisfy myself by page-slapping the development team at b5 with these images created by Big Swinging Developer

You Broke the Build!

\"You broke the build!\" graphic

“Builds on My Machine…”

\"Builds on my machine\" graphic

Where’s the Build?

\"Where\'s the build?\" graphic

Categories
Uncategorized

Enumerating Enumerable: Enumerable#each_with_index

Enumerating Enumerable

Here’s number 11 in the Enumerating Enumerable series, in which I’m trying to outdo RubyDoc.org in their documentation of Ruby’s key Enumerable module. In this article, I cover the each_with_index method.

In case you missed the earlier articles, they’re listed and linked below:

  1. all?
  2. any?
  3. collect / map
  4. count
  5. cycle
  6. detect / find
  7. drop
  8. drop_while
  9. each_cons
  10. each_slice

Enumerable#each_with_index Quick Summary

Graphic representation of the \"each_with_index\" method in Ruby\'s \"Enumerable\" module

In the simplest possible terms Think of each_with_index as a version of each that includes an extra piece of information: a number representing the current iteration’s element’s position in the collection.
Ruby version 1.8 and 1.9
Expects An optional block to receive the values from each iteration.
Returns
  • The original collection, if used with a block.
  • An Enumerator object that outputs the collection’s items and indexes, if used without a block.
RubyDoc.org’s entry Enumerable#each_with_index

Enumerable#each_with_index and Arrays

When used with on an array and given a block, each_with_index iterates through the array, passing each item in the array and the number representing its order in the array to the block. Once again, I’ll use the “Justice League” example:

justice_league = ["Aquaman", "Batman", "Black Canary", \
                  "Flash", "Green Arrow", "Green Lantern", \
                  "Martian Manhunter", "Superman", \
                  "Vixen", "Wonder Woman"]
justice_league = ["Aquaman", "Batman", "Black Canary", "Flash", "Green Arrow",
"Green Lantern", "Martian Manhunter", "Superman", "Vixen", "Wonder Woman"]

justice_league.each_with_index {|member, index| puts "#{index}: #{member}"}
=> 0: Aquaman
1: Batman
2: Black Canary
3: Flash
4: Green Arrow
5: Green Lantern
6: Martian Manhunter
7: Superman
8: Vixen
9: Wonder Woman
=> ["Aquaman", "Batman", "Black Canary", "Flash", "Green Arrow", "Green Lantern",
"Martian Manhunter", "Superman", "Vixen", "Wonder Woman"]

Note that unlike the each_cons and each_slice, each_with_index doesn’t return nil, but the original array, just like each does. each_cons and each_slice are newer methods that were introduced in Ruby 1.9; perhaps Matz and company decided that it made more sense for “each” methods to return nil from now on. each and each_with_index have return the original array as they always have, since making changes to these methods might break a lot of existing Ruby code. Hooray for those little inconsistencies that creep into every programming language!

Enumerable#each_with_index and Hashes

When used with on a hash and given a block, each_with_index iterates through the hash, converting each item in the hash into a two-element array (where the first element is the key and the second element is the corresponding value), and then passing that array and the number representing its order in the original array to the block. Once again, I’ll use the “Enterprise Crew” example:

enterprise_crew = {:captain => "Picard",
                   :first_officer => "Riker",
                   :science_officer => "Data",
                   :tactical_officer => "Worf",
                   :chief_engineer => "LaForge",
                   :chief_medical_officer => "Crusher",
                   :ships_counselor => "Troi",
                   :annoying_ensign => "Crusher",
                   :attractive_ensign => "Ro",
                   :expendable_crew_member => "Smith"}
=> {:captain=>"Picard", :first_officer=>"Riker", :science_officer=>"Data",
:tactical_officer=>"Worf", :chief_engineer=>"LaForge",
:chief_medical_officer=>"Crusher", :ships_counselor=>"Troi",
:annoying_ensign=>"Crusher", :attractive_ensign=>"Ro",
:expendable_crew_member=>"Smith"}

enterprise_crew.each_with_index {|member, index| puts "#{index}: #{member}"}
=> 0: [:captain, "Picard"]
1: [:first_officer, "Riker"]
2: [:science_officer, "Data"]
3: [:tactical_officer, "Worf"]
4: [:chief_engineer, "LaForge"]
5: [:chief_medical_officer, "Crusher"]
6: [:ships_counselor, "Troi"]
7: [:annoying_ensign, "Crusher"]
8: [:attractive_ensign, "Ro"]
9: [:expendable_crew_member, "Smith"]
=> {:captain=>"Picard", :first_officer=>"Riker", :science_officer=>"Data",
:tactical_officer=>"Worf", :chief_engineer=>"LaForge",
:chief_medical_officer=>"Crusher", :ships_counselor=>"Troi",
:annoying_ensign=>"Crusher", :attractive_ensign=>"Ro",
:expendable_crew_member=>"Smith"}

Enumerable#each_with_index Oddities

Blocks with a Single Parameter

What happens if you use each_with_index with a block that has only one parameter? You’d think that the block would accept the item and index passed to it as a two-element array, with the item as the first element and the corresponding index as the second element, but that’s not the case:

# For each item in justice_league, this line will output the following:
# {second letter of member's name} : {first letter of member's name} 
justice_league.each_with_index {|member| puts "#{member[1]}: #{member[0]}"}
=> q: A
a: B
l: B
l: F
r: G
r: G
a: M
u: S
i: V
o: W
=> ["Aquaman", "Batman", "Black Canary", "Flash", "Green Arrow", "Green Lantern"
, "Martian Manhunter", "Superman", "Vixen", "Wonder Woman"]

When each_with_index passes an item and its index to a block that takes only one parameter, the item goes into the paramter, and the index is discarded. Simply put, in this case, each_with_index behaves just like each.

Without a Block

What happens if you use each_with_index without a block to create an Enumerator object that spits out the next item when its next method is called? This:

hero = justice_league.each_with_index
=> #<Enumerable::Enumerator:0x159cb98>

hero.next
=> "Aquaman"

hero.next
=> "Batman"

hero.next
=> "Black Canary"

Note that calling next only yields the next item in the collection; the index information is lost. In this case, each_with_index behaves just like each.

Categories
Uncategorized

RubyFringe was Profitable, People are Happy, and the Sky Didn’t Fall. What Now?”

Collage of images from the RubyFringe summary article at \"Rethink\"

Over at Rethink, the blog of Accordion City-based development shop Unspace, Pete Forde shares his thoughts on the RubyFringe conference in an articles titled RubyFringe was Profitable, People are Happy, and the Sky Didn’t Fall. What Now?”.

The article covers all kinds of things including:

  • A loving poke at RailsConf (“A 400 person conference doesn’t become better with 1600 people, but if you’ve already done the hard work, why not scale up?”). That’s a reference to RailsConf 2006 and 2007.
  • The number of attendees (something that I’m going to cover in an article very soon)
  • Why they might not do another RubyFringe (think of all the movie sequels you’ve ever seen)
  • Women and tech conferences
  • You can hold a conference without sponsors (well, Engine Yard helped foot the bill for a party)
  • Consider going with just a single track
  • Just as Obie said that you shouldn’t undercharge for your services, you shouldn’t undercharge for a conference. Charge what it costs, and deliver real value
  • “Great food is important, because nobody can focus for fifteen hours on cold boxed lunches.” And RubyFringe had great food.
  • Care about the details! “This cannot be overstated, and the key word here is care.”

Meghann Millard of Unspace
Meghann Millard, RubyFringe cat herder supreme.

Pete said it in his article, and I feel it bears repeating: Meghann did an amazing job herding cats for RubyFringe, and if you attended RubyFringe and have a little cash to spare, it might be a nice idea to send her some flowers (or an Amazon gift certificate) for all the work she put in. I owe her big-time for thinking of me when she was looking for a host for the Friday night opening events as well as an emergency host when FAILCamp needed one. Thank you, Meghann! I salute you with a filet mignon on a flaming sword!

As for Pete thanking me for the RubyFringe guides and notes from the conference: it was my pleasure. I believed in the event from the get-go and was only too happy to apply the Burning Man ethos to this event (“There are no spectators, only participants”). Besides, that’s what we in the Accordion City tech community do!

If you’re thinking about putting together a tech conference, you should steal as many ideas as you can from RubyFringe, and Pete’s article is a good starting-off point.