September 26th, 2006

More Ruby in Prototype

14 comments on 996 words

It’s obvious that Ruby has been a big influence to Prototype. We’ve already talked about Enumerables, Arrays, and Hashes, and how powerful they are. Now, lets look at some new tools: inGroupsOf and eachSlice.

Convenience matters

Have you ever tried to build a table programatically with a certain number of cells per row? The resulting code can look a bit ugly and certainly leaves something to be desired. Back in March, the Rails team introduced in_groups_of to Ruby. Since that time, I’ve put it to good use. Here is an RHTML snippet that we use in the Mephisto admin:


<table id="files">
<% @assets.in_groups_of(5) do |assets_line| -%>
<tr>
  <% assets_line.each do |asset| %>
   <td>
     <%= render :partial => 'asset', :object => asset if asset %>
    </td>
   <% end %>
</tr>
<% end %>
</table>

The code above builds a table of assets in rows of 5. So basically, it takes 5 assets at a time and passes them to the block. When inside the block, each individual asset is looped over creating the columns for the tables.

in_groups_of goes Javascript

In the latest SVN version of Prototype, Sam introduced inGroupsOf. It’s similar to it’s Ruby counterpart, with the exception that you don’t pass an iterator to it. Instead you have to run it through each. Assuming we were doing the same thing–building a table, how would we accomplish that with inGroupsOf? Lets see.


<table>
  <thead>
    <th>First</th>
    <th>Second</th>
    <th>Third</th>
  </thead>
  <tbody id="numbers"></tbody>
</table>

We’re gonna take the HTML above, and programatically build the table from a group of numbers. Here is a look at the Javascript:


var tbody = $('numbers');
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
numbers.inGroupsOf(3, 0).each(function(group) {
 var tr = document.createElement('tr');
 group.each(function(num) {
   var td = document.createElement('td');
   td.innerHTML = num;
   tr.appendChild(td);
 });
 tbody.appendChild(tr);
});

When you run the code above, it will spit out a table like this:

table

Basically we’re taking the numbers array, and dividing it into groups of 3. The 0 passed as the second argument is a filler string that is used to fill the final group if it doesn’t contain enough entries. Next, we create a tr element, and then do an inner loop which creates the td elements with the correct number, and appends it to the tr. Finally, we break out of the inner loop and append our tr onto our tbody element.

each_slice goes Javascript

inGroupsOf uses eachSlice to do some of it’s dirty work. Both of the methods are very similar, with the exception that eachSlice takes an iterator, and doesn’t pad the last slice. If we had an ObjectRange object (better known at $R in Prototype) and wanted to divide it up into slices of two, we’d do this:


$R(0, 10).eachSlice(2, function(slice) {
  console.log(slice);
});

//Output
[0,1]
[2,3]
[4,5]
[6,7]
[8,9]
[10]

The first argument is the size of the slices, and the second one is the iterator, or block. Note how the last slice isn’t padded? Finally, the iterator function can also pass the loop index if you need it:


$R(0, 10).eachSlice(2, function(slice, index) {
  console.log(slice, index);
});

//Output
[0,1] 0
[2,3] 1
[4,5] 2
[6,7] 3
[8,9] 4
[10] 5

And there you have it, the new features freshly baked into Prototype.

Related note

I also want to mention that I spoke to soon about XPath in Prototype. While no one has concocted a solution for IE (which was my main opposition to XPath support), document.getElementsByClassName now uses XPath in browsers that support it and it’s significantly faster than before.

Discussion

  1. Rob Wilkerson Rob Wilkerson said on September 26th

    Which version of Prototype includes this feature? I keep reading, both here an other places, about some great new stuff, but none of the articles or blog posts indicate which version includes them.

    It looks like 1.4.0 is the latest “production” version, but the features I’m reading about sure aren’t in what I have. If the features are in the next version, is there any timeline for when that might get certified as production-ready?

    Thanks.

  2. Justin Palmer Justin Palmer said on September 26th

    Rob,

    Later on in the article I state that it’s the SVN version of Prototype. You can check out the source here: http://dev.rubyonrails.org/svn/rails/spinoffs/prototype

    When you check out the source, you’ll need to build it running `rake dist` from the command line in the root dir.

  3. rick rick said on September 26th

    You can also get a very recent compiled version from Edge Rails: http://dev.rubyonrails.org/browser/trunk/railties/html/javascripts/prototype.js?format=txt

  4. Rey Bango Rey Bango said on September 26th

    Justin, any news on the formation and organiztion of the Prototype core team that you mentioned in an earlier posting? I’d like to know how that’s coming along.

  5. Olle Jonsson Olle Jonsson said on September 26th

    Phew! Thanks, Justin, for the coverage of the bleeding Edge of Prototype. Again!

    Always a pleasure reading these reports. I almost always download latest Prototype because of them.

    Most of these convenient Prototype tools look and feel like refactorings of “general use”, for Javascripters hard at work. Not like shiny gadgets.

  6. Andrew Dupont Andrew Dupont said on September 26th

    @Rey: I’m told there’ll be an official announcement about Prototype Core once 1.5.0 goes final.

  7. Tobie Langel Tobie Langel said on September 26th

    Hi Justin,

    As ususal, great article and great add-ons to Prototype.

    Your new design looks great BTW.

    Anyone in particular we should contact to help with Prototype docs, etc?

    Regards,

    Tobie

  8. Rey Bango Rey Bango said on September 27th

    @Andrew: Thanks for the heads. Just trying to stay informed. :o)

  9. Justin Palmer Justin Palmer said on September 27th

    @Tobie: At the moment me and Andrew have taken the reigns on the documentation project. We’re still waiting on some initial setup of the system and a few other things before we start taking contributions, hopefully it’s not to much longer.

  10. Igwe Igwe said on September 27th

    Wow, your new design is really nice. I’m always slightly nervous when designing websites with dark backgrounds but good job here. Don’t worry, I won’t ask you to add some AJAX.

    On a sidenote, is your book going to be about writing rails apps with Protoype or general Javascript programming with Prototype?

  11. Lanfeust21 Lanfeust21 said on September 29th
    hi Justin, have you take a look at JQuery ? i am just curious about your feeling to that new library ?
  12. Justin Palmer Justin Palmer said on September 29th
    @Lanfeust21: JQuery is a good library, it's just not for me. In the end, you should use whatever you feel the most comfortable with and the one that makes you say subconsciously: "This freaking rocks!"
  13. Tarellel Tarellel said on October 2nd
    Great, site design Justin, I really like it. One hting I kind of miss with the new design, is your links of interest. I occasionally checked them out. I guess I'll have to resort to checking out your del.icio.us links right?
  14. Justin Palmer Justin Palmer said on October 3rd
    Tarellel: I might brink back the quick bits section one day. It would require me doing some Mephisto hacking though.

Sorry, comments are closed for this article.