Blog Post RSS ?

Blogs » Ruby on Rails » Insta-block with Symbol#to_proc
 

Insta-block with Symbol#to_proc


  • Save to
    Del.icio.us

by Tim Lucas

Something that might have slipped your radar in your Ruby readings is Symbol#to_proc, something that’s been in Rails since 0.14.4.

Using this nice little tidbit of Ruby tricky you can simplify code such as:


articles.collect { |a| a.title }
articles.sort { |a| a.created_at }

to


articles.collect(&:title)
articles.sort(&:created_at)

…and just in case you’re wondering why &:ruby_is_the_new_black doesn’t work in the beautiful ruby shell script you just wrote, it’s because Symbol#to_proc isn’t a standard Ruby thang. To quote Mauricio Fernandez who noted it’s recent inclusion in the upcoming Ruby 1.9:

Symbol#to_proc: first discovered by some anonymous Japanese Rubyist (fairly certain), rediscovered by Florian Groß (I saw that happen back when I wasted my time on #ruby-lang), then popula rized by Pragdave and Rails, finally adopted officially. It’s been a long journey.

“That’s nice,” you say, “but I still don’t really understand what all this Proc and block stuff is about.” Well, let me indulge you in some Ruby block mumblings.

I think the best way to describe a block if you’ve come from web-design-land is to think of it like an anonymous function in Javascript.

For example, the following piece of Ruby:


socceroos.each do |s|
  s.congratulate
end

is the equivalent to the following Javascript:


socceroos.each(function(s) {
  s.congratulate();
})

The block passed to a function is signified by an ampersand:


class Team
  def each(&block)
    for player in @players
      block.call(player)
    end
  end
end

In fact, the above pattern of calling the block is so common Ruby takes it one step further, allowing you to simply write:


class MyTeam
  def each
    for member in @members
      yield member
    end
  end
end

yield member is another way of saying “call the associated block passing it the member”. You don’t even need to add &block to the parameter list.

You would have seen this pattern when dealing with ActiveRecord. The ActiveRecord::Base class allows you to specify a block when creating new instances. For example, if Player was an ActiveRecord subclass you could do the following:


@player = Player.new do |p|
  p.name = "Ronaldo"
  p.nickname = "Porky"
end

How does ActiveRecord provide this neat API? Easy! It just checks whether you specified a block and, if so, calls the block, passing the new Player object to it.

The bare minimum logic to accomplish this would be:


class ActiveRecord::Base
  def initialize
    yield self if block_given?
  end
end
Tags: ,

This post has 4 responses so far

  1. Is this the code for symbol#to_proc, or is there a more general version?
    class Symbol def to_proc proc {|o| o.send(self)} end end

     
  2. Fenrir2, that’s just about it. You gotta take into account whether the proc invoker will pass in arguments:

    
    class Symbol
      def to_proc
        proc { |obj, *args| obj.send(self, *args) }
      end
    end
    

    See PragDave’s article on it as well as the latest version that’s included with Rails.

     
  3. […] Symbol.to_proc […]

     
  4. Ne v dengah ne v muzejnoj pyli

     

Sponsored Links

Leave a response

You are not logged in, log in with your SitePoint Forum username and password.

-OR- Post Anonymously

* Make sure any code samples are escaped (i.e. ‘<b>’ becomes ‘&lt;b&gt;’).

If not logged in, your comments will be placed in a moderation queue. This means your comment may not appear until one of our moderators approves it.

SitePoint Marketplace

Buy and sell Websites, templates, domain names, hosting, graphics and more.

Logo Design, Web page Design and more!

99designs

  • Custom logo designs created ‘just for you’.
  • Pick the design you like best.
  • Only pay if you’re satisfied with the result.

Want More Traffic?

Get up to five quotes from qualified SEO specialists, with no obligation!

Get A Free SEO Quote Now!