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.



395
396
397
398
399
# File 'lib/handshake.rb', line 395

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

Instance Attribute Details

#block_contractObject (readonly)

Returns the value of attribute block_contract.



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

def block_contract
  @block_contract
end

#postconditionsObject

:nodoc:



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

def postconditions
  @postconditions
end

#preconditionsObject

:nodoc:



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

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.



455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
# File 'lib/handshake.rb', line 455

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



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

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.



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

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.



419
420
421
# File 'lib/handshake.rb', line 419

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.



426
427
428
# File 'lib/handshake.rb', line 426

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)


410
411
412
413
414
# File 'lib/handshake.rb', line 410

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

#expects_block?Boolean

Returns:

  • (Boolean)


471
472
473
# File 'lib/handshake.rb', line 471

def expects_block?
  not @block_contract.nil?
end