Friday, March 31, 2006

Become a Ruby developer in 30 days or less

You've heard the Ruby hype. You've considered looking at the language. But, where do you get started?

Lesson 1: Pickaxe is the name we use to refer to Programming Ruby.

Homework: Go immediately to pragprog and purchase either the Pickaxe combo or the pdf version. Work through the book as soon as possible.

Lesson 2: You don't have to develop exclusively in Ruby to utilize the power of Ruby. Even if your project is in another language you can use one of Ruby's frameworks for the other tasks that your project will require.
  • Rake: Convert your project's build file to Rake as soon as possible. Rake is an internal DSL that allows you to create a build file with minimal effort. However, Rake allows you to use the full power of Ruby at any time if your task becomes more complicated.
  • Data Migration: Instead of keeping your database creation scripts in .sql files, give ActiveRecord Data Migrations a try. Using Data Migrations allows you to specify the structure of your database in Ruby. Also, at any time you can generate the sql files if they are needed. More info: UnderstandingMigrations. (Thank you Chris Stevenson for this idea)
Homework: Find a currently ugly task on your current project and replace it with a better Ruby implementation. The task doesn't have to be something as large as the entire build file or data migration plan. Simply replacing problematic batch file or generating a config file dynamically are great places to start.

Lesson 3: When you want to learn more about Ruby you should pair with other Rubyists. Ruby User Groups are great places to meet Rubyists. RubyGarden maintains a list of Ruby User Groups world wide.

Homework: Meet a Rubyist at your local Ruby User Group and ask them if you can pair with them on their current open source ruby contribution. When you meet, immediatly insist on driving. There's no better way to learn than being in the driver seat.

Congratulations, you are a Ruby developer. You likely already were much before 30 days, but I had to give you enough time to get to that monthly user group meeting. You now have permission to annoy the world with your constant reminders that Ruby is better.

Thursday, March 30, 2006

Ruby Attribute Initializer

update: following recommendation by Dan North, changed implementation by moving eval. This should result in better performance, see comment 1 for more information.

On my current project I found we often duplicated the pattern:
def method_name
@method_name ||= Klass.new
end
I saw this often enough that I decided to create a module to reduce the duplication. The module allows you to specify an attribute that will be initialized on the first execution. Additionally, it allows you to specify what type of class you want initialized and it allows you to provide constructor arguments if necessary.
# module definition
module AttributeInitializer
def attr_init(name, klass, *ctor_args)
eval "define_method(name) { @#{name} ||= klass.new(*ctor_args) }"
end

def self.append_features(mod)
mod.extend(self)
end
end

# example of usage
class Foo
include AttributeInitializer
attr_init :bar, Array, 1, "some_val"
end

# tests to ensure it works as expected
require 'test/unit'

class AttributeInitTest < Test::Unit::TestCase
def test_same_instance_is_returned
f = Foo.new
assert_equal f.bar, f.bar
end

def test_ctor_args_are_correctly_passed
f = Foo.new
assert_equal ["some_val"], f.bar
end
end
*Note: adding the constructor arguments is completely optional and the above code will also work if you change
attr_init :bar, Array, 1, "some_val"
to
attr_init :bar, Array
and
assert_equal ["some_val"], f.bar
to
assert_equal [], f.bar

Saturday, March 25, 2006

Ruby Delegation Module

Recently while working on a problem I needed an object that acted like an Array, but had additional methods. Since I was working in Ruby I could have added additional methods to the Array class or created a subclass of Array. However for my specific problem it seemed like a better option to create a new class, expose the necessary methods, and delegate their behavior to an instance variable of type Array.

Ruby already has a delegate class in the standard library, but it doesn't have exactly the behavior I was looking for. I hoped that including a Delegation module would allow me to specify which methods I wanted to delegate to with a simple list. This could be achieved by specifying which type of object I want to delegate to and which methods I wanted my object to support.
# This is the behavior I was looking for
class Foo
include Delegation

delegate Array, :size, :push, :pop, :<<, :[]
end
But the current Delegate class doesn't work that way. So, I decided to see how hard it would be to write it up myself.

The delegate method takes a type and one or many methods. The delegate method defines the method __delegate_instance__. The __delegate_instance__ method initializes a new instance of the specified type the first time it is executed, and returns that instance each additional execution. Then, the delegate method loops through each method in the methods argument and defines a method that delegates behavior to the method of the same name on the delegate instance.
def delegate(klass, *methods)
define_method("__delegate_instance__") { @__delegate_instance__ ||= klass.new }
methods.each do |method|
define_method(method.to_s) { |*args| __delegate_instance__.send method.to_sym, *args }
end
end

This is the majority of the Delegation module. The only other necessary behavior is a change to the append_features class method. Because delegate needs to be a method on the class and not an instance method the append_features method needs to be modified to extend the class instead of the instances of the class.
def self.append_features(mod)
mod.extend(self)
end
That's basically it. If the type you wanted to delegate to needed arguments for it's constructor you would need to alter the delegate method to take those arguments.

Full code plus tests:
module Delegation
def delegate(klass, *methods)
define_method("__delegate_instance__") { @__delegate_instance__ ||= klass.new }
methods.each do |method|
define_method(method.to_s) { |*args| __delegate_instance__.send method.to_sym, *args }
end
end

def self.append_features(mod)
mod.extend(self)
end
end

class Foo
include Delegation

delegate Array, :size, :push, :pop, :<<, :[]
end

require 'test/unit'

class DelegationTest < Test::Unit::TestCase
def test_methods_are_added_correctly
foo = Foo.new
foo.push "one"
assert_equal 1, foo.size
foo << "baz"
assert_equal 2, foo.size
assert_equal "baz", foo[1]
end
end

Thursday, March 02, 2006

GUI Patterns

I've recently been working with Martin Fowler on documenting GUI patterns. Currently there are two pattern names that are prevalent in the development community, Model View Presenter (MVP) and Presentation Model (PM). The problem is, these names mean different things to different people.

Both MVP & PM are documented as rich client patterns on Martin Fowler's site. However, the patterns have also been successfully adapted for the web. Mike Mason has a wonderful write-up on this very subject. But, the real question is whether the pattern is abstract enough to be applied to either format. The answer to that question relies on what is the definition of MVP and PM.

The definitions on Martin's website state that the distinction between MVP and PM is where the state is maintained. For MVP the state is maintained in the View, but for PM the state is maintained in the PM. Based on this definition both MVP and PM could be easily adapted for the web. Unfortunately, not everyone agrees on this definition.

A common area of discussion is whether the view references the presenter/presentation model or if the presenter/presentation model references the view. In the past this implementation detail has been considered as orthogonal to the definition. However, due to the growing confusion over the relevance of this detail I believe it's worth exploring. Some definitions even describe the reference dependency as the central theme in the pattern.

I think the larger issue is that the goal has been slightly lost in the implementation details of these patterns. Martin has expressed to me that he may document a more abstract pattern that describes decoupling the view from it's behavior by introducing another class. This is the heart of both MVP and PM.

However, documenting the abstract pattern alone would be far less valuable than including the information about MVP and PM. Both MVP and PM have implementation trade-offs that have been discovered in use. Not documenting the issues with both patterns would be disappointing.

I'm hoping Martin can sort most of the issues out, but you can help also. Post comments with your opinions (and/or links to samples) and I will include these ideas in the book if they are relevant.

Execute all Test::Unit tests in a directory

PickAxe gives an example of how to create test suites in Ruby. It's been awhile since I read it, but if I remember correctly it involves simply adding a require 'test_name' for each test you want to run in your suite. This does work, but it can become a maintenance pain.

When developing a Ruby application I generally put all my tests in a Test folder or in folders that are descendants of Test. When I want to execute all the tests, I simply need to require all files that are in or below Test.
require 'find'

Find.find(File.dirname(__FILE__)) do |path|
Find.prune if path =~ /#{File.expand_path('.')}\/#{__FILE__}$/
require path.reverse.chomp(File.expand_path('.').reverse).chomp('/').reverse.chomp('.rb') if !File.directory?(path)
end
That's it. All files below Test will be required and therefore executed.