Lessons from WriteBook - Lesson 1 - Eloquent Ruby Snippets
Here is a snippet from 37 Signal’s Writebook code base. I’ve extracted it as a quiz for you:
# how would you convert this array:
color_array = ["black", "blue", "green", "magenta", "orange", "violet", "white"]
# into this hash:
color_hash = {"black"=>"black", "blue"=>"blue",
"green"=>"green", "magenta"=>"magenta",
"orange"=>"orange", "violet"=>"violet",
"white"=>"white"}
# and do so eloquently?
Answer:
%w[ black blue green magenta
orange violet white ].index_by(&:itself)
# => {"black"=>"black", "blue"=>"blue",
# "green"=>"green", "magenta"=>"magenta",
# "orange"=>"orange", "violet"=>"violet", "white"=>"white"}
Let’s break down the above:
- what does
%w
mean?? Results in an array of strings. - What does index_by mean? Basically it converts an enumerable into a hash.
itself
. I had never heard of that. But it is a ruby method which returns the object itself.
Shamelessly extracted from Basecamp’s Writebook, for your learning pleasure:
class Book < ApplicationRecord
# ...
enum :theme, %w[ black blue green magenta orange violet white ].index_by(&:itself), suffix: true, default: :blue
end
The only way of learning is by reading and implementing it yourself.
But why?
Why go through the bother? Check out the docs on enums.
Declare an enum attribute where the values map to integers in the database, but can be queried by name.
Enum values map to an integer. The problem begins if you start adding enums to the array.
- enum :theme, %w[ red white]
+ enum :theme, %w[ blue red white] # blue is added
If you add blue at the start of the array, then it’s value will be 0
be default. But if you have existing values saved in your database - then you will have completely screwed up your data. Check out the warning:
Note that when an array is used, the implicit mapping from the values to database integers is derived from the order the values appear in the array. In the example, :active is mapped to 0 as it’s the first element, and :archived is mapped to 1. In general, the i-th element is mapped to i-1 in the database.
Therefore, once a value is added to the enum array, its position in the array must be maintained, and new values should only be added to the end of the array. To remove unused values, the explicit hash syntax should be used.
The benefit of doing it the 37 Signals way - is that it is fool-proof. Now you can add any value to the enum, and be assured that it will not screw up your data. (At least that’s my theory on why this particular method was adopted).
Permissions
I have extracted snippets purely for pedagogical purposes. It is entirely possible that someone might object - because I have not sought permission to do so. I don’t think anyone will care, but hey, you never know.
Errors
If you spot an error, don’t be shy about pointing it out!
Hopefully you gained something!