From: Robert Klemme Date: 2004-03-04T00:49:45+09:00 Subject: Re: Ruby won, of course (was: language contest ==> unit test framework from lisp to ruby) "Piergiuliano Bossi" schrieb im Newsbeitrag news:c24rte$da0$1@lacerta.tiscalinet.it... > Result: ruby won with the following version > > **********************CUT HERE********************** > def combine(*results) not results.flatten().include? false end > def check (*all) combine all.collect{|t|c =caller-[caller.last] > c.collect!{|l|(l.include? "rut.rb")? nil : l.sub(/.*in/, '')} > puts (eval t)?"pass ...#{c} #{t}":"FAIL ...#{c} #{t}";eval t} end > **********************CUT HERE********************** IMHO Ruby can do better (also removing some duplicate evaluation): def check (*all) c=caller[0...-1].map{|l|l.include?("rut.rb")? nil : l.sub(/.*in/, '')}.compact all.collect{|t|res=eval t; puts "#{res ?"pass":"FAIL"} ...#{c} #{t}";res}.all? end irb(main):078:0> check( "5+3", "4>3" ) pass ...g'g' 5+3 pass ...g'g' 4>3 => true irb(main):079:0> check( "5+3", "4>3", "4<3" ) pass ...g'g' 5+3 pass ...g'g' 4>3 FAIL ...g'g' 4<3 => false Or did I miss something? robert > > (my version would be more compact if body method follows def directly, I > should have thought about it). > > Just for fun, here are perl and smalltalk participants. > > Perl solution makes use of closures. > **********************CUT HERE********************** > 01: sub makeTest { > 02: my $testname = shift; > 03: my @tests = map { ref $_ ? $_ : makeTestRunner($_) } @_; > 04: return sub { my $suitename=shift; our $level++; my $result=1; > 05: map { $result &= $_->($suitename.$testname.' ') } @tests; > 06: --$level == 0 ? print $result ? "T":"F","\n" : $result; } } > 07: sub makeTestRunner { > 08: my $code = shift; return sub { my $result = eval $code; > 09: print $result?"pass":"fail"," ... ( ".shift().") $code\n"; > 10: $result ? 1:0 } } "End of conTest :-)"; > **********************CUT HERE********************** > > Smalltalk solution is based on recursion. > **********************CUT HERE********************** > Trigo class >> check: what > what size = 0 ifTrue: [^true] ifFalse: [^(Trigo report: (what at: 1)) > & (Trigo check: (what copyFrom: 2 to: what size))] > Trigo class >> filter > ^((thisContext sendersTo: nil) > select: [:each | '*test*' match: each printString]) reverse > Trigo class >> report: aTest > | result eval | > eval := Compiler evaluate: aTest. > eval ifTrue:[result:=': pass'] ifFalse:[result:=': FAIL']. > Trigo filter do:[:each|Transcript show:each printString,' ' ]. > Transcript show: aTest, result, '\' withCRs.^eval > **********************CUT HERE********************** > > This contest was a real fun! > Ciao, Giuliano > > > Piergiuliano Bossi wrote: > > A few days ago I made a post (rubytalk:92963 ==> [2]) about the > > development of a mini-framework in ruby related to unit testing and > > inspired by Peter Seibel [1]. Unfortunately, I have got no comments > > about it. > > > > Anyway, after some feedback on another mailing list from Gabriele Renzi, > > I have come up with the following version: > > > > **********************CUT HERE********************** > > def stack > > caller[3..-1].map {|m| m[/test_.*(?=')/]}.compact.reverse.join " " > > end > > def check(*tests) > > tests.map! {|t| puts "#{(v=eval(t)) ? 'pass' : 'FAIL'} ... > > (#{stack}) #{t.strip}"; v} > > combine_results(*tests) > > end > > def combine_results(*tests) > > tests.inject {|t1, t2| t1 && t2} > > end > > > > def test_plus > > check( > > "1 + 2 == 3", > > "1 + 2 + 3 == 6", > > "-1 + -3 == -4") > > end > > def test_multiply > > check( > > "2 * 2 == 4", > > "3 * 5 == 15") > > end > > > > def test_aritmetic > > combine_results( > > test_plus, > > test_multiply) > > end > > > > def test_math > > test_aritmetic > > end > > > > result = test_math > > puts "result=#{result}" > > **********************CUT HERE********************** > > > > As you can see, my ruby version looks more compact and more easily > > undestandable to my non-lisper eyes than Seibel's version. > > > > I have challenged a few friends to build the most compact version of the > > framework. There's a perl fan, a few ruby guys and a smalltalker in the > > arena. > > Constraints: > > *) the framework should express same functionality as Seibel's version > > as much as possible, nothing more, nothing less, given the peculiar > > limitations of the chosen language > > *) code should be "understandable" by the majority of participants > > *) if a line is longer than 70 chars then it is automatically splitted > > *) the program with the smallest amount of lines is the champion > > > > My version is 10 lines long, +1 for a line longer than 70 chars = 11, > > but I don't really participate, I'm the judge (wow!) and I'm financing > > the prize (some food, I think, probably pizza). > > > > A ruby guy has already anticipated that he has reached a version which > > is only 5 lines long. Inspired and challenged by his words I have come > > up with another version that based on the definition above is only 5 > > lines long too: > > > > **********************CUT HERE********************** > > def check(*tests) > > stack = caller.map {|m| m[/\w*(?=')/]}.compact.reverse.join " " > > tests.inject(true) {|ret, t| puts "#{(v=eval(t)) ? 'pass' : 'FAIL'} > > ... (#{stack}) #{t.strip}"; ret && v} > > end > > **********************CUT HERE********************** > > > > Doing this way there is no need of combine_results method, and several > > tests may be combined in one method simply using '&&' (or 'and') like > > the following: > > > > **********************CUT HERE********************** > > def test_aritmetic > > test_plus && > > test_multiply > > end > > **********************CUT HERE********************** > > > > Contest deadline is next Monday, 1st of March. > > I'll let you know the results, of course, but I'm curious to have your > > early feedback too, if possible. > > Ciao, Giuliano > > > > > > [1] - http://tinyurl.com/2b99d > > [2] - http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/92963 > > -- > If you want to send me an email in the address you have to write 'p', > then a dot, followed by 'bossi' at 'quinary', another dot and 'com' at last >