Posts dealing with ruby

SF Ruby Meeting

Ok, this is super late notice but I'll be at the San Francisco Ruby Meetup tonight, May 9 to give a quick demo of Measure Map. Josh Susser, who's been writing good things at has_many :through will be presenting on how to contribute to Rails.

yes, it's been almost three months since my last post. yes google is keeping me busy. yes I'll try to do something here more often. if you really care what I'm up to, please check my flickr stream.

This isn’t Typo

Thought I should mention that this site isn't using Typo anymore. It had been running on a very old, and heavily customized version which made it extremely hard to upgrade. I started looking at converting to new version with themes and felt like it was overkill. What was once little Typo has really grown into a non-trivial app.

Instead, I whipped up something really simple called Post. A short list of features..

All in 431 lines of code and 423 lines of test. Remember when this stuff was hard?

CalendarGrid 1.0.2

This release patches a bug in ActiveSupport where Time#at_beginning_of_day had a non-zero usec sometimes, on some platforms.

The fix has been in Rails for some time, but is not yet part of an official release. See:

Simply gem install calendar_grid to update to version 1.0.2.

Thanks to Cody Fauser for the note.

  • September 10, 2005
  • Dealing with ruby

Hacking Dispatcher without DI

For reasons I won't get into, it became necessary to make Rails go faster. But only for a couple url's, and without need for the majority of the framework. For a while, we ran these scripts with raw FCGI and a simplified Dispatcher that let you work with the request and response directly, bypassing the main Rails workflow.

But now we have the wonderful RailsFCGIHandler, with graceful signal handling, app reloading and more. I wanted our custom dispatcher to benefit from that too.

So, we want to use the RailsFCGIHandler but handle requests with our stripped down Dispatcher before Rails gets to it. My first thought was to override FCGIHandler#process_request

class CustomRailsFCGIHandler
  def process_request(cgi)
    MyDispatcher.dispatch(cgi)
    # Dispatcher.dispatch(cgi)
  rescue Object => e
    raise if SignalException === e
    dispatcher_error(e)
  end
end

CustomRailsFCGIHandler.process!

That's ok, but we've duplicated some tricky exception handling logic. Even worse, it's treating Ruby like a static language. We can do much better. First, there's no need to subclass RailsFCGIHandler. Simply opening the class and redefining process_request would do the same thing.

But, here's the cool part. We don't have to modify RailsFCGIHandler at all! The only functionality we need to change is in Dispatcher, so let's just modify it.

class Dispatcher
  class <<self
    alias :old_dispatch :dispatch
  end
  def self.dispatch(cgi)
    SimpleDispatcher.dispatch(cgi,false) do |request, response|
      case request.path
        when "/one" then Tracker::Controller.process(request, response, :one)
        when "/two" then Tracker::Controller.process(request, response, :two)
        else old_dispatch(cgi)
      end
    end
  end
end

RailsFCGIHandler.process!

That's it. Now our two high-availability url's are handled while still supporting Rails' normal workflow.

Here's SimpleDispatcher for reference. All it does is instantiate Rails' request and response objects, yield them, then take care of session propagation and write a response.

class SimpleDispatcher
  def self.dispatch(cgi = CGI.new, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS)
    request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi)
    begin
      yield request, response
    rescue
      response.body << $!.to_s
    ensure
      request.session.update if request.session && !request.session.kind_of?(Hash)
      response.out unless response.body.empty?
    end
  end
end

Back to Dependency Injection. In a static language, hardcoding Dispatcher.dispatch(cgi) would have been a sin. It forever ties us to a specific implementation. Design patterns help - template method or factory method come to mind. Or using a DI container with setter injection. But each of these techniques causes excess overhead in both usage and design.

The Ruby way gives us a simple (almost naïve) implementation that's as flexible as the most complicated architectural patterns.

This point is worth repeating. Without any coding or design overhead, the result is highly flexible. Sure you can accomplish the same result in Java, et al but how many more lines of code+config+tests did it take?

It's just not that complicated

When I worked in Java, dependency injection was a really cool, life saving technique. When I first came to Ruby, I immediately wondered about libraries for DI, Mock Objects and other such things.

It quickly became obvious that none of these things are all that necessary. Jim Weirich sums it all up perfectly in Dependency Injection: Vitally Important or Totally Irrelevant?

FOSCON

FOSCON was great. Thank you pdx.rb for putting on the event!

Keep an eye out for Rails/Flash integration using a Cocoa-like windowing system. Amazing, made-me-drool stuff. And all he showed was sample code.

Glenn Vanderburg's talk on domain specific languages for programmers was enough to make me rewrite a large chunk of code as soon as I got home. Update slides here

_why's performance was something to be seen. Truly.

CalendarGrid 1.0.1

CalendarGrid 1.0.1 is a major bugfix to 1.0. Please upgrade now. If you tried 1.0 and were utterly disappointed, I apologize.

Note to Rails users. Never ever rely on the nifty date math methods for real date calculation. Try this:

Time.local(2005,10,30) + 1.day
=> Sun Oct 30 23:00:00 PST 2005

Um, what?

1.day
=> 86400
Time.local(2005,10,30) - Time.local(2005,10,29)
=> 86400.0
Time.local(2005,10,31) - Time.local(2005,10,30)
=> 90000.0

Lesson learned. Be careful with dates. This all came about because I switched from using Date to Time for everything internal.

Just in case anyone doesn't know how slow (but accurate!) Date is...

bm do |x|
  x.report("Date.today") do 
    1000.times { Date.today }
  end
  x.report("Time.now") do 
    1000.times { Time.now }
  end
end
            user       system     total       real
Date.today  0.420000   0.010000   0.430000 (  0.452072)
Time.now    0.000000   0.000000   0.000000 (  0.003978)

Thanks to Ben Bleything for the heads up!

CalendarGrid 1.0

I'm pleased to announce my first open source project, called CalendarGrid.

CalendarGrid lets you build output like a calendar, with padding days at the beginning and end of months. It sports a flexible data structure so you can format it any way you want. You can also provide a 'plugin' to each day to give it extra knowledge. For example, this code was originally created for a booking system, so each day knew whether it was booked or not.

Find out more in the API docs-grid.rubyforge.org/.

Installation

Install with gems - gem install calendar_grid

Download from the official home at RubyForge

Sample usage

require 'calendar_grid'

cal = CalendarGrid.build
puts "Calendar from #{cal.first.strftime("%D")} to #{cal.last.strftime("%D")}"

cal.years.each do |y|
  puts y.year
  y.months.each do |m|
    puts m.strftime("%B")
    s = m.weeks.collect do |w|
      w.collect { |day| "#{(day.proxy?) ? '* ' : day.strftime("%d")}" }.join(" ")
    end
    puts s
    puts
  end
end

Output

Calendar from 06/01/05 to 05/31/06
2005

June
*  *  01 02 03 04 05
06 07 08 09 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 *  *  * 

...

Thanks to Graham Arrowsmith for letting me build it, and then release it to the community.

Spotlight on Ruby

A nifty Spotlight plugin so you can search Ruby code. Via MacOS X Hints

In other news, I just got 186 lines in Tetris! (old-school Gameboy, the only way to play) What's your highest?

Hash#remap

Since we're mapping Array's around, we might as well do Hash's too. (And yes, I actually needed these)

class Hash

  # remap the keys and/or values of a hash to a new hash
  def remap(hash={})
    each { |k,v| yield hash, k, v }
    hash
  end

  # remap the keys and/or values of a hash to self. Probably wouldn't
  # do the keys unless providing aliases.
  def remap!(&block)
    remap self, &block
  end

end

I just know you had to do this recently:

stuff = {"a"=>5, "b"=>10, "c"=>15}
stuff.remap do |h, k, v|
  h[(k * 2).to_sym] = v * 2
end
=> {:aa=>10, :bb=>20, :cc=>30}

Array#to_h redux

Since the last post I've been really busy writing code, moving into a new house and being sick. So first off, apologies for the lack of content here.

Next. Confession. I made a fatal flaw when coming up with Array#to_h. I didn't need it. Well, I needed something but it wasn't exactly what that method turned out to be. I got caught up trying to make a cool one liner (but learned a lot about Hash while doing it).

Turns out sometimes I wanted to play with keys, sometimes values and sometimes both. Turns out all I needed was something simple like this:

class Array

  # yield each value of the array and a hash, return the hash
  def to_h(hash={})
    each { |value| yield hash, value }
    hash
  end

end

Because really the only thing that bugged me about doing it inline was having to return the hash.. that dangling return value just never feels right. This tightens it up just enough.

def map_something(array)
  array.to_h do |hash, value|
    hash[value.to_sym] = transform_value value
  end
end

By the way, making hash a parameter to the method lets you do cool things like assign default values to all new elements. Another pointless example:

h = Hash.new { |hash,key| hash[key] = 5 }
[1,2,3].to_h(h) do |hash,value|
  hash[value] *= value
end
=> {1=>5, 2=>10, 3=>15}

So, one dangling issue. Should this be a method of Array or Enumerable? If Enumerable it should probably be overridden for Hash as Hash#to_h should simply return self.

  • June 8, 2005
  • Dealing with ruby

Array#to_h

I found myself writing something like this far too often:

def map_something(array)
  hash = {}
  array.each do |a|
    hash[a] = lookup_value a
  end
  hash
end

It bugged me every time, but digging through the Pick Axe never yielded (ahem) a simpler solution. What I wanted to do is this:

def map_something(array)
  array.to_h do |a|
    lookup_value a
  end
end

But of course you'd need Array#to_h. Here's the cleverest implementation I could think of.

class Array
  def to_h(default=nil)
    Hash[ *inject([]) { |a, value| a.push value, default || yield(value) } ]
  end
end

A pointless example:

a = [1, 2, 3]
a.to_h do |v|
  [v * 2, v * 3]
end
> {1=>[2, 3], 2=>[4, 6], 3=>[6, 9]}

I love Array#inject!

New friends

Little did I know when I jumped headfirst into Ruby that I'd also be switching out just about every tool in the toolbox. It was a huge undertaking all at once, but one I've thoroughly enjoyed. Last week I made another switch, from MySQL to PostgreSQL. This pretty much rounds out the whole spectrum.

I can honestly say I'm happier and more productive now. The time and energy spent learning all this stuff was well worth it. And honestly, it wasn't that bad.

Sorry, there are no things

You know when there's something in the back of your mind, something you want to check out that you never get around to? Here's one from why that just made my day!

things = [1,2,3] 

if things.each do |thing|
  puts thing
end.empty? then
  puts "no things!"
end

It takes the classic case of if there's things, use the things, otherwise do something completely different and makes it beautiful. This is extra handy in ERB since there's only three lines of logic instead of five. (Note using the for..in alternative as well).

<% if for thing in things %>
  <%= thing %>
  <% end.empty? then %>
    no things
<% end %>

Bonus points for anyone that can write the following more simply...

<% unless things.empty? %>
  <ul>
    <% for thing in things %>
      <li><%= thing %></li>
    <% end %>
  </ul>
<% else %>
  no things
<% end %>

Automatic body tag id with Rails

Sometimes you want to style a certain page (or a certain element of a certain page) differently than others. The easiest way to do that is to give a unique id to the body tag.

In your stylesheet you say something like:

body#my-unique-id a.rule {
  background-color: #f00;
}

Which, of course, makes that particular selector only apply to one page. As with everything, this is really easy to do in Rails. You can put something like this in application_helper.rb:

def bodytag_id
  a = controller.class.to_s.underscore.gsub(/_controller$/, '')
  b = controller.action_name.underscore
  "#{a}-#{b}".gsub(/_/, '-')
end

It simply takes the current controller and action, say MyController#the_action and converts id to my-controller-the-action. I prefer dashes in class names and id's. Personal preference.

Call it in your layout:

<body id="<%= bodytag_id %>" class="standard">

I like to give each layout a unique class name as well, to differentiate them in the same kind of way. Now every page on your site has the hooks necessary to customize its style.

Hello world and something clever

This is the first post to the first blog I ever put online.

That's not to say I've never designed a blog, coded a blog, or even written blog entries. I've done all that. No, this is just the first one I ever finished well enough to share with you. So what was different this time?

It's going to sound cliché, but, honestly, it was Ruby on Rails. Up until two months ago I had been working in Java with Spring and Hibernate. Programming was becoming a chore. It wasn't something I stayed up all night to do because I loved it; I was staying up all night wrestling with Tomcat/Eclipse/JSTL/Spring/Hibernate/Acegi/etc.

Before those dark days of Java, I worked in PHP. I wrote countless web platforms in PHP for fun, a couple of those even became real sites. They had nice features, were pretty flexible and extensible. They were based on many of the same ideas as Rails, but were never something I would call elegant. PHP just lacks that certain something.

So about two months ago, shortly after attending the Building of Basecamp workshop in Seattle, I gave in and decided to see what this Ruby hype was all about. Long story short, about three days later I decided to stop all Java development and convert existing projects to a language I'd only heard about days before.

This site is here because programming is fun again. Thanks Matz and David.