Saturday, September 30, 2006

Rails Model View Controller + Presenter?

Ruby on Rails directs you to use Model View Controller by convention. This often results in a one to many relationship between Controllers and Views. A common controller could contain the following code.
class StandardsController < ApplicationController

def list
@standards = Standard.find(:all)
end

def results
standards = Standard.find(:all)
@total_standards = standards.size
@standards_for_hr = standards.select { |standard| standard.department == 'hr }
@standard_categories = standards.collect { |standard| standard.category }.uniq
...
end

end
This controller implementation works fine; however, the results method can become a bear to test. To solve this issue my team began inserting another layer: a Presenter. The main responsibility of a Presenter is to expose data for the view to consume. After introducing the presenter the controller becomes much slimmer.
class StandardsController < ApplicationController

def list
@standards = Standard.find(:all)
end

def results
@presenter = Standard::ResultsPresenter.new()
end

end
The Standard::ResultsPresenter class handles aggregating all the required data.
class Standard::ResultsPresenter

def total_standards
standards.size
end

def standards_for_hr
standards.select { |standard| standard.department == 'hr }
end

def standard_categories
standards.collect { |standard| standard.category }.uniq
end

def standards
Standard.find(:all)
end

end
After introducing this abstraction the Presenter can be tested in isolation.
class Standard::ResultsPresenterTest < Test::Unit::TestCase

def test_total_standards
Standard.expects(:find).with(:all).returns([1,2,3])
assert_equal 3, Standard::ResultsPresenter.total_standards
end

def test_standards_for_hr
standard_stubs = [stub(:department=>'hr'), stub(:department=>'other')]
Standard.expects(:find).with(:all).returns(standard_stubs)
assert_equal 1, Standard::ResultsPresenter.standards_for_hr.size
end

def test_standard_categories
standard_stubs = [stub(:catagory=>'Ruby'), stub(:catagor=>'Ruby')]
Standard.expects(:find).with(:all).returns(standard_stubs)
assert_equal ['Ruby'], Standard::ResultsPresenter.standard_categories
end

end
We like this style because it's much cleaner than the previously required code that lived in the controller tests. However, there is overhead involved in generating this additional layer. Because of the overhead we generally don't add a presenter until we notice that testing has become painful in the controller test file.

Friday, September 29, 2006

Remove Subversion from a tree

The following code will remove all the .svn folders from a tree (starting at the current file's directory).
Find.find(File.dirname(__FILE__)) { |path| `rm -rf #{path}` if path =~ /\.svn$/}
I've needed this enough times that I thought it might save someone else some time.

When did I use this? Every time I start a new project I check it into a local subversion repository. After working on the code for a bit, if I decide that it's a project worth distributing I register it somewhere else (such as RubyForge). If my project is accepted, I'll transfer the code to the projects repository. The easiest way, I've found, to move the code is to remove the local .svn directories and check out version 0 of the new repository into the project's root. At this point, I can svn add everything and check in.

I'm sure there's a better way, but this is simple and it works.

Tuesday, September 26, 2006

Test::Unit test creation

Creating a unit test in Ruby is very similar to Java: create a method that begins with test_. In a recent discussion with some colleagues, Zak Tamsen and Muness Alrubaie, Zak described his distaste for this common convention. He continued by pointing out that using .NET Attributes was a superior approach for identifying tests.

This began a discussion on what a superior approach to writing tests could be when using Ruby. We implemented several examples before deciding on our preference.
test
def add_returns_the_sum_of_two_numbers
assert_equal 4, add(2, 2)
end

test 'add returns the sum of two numbers'
assert_equal 4 do
add(2,2)
end
Each implementation contained limitations. In the end we chose to go with a very simple implementation that is similar to how RSpec defines specifications.
test 'add returns the sum of two numbers' do
assert_equal 4, add(2, 2)
end
To accommodate this syntax we added the test class method to Test::Unit::TestCase.
class << Test::Unit::TestCase
def test(name, &block)
test_name = :"test_#{name.gsub(' ','_')}"
raise ArgumentError, "#{test_name} is already defined" if self.instance_methods.include? test_name.to_s
define_method test_name, &block
end
end
An additional benefit we were able to include in our change was the ability to raise an error when a test was defined with a duplicate name (or description in our case).

However, moving to this new style of test definition can cause issues. The first noticeable issue was that TextMate would no longer run individual tests. We quickly fixed this issue by looking at the code in the Ruby Bundle. The fix was to change the regex that selects the method you are testing. The code below shows how you can capture either the previous call to the test class method or the previously defined test method.
File.open(ENV['TM_FILEPATH']) do |f|
f.read.split("\n")[0...n].reverse.each do |line|
if line =~ /^\s*test\s+"([_a-z][_a-z0-9 ]*[\?!]?)"\s+do\s*$/i
print "test_#{$1.gsub(' ', '_')}"
break
elsif line =~ /^\s*def ([_a-z][_a-z0-9]*[\?!]?)/i
print $1
break
end
end
end
We also created a TextMate snippet in the Ruby Bundle to help us create tests in our new style. The following code is the snippet for easily creating tests.
test "${1:test name}" do
$0
end
After these quick changes we are quite happy working with our new format for creating tests.

Thursday, September 21, 2006

Ruby Stub Variations: Stubba

Ruby Stub Variations: Introduction
Ruby Stub Variations: OpenStruct
Ruby Stub Variations: TestStub
Ruby Stub Variations: Struct
Ruby Stub Variations: Stubba

In my last entry I described how, using Struct, you can create stubs without creating your own stub implementations. Struct also provides you the power of creating and keeping reference to a class. But, on many occasions you don't need the extra capability. On these occasions the unnecessary flexibility requires you to enter additional code. There is another alternative that allows you to initialize a class similarly to OpenStruct: Stubba.

Stubba is a stubbing framework that provides great flexibility. The example test can be implemented using Stubba with the following code.
def test_values_are_appened_to_insert_statement
statement = Insert.into[:table_name].values do
stub(:to_sql=>'select column1, column2 from table2')
end
assert_equal "insert into table_name select column1, column2 from table2", statement.to_sql
end
Stubba provides the same simplicity of OpenStruct and addresses the limitations. Stubba correctly responds to predefined methods and even returns as expected from respond_to?. However, the major benefit to using Stubba is the ability to temporarily change behavior of existing objects. For example, if I chose to use the Select class, but wanted to stub out the to_sql method I would use the following code.
def test_values_are_appened_to_insert_statement
Select.any_instance.stubs(:to_sql).returns('select column1, column2 from table2')
statement = Insert.into[:table_name].values do
Select[:column1, :column2].from[:table2]
end
assert_equal "insert into table_name select column1, column2 from table2", statement.to_sql
end
Stubba is a great alternative to the previously mentioned stub alternatives. In the end, which stub you choose should be based on your needs of your project.

Tuesday, September 19, 2006

Ruby Form Template Method Using Extend

In Martin Fowler's book, Refactoring, he describes how you can form a template method to eliminate duplicate behavior. I wont get into the motivations for doing such a thing; for that, I suggest buying the book. However, I would like to use the example to show how I would implement it using Ruby.

The prefactored code in Ruby could look like this:
class Customer
def statement
result = "Rental Record for #{name}\n"
_rentals.each do |rental|
result += "\t#{rental.movie.title}\t#{rental.charge}\n"
end
result += "Amount owed is #{total_charge}\n"
result += "You earned #{total_frequent_renter_points} frequent renter points"
end

def html_statement
result = "<h1>Rentals for <em>#{name}</em></h1><p>\n"
_rentals.each do |rental|
result += "#{rental.movie.title}: #{rental.charge}<br>\n"
end
result += "<p>You owe <em>#{total_charge}</em></p>\n"
result += "On this rental you earned <em>#{total_frequent_renter_points}</em> frequent renter points<p>"
end
end
The first refactoring step is to create a Statement base class and two derived classes that inherit from Statement. However, we will need a Statement class and two modules that contain the methods we require.
class Statement
end

module TextStatement
end

module HtmlStatement
end
The next step is to alter Customer to use our new Statement class.
class Customer
def statement
Statement.new.extend(TextStatement).value(self)
end

def html_statement
Statement.new.extend(HtmlStatement).value(self)
end
end

module TextStatement
def value(customer)
result = "Rental Record for #{customer.name}\n"
customer.rentals.each do |rental|
result += "\t#{rental.movie.title}\t#{rental.charge}\n"
end
result += "Amount owed is #{customer.total_charge}\n"
result += "You earned #{customer.total_frequent_renter_points} frequent renter points"
end
end

module HtmlStatment
def value(customer)
result = "<h1>Rentals for <em>#{customer.name}</em></h1><p>\n"
customer.rentals.each do |rental|
result += "#{rental.movie.title}: #{rental.charge}<br>\n"
end
result += "<p>You owe <em>#{customer.total_charge}</em></p>\n"
result += "On this rental you earned <em>#{customer.total_frequent_renter_points}</em> frequent renter points<p>"
end
end
Next, Martin begins to move the differing behavior to separate methods.
module TextStatement
def value(customer)
result = header_string(customer)
customer.rentals.each do |rental|
result += each_rental_string(rental)
end
result += footer_string(customer)
end

def header_string(customer)
"Rental Record for #{customer.name}\n"
end

def each_rental_string(rental)
"\t#{rental.movie.title}\t#{rental.charge}\n"
end

def footer_string(customer)
"Amount owed is #{customer.total_charge}\n" +
"You earned #{customer.total_frequent_renter_points} frequent renter points"
end
end

module HtmlStatement
def value(customer)
result = header_string(customer)
customer.rentals.each do |rental|
result += each_rental_string(rental)
end
result += footer_string(customer)
end

def header_string(customer)
"<h1>Rentals for <em>#{customer.name}</em></h1><p>\n"
end

def each_rental_string(rental)
"#{rental.movie.title}: #{rental.charge}<br>\n"
end

def footer_string(customer)
"<p>You owe <em>#{customer.total_charge}</em></p>\n" +
"On this rental you earned <em>#{customer.total_frequent_renter_points}</em> frequent renter points<p>"
end
end
The final (hopefully obvious) step is to pull up the value method.
class Statement
def value(customer)
result = header_string(customer)
customer.rentals.each do |rental|
result += each_rental_string(rental)
end
result += footer_string(customer)
end
end

module TextStatement
def header_string(customer)
"Rental Record for #{customer.name}\n"
end

def each_rental_string(rental)
"\t#{rental.movie.title}\t#{rental.charge}\n"
end

def footer_string(customer)
"Amount owed is #{customer.total_charge}\n" +
"You earned #{customer.total_frequent_renter_points} frequent renter points"
end
end

module HtmlStatement
def header_string(customer)
"<h1>Rentals for <em>#{customer.name}</em></h1><p>\n"
end

def each_rental_string(rental)
"#{rental.movie.title}: #{rental.charge}<br>\n"
end

def footer_string(customer)
"<p>You owe <em>#{customer.total_charge}</em></p>\n" +
"On this rental you earned <em>#{customer.total_frequent_renter_points}</em> frequent renter points<p>"
end
end
At this point, forming a template method by using extend should be clear. But why use extend instead of inheritance? The answer is you would use extend if the modules you were creating could be used to extend various classes.

For example, let's imagine that the next requirement of our application is to display the above information for only the previous month. The current statement class gives a list of each rental associated with a customer for all months. To satisfy our new requirement we could create a MonthlyStatement class similar to the code below.
MonthlyStatement
def value(customer)
result = header_string(customer)
rentals = customer.rentals.collect { |rental| rental.date > DateTime.now - 30 }
rentals.each do |rental|
result += each_rental_string(rental)
end
end
end
The advantage to the module approach and mixins is now clear: if we had chosen inheritance we would not need to create a TextMonthlyStatement class and a HtmlMonthlyStatement class. However, because we chose to use modules instead of inheritance, we can simply mixin their behavior and achieve reuse without additional classes.
class Customer
def statement
Statement.new.extend(TextStatement).value(self)
end

def html_statement
Statement.new.extend(HtmlStatement).value(self)
end

def monthly_statement
MonthlyStatement.new.extend(TextStatement).value(self)
end

def monthly_html_statement
MonthlyStatement.new.extend(HtmlStatement).value(self)
end
end