Ruby En Rails 2007 Conference

Posted by andy

On June 7th the Ruby En Rails 2007 Conference will be held here in Amsterdam. I'm really looking forward to meeting up with the dutch Rails crowd. I'll be giving a lighting talk on Mongrel clustering and will share my experience with this in use on a busy site. Also looking forward to some of the talks, especially the opening keynote. Hope to see you there!!

Update: I just read there are no more seats left, so hope you got in!

Rewriting a (large) PHP application in Rails, part 2

Posted by andy

In my previous post on this topic I described the method we used to convert a legacy MySQL PHP database to a Rails conformant PostgreSQL hosted version. In this article I will tell a bit about how we converted the HTML of the application to Rails layout templates and partials.

Extracting HTML from Firefox DOM

We first started out with attempting to rewrite the table heavy design to CSS. We soon realised that this was a project on itself so we decided to work with what we have. Since most of the HTML code is intermingled with PHP logic it was really not an option to examine the numerous .php files and cut ‘n paste what we needed. We basically used the excellent Firefox View Formatted Source extension to take snapshots of the DOM tree of rendered pages (look here if you’re on FF2).

Getting the HTML from the Firefox DOM meant we had properly balanced HTML! The real work was to extract layout templates and to identify the partials. This turned out to relatively easy. The really hard part was to get the code to display properly in Internet Explorer, which unfortunately still makes up about 70% of all traffic to the site.

Writing down business logic

The original project never had functional or technical specifications so I scheduled 3 sessions spread over 2 weeks with the (back-end) users of the system. We identified the business logic and rules of the system as best as we could during these (1-2 hour) sessions. The whole business logic was then written again from scratch in Ruby. I figured it would have take much longer if I had examined the PHP code myself. This might not be an option for you though. Anyway, during these 2 weeks at the end of each day a small number of functionalities would be delivered for testing. In practice the user(s) would only test functionality and provide feedback every 3-4 days (busy schedules on both sides, so noone enforced this). Could have been better.

TDD, or rather WTAD (Write Test After Developing)

It was really really hard to bring up the discipline of writing the Test code before Developing the functionality. In practice tests were only written after something was seen working already. What do you do, honestly? :)

The final part will contain details about the deployment (Mongrels, W00t!) and also some interesting statistics on how many lines were left after the rewrite. Stay tuned..

Using MPlayer identify with Ruby

Posted by andy

For a project I need to fetch some metadata from WAV recordings. Mplayer can extract this information nicely with the -identify command. I’m using Ruby Sessions for executing the external mplayer command, although a simple IO.POpen() might do fine too. The code wrapper class looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
require 'rubygems'
require_gem 'session'

class MediafileInfo
        MPLAYER_BINARY = "mplayer"
        MPLAYER_IDENTIFY = "-identify -vo null -ao null -frames 0"

        def initialize(filename)
                stdout, stderr = '', ''
                shell = Session::Shell.new
                shell.execute "#{MPLAYER_BINARY} #{MPLAYER_IDENTIFY} #{filename}", :stdout => stdout, :stderr => stderr

                vars = (stdout.split(/\n/).collect! { |o| o if o =~ /^ID_/ } ).compact!

                vars.each { |v|
                        a, b = v.split("=")
                        eval "@#{a.to_s.downcase} = \"#{b}\""
                }
        end

        # Intercept calls
        def method_missing(method_name, *args)
                value = eval "@id_#{method_name.to_s.downcase}"
        end
end

All ID_* lines that mplayer spits out will now be method calls (and instance variables) of your MediafileInfo object. The method_missing call is there to do proper value defaulting if the variable doesn’t exist, but I’m not using it as such right now. To get the playing time of every type of mediafile that mplayer understands you simply do someting like:
1
2
3
info = MediafileInfo.new("voicemail.wav")

puts "Voicemail playtime: #{info.length.to_i} seconds"
Ruby 0wnz! :)