rdbc 0.0.1
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.
- data/README +49 -0
- data/Rakefile +37 -0
- data/lib/design_by_contract.rb +141 -0
- data/test/design_by_contract_test.rb +34 -0
- data/test/stack.rb +41 -0
- data/test/stack_contract.rb +33 -0
- data/test/stack_test.rb +37 -0
- data/test/suite.rb +12 -0
- metadata +57 -0
data/README
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
=Design by Contract for Ruby
|
2
|
+
|
3
|
+
This library supports Design by Contract for Ruby.
|
4
|
+
|
5
|
+
=Example
|
6
|
+
|
7
|
+
===stack.rb
|
8
|
+
:include:test/stack.rb
|
9
|
+
===stack_contract.rb
|
10
|
+
:include:test/stack_contract.rb
|
11
|
+
|
12
|
+
=Support
|
13
|
+
|
14
|
+
The project home is at RubyForge: http://rubyforge.org/projects/rdbc
|
15
|
+
|
16
|
+
Feel free to send:
|
17
|
+
* bug reports
|
18
|
+
* support requests
|
19
|
+
* feature requests
|
20
|
+
* patches
|
21
|
+
|
22
|
+
=Copyright
|
23
|
+
|
24
|
+
Copyright (c) 2007 by Armin Jöllenbeck
|
25
|
+
<armin.joellenbeck@googlemail.com[mailto:armin.joellenbeck@googlemail.com]>
|
26
|
+
|
27
|
+
All rights reserved.
|
28
|
+
|
29
|
+
Redistribution and use in source and binary forms, with or without
|
30
|
+
modification, are permitted provided that the following conditions
|
31
|
+
are met:
|
32
|
+
1. Redistributions of source code must retain the above copyright
|
33
|
+
notice, this list of conditions and the following disclaimer.
|
34
|
+
2. Redistributions in binary form must reproduce the above copyright
|
35
|
+
notice, this list of conditions and the following disclaimer in the
|
36
|
+
documentation and/or other materials provided with the distribution.
|
37
|
+
3. The names of the contributors may not be used to endorse or promote products
|
38
|
+
derived from this software without specific prior written permission.
|
39
|
+
|
40
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
41
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
42
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
43
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
44
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
45
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
46
|
+
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
47
|
+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
48
|
+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
49
|
+
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rake/gempackagetask'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
|
6
|
+
task :default => [:test]
|
7
|
+
|
8
|
+
|
9
|
+
Rake::TestTask.new do |t|
|
10
|
+
t.libs << 'test'
|
11
|
+
t.test_files = 'test/suite.rb'
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
Rake::RDocTask.new(:doc) do |t|
|
16
|
+
t.main = 'README'
|
17
|
+
t.rdoc_files.include('README', 'lib/**/*.rb')
|
18
|
+
t.rdoc_dir = 'doc'
|
19
|
+
t.title = 'Design by Contract for Ruby'
|
20
|
+
t.options = ['--all', '--charset', 'utf8']
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
spec = Gem::Specification.new do |s|
|
25
|
+
s.author = 'Armin Joellenbeck'
|
26
|
+
s.email = 'armin.joellenbeck@googlemail.com'
|
27
|
+
s.name = 'rdbc'
|
28
|
+
s.summary = 'Design by Contract for Ruby.'
|
29
|
+
s.version = '0.0.1'
|
30
|
+
s.has_rdoc = true
|
31
|
+
s.extra_rdoc_files << 'README'
|
32
|
+
s.rdoc_options = ['--main', 'README', '--all', '--charset', 'utf8']
|
33
|
+
s.files = FileList['lib/**/*', 'bin/*', '[A-Z]*', 'test/**/*'].to_a
|
34
|
+
end
|
35
|
+
|
36
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
37
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'test/unit/assertions'
|
2
|
+
|
3
|
+
|
4
|
+
class Object
|
5
|
+
|
6
|
+
protected
|
7
|
+
|
8
|
+
def singleton_class
|
9
|
+
class << self
|
10
|
+
self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def define_singleton_method(method, &block)
|
15
|
+
singleton_class.send(:define_method, method, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
class Class
|
22
|
+
|
23
|
+
def contract(klass)
|
24
|
+
@old_new = self.method(:new)
|
25
|
+
self.define_singleton_method(:new) do |*args|
|
26
|
+
object = @old_new.call(*args)
|
27
|
+
contract = klass.new
|
28
|
+
@proxy = DesignByContract::Proxy.new(object, contract)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
module DesignByContract
|
36
|
+
|
37
|
+
|
38
|
+
class Contract
|
39
|
+
include Test::Unit::Assertions
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
class Proxy
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def initialize(object, contract)
|
48
|
+
@object = object
|
49
|
+
@contract = contract
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_missing(method, *args)
|
53
|
+
# duplicate the object under contract for use in the pre condition
|
54
|
+
object_pre = @object.dup
|
55
|
+
|
56
|
+
# call pre condition
|
57
|
+
method_pre = self.class.method_pre(method)
|
58
|
+
if @contract.respond_to?(method_pre)
|
59
|
+
@contract.send(method_pre, @object, *args)
|
60
|
+
end
|
61
|
+
|
62
|
+
# call the wrapped method
|
63
|
+
result = @object.send(method, *args)
|
64
|
+
|
65
|
+
# call the invariant condition
|
66
|
+
if @contract.respond_to?(:invariant)
|
67
|
+
@contract.invariant(object_pre, @object)
|
68
|
+
end
|
69
|
+
|
70
|
+
# call the post condition
|
71
|
+
method_post = self.class.method_post(method)
|
72
|
+
if @contract.respond_to?(method_post)
|
73
|
+
@contract.send(method_post, object_pre, @object, result, *args)
|
74
|
+
end
|
75
|
+
|
76
|
+
# return the return value of the call to the wrapped method
|
77
|
+
result
|
78
|
+
end
|
79
|
+
|
80
|
+
class << self
|
81
|
+
|
82
|
+
def method_pre(method)
|
83
|
+
self.method_with_suffix(method, :pre)
|
84
|
+
end
|
85
|
+
|
86
|
+
def method_post(method)
|
87
|
+
self.method_with_suffix(method, :post)
|
88
|
+
end
|
89
|
+
|
90
|
+
protected
|
91
|
+
|
92
|
+
def method_with_suffix(method, type)
|
93
|
+
operator = OPERATOR[method]
|
94
|
+
suffix = '_' + type.to_s
|
95
|
+
if operator.nil?
|
96
|
+
method_string = method.to_s
|
97
|
+
length = method_string.length
|
98
|
+
head = method_string[0...length-1]
|
99
|
+
tail = method_string[length-1...length]
|
100
|
+
if ['?', '!', '='].include?(tail)
|
101
|
+
(head + suffix + tail).to_sym
|
102
|
+
else
|
103
|
+
(method_string + suffix).to_sym
|
104
|
+
end
|
105
|
+
else
|
106
|
+
('op_' + operator.to_s + suffix).to_sym
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
OPERATOR = {
|
113
|
+
:[] => :element_read,
|
114
|
+
:[]= => :element_write,
|
115
|
+
:** => :power,
|
116
|
+
:~ => :not,
|
117
|
+
:+@ => :unary_plus,
|
118
|
+
:-@ => :unary_minus,
|
119
|
+
:* => :product,
|
120
|
+
:/ => :quotient,
|
121
|
+
:% => :modulo,
|
122
|
+
:+ => :plus,
|
123
|
+
:- => :minus,
|
124
|
+
:>> => :right_shift,
|
125
|
+
:<< => :left_shift,
|
126
|
+
:& => :and,
|
127
|
+
:^ => :xor,
|
128
|
+
:| => :or,
|
129
|
+
:<= => :less_or_equal,
|
130
|
+
:< => :less,
|
131
|
+
:> => :greater,
|
132
|
+
:>= => :greater_or_equal,
|
133
|
+
:<=> => :comparison,
|
134
|
+
:== => :eql,
|
135
|
+
:=== => :case_comparison,
|
136
|
+
:=~ => :match
|
137
|
+
}
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'design_by_contract'
|
4
|
+
|
5
|
+
|
6
|
+
class DesignByContractTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def assert_method_pre(expected_method_pre, method)
|
9
|
+
assert_equal(expected_method_pre,
|
10
|
+
DesignByContract::Proxy.method_pre(method))
|
11
|
+
end
|
12
|
+
|
13
|
+
def assert_method_post(expected_method_post, method)
|
14
|
+
assert_equal(expected_method_post,
|
15
|
+
DesignByContract::Proxy.method_post(method))
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_method_pre
|
19
|
+
assert_method_pre(:method_pre, :method)
|
20
|
+
assert_method_pre(:method_pre?, :method?)
|
21
|
+
assert_method_pre(:method_pre!, :method!)
|
22
|
+
assert_method_pre(:method_pre=, :method=)
|
23
|
+
assert_method_pre(:op_plus_pre, :+)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_method_post
|
27
|
+
assert_method_post(:method_post, :method)
|
28
|
+
assert_method_post(:method_post?, :method?)
|
29
|
+
assert_method_post(:method_post!, :method!)
|
30
|
+
assert_method_post(:method_post=, :method=)
|
31
|
+
assert_method_post(:op_plus_post, :+)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/test/stack.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'stack_contract'
|
2
|
+
|
3
|
+
|
4
|
+
class Stack
|
5
|
+
|
6
|
+
contract StackContract
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@elements = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize_copy(orig)
|
13
|
+
@elements = orig.elements
|
14
|
+
end
|
15
|
+
|
16
|
+
def elements
|
17
|
+
@elements.dup
|
18
|
+
end
|
19
|
+
|
20
|
+
def size
|
21
|
+
@elements.size
|
22
|
+
end
|
23
|
+
|
24
|
+
def empty?
|
25
|
+
self.size == 0
|
26
|
+
end
|
27
|
+
|
28
|
+
def top
|
29
|
+
@elements.last
|
30
|
+
end
|
31
|
+
|
32
|
+
def push(element)
|
33
|
+
@elements.push(element)
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def pop
|
38
|
+
@elements.pop
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'design_by_contract'
|
2
|
+
|
3
|
+
|
4
|
+
class StackContract < DesignByContract::Contract
|
5
|
+
|
6
|
+
def push_post(stack_pre, stack, result, element)
|
7
|
+
assert_nil(result)
|
8
|
+
assert_equal(element, stack.top)
|
9
|
+
assert_equal(stack.size, stack_pre.size + 1)
|
10
|
+
end
|
11
|
+
|
12
|
+
def pop_pre(stack)
|
13
|
+
assert_operator(stack.size, :>=, 1)
|
14
|
+
end
|
15
|
+
|
16
|
+
def pop_post(stack_pre, stack, result)
|
17
|
+
assert_equal(stack_pre.top, result)
|
18
|
+
assert_equal(stack_pre.size - 1, stack.size)
|
19
|
+
end
|
20
|
+
|
21
|
+
def top_pre(stack)
|
22
|
+
assert_operator(stack.size, :>=, 1)
|
23
|
+
end
|
24
|
+
|
25
|
+
def top_post(stack_pre, stack, result)
|
26
|
+
assert_equal(stack_pre.size, stack.size)
|
27
|
+
end
|
28
|
+
|
29
|
+
def invariant(stack_pre, stack)
|
30
|
+
assert_operator(stack.size, :>=, 0)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/test/stack_test.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'stack'
|
4
|
+
|
5
|
+
|
6
|
+
class StackTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@stack = Stack.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_empty
|
13
|
+
assert(@stack.empty?)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_top
|
17
|
+
assert_raise Test::Unit::AssertionFailedError do
|
18
|
+
@stack.top
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_pop
|
23
|
+
assert_raise Test::Unit::AssertionFailedError do
|
24
|
+
@stack.pop
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_push_top_pop
|
29
|
+
element = 0
|
30
|
+
@stack.push(element)
|
31
|
+
assert(!@stack.empty?)
|
32
|
+
assert_equal(element, @stack.top)
|
33
|
+
assert_equal(element, @stack.pop)
|
34
|
+
assert(@stack.empty?)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/test/suite.rb
ADDED
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: rdbc
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.1
|
7
|
+
date: 2007-02-17 00:00:00 +01:00
|
8
|
+
summary: Design by Contract for Ruby.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: armin.joellenbeck@googlemail.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
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
|
+
- Armin Joellenbeck
|
31
|
+
files:
|
32
|
+
- lib/design_by_contract.rb
|
33
|
+
- Rakefile
|
34
|
+
- README
|
35
|
+
- test/design_by_contract_test.rb
|
36
|
+
- test/stack_contract.rb
|
37
|
+
- test/stack_test.rb
|
38
|
+
- test/stack.rb
|
39
|
+
- test/suite.rb
|
40
|
+
test_files: []
|
41
|
+
|
42
|
+
rdoc_options:
|
43
|
+
- --main
|
44
|
+
- README
|
45
|
+
- --all
|
46
|
+
- --charset
|
47
|
+
- utf8
|
48
|
+
extra_rdoc_files:
|
49
|
+
- README
|
50
|
+
executables: []
|
51
|
+
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
requirements: []
|
55
|
+
|
56
|
+
dependencies: []
|
57
|
+
|