armin-joellenbeck-rdbc 0.0.7 → 0.1.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.
- data/{README → README.rdoc} +23 -30
- metadata +8 -23
- data/Rakefile +0 -32
- data/examples/stack.rb +0 -43
- data/examples/stack_contract.rb +0 -36
- data/lib/contract.rb +0 -35
- data/lib/contract_decorator.rb +0 -60
- data/lib/translate.rb +0 -58
- data/rdbc.gemspec +0 -26
data/{README → README.rdoc}
RENAMED
@@ -6,20 +6,14 @@ This library supports Design by Contract for Ruby.
|
|
6
6
|
|
7
7
|
Install the *rdbc* gem itself by the following command:
|
8
8
|
|
9
|
-
$ gem install rdbc
|
9
|
+
$ gem install armin-joellenbeck-rdbc --source http://gems.github.com
|
10
10
|
|
11
11
|
=Usage
|
12
12
|
|
13
13
|
A a standard example for Design by Contract consider the following Stack
|
14
14
|
class and its contract StackContract.
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
:include:examples/stack.rb
|
19
|
-
|
20
|
-
===stack_contract.rb
|
21
|
-
|
22
|
-
:include:examples/stack_contract.rb
|
16
|
+
:include:spec/stack_spec.rb
|
23
17
|
|
24
18
|
The mechanics are really simple. There is the class Stack.
|
25
19
|
For instances of this class you can define a contract by subclassing
|
@@ -29,24 +23,26 @@ Then connect the class Stack to its contract StackContract by using the line
|
|
29
23
|
contract StackContract
|
30
24
|
in the class definition of Stack.
|
31
25
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
*
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
*
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
26
|
+
Then the following happens when a method of a Stack instance is called:
|
27
|
+
|
28
|
+
1. the corresponding pre condition is called with the parameters:
|
29
|
+
* the instance itself
|
30
|
+
* the parameters of the method call
|
31
|
+
|
32
|
+
2. the method is called
|
33
|
+
|
34
|
+
3. the corresponding post condition is called with the parameters:
|
35
|
+
* the instance before the method is called
|
36
|
+
* the instance after the method is called
|
37
|
+
* the return value of the method call
|
38
|
+
* the parameters of the method call
|
39
|
+
|
40
|
+
4. the invariant is called with the parameters:
|
41
|
+
* the instance before the method is called
|
42
|
+
* the instance after the method is called
|
43
|
+
|
44
|
+
The instance before the execution of *method* in 3. and 4.
|
45
|
+
is in fact a copy of the instance before the execution. So you have to implement
|
50
46
|
the method *initialize_copy* in the class under contract, i.e. the class
|
51
47
|
Stack.
|
52
48
|
|
@@ -54,9 +50,6 @@ In any of these contract methods you can use assertions as in Test::Unit tests.
|
|
54
50
|
When an assertion fails, the exception Test::Unit::AssertionFailedError
|
55
51
|
is raised.
|
56
52
|
|
57
|
-
When the method is an operator the *_pre* and *_post* suffixes are appended
|
58
|
-
to the names of the operator according to the constant #Translate::OPERATOR.
|
59
|
-
|
60
53
|
=Support
|
61
54
|
|
62
55
|
The project home is at
|
@@ -71,7 +64,7 @@ Feel free to send:
|
|
71
64
|
|
72
65
|
=Copyright
|
73
66
|
|
74
|
-
Copyright (c) 2007 -
|
67
|
+
Copyright (c) 2007 - 2009 by Armin Jöllenbeck
|
75
68
|
<armin@joellenbeck.net[mailto:armin@joellenbeck.net]>
|
76
69
|
|
77
70
|
All rights reserved.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: armin-joellenbeck-rdbc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Armin Joellenbeck
|
@@ -9,18 +9,10 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2009-05-16 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
name: armin-joellenbeck-decorator
|
17
|
-
version_requirement:
|
18
|
-
version_requirements: !ruby/object:Gem::Requirement
|
19
|
-
requirements:
|
20
|
-
- - ">="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: "0"
|
23
|
-
version:
|
14
|
+
dependencies: []
|
15
|
+
|
24
16
|
description: ""
|
25
17
|
email: armin@joellenbeck.net
|
26
18
|
executables: []
|
@@ -28,16 +20,9 @@ executables: []
|
|
28
20
|
extensions: []
|
29
21
|
|
30
22
|
extra_rdoc_files:
|
31
|
-
- README
|
32
|
-
files:
|
33
|
-
|
34
|
-
- Rakefile
|
35
|
-
- rdbc.gemspec
|
36
|
-
- examples/stack_contract.rb
|
37
|
-
- examples/stack.rb
|
38
|
-
- lib/contract.rb
|
39
|
-
- lib/translate.rb
|
40
|
-
- lib/contract_decorator.rb
|
23
|
+
- README.rdoc
|
24
|
+
files: []
|
25
|
+
|
41
26
|
has_rdoc: true
|
42
27
|
homepage: http://github.com/armin-joellenbeck/rdbc/tree/master
|
43
28
|
post_install_message:
|
@@ -46,7 +31,7 @@ rdoc_options:
|
|
46
31
|
- --charset
|
47
32
|
- utf8
|
48
33
|
- --main
|
49
|
-
- README
|
34
|
+
- README.rdoc
|
50
35
|
- --title
|
51
36
|
- Design by Contract for Ruby
|
52
37
|
require_paths:
|
data/Rakefile
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'rake/gempackagetask'
|
2
|
-
require 'rake/rdoctask'
|
3
|
-
require 'spec/rake/spectask'
|
4
|
-
|
5
|
-
task :default => 'spec'
|
6
|
-
|
7
|
-
task :all => [:clobber, :spec, :doc, :package]
|
8
|
-
|
9
|
-
Spec::Rake::SpecTask.new do |t|
|
10
|
-
t.libs << 'spec' << 'examples' << 'lib'
|
11
|
-
t.spec_opts << '--diff' << 'unified'
|
12
|
-
t.spec_opts << '--format' << 'progress'
|
13
|
-
end
|
14
|
-
|
15
|
-
Rake::RDocTask.new(:doc) do |t|
|
16
|
-
t.rdoc_dir = 'doc'
|
17
|
-
t.rdoc_files.include('README', 'lib/**/*.rb')
|
18
|
-
t.options = [
|
19
|
-
'--all',
|
20
|
-
'--charset', 'utf8',
|
21
|
-
'--inline-source',
|
22
|
-
'--main', 'README',
|
23
|
-
'--title', 'Design by Contract for Ruby'
|
24
|
-
]
|
25
|
-
end
|
26
|
-
|
27
|
-
Rake::GemPackageTask.new(eval(File.read('rdbc.gemspec'))) do |pkg|
|
28
|
-
end
|
29
|
-
|
30
|
-
task :auto do
|
31
|
-
sh 'RUBYLIB=spec:examples:lib:$RUBYLIB autospec'
|
32
|
-
end
|
data/examples/stack.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
require 'stack_contract'
|
2
|
-
|
3
|
-
class Stack
|
4
|
-
|
5
|
-
contract StackContract
|
6
|
-
|
7
|
-
class NoPopForEmptyStack < RuntimeError
|
8
|
-
end
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
@objects = []
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize_copy(orig)
|
15
|
-
@objects = orig.objects
|
16
|
-
end
|
17
|
-
|
18
|
-
def objects
|
19
|
-
@objects.dup
|
20
|
-
end
|
21
|
-
|
22
|
-
def size
|
23
|
-
@objects.size
|
24
|
-
end
|
25
|
-
|
26
|
-
def empty?
|
27
|
-
size == 0
|
28
|
-
end
|
29
|
-
|
30
|
-
def top
|
31
|
-
@objects.last
|
32
|
-
end
|
33
|
-
|
34
|
-
def pop
|
35
|
-
@objects.pop
|
36
|
-
end
|
37
|
-
|
38
|
-
def push(object)
|
39
|
-
@objects.push(object)
|
40
|
-
nil
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
data/examples/stack_contract.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'contract'
|
2
|
-
|
3
|
-
class StackContract < Contract
|
4
|
-
|
5
|
-
post :push do |stack_pre, stack, exception, result, element|
|
6
|
-
assert_nil(result)
|
7
|
-
assert_equal(element, stack.top)
|
8
|
-
assert_equal(stack.size, stack_pre.size + 1)
|
9
|
-
end
|
10
|
-
|
11
|
-
pre :pop do |stack|
|
12
|
-
assert_operator(stack.size, :>=, 0)
|
13
|
-
end
|
14
|
-
|
15
|
-
post :pop do |stack_pre, stack, exception, result|
|
16
|
-
if stack_pre.empty?
|
17
|
-
assert_kind_of(Stack::NoPopForEmptyStack, exception)
|
18
|
-
else
|
19
|
-
assert_equal(stack_pre.top, result)
|
20
|
-
assert_equal(stack_pre.size - 1, stack.size)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
pre :top do |stack|
|
25
|
-
assert_operator(stack.size, :>=, 1)
|
26
|
-
end
|
27
|
-
|
28
|
-
post :top do |stack_pre, stack, exception, result|
|
29
|
-
assert_equal(stack_pre.size, stack.size)
|
30
|
-
end
|
31
|
-
|
32
|
-
invariant do |stack|
|
33
|
-
assert_operator(stack.size, :>=, 0)
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
data/lib/contract.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'test/unit/assertions'
|
2
|
-
|
3
|
-
require 'contract_decorator'
|
4
|
-
|
5
|
-
|
6
|
-
class Contract
|
7
|
-
|
8
|
-
class << self
|
9
|
-
|
10
|
-
def pre(method, &block)
|
11
|
-
define_method(Translate.method_pre(method), &block)
|
12
|
-
end
|
13
|
-
|
14
|
-
def post(method, &block)
|
15
|
-
define_method(Translate.method_post(method), &block)
|
16
|
-
end
|
17
|
-
|
18
|
-
def invariant(&block)
|
19
|
-
define_method(:invariant, &block)
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
include Test::Unit::Assertions
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
class Class
|
30
|
-
|
31
|
-
def contract(contract_class)
|
32
|
-
decorate ContractDecorator(contract_class)
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
data/lib/contract_decorator.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'decorator'
|
3
|
-
|
4
|
-
require 'translate'
|
5
|
-
|
6
|
-
|
7
|
-
class ContractDecorator < Decorator
|
8
|
-
|
9
|
-
class << self
|
10
|
-
attr_accessor :contract_class
|
11
|
-
end
|
12
|
-
|
13
|
-
def initialize(object)
|
14
|
-
super(object)
|
15
|
-
@contract = self.__class__.contract_class.new
|
16
|
-
end
|
17
|
-
|
18
|
-
def method_missing(method, *args)
|
19
|
-
# clone the object under contract for use in the pre condition
|
20
|
-
object_pre = @object.clone
|
21
|
-
|
22
|
-
# call pre condition
|
23
|
-
method_pre = Translate.method_pre(method)
|
24
|
-
if @contract.respond_to?(method_pre)
|
25
|
-
@contract.send(method_pre, @object, *args)
|
26
|
-
end
|
27
|
-
|
28
|
-
# call the wrapped method
|
29
|
-
exception = nil
|
30
|
-
begin
|
31
|
-
result = @object.send(method, *args)
|
32
|
-
rescue => exception
|
33
|
-
end
|
34
|
-
|
35
|
-
# call the invariant condition
|
36
|
-
if @contract.respond_to?(:invariant)
|
37
|
-
@contract.invariant(@object)
|
38
|
-
end
|
39
|
-
|
40
|
-
# call the post condition
|
41
|
-
method_post = Translate.method_post(method)
|
42
|
-
if @contract.respond_to?(method_post)
|
43
|
-
@contract.send(method_post, object_pre, @object, exception, result, *args)
|
44
|
-
end
|
45
|
-
|
46
|
-
# return the return value of the wrapped method call or raise the exception
|
47
|
-
if exception.nil?
|
48
|
-
result
|
49
|
-
else
|
50
|
-
raise exception
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
|
56
|
-
def ContractDecorator(contract_class)
|
57
|
-
klass = Class.new(ContractDecorator)
|
58
|
-
klass.contract_class = contract_class
|
59
|
-
klass
|
60
|
-
end
|
data/lib/translate.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
module Translate
|
2
|
-
|
3
|
-
def self.method_pre(method)
|
4
|
-
method_with_suffix(method, :pre)
|
5
|
-
end
|
6
|
-
|
7
|
-
def self.method_post(method)
|
8
|
-
method_with_suffix(method, :post)
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def self.method_with_suffix(method, type)
|
14
|
-
operator = OPERATOR[method]
|
15
|
-
suffix = '_' + type.to_s
|
16
|
-
if operator.nil?
|
17
|
-
method_string = method.to_s
|
18
|
-
length = method_string.length
|
19
|
-
head = method_string[0...length-1]
|
20
|
-
tail = method_string[length-1...length]
|
21
|
-
if ['?', '!', '='].include?(tail)
|
22
|
-
(head + suffix + tail).to_sym
|
23
|
-
else
|
24
|
-
(method_string + suffix).to_sym
|
25
|
-
end
|
26
|
-
else
|
27
|
-
('op_' + operator.to_s + suffix).to_sym
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
OPERATOR = {
|
32
|
-
:[] => :element_read,
|
33
|
-
:[]= => :element_write,
|
34
|
-
:** => :power,
|
35
|
-
:~ => :not,
|
36
|
-
:+@ => :unary_plus,
|
37
|
-
:-@ => :unary_minus,
|
38
|
-
:* => :product,
|
39
|
-
:/ => :quotient,
|
40
|
-
:% => :modulo,
|
41
|
-
:+ => :plus,
|
42
|
-
:- => :minus,
|
43
|
-
:>> => :right_shift,
|
44
|
-
:<< => :left_shift,
|
45
|
-
:& => :and,
|
46
|
-
:^ => :xor,
|
47
|
-
:| => :or,
|
48
|
-
:<= => :less_or_equal,
|
49
|
-
:< => :less,
|
50
|
-
:> => :greater,
|
51
|
-
:>= => :greater_or_equal,
|
52
|
-
:<=> => :comparison,
|
53
|
-
:== => :eql,
|
54
|
-
:=== => :case_comparison,
|
55
|
-
:=~ => :match
|
56
|
-
}
|
57
|
-
|
58
|
-
end
|
data/rdbc.gemspec
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
Gem::Specification.new do |s|
|
2
|
-
s.name = 'rdbc'
|
3
|
-
s.version = '0.0.7'
|
4
|
-
s.summary = 'Design by Contract for Ruby.'
|
5
|
-
s.author = 'Armin Joellenbeck'
|
6
|
-
s.email = 'armin@joellenbeck.net'
|
7
|
-
s.homepage = 'http://github.com/armin-joellenbeck/rdbc/tree/master'
|
8
|
-
s.description = <<-EOF
|
9
|
-
EOF
|
10
|
-
s.files = Dir.glob([
|
11
|
-
'README',
|
12
|
-
'Rakefile',
|
13
|
-
'*.gemspec',
|
14
|
-
'examples/**/*',
|
15
|
-
'lib/**/*',
|
16
|
-
])
|
17
|
-
s.has_rdoc = true
|
18
|
-
s.extra_rdoc_files << 'README'
|
19
|
-
s.rdoc_options = [
|
20
|
-
'--all',
|
21
|
-
'--charset', 'utf8',
|
22
|
-
'--main', 'README',
|
23
|
-
'--title', 'Design by Contract for Ruby'
|
24
|
-
]
|
25
|
-
s.add_dependency('armin-joellenbeck-decorator')
|
26
|
-
end
|