February 21, 2006

Design by contract for Ruby

Here's a nice little module Brian and I hacked together a few weeks ago. It adds basic design by contract capabilities to classes with a fairly clean syntax (yay for Ruby's flexibility!)

Take a look for yourself:

class Foo
   include DesignByContract

   pre(:sqrt, "value must be >= 0") { |v| v >= 0 }

   pre("divisor must be != 0") { |dividend, divisor| divisor != 0 }
   post { |result, a, b| a - b * result < 1e-3 }
   def div(dividend, divisor)
      dividend / divisor
   end

   def sqrt(value)
      Math.sqrt value
   end

   post(:sqrt, "error is greater than expected") { |result, value|
         result * result - value < 1e-3
   }
end


When the DesignByContract module is included in a class, the pre and post methods become available. The parameters to these methods are a symbol representing the method to add the pre or post condition to, the message to print if the condition fails and a block that implements the condition.

The method name and message are optional, though. If the method name is missing, the condition will applied to the first method definition following the pre/post declaration. Note that if the method name is present, the condition can be defined anywhere in the class definition, as shown in the example above.

The condition block receives all the arguments passed to the method it applies to. They must return a boolean value indicating whether the condition succeeded. A minor difference between pre and post blocks is that the post block receives the result returned by the method as the first argument. This makes it possible to validate the results against the inputs such as in:

post { |result, dividend, divisor| dividend - divisor * result < 1e-3 }


Get it here!

How it works


In a nutshell, the pre and post methods intercept the existing method using the technique I described a few weeks ago (i.e., no poluting the class' namespace with aliased methods). The new methods test the provided condition before or after delegating the call to the original method and raise an exception if the condition fails.

There is a small caveat, though. If pre/post are called before the method is first created, it cannot be intercepted. To get around this the module uses an alternative trick. Whenever the module is included, it hooks into the method_added callback of class it's included into. If pre/post are called and the corresponding method does not exist, the interception is scheduled until the method is added.

Labels:

12 Comments:

Blogger Martin said...

Hey Ian,
It's good to hear somebody found this code helpful. And yeah, feel free to use it however you like.

April 15, 2006 11:31 AM  
Blogger Martin said...

BTW, I just made the license for that code explicit. I'm making it available under the MIT license. Let me know if that's not suitable for your use and I'll change it.

April 15, 2006 11:39 AM  
Blogger chicoary said...

Very good! But I noticed that the pre/post invocation order is not guaranteed.

June 01, 2006 6:31 AM  
Blogger bparanj said...

where is the invariant?

July 05, 2006 8:57 PM  
Blogger Martin said...

Erik,

I just uploaded a new version that fixes that issue.

Get it here: http://utils.ning.com/ruby/dbc.rb

August 19, 2006 6:43 PM  
Blogger Twm said...

Thanks for this. It looks like a very clean, natural implementation.
This doesn't seem to work for private methods. Nothing happens at all when i put a pre in front of a private.
I'd like to use this to state contracts between internal private methods as well as for public interfaces. How do i do that?

Ditto the comment about disabling it for release code.

October 08, 2006 5:50 PM  
Blogger legionnaired said...

This is a great module for ruby code, I think I want to add some functionality to a rails addon for rails developers, to give controllers, models, and views some basic requires/ensures capability. There'll probably be a tool as well that'll allow you to generate an app-specific cheat sheet of what each component makes use of... Would it be possible for me to commit some stuff to rdbc?

March 11, 2008 12:25 PM  
Blogger bestonline323 said...

That's a helpful code, thanks.

------------------------------------------
Interior Design Furniture Scotland

June 16, 2008 12:59 PM  
Blogger Adi said...

Pandeglang is one of many places in Indonesia are eligible for tourist destination.
Kenali dan Kunjungi Objek Wisata di Pandeglang Objek Wisata di Pandeglang Kenali dan Kunjungi Objek Wisata di Pandeglang Pantai Carita Seni Saman Rampak Bedug

October 29, 2009 11:07 PM  
Anonymous Anonymous said...

araç sorgulama
sorgulama
ehliyet
açıköğretim
bağkur sorgulama
ssk sorgulama
emekli sandığı
cinsellik
radyo dinle
korku
evlilik
hikaye
gazeteler
ilan
ssk
iş ilanları
bağkur
gazete oku

January 17, 2010 1:49 PM  
Blogger Unknown said...

Guccio Gucci,son of an Italian trader founded the House of Gucci gucci boots outlet in Florence in 1906. Guccio, authentic gucci bags an extraordinary craftsman, started selling luxury goods in the 1920s. cheap gucci shoes In 1938, Gucci opened a boutique in Rome discount Gucci bags.Aldo expanded the company by opening more stores. newest gucci handbags In 1953, New York got its first Gucci store gucci handbags 2010 and by the late '60s, more such stores were launched in London, Paris and Tokyo. Being a proud owner of a watch Armani watches outlet is a wondrous thing that many take for granted. watch wholesale No one remembers back when things were simple and discount DG watches they had to call "time and temperature" to get an accurate time cheap Chanel watches. Now certain devices run on their own newest GUCCI watches with no batteries.
Juicy couture handbags are among the brands Juicy couture which have gained a great repute over a longer period of time. The quality authentic Juicy bags and material used for their manufacturing is up to the mark Juicy handbags outlet and has no match.
Thus with the holiday shopping season approaching rapidly tiffany 2010, as an investor, the best gift you may give yourself this year is not a ring from tiffany, but shares from Tiffany. With a fairly good fundamentals, tiffany outlet a strong presence over its competitors, discount tiffany charms and a favorable economic situation to feed upon, I would not be hesitant to take a short term risk cheap tiffany Bangles in locating some luck with.
stylers are often available with free gifts, discount ghds or other incentives, which can sometimes on offer ghd outlet seems too good to be true, ghd then it probably is. There are many imitation cheap ghd flooding the market , so you need to keep ghd straighteners your withs about you. wholesale edhardy t shirt Whether you like the colour or want to do your bit for charity, Moncler T-shirtsvery popular when they are available. jumpman 23

April 12, 2010 7:07 PM  
Blogger Unknown said...

here shoes college abercrombie clothingabercrombie outletcenturies abercrombie and fitch shirtsand abercrombie fitch outlet fluorabercrombie & fitch clothing leather abercrombie and fitch clothesman-made abercrombie and fitch clothing flexibiabercrombie fitch fabri any abercrombie & fitchcan feel abercrombie fitch clothing Christopher abercrombie and fitchBURBERRY abercrombie and fitch outlet clothing cheap abercrombie fitch tinuously abercrombie shirt the UK and global explorers, adventurers discount abercrombie and fitch clothes sports to ed hardy wholesale throughs cheap ed hardy wholesaleNew BURBERRY discount ed hardy wholesale embodies wholesale ed hardy vitality BURBERRY ed hardy outlet attitude paulsmith British paulsmith outlet BURBERRY paulsmith 2010productcheap paulsmith national discount paulsmith brand (paul smith shoes and Burberry Lookbook Burberry outletoutspoken cheap Burberry Burberry discount Burberry to brand. Burberry (Burberry) newest Burberrygirls Burberry Shoes outlet fascination vest Burberry bagsshortsBurberry purseinnovative Burberry sunglasses Oh will newest Burberry suit it will moncler T-shirts

April 12, 2010 8:23 PM  

Post a Comment

<< Home