jlaine.net

Build Your Green Home

The “summer project” for Rod, me and Loren, EcoHomeResource is now live. The site is a hub of information and news for everyone wanting to build a green home or to make their current apartments more eco-friendly.

My dream has for quite some time (since reading Natural Capitalism and Cradle to Cradle, to be exact) been to build us a carbon-positive home, so the project has been spot-on for me.

The actual blog/CMS is using Movable Type but the backend database for products and companies is built on Merb and Datamapper. The integration of the platforms has definitely been a challenge but the decision to use separate pieces loosely joined by web services gives us a chance to reuse the database easily in the future if need be.

Playing around with new tools such as Merb, DM and jQuery (and, err… perl) has been really educational and fun. The project also gave us a chance to help hone open source products such as Datamapper even further.

If you’re building a new house, renovating your existing home, or just looking for tips to be more eco-efficient with what you already got, go and check out EcoHomeResource! You won’t walk out empty-handed.

Unplugged

Early last year I was shopping for in-canal earplugs because I wanted a pair of reasonably sound-isolating plugs that stay in my ears, even when running or biking. The standard iPod plugs are not meant for me. Even if I could stand the sound quality (which I don’t), all I have to do is to lean my head on one side and the earplug drops on the ground. The same goes pretty much for all the “normal” earplugs, thus I needed more drastic measures.

My first idea was to buy a pair of Sennheiser CX300 plugs, cause I’d had a couple of different Sennheisers in the past and been fairly happy with all of them. James proposed that I’d get Shure E2C’s instead; he’d used both and thought the Shures were vastly superior, sitting tighter in the ear and being better sound-isolating. I believed him and ordered a pair from Amazon.co.uk, which he then brought to our Caboose meetup in Paris.

In general I’ve been very happy with the earphones. They sound great, pretty much as good as my Sennheiser PX200 headphones. And most of all, after you find the best fitting sleeve for your ear (they come with a selection of sleeves), they sit in your ear like plague.

However, while the Shures have worked really well in sometimes fairly rough use, their cables haven’t stood up the use as well. The rubber covering the cable first started cracking from behind my ears, and now there are even more cracks where the protective metal coil comes out of the cable covering.

Yesterday’s tweet by lazyatom finally pushed me over the edge to ask for a replacement. I started with the Finnish distributor even though I bought the pair from UK, just to try out my luck. And lucky I was (unlike some others). The distributor promised to send me a replacement pair if I’d just mail them the phones. They’re now in the mail, fingers crossed that I’ve got a new pair soon. Kudos for that to Noretron.

In July, when we jumped on a train for our honeymoon in Norway, I forgot my E2C’s back home. Two weeks without earplugs just couldn’t do, so I went shopping in the airport to see if they’d have some good alternatives on sale. One reasonably priced model that looked liked it would fit the bill was Koss The Plug. Priced at less than €20, I figured I wouldn’t lose much even if they wouldn’t turn out to be good. Which they didn’t.

While The Plugs sit fairly well inside the ear canal, the foam plug is the only thing keeping them in place. The Shures, no the other hand, have the earphone body sitting inside the earlobe as well, and the cable going behind the ear. So sooner or later gravity will pull The Plug out of the ear, and that moment comes very soon if you’re both sweating and moving at the same time.

The biggest problem with the Koss plugs, however, is that (at least with my iPod Shuffle) they somehow hugely amplify the silent humming caused by a player when it’s on. That causes the phones to be nearly unusable on lower volumes, e.g. when I listen to a podcast before falling asleep. With the lowest volume I can hardly hear the voice of the hosts from the humming. This is a problem I haven’t encountered with any other pair of plugs, including the ones coming with iPods. Thus I don’t recommend buying The Plugs even though they are cheap. Cough up a few dozen bucks more and get a good pair of Shures instead. I’m at least eagerly waiting for my replacement Shure buds, that’s how big the difference between the two is.

A Week of Ruby/Rails/BDD/Ajax Training in December

After my last Ruby on Rails workshop held last year I’ve often been asked when there is going to be another one. Here it comes.

December 1st to 5th, we will join forces with Antti Tarvainen from Leonidas and give a week of one-day workshops in Helsinki with separate but closely related themes:

  1. Beginning Ruby
  2. Beginning Rails
  3. Advanced Ruby
  4. BDD on Rails
  5. Advanced Ajax on Rails

You can choose as many of the days to attend to as you want to (a smörgåsbord if I may), but if you will join us for the whole week, the last day will be on us. The early bird price is 500€/day, with group and alumni discounts available. The price includes a plentiful lunch buffet (of course), kick-ass course materials and some goodies we’ll disclose a bit later. The course will be held in Finnish.

I’m really excited about the course. The last time I gave a Ruby workshop was real fun and I learned a ton from it. One thing I understood while attending Pragmatic Studios is that having more than one teacher really makes a big difference, since instead of a monologue you give the students a real discussion about the topics. I know Antti from a while back and know from his classes at TUT that he’s a great instructor, so I really look forward to being able to teach together with him.

Read more and register yourself for the classes from our brand-new Rapids Training website. Hope to see you all in December!

Making Emacs Keybindings Work With Zsh and Screen

I’ve always (as in from the early OpenACS days) been an emacs guy on linux. Sure, I do most of my development on TextMate these days, but for all text editing on servers I still prefer emacs and have its keybindings tattooed deep in my brain:

Ctrl-a Beginning of line
Ctrl-e End of line
Ctrl-k Kill the rest of the line

Of course, these are the default bindings in bash as well.

However, I’m using GNU screen to stay sane while working over unreliable server connections. Screen uses Ctrl-a by default as its escape key so to make it work correctly, I’ve had this in my .bash_profile files for a long time:

alias scr="TERM=vt100 ; screen -e^Oo"
alias scd="TERM=vt100 ; screen -d -r"

That makes (among other things) Ctrl-o to be the escape key binding and lets Ctrl-a do the thing it’s supposed to do.

However, I’ve heard so much talk about zsh from many directions lately, that I had to try it out myself. With zsh (.zshrc downloaded from here) the keys worked fine without screen, but within a screen session they broke. Here’s what I had to do to make everything work.

First, setting the default escape key in the screen alias command didn’t work. I had to do it in the ~/.screenrc file instead:

escape ^Oo
startup_message off

(The second line just turns off the annoying splash screen)

However, with this and the default key bindings Ctrl-a and friends still didn’t work in screen, they were just output as literals on the screen. Some determined googling finally turned up the key (pun unintended) to the puzzle:

bindkey -e

Adding that one line into my .zshrc among the other keybindings solved the problem. Now I’m one happy zsh+screen camper, although my journey is still at a very early stage and I’m yet to learn the more advanced zsh goodies. The nice thing has been that without learning really anything new (or changing any habits), I’m still benefiting from using zsh.

From Rails Ajax Helpers to Low Pro, Part 3 (+ Some Announcements)

This is the third part of my introduction to Low Pro series, something that has been taken… hmmm… a while. The two first parts can be found here:

Coincidentally, all these pieces are also part of my new ebook, Unobtrusive Prototype, straight from the Peepcode oven. If you liked the articles, you might really enjoy the book. It will have all the code rewritten for Rails 2.1 (as has this article btw), it is professionally edited unlike my rumblings here, and has a much wider coverage of Low Pro, including writing your own Behaviors and event delegation.

I also managed to give a tutorial on the topics covered in the book in RailsConf Europe in Berlin last week. The tutorial slides can be found at Slideshare, where they also got a short featured treatment.







I moved the sample code for the articles and the book to my GitHub account. The Chapter 5 branch should be pretty much where this article starts at. If you’re not into git (yet), just click the “Download” button on the page to suck a zip file of the whole source code to your box.

Going DRY with multiple elements

Now that we have taken care of adding items to our to-do lists, let’s have a look at the the action of ticking items done and undone. The index.html.erb view uses the Rails’ partial mechanism to display the lists of items. Here’s how the _item.html.erb partial looks like:

<% @item = item %>
<li id="<%= item.state %>_<%= item.id %>">
  <%= check_box("item[]", :done, :id => "#{item.state}_box_#{item.id}") %>
  <label for="<%= "#{item.state}_box_#{item.id}" %>">
    <%= item.description %>
  </label>
  <%= observe_field("#{item.state}_box_#{item.id}", 
                    :url => item_path(item), 
                    :method => :put) %>
</li>

observe_field is a Rails helper that attaches an Javascript observer to the field in question. Whenever the field is changed (or every n seconds, if the time n is given as a parameter to the observe_field call), an Ajax call (in this case to item_path(item)) is made. In our app, the responding update action will then update the state of the item in the database and return Javascript that will move the item to the correct list on the page.

Here’s an example of what the list of items looks like to the browser:

<li id="undone_1">
<input id="undone_box_1" name="item[1][done]" type="checkbox" value="1" />
<input name="item[1][done]" type="hidden" value="0" />
<label for="undone_box_1">
  Buy carrots
</label>
<script type="text/javascript">
//<![CDATA[
new Form.Element.EventObserver('undone_box_1',
                  function(element, value) {
                    new Ajax.Request('/items/1', 
                                     {asynchronous:true, 
                                      evalScripts:true, 
                                      method:'put', 
                                      parameters:value + '&authenticity_token=' +
                encodeURIComponent('8d829cfcccdf4d2b494891ef47cc95893faa361e')})})
//]]>
</script>
</li>
<li id="undone_2">
<input id="undone_box_2" name="item[2][done]" type="checkbox" value="1" />
<input name="item[2][done]" type="hidden" value="0" />
<label for="undone_box_2">
  Return bottles to recycling
</label>
<script type="text/javascript">
//<![CDATA[
new Form.Element.EventObserver('undone_box_2', 
                  function(element, value) {
                    new Ajax.Request('/items/2', 
                                     {asynchronous:true, 
                                       evalScripts:true, method:'put', 
                                       parameters:value + '&authenticity_token=' +
                encodeURIComponent('8d829cfcccdf4d2b494891ef47cc95893faa361e')})})
//]]>
</script>
</li>

Imagine a list that has a couple dozen items. Not exactly DRY, is it, especially compared to how clean the source code of a Rails app tends to be?

Even if we set aside all the objections for the ugly code above, there is still the issue of the form not working at all without Javascript. Not good.

Let’s again start our round of refactoring by making the checkboxes work without javascript. For that, we’ll remove the observe_field call from the partial:

<% @item = item %>
<li id="<%= item.state %>_<%= item.id %>">
  <%= check_box("item[]", :done, :id => "#{item.state}_box_#{item.id}") %>
  <label for="<%= "#{item.state}_box_#{item.id}" %>">
    <%= item.description %>
  </label>
</li>

Now, to make our form work again, we need to figure out what it’s supposed to do and where we should send it to. Thinking restfully, by submitting a form with multiple items checked or unchecked, we are modifying a to-do list. Let’s thus create a simple controller for the imaginary List resource (remember, resources don’t need to map directly to ActiveRecord models).

script/generate controller Lists

Then add the necessary route to config/routes.rb

  map.resources :items
  map.resource :list

For simplicity’s sake, let’s pretend our app can only handle a single to-do list (it’s our personal to-do list app, after all) and use the single form of resource routes with it.

In our to-do list page, we currently have a form that’s unable to submit anything. Let’s add a submit button to it and also change the form in app/views/items/index.html.erb to point to the lists controller:

<% form_for :list, :url => list_path, :html => {:method => :put} do |f| %>
  <h3>
    Not done:
  </h3>

  <ul id="undone">
    <%= render :partial => "item", :collection => @not_done %>
  </ul>

  <h3>
    Done:
  </h3>

  <ul id="done">
    <%= render :partial => "item", :collection => @done %>
  </ul>
  
  <p>
    <%= submit_tag "Save changes", :id => "save_changes" %>
  </p>
<% end %>

Now let’s create a really simple update action to our new controller for the mass assignment of items:

class ListsController < ApplicationController
  def update
    params[:item].each do |key, values|
      item = Item.find(key)
      item.update_attributes(values)
    end
    
    redirect_to items_path
  end
end

If you now test the application with Javascript turned off, updating the item state should work fine. We can thus continue to the hijacking phase.

First of all, let’s hide the submit button because we don’t need it in the Ajax’ed form.

Event.addBehavior({
  'body' : function() {
    $('add_form').hide();
    $('add_new_link').show();
    $('save_changes').hide();
  },
  '#add_new_link:click' : function(e) {
    $('add_form').toggle();
    e.stop();
  },
  '#add_form' : Remote.Form
});

Now, what we need to do is to make clicking a checkbox to call the update action for the current item. This is easily done in the js file:

Event.addBehavior({
  'body' : function() {
    $('add_form').hide();
    $('add_new_link').show();
    $('save_changes').hide();
  },
  '#add_new_link:click' : function(e) {
    $('add_form').toggle();
    e.stop();
  },
  '#add_form' : Remote.Form,
  'input[type=checkbox]:click' : function() {
    var id = this.id.match(/\d{1,}$/);
    var auth_token = this.up('form').
                          select('[name=authenticity_token]').
                          first().value;
    new Ajax.Request('/items/' + id, 
                     {asynchronous:true, 
                      evalScripts:true, 
                      method: 'put',
                      parameters: {
                        authenticity_token: auth_token
                      }});
  }
});

We use the CSS3 selector syntax to get every input of type checkbox, then fetch the item id from the element id using a regular expression and finally call the update method of the items controller to update the item. The cool thing about addBehaviour is that the behaviour is attached to all elements returned by the selector. Thus adding a single call function to our javascript file automatically attaches the function to as many list items as needed.

Note that because of the spam-defense mechanism in Rails, we also need to send the authenticity token with our call. We use the cool Prototype selector functions to easily get to the current token inside the form.

An astute reader might have noticed that if you click an item in the list, and then try to re-click the same item after it’s moved to the opposing list, it’s not moved back automatically. This is because our Ajax update action created a new list item and added it to the list, and by default Event.addBehaviour does not reattach behaviours after each Ajax call.

We have a couple of ways to fix the situation. The simplest would be to add this line to our Javascript file:

Event.addBehavior.reassignAfterAjax = true;

However, the simplest way is not always the best. By reassigning behaviours automatically after each Ajax call we can deteriorate the Javascript performance considerably, and the effect gets larger when there are more items watched.

Second, a bit more surgical option would be to reload the addBehaviour rules in a callback of the Ajax call:

onComplete : function() {
  Event.addBehavior.reload();
}

This way the behaviours would only be reassigned after the particular Ajax call, not all of them. However, it’s still a bit heavy-handed.

Let’s take a step back and think how we could avoid reassigning all the behaviours for the new element. An obvious answer would of course be not to create a new element at all, but instead just move the existing one (with all the behaviours already attached).

In app/views/items/update.js.rjs we can see that the code first removes a list item and then adds a new one into the list of items in the opposite state:

page["[email protected][email protected]}"].remove
page.insert_html :top, @item.state, :partial => "item"

We can fairly easily change that code to not delete/create a new node to the page, but instead move the list item to the correct place in the DOM:

page << "
  var el = $([email protected][email protected]}');
  $([email protected]}').insert({ top: el.remove() });
  el.id = [email protected][email protected]}';
"

This time we don’t use the RJS syntax but instead just output plain old Javascript back to the browser. We first fetch the list element we’re about to move. We then remove it from the DOM tree, just to again insert it to the bottom of the list it now belongs to. In the end we change the id of the item to reflect its new state as well.

If you now try the app again, you should be able to tick and untick the items at will, and everything should work just fine. The behaviour assigned to the list element on the page load sticks to it through all the moving and renaming of the element.

If you enjoyed the article, consider grabbing a copy of my new ebook, Unobtrusive Prototype, straight from the Peepcode oven. It will have all the code rewritten for Rails 2.1, it is professionally edited unlike my rumblings here, and has a much wider coverage of Low Pro, including writing your own Behaviors and event delegation. If you’re quick and have a close look at my presentation slides in the beginning of this article, you might even find a way to get your copy for half the normal price!

Sonera’s at It Again

[UPDATE] Now the people in the Nordic have followed the lead of fuckyourogers.com:

Sonera, the poor man’s AT&T, the old Finnish national telcom that got “famous” in the dawn of the century by buying thin German air for $7.5 Billions (and later writing it off as worthless), is on fire again. The company that’s nowadays merged with its Swedish counterpart Telia, announced a while ago that they will be the ones bringing the 3G iPhone to the Northern Europe. I guess some warning bells should have been in place considering the company is pretty much the only one that still doesn’t offer a reasonable unlimited data plan for its GSM customers. However, initially the excitement over iPhone finally (officially) reaching this corner of the world took over and I even considered becoming a Sonera client.

Today, the truth was revealed when the iPhone 3G plans were announced. Not a single plan has unlimited data. Not even the €90/month Large plan (which has 1GB/month of data). The small and medium plans come with measly 100 and 250 MB a month. Considering that watching a few YouTube movies consumes pretty much the whole monthly quota, the plans seem nothing but laughable1.

[UPDATE] Here’s the whole pricing table:

Plan Small Medium Large
Price 31,69 €/month + 159 €/8 GB or 245 €/16 GB iPhone 51,49 €/month + 79 €/8 GB or 165 €/16 GB iPhone 89,99 €/month + 1 €/8 GB or 85 €/16 GB iPhone
Includes
(min/month) 100 250 1000
SMS messages/month 100 250 1000
Data (MB/month) 100 250 1000
Home Run hotspot usage yes yes yes
Additional calls
Starting a call 0,049 € 0,049 € 0,049 €
Cost/min 0,079 € 0,079 € 0,079 €
Additional text msg 0,079 € 0,079 € 0,079 €
Data/MB 1,49 € 1,49 € 1,49 €

Now, the plans might have been ok 5 years ago2, but they totally overlook the platform what iPhone has become in the countries it’s been on sale so far. An iPhone is not just a phone anymore, it’s a whole new computing platform, which pretty much needs an unlimited data plan.

One huge selling point for the new phone will no doubt be Mobile Me. The chance to automatically and wirelessly sync your life between your computers and your phone sounds almost too good to be true. With €1.49/MB for the over quota data transfer, the syncing doesn’t exactly sound like a realistic option anymore.

Fortunately everything is not lost for us. You can buy the phone from Sonera even without the ridiculous plans. The 8GB and 16GB models cost €429 and €519 respectively if you don’t take any real plan with them. You do have to sign up for a custom plan for 24 months, though, but the cheapest comes at €1.99/month and thus only adds €48 to the total cost of ownership. That might just about cut it for me, but for the masses? Not so much. I hope I’ll be wrong, but to me it seems that Sonera is once again going to kill something that would’ve had potential to be something disruptive.

Oh well, I hear they’re going to sell cheap unlocked iPhones in Italy…

[UPDATE] Gruber links to The Unofficial Apple Weblog’s entry about Rogers unveiling their plans as well, stating that ‘they suck’. However, compared to the offering from Sonera, Rogers’ plans seem to be downright cheap (even the cheapest plan comes with 400MB of data and 150 mins of weekday calls compared to 100MB and 100 mins all the time). Thanks also to Vesa for the comment about Rogers’ plans.

1 The prices seem even more laughable considering that pretty much every other operator offers unlimited data plans starting from €10/month.

2 Even though we did, in fact, have unlimited GPRS plans in here back then, something which was unheard of in the Middle Europe where I used to live those days.

Specifying Indeces in DataMapper

I’ve been working with Merb and DataMapper in the context of a new project for a week now, and the experience has been both pleasant and interesting. On one hand the stack is solid and super-fast (like, desktop app fast), on the other there are a lot of things that catch you if you don’t manage to remove the Rails hat off your head. The youth of the frameworks still shows (especially in DataMapper which has recently seen a major refactoring to make it more modular the same way Merb was reworked a bit earlier) but at the same time I get the chance to help with some really cool up-and-coming open source software. If you don’t consider that a plus, maybe you should still wait a couple months before you consider these critters for a production app.

One clear symptom of the young age of both Merb and DataMapper is the lack of documentation. They both have documentation sections on their respective websites and there are other efforts such as Merbunity going on, but you still have to have the guts to dive into the source code if you want to find out how some of the less common use cases work.

Here’s a short piece on how to declare indeces for your DataMapper models. I plan to continue publishing this kind of tutorials for other functionality as well, and to contribute them back to the “official” docs when appropriate.

The big difference

The big conceptual different between ActiveRecord and DataMapper is that in ActiveRecord, the place where the properties of database tables are defined are the migration files. The actual tables are then built according to the migrations and the actual model classes build their property to methods from the database schema.

In DataMapper, the properties are defined in the actual model file. DM has so called auto migrations that compare the model file and the database schema, and modify the schema if the two don’t match.

Here’s an example DataMapper model:

class User
  include DataMapper::Resource

  property :id,         Integer, :serial => true
  property :first_name, String
  property :last_name,  String
  property :bio,        Text
  property :single,     Boolean
end

Seems clean, doesn’t it. Looking at a model it is clear what properties it has and what methods it supports. But what about indeces? In AR migrations, you would use the create_index method. In DataMapper, index is an option given to the property method:

property :last_name,    String, :index => true

Or, if you want the index to be unique:

property :last_name,    String, :unique_index => true

OK, but what if you need multi-column composite indeces? Easy. Instead of true, give the index a name using a symbol:

property :last_name,     String, :index => :name
property :first_name,    String, :index => :name

This will create an index called index_products_name for the table, spanning columns last_name and first_name. The columns are added to the index in order of appearance, so in this case the indexing order would be last name, first name. If you want to change that order, just change the order of you property calls in the model call definition.

There you have it! No rocket surgery, but something I had to dive into the source code to find out.

Start From the Heart

My friend Lars Pind is slowly migrating himself from a software developer to a coach. His new startup is called Start from the Heart, where Lars tries to help people start companies that represent their true soul. The guiding principle behind Start from the Heart is that there should be a deeper meaning in the business you pursue than just the money. As exactly that has been a driving force behind us at dotherightthing.com, it’s no wonder the premise of SftH really resonated with me.

Lars is putting up a series of exercises for the participants of the program and giving out them for free. I worked through the first assignment and must say that it’s a great one, getting a smile on your face. If you’re thinking about starting your own company (or have ever contemplated it), I would highly recommend giving Start from the Heart a try. I’m certainly enjoying it from the bottom of my heart (no pun intended).

&lified

UPDATE Now ampersand even has its own blog.

Ampersand has received a lot of press lately and I decided to put my oar in as well.

My recent history with ampersand is kind of embarrassing, to say the least. I was giving a Ruby class in UK a few years back and during a class, I asked a participant whether there is some other term for the at sign in English. “Sure”, she said, “it’s ampersand.” To this day I’m not sure whether she thought I said et sign, or genuinely mixed up asperand and ampersand. But for quite some time after that, I happily treated @ as ampersand.

But neither linguistics or typography is the topic of today’s article. Let’s rather talk about ampersand (the real one) in Ruby.

In Ruby, an ampersand denotes a block parameter. But let’s not get ahead of ourselves. A little background might be in place.

One of the coolest features in Ruby are code blocks, or closures. They are basically anonymous functions, but as pretty much everything in Ruby, they are also objects. They are anonymous functions, that have little use just by themselves. However, you can turn them into Proc objects either with the Proc.new constructor or using the lambda kernel method. The common best practice to mark code blocks is to use the curly braces with one-liners and do..end with blocks that span multiple lines:

yell = lambda { puts "AAARGH!!!" }
whisper = Proc.new do
 puts "whee"
end
yell.call
whisper.call

➥

AAARGH!!!
whee

Maybe the most useful application of Proc objects in Ruby are block parameters. Anyone with some knowledge of Ruby is familiar with the following:

>> arr = %w(apple orange kiwi)
=> ["apple", "orange", "kiwi"]
>> arr.each {|i| puts i[0,2]}
ap
or
ki
=> ["apple", "orange", "kiwi"]

As you can see, in this case you need to use neither Proc.new nor lambda with the block; it’s converted to a Proc object implicitly. But as the method receives just a Proc object as its parameter, you could also say something like this, right:

>> put_two = lambda {|i| puts i[0,2]}
=> #<Proc:0x00329060@(irb):41>
>> arr.each(put_two)

Err, not quite. It turns out Ruby methods can take two kinds of parameters—a number of normal parameters and a block parameter. In the code above the interpreter will think that the put_two Proc object is passed as a normal parameter to the each call, and since each doesn’t take any normal parameters, you will get an error:

>> arr.each(put_two)
ArgumentError: wrong number of arguments (1 for 0)
	from (irb):42:in `each'
	from (irb):42

And this is what brings us back to the ampersand:

>> arr.each(&put_two)
ap
or
ki
=> ["apple", "orange", "kiwi"]

So the ampersand is used to tell the interpreter that the following reference is the block parameter of the method.

One fairly common idiom in the Rails world is this kind of construct:

>> arr.map(&:length)

It is effectively the same as

>> arr.map {|i| i.length }
=> [5, 6, 4]

However, if you start a plain irb session, you will notice something isn’t quite right:

>> arr.map(&:length)
TypeError: wrong argument type Symbol (expected Proc)
	from (irb):2

That’s right. The cool shorthand method that worked so nicely in your Rails app doesn’t work in plain Ruby. That’s because there is some Rails magic behind the &:method call. This magic is e.g. the reason why Ezra has prohibited using the shortcut in Merb framework code.

But let’s have a closer look at what’s actually happening behind the scenes in the shortcut. The thing that’s different from our earlier calls is that there is a colon between the ampersand and the word “length”. This means that we’re not using a variable or method called length, but the symbol :length. If you’re not familiar with Ruby symbols (or even if you are), reading Josh’s recent article on symbols is a worthwhile read.

Now that we know that we’re trying to pass a symbol as the block parameter to a method (and that it’s not really working, as the error above indicates), we need a way to convert it to a Proc object like expected by the method. Ruby has a slew of type conversion methods that are called implicitly whenever it’s clear that a certain type of object is needed. Inside a string for example, to_s is called automatically for every object that is not a string itself:

>> "Nice array: " + arr
TypeError: can't convert Array into String
	from (irb):6:in `+'
	from (irb):6
>> "Nice array: #{arr}"
=> "Nice array: appleorangekiwi"
>> "Nice array: " + arr.to_s
=> "Nice array: appleorangekiwi"

In the same vein, since a block parameter of a method needs to be a Proc object, to_proc is called automatically for all other objects in an effort to get a hold of a proc. So could it work if we just added a to_proc method to the Symbol class? Let’s find out!

class Symbol
  def to_proc
    lambda {|i| i.send(self)}
  end
end

Here we make to_proc a lambda function that will use the send method to call the method with the same name as the Symbol object in question (self) for the element that’s passed to it. (That got too confusing so let’s just use examples). So

arr.send(:length)

is the same as

arr.length

And thus

:length.to_proc

would become

lambda {|i| i.send(:length)}

Now, let’s see how our new method performs:

>> arr.map(&:reverse)
=> ["elppa", "egnaro", "iwik"]

Perfect!

While Symbol#to_proc is a clever and perhaps an elegant hack, it’s still kind of a hack. So should you use it in your code? I tend to side with Ezra on this. If you’re writing framework code, you should probably err on the side of readability and common usage, and thus avoid “magical shortcuts” like these. But in application code, why not. I certainly do.