armin-joellenbeck-rdbc 0.0.7 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|