Class: Handshake::MethodContract

Inherits:
ProcContract show all
Defined in:
lib/handshake.rb

Overview

Class representing method contracts. Not for external use.

Instance Attribute Summary collapse

Attributes inherited from ProcContract

#accepts, #returns

Instance Method Summary collapse

Methods inherited from ProcContract

#accepts_varargs?, #check_returns!, #signature=

Constructor Details

#initialize(method_name) ⇒ MethodContract

Returns a new instance of MethodContract.



376
377
378
379
380
381
# File 'lib/handshake.rb', line 376

def initialize(method_name)
  @method_name = method_name
  @preconditions, @postconditions = [], []
  @accepts, @returns = [], []
  @block_contract = nil
end

Instance Attribute Details

#block_contractObject (readonly)

Returns the value of attribute block_contract.



374
375
376
# File 'lib/handshake.rb', line 374

def block_contract
  @block_contract
end

#postconditionsObject

:nodoc:



373
374
375
# File 'lib/handshake.rb', line 373

def postconditions
  @postconditions
end

#preconditionsObject

:nodoc:



373
374
375
# File 'lib/handshake.rb', line 373

def preconditions
  @preconditions
end

Instance Method Details

#accepts=(args) ⇒ Object

If the last argument is a Block, handle it as a special case. We do this to ensure that there’s no conflict with any real arguments which may accept Procs.



437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
# File 'lib/handshake.rb', line 437

def accepts=(args)
  if args.last == Block # Transform into a ProcContract
    args.pop
    @block_contract = ProcContract.new
    @block_contract.accepts = ClauseMethods::ANYTHING
    @block_contract.returns = ClauseMethods::ANYTHING        
  elsif args.last.is_a?(ProcContract)
    @block_contract = args.pop
  end

  if args.find_all {|o| o.is_a? Array}.length > 1
    raise ContractError, "Cannot define more than one expected variable argument"
  end
  super(args)
end

#check_accepts!(*args, &block) ⇒ Object



383
384
385
386
387
388
# File 'lib/handshake.rb', line 383

def check_accepts!(*args, &block)
  super(*args, &block)
  if expects_block?
    check_equivalence!(block, Proc)
  end
end

#check_conditions!(o, args, conditions) ⇒ Object

Checks the given conditions against the object, passing the given args into the block. Throws :contract if any fail or if an exception is raised. Because of the need to evaluate the condition in the context of the object itself, a temporary method called bound_condition_passes? is defined on the object, using the block associated with the condition. TODO Is there a better way to evaluate an arbitary block in a particular binding? There must be.



418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/handshake.rb', line 418

def check_conditions!(o, args, conditions)
  conditions.each do |condition|
    o.class.instance_eval do
      define_method(:bound_condition_passes?, &(condition.block))
    end
    begin
      o.bound_condition_passes?(*args)
    rescue Test::Unit::AssertionFailedError => afe
      throw :contract, AssertionFailed.new(afe.message)
    rescue Exception => e
      throw :contract, e
    end
    o.class.send(:remove_method, :bound_condition_passes?)
  end
end

#check_post!(o, *args) ⇒ Object

Checks the postconditions of this contract against the given object and return values. Any assertions thrown are re-raised as Handshake::AssertionViolation errors.



401
402
403
# File 'lib/handshake.rb', line 401

def check_post!(o, *args)
  check_conditions!(o, args, @postconditions)
end

#check_pre!(o, *args) ⇒ Object

Checks the preconditions of this contract against the given object and arugment values. Any assertions thrown are re-raised as Handshake::AssertionFailed errors.



408
409
410
# File 'lib/handshake.rb', line 408

def check_pre!(o, *args)
  check_conditions!(o, args, @preconditions)
end

#defined?Boolean

Returns true only if this MethodContract has been set up to check for one or more contract conditions.

Returns:

  • (Boolean)


392
393
394
395
396
# File 'lib/handshake.rb', line 392

def defined?
  [ preconditions, postconditions, accepts, returns ].any? do |ary|
    not ary.empty?
  end
end

#expects_block?Boolean

Returns:

  • (Boolean)


453
454
455
# File 'lib/handshake.rb', line 453

def expects_block?
  not @block_contract.nil?
end