From: John Carter Date: 2007-08-03T09:18:30+09:00 Subject: Re: Is there a standard "assert" idiom in Ruby? On Thu, 2 Aug 2007, Kenneth McDonald wrote: > If you saw an earlier version of this question, apologies...I haven't seen > it, so assume I accidentally deleted it or it got lost or some such. > > In other languages, I'm accustomed to using "assert" as a sort of enforceable > documentation. Is there an equivalent statement or idiom in Ruby? I find that > simply raising exceptions isn't quite right; exceptions are normally used > when one thinks something might be done about a problem, whereas asserts are > used to check that something is the way it always should be. I been around this particular block a few times and have come up with the simplest... def foo( a) raise "ASSERTION FAILURE! a '#{a}' not nice!" unless a.nice? end Note a couple of other things... I have thought about creating an class AssertionFailure < Exception end But I'm not sure I care to. By an assertion failing I'm saying "Something untoward/unclean has happened. I know not what, I have just spotted the symptom. Give me some info, give me a backtrace, and I'll sort it out later. The program has gone barking mad, take it out back and shoot it" Variants on the above, I may change the ASSERTION FAILURE to PRECONDITION is that's what I mean... def foo( a) raise "PRECONDITION FAILURE! a '#{a}' not nice!" unless a.nice? end Or I may let ruby do it's thing so instead of def foo( a) raise "PRECONDITION FAILURE! a '#{a}' is nil!" if a.nil? a.doStuff() end I prefer... def foo( a) a.doStuff() end And let Ruby throw the appropriate exception (which gives me a back trace any way.) Note I _never_ do something like... x = ARGV[0].to_f raise "ASSERTION FAILURE: x '#{x}' is negative" if x < 0 puts x ** 0.5 An assertion failure _always_ means I have may a mistake, _never_ the user. In fact some of my scripts have at the end... rescue Exception => details puts "This is John's Fault. Call John now and tell him to fix it.: puts details.to_s ... Speedwise I profile, and if one of my asserts show up in a hot spot... A # or two later it is gone from the execution path, but is still there as documentation. Another approach is to try lift the assert up the call tree. Usually you escape some loop. def foo(a) @n.times {|s| bah(s,a) end def bah(s,a) raise "ASSERT FAILURE!" unless a.nice? # do things with s and nice a end becomes... def foo(a) raise "ASSERT FAILURE!" unless a.nice? @n.times {|s| bah(s,a) end def bah(s,a) # raise "ASSERT FAILURE!" unless a.nice? # do things with s and nice a end John Carter Phone : (64)(3) 358 6639 Tait Electronics Fax : (64)(3) 359 4632 PO Box 1645 Christchurch Email : john.carter@tait.co.nz New Zealand