ruby_contracts 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -38,6 +38,14 @@ Run this sample with `ENABLE_ASSERTION=1 bundle exec ruby example.rb`.
38
38
 
39
39
  Without the environment variable `ENABLE_ASSERTION` you have zero overhead and zero verification.
40
40
 
41
+ ## Class inheritance
42
+
43
+ When you inherit a class that contains contracts, all contracts must be satified by the subclass.
44
+
45
+ If you override a method, you still have to satisfy the existing contracts for this method and you can add some others.
46
+
47
+ See the [issue #1](https://github.com/nicoolas25/ruby_contracts/issues/1) for an example.
48
+
41
49
  ## Contributing
42
50
 
43
51
  1. Fork it
@@ -1,3 +1,3 @@
1
1
  module RubyContracts
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -3,14 +3,40 @@ require "ruby_contracts/version"
3
3
  module Contracts
4
4
  class Error < Exception ; end
5
5
 
6
+ def self.empty_contracts
7
+ {:before => [], :after => []}
8
+ end
9
+
6
10
  module DSL
7
11
  def self.included(base)
8
12
  base.extend Contracts::DSL::ClassMethods
13
+ base.__contracts_initialize
9
14
  end
10
15
 
11
16
  module ClassMethods
12
- def self.extended(base)
13
- base.instance_eval "@__contracts = {:before => [], :after => []}"
17
+ def inherited(subclass)
18
+ super
19
+ subclass.__contracts_initialize
20
+ end
21
+
22
+ def __contracts_initialize
23
+ @__contracts = Contracts.empty_contracts
24
+ @__contracts_for = {}
25
+ end
26
+
27
+ def __contracts_for(name, current_contracts=nil)
28
+ inherited_contracts = ancestors[1..-1].reduce(Contracts.empty_contracts) do |c, klass|
29
+ ancestor_hash = klass.instance_variable_get('@__contracts_for') || {}
30
+ c[:before] += ancestor_hash.has_key?(name) ? ancestor_hash[name][:before] : []
31
+ c[:after] += ancestor_hash.has_key?(name) ? ancestor_hash[name][:after] : []
32
+ c
33
+ end
34
+ current_contracts = @__contracts_for[name] || current_contracts || Contracts.empty_contracts
35
+
36
+ contracts = Contracts.empty_contracts
37
+ contracts[:before] = current_contracts[:before] + inherited_contracts[:before]
38
+ contracts[:after] = current_contracts[:after] + inherited_contracts[:after]
39
+ contracts
14
40
  end
15
41
 
16
42
  def __contract_failure!(name, message, result, *args)
@@ -32,16 +58,20 @@ module Contracts
32
58
  end
33
59
 
34
60
  def method_added(name)
35
- if ENV['ENABLE_ASSERTION'] && (!@__contracts[:before].empty? || !@__contracts[:after].empty?)
36
- __contracts_copy = @__contracts
37
- @__contracts = {:before => [], :after => []}
61
+ super
62
+
63
+ return unless ENV['ENABLE_ASSERTION']
64
+ return if @__contracts_for.has_key?(name)
38
65
 
66
+ __contracts = @__contracts_for[name] ||= __contracts_for(name, @__contracts)
67
+ @__contracts = Contracts.empty_contracts
68
+
69
+ if !__contracts[:before].empty? || !__contracts[:after].empty?
39
70
  original_method_name = "#{name}__with_contracts"
40
71
  define_method(original_method_name, instance_method(name))
41
72
 
42
-
43
73
  count = 0
44
- before_contracts = __contracts_copy[:before].reduce("") do |code, contract|
74
+ before_contracts = __contracts[:before].reduce("") do |code, contract|
45
75
  type, *args = contract
46
76
  case type
47
77
  when :type
@@ -71,7 +101,7 @@ module Contracts
71
101
  end
72
102
  end
73
103
 
74
- after_contracts = __contracts_copy[:after].reduce("") do |code, contract|
104
+ after_contracts = __contracts[:after].reduce("") do |code, contract|
75
105
  type, *args = contract
76
106
  case type
77
107
  when :type
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_contracts
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-03 00:00:00.000000000 Z
12
+ date: 2013-06-11 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Micro DSL to add pre & post condition to methods. It try to bring some
15
15
  design by contract in the Ruby world.