This page contains automated test results for code from O'Reilly's Ruby Cookbook. If this code looks interesting or useful, you might want to buy the whole book.

Enforcing Software Contracts (written by Maurice Codik)
CodeExpectedActual
module Contracts
  def valid_contract(input)
    if @user_defined and @user_defined[input]
      @user_defined[input]
    else
      case input
      when :number
        lambda { |x| x.is_a? Numeric }
      when :string
        lambda { |x| x.respond_to? :to_str }
      when :anything
        lambda { |x| true }
      else
        lambda { |x| false }
      end
    end
  end
  class ContractViolation < StandardError
  end 
  def define_data(inputs={}.freeze)
    @user_defined ||= {}
    inputs.each do |name, contract|
      @user_defined[name] = contract if contract.respond_to? :call
    end
  end
  def contract(method, *inputs)
    @contracts ||= {}
    @contracts[method] = inputs
    method_added(method)
  end
  def setup_contract(method, inputs)
    @contracts[method] = nil
    method_renamed = "__#{method}".intern
    conditions = ""
    inputs.flatten.each_with_index do |input, i|
      conditions << %{
       if not self.class.valid_contract(#{input.inspect}).call(args[#{i}])
          raise ContractViolation, "argument #{i+1} of method '#{method}' must satisfy the '#{input}' contract", caller
        end
      }
    end
   class_eval %{
       alias_method #{method_renamed.inspect}, #{method.inspect}
       def #{method}(*args)
         #{conditions}
         return #{method_renamed}(*args)
       end
     }
  end
  def method_added(method)
    inputs = @contracts[method]
    setup_contract(method, inputs) if inputs
  end
end
class TestContracts
  def hello(n, s, f)
    n.times { f.write "hello #{s}!\n" }
  end
  extend Contracts
  writable_and_open = lambda do |x| 
    x.respond_to?('write') and x.respond_to?('closed?') and not x.closed?
  end
  define_data(:writable => writable_and_open,
              :positive => lambda {|x| x >= 0 })
  contract :hello, [:positive, :string, :writable]
end
tc = TestContracts.new
tc.hello(2, 'world', $stdout)
hello world!
hello world!
hello world!
hello world!
tc.hello(-1, 'world', $stdout)
Contracts::ContractViolation: argument 1 of method 'hello' must satisfy the
'positive' contract
Error! (Exception?) Here's stdout:
Contracts::ContractViolation: argument 1 of method 'hello' must satisfy the 'positive' contract
	from (irb):69
tc.hello(2, 3001, $stdout)
test-contracts.rb:22: argument 2 of method 'hello' must satisfy the 
'string' contract (Contracts::ContractViolation)
Error! (Exception?) Here's stdout:
Contracts::ContractViolation: argument 2 of method 'hello' must satisfy the 'string' contract
	from (irb):70
closed_file = open('file.txt', 'w') { }
tc.hello(2, 'world', closed_file)
Contracts::ContractViolation: argument 3 of method 'hello' must satisfy the 
'writable' contract
Error! (Exception?) Here's stdout:
Contracts::ContractViolation: argument 3 of method 'hello' must satisfy the 'writable' contract
	from (irb):72
contract :hello, [:positive, :string, :writable]
def hello(n,s,f)
  if not (n >= 0)
    raise ContractViolation, 
    "argument 1 of method 'hello' must satisfy the 'positive' contract", caller
  end
  if not (s.respond_to? String)
    raise ContractViolation,
    "argument 2 of method 'hello' must satisfy the 'string' contract", 
    caller
  end
  if not (f.respond_to?('write') and f.respond_to?('closed?') 
          and not f.closed?)
    raise ContractViolation, 
    "argument 3 of method 'hello' must satisfy the 'writable' contract",
    caller
  end
  return __hello(n,s,f)
end
def __hello(n,s,f)
  n.times { f.write "hello #{s}!\n" }
end
nil