From: Phlip Date: 2004-02-27T04:09:47+09:00 Subject: TDD Roman Numeral tutorial in Ruby Jim Rogers wrote: > > > assert ("I" == roman(1)); > > > /* assert ("II" == roman(2)); > > > assert ("III" == roman(3)); > > > assert ("IV" == roman(4)); > > > assert ("V" == roman(5)); > > > assert ("VI" == roman(6)); > > > assert ("VII" == roman(7)); > > > assert ("VIII" == roman(8)); > > > */ > I would change the entire approach to the following: > > type Roman_Numerals is (I, II, III, IV, V, VI, VII, VIII); Your implementation duplicates I, V, etc. If you were to resolve that duplication, it would form little tables. Then adding L, C, M etc. would get easier. I ran the experiment in Ruby, and put the result here: http://www.xpsd.org/cgi-bin/wiki?TestDrivenDevelopmentTutorialRomanNumerals The (unfinished) implementation is here: Symbols = { 1=>'I', 5=>'V', 10=>'X', 50=>'L', 100=>'C', } def roman(num) return Symbols[num] if Symbols.has_key?(num) [ [100, 1], [100, 10], [ 50, 10], [ 10, 1], [ 5, 1], [ 1, 0], ].each do |cutPoint, subtractor| if num > cutPoint then return roman(cutPoint) + roman(num - cutPoint) end if num >= cutPoint - subtractor and num < cutPoint then return roman(subtractor) + roman(num + subtractor) end end end That code can't do 49 (IL) yet, and it obviously can't do D or M yet. But it's just as obvious how to add those. That's the point: Removing duplication while growing a design in ways that improve its extensibility. There's plenty of "duplication" of various sorts in the above code. But merging it wouldn't make the design more extensible in the direction of more advanced roman numeral codes. It turned out that merging the components of the output strings - I, V etc. - focused the design directly on what was important. -- Phlip http://www.xpsd.org/cgi-bin/wiki?TestFirstUserInterfaces