From: Steven Shaw Date: 2005-02-27T15:30:01+09:00 Subject: Re: A Ruby-relevant quote from Alan Kay I came across what looked like a keyword argument calling syntax via http://www.zenspider.com/Languages/Ruby/QuickRef.html - I've updated my code and it's pretty close to have I hoped it could be. I had to use the '*' notation for optional "rest" arguments so that I could allow for an optional else block. The "keyword arguments" come through as a single Hash into the first element of rest. Here's what it looks like: result = (i > 10).if Proc.new { puts "i > 10" i }, :else => Proc.new { puts "i <= 10" 0 }; I discovered that you can use "proc" instead of "Proc.new": result = (i > 10).if proc{ puts "i > 10" i }, :else => proc{ puts "i <= 10" 0 }; Anyone know a way of making this even more concise? Within using the built-in syntax... :-) Here's the updated code with Csaba's ifthen, and my on_false/unless and on_true/when methods removed for clarity. ######### module TrueModule def if(ifblock, *rest) ifblock.call end end module FalseModule def if(ifblock, *rest) if rest.length == 1 then keyargs = rest[0] elseblock = keyargs[:else] if elseblock elseblock.call end end end end class Object include TrueModule end [NilClass, FalseClass].each { |c| c.send :include, FalseModule } if $0 == __FILE__ then def test_single_block_if(item) actual = item.if Proc.new{ puts "TRUE"; 1 } puts "actual = #{actual.inspect}" # using built-in if expected = if (item) puts "TRUE" 1 end puts "expected = #{expected.inspect}" if actual != expected puts "FIXME: single-block if failed" end end def test_multi_block_if(item) actual = item.if Proc.new { puts "item is true" 1 }, :else => Proc.new { puts "item is false" 0 }; puts "actual = #{actual.inspect}" # using built-in if & then expected = if item puts "item is true" 1 else puts "item is false" 0 end puts "expected = #{expected.inspect}" if actual != expected puts "FIXME: multi-block if failed" end end def test_single_block_if_not(item) actual = (not item).if Proc.new{ puts "FALSE"; 0 } puts "actual = #{actual.inspect}" # using built-in if not expected = if (not item) puts "FALSE" 0 end puts "expected = #{expected.inspect}" if actual != expected puts "FIXME: multi-block if failed" end end # try multiblock if. true.if Proc.new { puts "yep" }, :else => Proc.new { puts "nah" } false.if Proc.new { puts "yep" }, :else => Proc.new { puts "nah" } # try singleblock if. true.if Proc.new { puts "yep" } false.if Proc.new { puts "never executes" } [1, 0, "Hello", false, true, nil].each { |item| puts "--- #{item.inspect} ---" test_single_block_if(item) test_single_block_if_not(item) test_multi_block_if(item) } end if __FILE__ == $0 require "runit/testcase" require 'runit/cui/testrunner' require 'runit/testsuite' class Testing_class < RUNIT::TestCase def test1 result = 1.if Proc.new { 10 } assert_equal(result, 10); end def test2 result = false.if Proc.new { 10 } assert_equal(result, nil); end def test3 result = nil.if Proc.new { 10 } assert_equal(result, nil); end end RUNIT::CUI::TestRunner.run(Testing_class.suite) end #########