Forum: Ruby Handshake, an informal contract system for Ruby

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
A90e7575867bdbb5afca576947432a7e?d=identicon&s=25 Brian Guthrie (Guest)
on 2007-05-08 10:54
(Received via mailing list)
Handshake is an informal contract system for Ruby.  It allows
developers to apply clear, concise, and enforceable interfaces to
classes, in three forms:

 - method signatures
 - class invariants
 - pre- and post-conditions

Note that Handshake will only enforce checked contracts if the $DEBUG
flag is set to true (ruby -d).

Method signature contracts are applied in the following way:

  class Foo
    include Handshake

    contract [ all, acceptable, arguments ] => return_value
    def method(arg, ...) ...
  end

Signature contracts accept clauses, which are defined as any object
that implements the === method.  When specified with a symbol, they
will be applied the named method; when specified without one, they
will be applied to the next defined method.  Handshake comes with a
number of useful clauses predefined:

  contract :foo, any?(String, 0..5) => Symbol
  contract :sum, many?(Integer) => Integer
  contract :deposit, positive_n? => Integer

It can also apply contracts to varargs and anonymous blocks:

  contract [ String, [ Integer ] ] => anything
  def foo(str, *ints) ...

  contract :each, Block(String => anything) => many?(String)

In addition, users can define their own custom project-specific
clauses very easily.  See the RDoc for Handshake::ClauseMethods for
more information.

Class invariants accept a message and a block, which is expected to
return a boolean value.  Their value is checked before and after each
method invocation and are scoped to allow checking of instance
variables and private methods.

  class NonEmptyArray < Array
    include Handshake
    invariant("should never be empty") { not empty? }
  end

Pre- and post-conditions allow for grouping common sets of assertions,
typically those that require checking arguments against one another.
All Test::Unit assertions are available, although they raise a
Handshake::ContractViolation exception here upon failure.

  before do |first_half, second_half|
    assert_equal 10, first_half.length + second_half.length
  end
  def accepts_ten_items(first_half, second_half) ...

Handshake is implemented by aliasing the new method of any class that
includes it.  The modified new method returns a proxy object in place
of the original object that looks, acts, and feels like the real
thing.  It acts as a barrier, and all method invocations that cross
the barrier are checked against the defined contracts.  It differs in
this manner from other Ruby DBC-style systems, which generally alias
each contract-checked method as necessary.  Because of both this and
its grave irrelevance to a Rails context, I wouldn't recommend trying
to use Handshake with any Rails projects.

Handshake is written in pure Ruby, is available as open source under
the same license as Ruby, and is installable as a gem (latest
version=0.3.0).  It lives at http://rubyforge.org/projects/handshake,
and the RDoc is available at http://handshake.rubyforge.org.

I'd love to hear any comments, criticisms, and suggestions.  I'm also
presenting Handshake tonight at the Boston Rubygroup and figured,
well, I should probably announce the silly thing on ruby-talk first.

Brian Guthrie
btguthrie@gmail.com
http://blog.brianguthrie.com
This topic is locked and can not be replied to.