rubydbc 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/dbc.rb +110 -0
  2. metadata +46 -0
data/lib/dbc.rb ADDED
@@ -0,0 +1,110 @@
1
+ #
2
+ # Copyright (c) 2006 Martin Traverso, Brian McCallister
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+
24
+ module DesignByContract
25
+ @@pending = Hash.new { |hash, key| hash[key] = {} }
26
+
27
+ private
28
+
29
+ def self.extract(this, method_name, message)
30
+ if method_name.respond_to?(:to_str)
31
+ # no method symbol specified, just the message
32
+ message = method_name
33
+ method_name = nil
34
+ elsif !method_name.nil? && this.method_defined?(method_name)
35
+ old_method = this.instance_method(method_name)
36
+ end
37
+
38
+ return old_method, method_name, message
39
+ end
40
+
41
+ def self.schedule(type, mod, method_name, message, condition)
42
+ @@pending[mod][method_name] ||= []
43
+ @@pending[mod][method_name] << {:type => type, :message => message, :condition => condition}
44
+ end
45
+
46
+ def self.included(mod)
47
+ old_method_added = mod.method :method_added
48
+
49
+ new_method_added = lambda { |id|
50
+ if @@pending.has_key? mod
51
+ # save the list of methods and clear the entry
52
+ # otherwise, we'll have infinite recursion on the call to mod.send(...)
53
+ hooks = @@pending[mod].values_at(id, nil).compact.flatten
54
+ @@pending[mod].delete id
55
+ @@pending[mod].delete nil
56
+
57
+ # define scheduled hooks
58
+ hooks.each do |entry|
59
+ mod.send entry[:type], id, entry[:message], &entry[:condition]
60
+ end
61
+ end
62
+
63
+ old_method_added.call id
64
+ }
65
+
66
+ (class << mod; self; end).send :define_method, :method_added, new_method_added
67
+
68
+ class << mod
69
+ def pre(method_name = nil, message = nil, &condition)
70
+ old_method, method_name, message = DesignByContract.extract self, method_name, message
71
+
72
+ unless old_method.nil?
73
+ # make a method out of the condition so that we can bind it against self
74
+ # and pass it the arguments (it'd be easier if instance_eval accepted arguments...)
75
+ define_method(method_name, &condition)
76
+ condition_method = instance_method(method_name)
77
+ define_method(method_name) { |*args|
78
+ unless condition_method.bind(self).call(*args)
79
+ raise "Pre-condition #{'\'' + message + '\' ' if message}failed"
80
+ end
81
+
82
+ old_method.bind(self).call(*args)
83
+ }
84
+ else
85
+ DesignByContract.schedule :pre, self, method_name, message, condition
86
+ end
87
+ end
88
+
89
+ def post(method_name = nil, message = nil, &condition)
90
+ old_method, method_name, message = DesignByContract.extract self, method_name, message
91
+
92
+ unless old_method.nil?
93
+ # make a method out of the condition so that we can bind it against self
94
+ # and pass it the arguments (it'd be easier if instance_eval accepted arguments...)
95
+ define_method(method_name, &condition)
96
+ condition_method = instance_method(method_name)
97
+ define_method(method_name) { |*args|
98
+ result = old_method.bind(self).call(*args)
99
+ unless condition_method.bind(self).call(result, *args)
100
+ raise "Post-condition #{'\'' + message + '\' ' if message}failed"
101
+ end
102
+ return result
103
+ }
104
+ else
105
+ DesignByContract.schedule :post, self, method_name, message, condition
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.1
3
+ specification_version: 1
4
+ name: rubydbc
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.0.0
7
+ date: 2007-02-22 00:00:00 -08:00
8
+ summary: A Design by Contract mixin for Ruby
9
+ require_paths:
10
+ - lib
11
+ email: mtraverso@acm.org
12
+ homepage: http://rubyforge.org/projects/rubydbc
13
+ rubyforge_project:
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Martin Traverso
31
+ files:
32
+ - lib/dbc.rb
33
+ test_files: []
34
+
35
+ rdoc_options: []
36
+
37
+ extra_rdoc_files: []
38
+
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ requirements: []
44
+
45
+ dependencies: []
46
+