Module: Contracts::DSL::ClassMethods

Defined in:
lib/ruby_contracts/dsl.rb

Instance Method Summary collapse

Instance Method Details

#__contract_failure!(name, message, result, *args) ⇒ Object

Raises:



41
42
43
44
# File 'lib/ruby_contracts/dsl.rb', line 41

def __contract_failure!(name, message, result, *args)
  args.pop if args.last.kind_of?(Proc)
  raise Contracts::Error.new("#{self}##{name}(#{args.join ', '}) => #{result || "?"} ; #{message}.")
end

#__contracts_for(name, current_contracts = nil) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/ruby_contracts/dsl.rb', line 27

def __contracts_for(name, current_contracts=nil)
  if @__contracts_for.has_key?(name) && !current_contracts
    @__contracts_for[name]
  else
    contracts = ancestors[1..-1].reverse.reduce([]) do |c, klass|
      ancestor_hash = klass.instance_variable_get('@__contracts_for')
      c += ancestor_hash[name] if ancestor_hash && ancestor_hash.has_key?(name)
      c
    end
    contracts << current_contracts if current_contracts
    @__contracts_for[name] = contracts
  end
end

#__contracts_initializeObject



22
23
24
25
# File 'lib/ruby_contracts/dsl.rb', line 22

def __contracts_initialize
  @__contracts = Contracts::List.new
  @__contracts_for = {}
end

#__eval_after_contracts(name, context, arguments, result) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/ruby_contracts/dsl.rb', line 106

def __eval_after_contracts(name, context, arguments, result)
  __contracts_for(name).each do |contracts|
    after_contracts = contracts.after_contracts
    next if after_contracts.empty?
    after_contracts.each do |contract|
      begin
        unless satisfied = contract.satisfied?(context, arguments, result)
        __contract_failure!(name, contract.message, result, arguments)
          break
        end
      rescue
        __contract_failure!(name, "Contract evaluation failed with #{$!} for #{contract.class} #{contract.message}", result, arguments)
      end
    end
  end
end

#__eval_before_contracts(name, context, arguments) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/ruby_contracts/dsl.rb', line 81

def __eval_before_contracts(name, context, arguments)
  last_failure_msg = nil
  __contracts_for(name).each do |contracts|
    before_contracts = contracts.before_contracts
    next if before_contracts.empty?
    success = true
    before_contracts.each do |contract|
      begin
        unless satisfied = contract.satisfied?(context, arguments)
          last_failure_msg = contract.message
          success = false
          break
        end
      rescue
        last_failure_msg = "Contract evaluation failed with #{$!} for #{contract.class} #{contract.message}"
        success = false
        break
      end
    end
    return if success
  end

  __contract_failure!(name, last_failure_msg, nil, arguments) if last_failure_msg
end

#inherited(subclass) ⇒ Object



17
18
19
20
# File 'lib/ruby_contracts/dsl.rb', line 17

def inherited(subclass)
  super
  subclass.__contracts_initialize
end

#method_added(name) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/ruby_contracts/dsl.rb', line 59

def method_added(name)
  super

  return if @__skip_other_contracts_definitions

  __contracts = __contracts_for(name.to_s, @__contracts)
  @__contracts = Contracts::List.new

  if !__contracts.first.empty?
    @__skip_other_contracts_definitions = true
    original_method = instance_method(name)
    define_method(name) do |*args, &block|
      __args = block.nil? ? args : args + [block]
      self.class.__eval_before_contracts(name.to_s, self, __args)
      result = original_method.bind(self).(*args, &block)
      self.class.__eval_after_contracts(name.to_s, self, __args, result)
      return result
    end
    @__skip_other_contracts_definitions = false
  end
end

#post(message = nil, &block) ⇒ Object



55
56
57
# File 'lib/ruby_contracts/dsl.rb', line 55

def post(message=nil, &block)
  @__contracts << Contracts::Postcondition.new(message, block)
end

#pre(message = nil, &block) ⇒ Object



51
52
53
# File 'lib/ruby_contracts/dsl.rb', line 51

def pre(message=nil, &block)
  @__contracts << Contracts::Precondition.new(message, block)
end

#type(options) ⇒ Object



46
47
48
49
# File 'lib/ruby_contracts/dsl.rb', line 46

def type(options)
  @__contracts << Contracts::InputType.new(options[:in].kind_of?(Array) ? options[:in] : [options[:in]])   if options.has_key?(:in)
  @__contracts << Contracts::OutputType.new(options[:out]) if options.has_key?(:out)
end