rubydbc 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+