Beautiful multi-line blocks in Ruby

“I need a new drug”:http://youtube.com/watch?v=MMSFX1Vb3xQ. One that won’t quit. One that will let me sensibly structure the use of blocks in Ruby such that they can run across multiple lines and yet still chain blocks together.

OK, so its not really a drug I need, per se. Though, I’m sure what Huey Lewis really needed was a new drug. But what I need is a convention, or perhaps some syntax. It should say to you, “HEY. Adam’s doing something clever with blocks here. Keep your eyes open.”

I find myself desiring a new syntax and/or convention, when using blocks. I’ve been trying to write in a more functional style lately, especially a pure-functional style wherein you never call a method for its side-effects. I don’t think I’m the only person doing this. Jim Weirich sort of alluded to it in a post about “when to use @do/end@ vs. braces”:http://onestepback.org/index.cgi/Tech/Ruby/BraceVsDoEnd.rdoc. Rick DeNatale “took it a step further”:http://talklikeaduck.denhaven2.com/articles/2007/10/02/ruby-blocks-do-or-brace. I want to lay it bare.

Let’s start with something innocuous:


ary = [1,2,3]

result = ary.map do |n|
  x = n * 4
end

result # => [4, 8, 12]

You get the value back of each object in the array, mapped to the result of calling the block. Fun times. Now, let’s put it on one line and do something clever with it.


ary.map { |n| n * 4 }.select { |n| n == 4 } # => [4]

Now we’re cooking! Ruby’s syntax allows us to chain methods and blocks. Which turns out nice in this case where I want to filter down the array of mapped values. But let’s pretend we need to do something clever in those blocks.

  
    ary.map { |n|
      n * 4
      # Some
      # clever
      # things...
    }.select { |n|
      n == 4
      # More
      # clever
      # things...
    }.any? { |n|
      n == 4
      # Gratuitiou
      # clever
      # things...
    } # true
  

That’s the best I could come up with for chained, multi-line blocks. It looks “Weirichian”. Despite that, it kinda makes me vomit in my mouth.

So, since “I got awesome feedback on my last question of taste”:http://therealadam.com/archive/2008/04/28/can-i-send-you-a-message/, I’m tapping you, my favorite Ruby developer, for more. The ground rules are that you can’t extract the logic into a real method and you can’t jam everything onto one line. You have to use multi-line blocks. What looks good to you here?


Can I send you a message?

@Object#send@ - the joy of Rubyists and the scourge of those who would write refactoring tools. Let’s talk about it.

I recently ended up writing some code that would have proven really hideous if I couldn’t call @#send@. So I had a class like the following (written using code generation for brevity):


class Foo
  %w{one two three}.each do |name|
    class_eval <<-EOC
      def #{name}
        '#{name}'
      end
    EOC
  end
end

I needed to call @one@, @two@ or @three@ from a bit of code that takes some user input (in this case, an attribute value in a template language). So I cooked something like this up:


%w{one two three foo}.each do |arg|
  meth = case arg
  when 'one'
    :one
  when 'two'
    :two
  when 'three'
    :three
  else
    raise 'Unknown arg'
  end

  puts Foo.new.send(meth)

end

So I’m using a case statement to convert valid method names to symbols, which I then pass to @#send@ and bam!, my method is called. This made my code a ton easier to write and I’m here espousing the technique to you.

But what is the drawback? Well, if someone were to ever really get up the courage to tackle the task of building a refactoring browser for Ruby, this sort of thing would give them fits. They can’t really tell where those methods are called on my class until they are actually called. Heck, given the code above, they can’t even figure out what methods exist on @Foo@ without running the code.

The other drawback is that this code is a little hard to read. Most new casual Rubyists won’t think to search for the symbol version of a method name. Its even harder if you’re still somewhat new to Ruby and you aren’t aware this sort of thing even happens.

For me personally, the concise code I can write with @#send@ far outweighs the drawbacks. I preach the importance of code reading regularly, and its how one can get over the “hump” that is knowing how to navigate software that sends dynamic messages to objects.

Your homework is to share how you feel about @#send@ in the comments.


Exploratory hacking in TextMate

My first foray into screencasting:

‘Tis a little tutorial on a little bit of joy I use regularly. In TextMate, you can add xmp markers like so:


1 + 2 # =>
String.class # =>
%w{foo bar baz}.each { |w| w.upcase } # =>

Then if you hit Ctrl+Shift+Command+E, you get this:


1 + 2 # => 3
String.class # => Class
%w{foo bar baz}.each { |w| w.upcase } # => ["foo", "bar", "baz"]

This is a great way to do exploratory hacking. Plus, you don’t feel like you’re doing “printf” style debugging. And that makes everyone feel cooler!


Interviewed by RubyLearning

Ruby Interview: Adam Keys of FiveRuns - Satish’s ability to find an absurd picture of me from five years ago is impressive. The interview focuses on ideas for buddying Rubyists. So if you’re budding, check it out. Really, you should at least check it out for the picture.


I&#39;ll see you at Dallas TechFest

For the past couple of months I’ve been -procrastinating- helping to organize the Ruby track for the Dallas TechFest Dallas TechFest. Its is a language and technology agnostic conference on May 3rd. There are tracks covering Ruby, Java, .NET, Emerging Technologies and Flex. Its a great opportunity to see sessions on your own language of choice while learning what the other guys are up to, all under one roof.

Confirmed speakers for the Ruby track are:

  • Jim Hughes
  • Yehuda Katz
  • Glenn Vanderburg

…and myself. Other presentations of interest to Rubyists:

  • Getting started with the ASP.NET MVC framework
  • REST: the basics and the not so basic
  • Pardon the interruption: what’s the deal with Groovy?
  • Developing native applications for the iPhone
  • Google Android

I hope you’ll come out on May 3rd, 2008 learn something new, either in the area you work with today, or in a new technology that interests you.

Cost: $0 (!) Where: Addison Conference and Theatre Center When: May 3rd, 2008, 8 AM to 7 PM


IIS 7, IE 8, Iron Ruby MEGA-MIX

Not only do you get a Mega-MIX, I’ll try it in haiku form. Because, I’m feeling sassy.

h2. On IIS

Metabase to angle
brackets; FastCGI now,
Mongrel later on

Decoded: they dropped the metabase for XML configuration, they can PHP and Rails apps through FastCGI now and they’re working on something like @mod_proxy_balancer@

h2. On IE 8

Security blah
Many fancy features; ask
Chris for IE validator

Decoded: even more security improvements, lots of fancy new features (see Ajaxian for more coverage), and over beers, Chris Wilson thought it was not entirely implausible to build some manner of Firebug extension that warns you about possible IE incompatibilities in the current page.

h2. On IronRuby

Rails someday; outside
people build test suite; polyglot
code reality

Decoded: they want to run Rails on IIS at some point, some non-MS contributors built them a test suite so they know what Ruby interpreter APIs they need to build but didn’t have to poke around in MRI to figure it out, programming in multiple languages using the DLR on top of the CLR is possible.


Fix Subversion conflicts

Got a case where you did a @svn up@ and now you have a bunch of conflicts where you just want to overwrite your changes? I’ve got a little bit of Ruby cleverness for you:


  `svn status`.split("\n").grep(/^C/).map { |c| c.scan(/\S+/).last }.each { |c| `svn cat #{c} > #{c} && svn resolved #{c}` }

I run this from @irb@ at the root of my Subversion working directory. It makes me happy.

Update: lord that looks ugly on one line!


  status = `svn status`.split("\n")
  conflicts = status.grep(/^C/)
  files = conflicts.map { |c| c.scan(/\S+/).last }
  conflicts.each do |c|
    `svn cat #{c} > #{c} && svn resolved #{c}`
  end

SCIENCE

All I can say is SCIENCE!

Tom Preston Werner on God’s memory leak