Archive for the ‘Ruby’ Category

Going crazy with to_proc

You all know Symbol#to_proc, right? It allows you to write this:

It has been in Rails as long as I can remember, and is in Ruby 1.8.7 and 1.9.x. I love it to death and I use it everywhere I can.

It is actually quite simple, and you can implement it yourself:

It works because when you prepend an ampersand (&) to any Ruby object, it calls #to_proc to get a proc to use as block for the method.

What I always regretted though was not being to pass any arguments, so I hacked and monkeypatched a bit, and got:

So you can now write:

Not that this is any shorter than just creating the darn block in the first place. But hey, it’s a good exercise in metaprogramming and show of more of Ruby’s awesome flexibility.

After this I remembered something similar that annoyed me before. It’s that Rails helper methods are just a bag of methods available to, because they are mixed in your template. So if you have an array of numbers that you want to format as currency, you’d have to do:

What if I could apply some to_proc-love to that too? All these helper methods cannot be added to strings, fixnums, and the likes; that would clutter way to much. Rather, it might by a nice idea to use procs that understands helper methods. Here is what I created:

I used a clean blank class (in Ruby 1.9, you’d want to inherit it from BasicObject), in which I will provide the proper proc-object. I play around with the argument list a bit, handling multiple arguments and blocks too. You can now use this syntax:

That is a lot sexier if you as me. And you can use it in any object, not just inside views. And lets add some extra arguments and some Enumerator-love too:

In case you are wondering, the position you can specify is to tell where the arguments need to go. Position 0 is the method name, so you shouldn’t use that, but any other value is okay. An example might be that you cant to wrap an array of texts into span-tags:

So there you have it. I’m probably solving a problem that doesn’t exist. It is however a nice example of the awesome power of Ruby. I hope you’ve enjoyed this little demonstration of the possible uses of to_proc.

  • Print
  • email
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Reddit
  • RSS
  • Twitter

3 times ActiveSupport 3

Rails 3 is coming. All the big changes are spoken of elsewhere, so I’m going to mention some small changes. Here are 3 random new methods added to ActiveSupport:

presence

First up is Object#presence which is a shortcut for Object#present? && Object. It is a bit of a sanitizer. Empty strings and other blank values will return nil and any other value will return itself. Use this one and your code might be a tad cleaner.

"".presence # => nil
"foo".presence #=> "foo"

# without presence:
if params[:foo].present? && (foo = params[:foo])
  # ..
end

# with presence:
if foo = params[:foo].presence
  # ...
end

# The example Rails gives:
state = params[:state] if params[:state].present?
country = params[:country] if params[:country].present?
region = state || country || 'US'
# ...becomes:
region = params[:state].presence || params[:country].presence || 'US'

I like this way of cleaning up you’re code. I guess it’s Rubyesque to feel the need to tidy and shorten your code like this.

uniq_by

Another funny one is Array.uniq_by (and it sister-with-a-bang-method). It works as select, but returns only the first element from the array that complies with the block you gave it. Here are some examples to illustrate that:

[ 1, 2, 3, 4 ].uniq_by(&:odd?) # => [ 1, 2 ]

posts = %W"foo bar foo".map.with_index do |title, i|
  Post.create(:title => title, :index => i)
end
posts.uniq_by(&:title)
# => [ Post("foo", 0), Post("bar", 1) ] ( and not Post("foo", 2) )

some_array.uniq_by(&:object_id) # same as some_array.uniq

exclude?

And the final one for today is exclude? which is the opposite of include?. Nobody likes the exclamation mark before predicate methods.

# yuck:
!some_array.include?(some_value)
# better:
some_array.exclude?(some_value)

And it also works on strings:

# even more yuck:
!"The quick fox".include?("quick") # => false
# better:
"The quick fox".exclude?("quick") # => false

The full release notes of Rails 3 can be read here.

  • Print
  • email
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Reddit
  • RSS
  • Twitter

http_accept_language released as a gem

I released an old Rails plugin as gem today. Slowly but surely, all my plugins will be converted to gems.

This time it’s an old one: http_accept_language

  • Splits the http-header into languages specified by the user
  • Returns empty array if header is illformed.
  • Corrects case to xx-XX
  • Sorted by priority given, as much as possible.
  • Gives you the most important language
  • Gives compatible languages

For more information, read the README on GitHub.

  • Print
  • email
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Reddit
  • RSS
  • Twitter

Basic Named Scopes

Cal it tiny, I don’t care. I’ve made a gem named BasicNamedScopes.

Basic Usage

I was fed up with writing:

Post.all(:conditions => { :published => true },
  :select => :title, :include => :author)

So with BasicNamedScopes, you can now write:

Post.conditions(:published => true).select(:title).with(:author)

All named scopes are called the same, except for include, which is now called with, because include is a reserved method.

Reuse them by making class methods:

class Post < ActiveRecord::Base
  def self.published
    conditions(:published => true)
  end

  def self.visible
    conditions(:visible => true)
  end

  def self.index
    published.visible
  end
end

Also, the all-method is a named scope now, so you can chain after callling all, for greater flexibility.

Post.all.published

Arrays can be used as multple parameters too, sparing you some brackets.

Post.with(:author, :comments).conditions("name LIKE ?", query)

The read_only and lock scopes default to true, but can be adjusted.

Post.readonly         # => same as Post.all(:readonly => true)
Post.readonly(false)  # => same as Post.all(:readonly => false)

Why?

NamedScopes are really handy and they should play a more central theme in ActiveRecord. While I heard that Rails 3 will support similar syntax, there is no reason to wait any longer.

I find defining named scopes very ugly, especially when dealing with parameters. Just compare the amount of curly braces!

# Using normal named scope:
named_scope :name_like,
  lambda { |query| { :conditions => ["name LIKE ?", query] } }

# Using BasicNamedScopes
def self.name_like(query)
  conditions("name LIKE ?", query)
end

Also, regular named scopes don’t support using other named scopes at all!

I found myself implementing these named scopes (mostly conditions, but others too) so often, that a little gem like this would be the obvious choice. Use it if a gem like searchlogic is overkill for your needs.

Installing

The gem is called “basic_named_scopes”. You know how to install it.

gem install basic_named_scopes

Use it in Rails:

config.gem "basic_named_scopes"
  • Print
  • email
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Reddit
  • RSS
  • Twitter

Cucumber 0.5 and my little commit

The strangest thing happened to me this week. I was working on a little side project at work. It seemed like a nice time to try out some new gems (Bundler and Devise: love it! InheritedResources, not that much, Formtastic, very nice). I was experimenting with Cucumber and writing Dutch features too.

I had figured that the supplied dutch keywords in languages.yml were not very practical. It supplied “Gegeven” as a naive translation of “Given“. Although this is correctly translated, it is very unpractical to form Dutch sentences with it. The only to really start a sentence with “Gegeven” is to write “Gegeven het feit dat…” (“Given the fact that…“). It’s very strange to say “Gegeven dat ik een profiel heb” (“Given I have a profile“) in Dutch.

I decided to use the synonym “Stel” like in “Stel ik heb een profiel“. Not entirely correct either because it misses a comma after “Stel“, but much better, in my honest opinion. So I forked cucumber, changed languages.yml and used this as custom git repository in my Gemfile.

Apparently I was in the middle of a Release Candidate, so what I had committed on github. The Rails integration was extracted out in that version (like RSpec does) to the “cucumber-rails” gem. This gave about an evening of confusion, but I got it to work eventually.

Two days later, we had visitors at our company, from another Ruby company, talking about cooperation on future projects. I introduced myself and he was trying to remember if he’d seen anything on the interwebs by me. That seems to be common. When meeting people on conferences it’s always the same question: “Do I know any of your gems?”.

Anyway, he had actually read my name recently, namely in the commit log of cucumber. Without asking or sending a pull request, they had added my commit to the 0.5 release of cucumber. A pleasant surprise! Aslak Hellesøy, you’re a very observant GitHub user!

By the way, you can still use “Gegeven“, as it is just an alias.

I am constantly wrestling with the best way write cucumber features down. Does anyone have Dutch features? Do you write them down with your customers or are they for developers only? Can you share some of them? Here are some of mine:


Scenario: Inloggen
  Stel ik ben uitgelogd
  En ik heb een account voor "gebruiker@test.com" met het wachtwoord "geheim"
  En ik ben op de inlogpagina
  Als ik de volgende velden invul:
    | E-mailadres | gebruiker@test.com  |
    | Wachtwoord  | geheim              |
  En ik op "Inloggen" druk
  Dan zie ik de melding "Je bent ingelogd"

Scenario: Verkeerd wachtwoord
  Stel ik ben uitgelogd
  En ik heb een account voor "gebruiker@test.com" met het wachtwoord "geheim"
  En ik ben op de inlogpagina
  Als ik de volgende velden invul:
    | E-mailadres | gebruiker@test.com  |
    | Wachtwoord  | verkeerd            |
  En ik op "Inloggen" druk
  Dan zie ik de foutmelding "Ongeldig e-mailadres of wachtwoord"

The RSpec BookBy the way, don’t forget to order the RSpec and Friends book. It’ll be released this februari and is a really good read if you want to learn BDD, RSpec or Cucumber.

  • Print
  • email
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Reddit
  • RSS
  • Twitter
Return top

About me

I am a Ruby programmer from Rotterdam, Netherlands. I started working with Ruby on Rails about 3 years ago and I've fallen in love with the language ever since.

When learning Ruby I noticed that the most useful information comes from blogs of other Ruby developers. I try to contribute to that.

I also am into writing plugins and gems. I hope you like my contributions and leave a comment if you do.