Wednesday, August 30, 2006

Ruby Quiz #6: Too Simple?

Matt Secoske and I were pairing last night and we decided to work on quiz #6 from the Ruby Quiz book. Here's our code complete with tests.
require 'test/unit'
require 'test/unit/ui/console/testrunner'

module Enumerable
def in?(candidate)
any? {|any| any.in? candidate}
end
end


class Fixnum
def in?(candidate)
equal? candidate
end
end


class Range
def in?(candidate)
include? candidate
end
end


class BuildRegexp
GUARD = /^[0123456789]+$/

def initialize(candidates)
@candidates = candidates
end

def =~(candidate)
GUARD =~ candidate && (@candidates.in? candidate.to_i)
end
end

class Regexp
def self.build(*candidates)
BuildRegexp.new(candidates)
end

end


class BuildTest < Test::Unit::TestCase
def test_lucky()
lucky = Regexp.build(3,7)
assert('7' =~ lucky)
assert(!('13' =~ lucky))
assert('3' =~ lucky)
end

def test_month()
month = Regexp.build(1..12)
assert(!('0' =~ month))
assert('1' =~ month)
assert('12' =~ month)
end

def test_day()
day = Regexp.build(1..31)
assert('6' =~ day)
assert('16' =~ day)
assert(!('Tues' =~ day))
end

def test_year()
year = Regexp.build(98,99,2000..2005)
assert(!('04' =~ year))
assert('2004' =~ year)
assert('98' =~ year)
end

def test_num()
num = Regexp.build(0..1_000_000)
assert(!('-1' =~ num))
end

end

Test::Unit::UI::Console::TestRunner.new(BuildTest.suite()).start()

Of course, we excitedly looked up the answer in the book and were shocked. Their final answer was longer and harder to understand. Our code uses less of the regular expression class. In fact, we only used it as a guard to make sure we could convert the input to a number. We also made heavy use of polymorphism and duck typing(in?, =~). As you can see the code is very short.

The quiz was to build a Regexp to handle any list or range of numbers. The tests are taken exactly from the book and of course, we wrote them first. Well, actually, we wrote them at each stage. At one point, we were using Regexp extensively until we hit the last test. And that is when the change in requirements caused all of the code you see above.

How fun! We looked at each other and wondered, "Was our solution too simple?" We then laughed and said, "Nah." We were both proud for our simple and readable solution.

1 comment:

Matt Secoske said...

I was thinking about this this morning. While we did hit everything that was specified in the quiz AND passed all the tests, I think there was an unspoken rule that you should provide all of the Regex functionality:

1. Regex.match
2. MatchData
3. the $ functions ($&, $1, $', etc)

Overall, I think our solution solved what the quiz laid out, but fails in the sense that it does not fully support Regex. Maybe next time we get together :)

Amazon