3
OCT2008
I'm Addicted to the Word Array
Continuing with my recent trend of showing of fun uses of Ruby syntax, I have a confession to make: I'm addicted to Ruby's "word Array
." I really am.
I suspect most of you know this, but the word Array
is a shortcut that can lessen the quote-comma-quote syndrome of simple a simple Array
like:
["a", "wordy", "Array"]
You can create the same Array
with the word Array
syntax:
%w[a wordy Array]
That's essentially just a String
that will automatically be split()
on whitespace to build an Array
. You can use any amount of space any place you like, so you can layout the data in whatever way makes the most sense for you:
require "pp"
pp %w[ one two three
four five six
seven eight nine
zero ]
# >> ["one",
# >> "two",
# >> "three",
# >> "four",
# >> "five",
# >> "six",
# >> "seven",
# >> "eight",
# >> "nine",
# >> "zero"]
Note that you can chose the punctuation characters used at either ends of the Array
, some of which are paired while others just repeat:
%w(a wordy Array)
%w{a wordy Array}
%w<a wordy Array>
%w!a wordy Array!
%w%a wordy Array%
%w#a wordy Array#
I tend to just stick with %w[ … ]
though because I like how it parallels the [ … ]
for a normal Array
. It's pretty smart too and will allow nested brackets, as long as they are paired properly:
p %w[ [[]] abc[1] [start end] ]
# >> ["[[]]", "abc[1]", "[start", "end]"]
With just that much, this feature is crazy useful. Here are examples with Rails validations and filters, platform-safe relative path building, and simple iteration just to give you some ideas:
STATUSES = %w[Pending Requested Booked Declined Submitted]
validates_inclusion_of :status, :in => STATUSES
before_filter :find_user, :only => %w[show edit update destroy]
$LOAD_PATH << File.join(File.dirname(__FILE__), *%w[.. lib])
Card = Struct.new(:face, :suit)
cards = [ ]
%w[heart spade club diamond].each do |suit|
%w[A 2 3 4 5 6 7 8 9 T J Q K].each do |face|
cards << Card.new(face, suit)
end
end
Everyone of those examples was pulled out of real code I've written. I'm a serious 12 stepper on this issue.
That's the basics. However, like most delights in Rubyland, the word Array
hides some lesser known surprises. First, did you know that you can embed entries with spaces in them?
SORT_OPTIONS = %w[ Default
Name
Price
Average\ Rating ]
p SORT_OPTIONS
# >> ["Default", "Name", "Price", "Average Rating"]
As you can see, a simple backslash escapes spaces. Now this is a technique you can definitely abuse and if you find yourself escaping every other space, you should probably just break down and build a normal Array
. This is great for the occasional multiword entry though.
It doesn't stop there either. Remember when I said the word Array
is essentially a String
? Well, you can even mix in some interpolation, if you switch to the capital W
:
MODE = Object.const_defined?(:Test) ? :test : :data
PATH = File.join(File.dirname(__FILE__), *%W[.. .. #{MODE} db.sqlite])
This is code from a trivial SQLite wrapper I made. It determines what MODE
to run in with a simple test that will pass after Test::Unit
has been loaded. It then builds a PATH
to the database using the selected MODE
. It's interpolation in the word Array
that makes that easy to do.
It's probably worth mentioning that interpolated values are not subject to internal splitting:
var = "three four"
ary = %W[one two #{var}]
p ary
# >> ["one", "two", "three four"]
The capital W
version supports some other String
escapes as well, though I confess that I've never made use of this:
p %W[\t \x20 \n]
# >> ["\t", " ", "\n"]
Well, that's all the word Array
goodness I can pack into a single blog post. Hopefully you are sold and I'll be seeing a lot more of you at the Word Array
Anonymous User meetings.
Comments (1)
-
Dan Manges October 5th, 2008 Reply Link
I like
%w
for rake task dependencies.task :foo => %w[db:prepare some:other:task]