My Secret Life as a Spaghetti Coder
home | about | contact | privacy statement
Given a class LeapYear with method isleap? and a data file consisting of year, isleap(true/false) pairs, we want to generate individual tests for each line of data. Using Ruby, this is quite simple to do. One way is to read the file, and build a string of the code, then write that to a file and then load it. That would certainly work, but using define_method is a bit more interesting. Here is the code my partner Clay Smith and I came up with:

require 'test/unit'
require 'leapyear'
class LeapYearTest < Test::Unit::TestCase
   def setup
     @ly = LeapYear.new
   end
   def LeapYearTest.generate_tests
     filename = "testdata.dat"
     file = File.new(filename, "r") #reading the file
     file.each_line do |line| #iterate over each line of the file
      year, is_leap = line.split; #since a space separates the year from if it is a leap year or not, we split the line along a space
      code = lambda { assert_equal(is_leap.downcase=="true", @ly.isleap?(year.to_i)) } #create some code
      define_method("test_isleap_" + year, code) #define the method, and pass in the code
     end
     file.close
   end
end

LeapYearTest.generate_tests

One thing to note, that I initially had trouble with, was the to_i. At first, it never occurred to me that I should be using it, since with Coldfusion a string which is a number can have operations performed on it as if it were a number. In Ruby, I needed the to_i, as isleap? was always returning false with the String version of year.

A more interesting item to note is that in the line where we define the method, if you were to attach a block like this:

define_method("test_isleap_"+year) { assert_equal(is_leap.downcase=="true", @ly.isleap?(year.to_i)) }

Then the solution will not work. It creates the correct methods, but when it evaluates them, it appears as though it will use the last value of year, rather than the value at the time of creation.

Hey! Why don't you make your life easier and subscribe to the full post or short blurb RSS feed? I'm so confident you'll love my smelly pasta plate wisdom that I'm offering a no-strings-attached, lifetime money back guarantee!


Comments
Leave a comment

Ahem, guess what, Dr. Venkat gives this same question again this year for his Ruby on Rails class.

The solution looks good. Did you get a 10 on this one? ^_^

Posted by Dat Chu on Mar 30, 2007 at 08:06 PM UTC - 5 hrs

Honestly, I forget what the grade was, and I'm hesitant to call anything a 10, because I'm not sure I got one the entire semester =)... But, I do remember having TONS of trouble with this, mainly due to the last code block there. That took forever to figure out what was going wrong!

Posted by Sam on Mar 31, 2007 at 09:14 AM UTC - 5 hrs

Thanks for the helpful post.
Can you post a little more detail as to why the last value of year gets used each time, when the define_method is put on a single line?

define_method("test_isleap_"+year) { assert_equal(is_leap.downcase=="true", @ly.isleap?(year.to_i)) }

How does a lambda closure stop this from happening?

Posted by Sam on Nov 19, 2007 at 03:29 AM UTC - 5 hrs

Hi Sam,
I never took the time to figure out why the behavior was different. I did a little experimenting today, and cannot seem to find a difference either.

My best guess is that in the 2nd version, the binding to local variables happens later than the first (well, I suppose that much is obvious). What's not obvious is why.

I'm going to post that question on Ruby Talk and see if some of the gurus there can help me understand.

Posted by Sammy Larbi on Nov 19, 2007 at 03:05 PM UTC - 5 hrs

The best I can tell now is that either it was a problem that got fixed in a newer version of Ruby, or I was mistaken when I wrote it.

Posted by Sammy Larbi on Nov 20, 2007 at 09:46 AM UTC - 5 hrs

Leave a comment

Leave this field empty
Your Name
Email (not displayed, more info?)
Website

Comment:

Subcribe to this comment thread
Remember my details
Google
Web CodeOdor.com

Me
Picture of me

Topics
.NET (19)
AI/Machine Learning (14)
Answers To 100 Interview Questions (10)
Bioinformatics (2)
Business (1)
C and C++ (6)
cfrails (22)
ColdFusion (78)
Customer Relations (15)
Databases (3)
DRY (18)
DSLs (11)
Future Tech (5)
Games (5)
Groovy/Grails (8)
Hardware (1)
IDEs (9)
Java (38)
JavaScript (4)
Linux (2)
Lisp (1)
Mac OS (4)
Management (15)
MediaServerX (1)
Miscellany (76)
OOAD (37)
Productivity (11)
Programming (168)
Programming Quotables (9)
Rails (31)
Ruby (67)
Save Your Job (58)
scriptaGulous (4)
Software Development Process (23)
TDD (41)
TDDing xorblog (6)
Tools (5)
Web Development (8)
Windows (1)
With (1)
YAGNI (10)

Resources
Agile Manifesto & Principles
Principles Of OOD
ColdFusion
CFUnit
Ruby
Ruby on Rails
JUnit



RSS 2.0: Full Post | Short Blurb
Subscribe by email:

Delivered by FeedBurner