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:



37
38
39
40
# File 'lib/ruby_contracts/dsl.rb', line 37

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



23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/ruby_contracts/dsl.rb', line 23

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



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

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

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



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

def __eval_after_contracts(name, context, arguments, result)
  __contracts_for(name).each do |contracts|
    next if contracts.empty?
    contracts.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



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

def __eval_before_contracts(name, context, arguments)
  last_failure_msg = nil
  __contracts_for(name).each do |contracts|
    next if contracts.empty?
    success = true
    contracts.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



13
14
15
16
# File 'lib/ruby_contracts/dsl.rb', line 13

def inherited(subclass)
  super
  subclass.__contracts_initialize
end

#method_added(name) ⇒ Object



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

def method_added(name)
  super

  return if @__skip_other_contracts_definitions

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

  if !__contracts.empty?
    @__skip_other_contracts_definitions = true
    original_method_name = "#{name}_without_contracts"
    define_method(original_method_name, instance_method(name))

    method = <<-EOM
      def #{name}(*args, &block)
        __args = block.nil? ? args : args + [block]
        self.class.__eval_before_contracts("#{name}", self, __args)
        result = #{original_method_name}(*args, &block)
        self.class.__eval_after_contracts("#{name}", self, __args, result)
        return result
      end
    EOM

    class_eval method

    @__skip_other_contracts_definitions = false
  end
end

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



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

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

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



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

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

#type(options) ⇒ Object



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

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