duckpond 1.2.1 → 1.2.2
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +18 -18
- data/docs/the_solution.txt +4 -4
- data/lib/duckpond/contract.rb +11 -9
- data/lib/duckpond/version.rb +1 -1
- data/spec/clauses/method_clause/method_clause_usage_spec.rb +7 -7
- data/spec/contract_spec.rb +7 -7
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25f58d57f27f8eea84453a30e35456fc61c0d320
|
4
|
+
data.tar.gz: c37bc4985281d5a60b166ac78f02bb5a680b18db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea56f737804b79577766ea0d0ca015faf6963b6bb8ad2fb3fa545583dfd8c36b3121e145a0011b5c13f8c0676adf513c66e173896976dc359f7ada620c2c7bad
|
7
|
+
data.tar.gz: dcbaddf7457e2eea1e97ae467d42fd260c8dc1a1348218fb88477d488c1a02db80a437f247feeba95f2fd81bfbe0c4270cd3c724f812717e7155db17df8df9e6
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -9,9 +9,9 @@ Explicit duck typing for ruby.
|
|
9
9
|
|
10
10
|
## Introduction
|
11
11
|
|
12
|
-
Duck Typing can make code confusing and unreadable, particularly
|
13
|
-
when multiple developers are working on the same project or when
|
14
|
-
projects are inherited by new developers.
|
12
|
+
Duck Typing can make code confusing and unreadable, particularly
|
13
|
+
when multiple developers are working on the same project or when
|
14
|
+
projects are inherited by new developers.
|
15
15
|
|
16
16
|
* [the_problem](docs/the_problem.txt) - This outlines the problems with duck typing.
|
17
17
|
|
@@ -35,11 +35,11 @@ Or install it yourself as:
|
|
35
35
|
|
36
36
|
## Usage
|
37
37
|
|
38
|
-
There is now a [screencast](https://www.youtube.com/watch?v=XTFigHzAfsk&feature=youtu.be) demonstrating the duckpond gem!
|
38
|
+
There is now a [screencast](https://www.youtube.com/watch?v=XTFigHzAfsk&feature=youtu.be) demonstrating the duckpond gem!
|
39
39
|
|
40
|
-
Usage is demonstrated in '[the_solution](docs/the_solution.txt)', but in a nutshell you
|
41
|
-
create "contract" classes by inheriting from DuckPond::Contract. These classes should
|
42
|
-
be commented extensively.
|
40
|
+
Usage is demonstrated in '[the_solution](docs/the_solution.txt)', but in a nutshell you
|
41
|
+
create "contract" classes by inheriting from DuckPond::Contract. These classes should
|
42
|
+
be commented extensively.
|
43
43
|
|
44
44
|
The "has_method" method is used to specify which methods the contract expects to see. The
|
45
45
|
following contract describes classes which respond to #length and #to_s
|
@@ -49,24 +49,24 @@ following contract describes classes which respond to #length and #to_s
|
|
49
49
|
has_method :to_s
|
50
50
|
end
|
51
51
|
|
52
|
-
Once you've declared a contract, you can compare objects to it to see if the contract is
|
52
|
+
Once you've declared a contract, you can compare objects to it to see if the contract is
|
53
53
|
fulfilled by the object:
|
54
54
|
|
55
|
-
MyContract.
|
55
|
+
MyContract.fulfilled_by? "Hello"
|
56
56
|
=> true
|
57
|
-
MyContract.
|
57
|
+
MyContract.fulfilled_by? 12
|
58
58
|
=> false
|
59
59
|
|
60
|
-
There is also a "bang" version of the #
|
60
|
+
There is also a "bang" version of the #fulfilled_by method, that raises an error instead
|
61
61
|
of returning false. The error message details why it got raised.
|
62
62
|
|
63
|
-
MyContract.
|
63
|
+
MyContract.fulfilled_by! :foo
|
64
64
|
=> DuckPond::Contract::ContractInfringementError:
|
65
|
-
One or more clauses from MyContract were not fulfilled by :foo (Symbol)
|
65
|
+
One or more clauses from MyContract were not fulfilled by :foo (Symbol)
|
66
66
|
Expected subject to respond to method 'length'
|
67
67
|
|
68
68
|
|
69
|
-
Contracts can be combined into composite "super contracts" - contracts which are made up of
|
69
|
+
Contracts can be combined into composite "super contracts" - contracts which are made up of
|
70
70
|
various other contracts. This ties in with the reccomendation of preferring composition over inheritance:
|
71
71
|
|
72
72
|
class MyCompositeConrtact < DuckPond::Contract
|
@@ -75,7 +75,7 @@ various other contracts. This ties in with the reccomendation of preferring comp
|
|
75
75
|
end
|
76
76
|
|
77
77
|
Another feature of duckpond is the ability to specify what your expected result from a contract should be. For example,
|
78
|
-
the following contract expects a subject to have a method called "even" and for that method, when called, to return a
|
78
|
+
the following contract expects a subject to have a method called "even" and for that method, when called, to return a
|
79
79
|
true value:
|
80
80
|
|
81
81
|
class MyEvenContract < DuckPond::Contract
|
@@ -83,7 +83,7 @@ true value:
|
|
83
83
|
end
|
84
84
|
|
85
85
|
If the method needs args, you can specify those too. This next contract will pass the string "Hell" to the #include? method,
|
86
|
-
and expect the value to be true. This contract will therefore be satisfied by strings containing the word "Hell" that are
|
86
|
+
and expect the value to be true. This contract will therefore be satisfied by strings containing the word "Hell" that are
|
87
87
|
five characters long (such as the word "Hello"):
|
88
88
|
|
89
89
|
class MyHellContract < DuckPond::Contract
|
@@ -124,7 +124,7 @@ And then be implemented in a method like this:
|
|
124
124
|
|
125
125
|
class Emailer
|
126
126
|
def send(email)
|
127
|
-
IEmailable.
|
127
|
+
IEmailable.fulfilled_by! email
|
128
128
|
email.send
|
129
129
|
end
|
130
130
|
end
|
@@ -137,7 +137,7 @@ CI tests exist for the following rubies, other versions are not supported but sh
|
|
137
137
|
- 2.3.0
|
138
138
|
- 2.2.4
|
139
139
|
- 2.1.8
|
140
|
-
- jruby-19mode
|
140
|
+
- jruby-19mode
|
141
141
|
|
142
142
|
|
143
143
|
## Contributing
|
data/docs/the_solution.txt
CHANGED
@@ -11,14 +11,14 @@ end
|
|
11
11
|
# Then use it to check stuff!
|
12
12
|
#
|
13
13
|
|
14
|
-
ObjContract.
|
14
|
+
ObjContract.fulfilled_by? "Hello"
|
15
15
|
=> true (or false if not fulfilled)
|
16
16
|
|
17
17
|
#
|
18
18
|
# The "bang" version will raise an error if the object isn't the duck.
|
19
19
|
#
|
20
20
|
|
21
|
-
ObjContract.
|
21
|
+
ObjContract.fulfilled_by! "Hello"
|
22
22
|
=> true (or error if not fulfilled)
|
23
23
|
|
24
24
|
#
|
@@ -27,7 +27,7 @@ ObjContract.fulfills! "Hello"
|
|
27
27
|
|
28
28
|
class Foo
|
29
29
|
def self.bar(obj)
|
30
|
-
ObjContract.
|
30
|
+
ObjContract.fulfilled_by! obj
|
31
31
|
|
32
32
|
obj.foo!
|
33
33
|
fooinator = Test::Fooinator.new
|
@@ -39,7 +39,7 @@ end
|
|
39
39
|
#
|
40
40
|
# Viola!
|
41
41
|
#
|
42
|
-
# Final Tips:
|
42
|
+
# Final Tips:
|
43
43
|
#
|
44
44
|
# * Contracts should be commented liberally. They form the descripiton
|
45
45
|
# of a contract just as interfaces would in strongly typed languages.
|
data/lib/duckpond/contract.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'duckpond/contract/convinience_methods'
|
2
2
|
require 'duckpond/contract/contract_infringement_error'
|
3
3
|
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# DuckPond::Contract
|
6
6
|
#
|
7
|
-
# Contracts are essentially lists of properties that a class could have.
|
8
|
-
# They are not intended to ever be instantiated, and are completely
|
7
|
+
# Contracts are essentially lists of properties that a class could have.
|
8
|
+
# They are not intended to ever be instantiated, and are completely
|
9
9
|
# configured at the class level.
|
10
10
|
#
|
11
11
|
module DuckPond
|
@@ -56,26 +56,27 @@ module DuckPond
|
|
56
56
|
end
|
57
57
|
|
58
58
|
#
|
59
|
-
#
|
59
|
+
# fulfilled_by?
|
60
60
|
#
|
61
61
|
# Returns true if this contract fulfills the passed-in object,
|
62
62
|
# otherwise false.
|
63
63
|
#
|
64
|
-
def
|
64
|
+
def fulfilled_by?(obj)
|
65
65
|
DuckPond::Inspection.new(obj).tap do |inspection|
|
66
66
|
return inspection.fulfilled_by? self
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
|
70
|
+
# For backward compatibility
|
71
|
+
alias_method :fulfills?, :fulfilled_by?
|
71
72
|
|
72
73
|
#
|
73
|
-
#
|
74
|
+
# fulfilled_by!
|
74
75
|
#
|
75
76
|
# Raises a ContractInfringementError unless this contract fulfills
|
76
77
|
# the passed in object, otherwise returns true.
|
77
78
|
#
|
78
|
-
def
|
79
|
+
def fulfilled_by!(obj)
|
79
80
|
DuckPond::Inspection.new(obj).tap do |inspection|
|
80
81
|
unless inspection.fulfilled_by? self
|
81
82
|
raise ContractInfringementError.new(self, obj, inspection)
|
@@ -85,7 +86,8 @@ module DuckPond
|
|
85
86
|
end
|
86
87
|
end
|
87
88
|
|
88
|
-
|
89
|
+
# For backward compatibility
|
90
|
+
alias_method :fulfills!, :fulfilled_by!
|
89
91
|
|
90
92
|
end
|
91
93
|
end
|
data/lib/duckpond/version.rb
CHANGED
@@ -7,23 +7,23 @@ describe 'MethodClause usage' do
|
|
7
7
|
#
|
8
8
|
describe SpecificLengthContract do
|
9
9
|
it 'checks a methods response is correct' do
|
10
|
-
expect(SpecificLengthContract.
|
11
|
-
expect(SpecificLengthContract.
|
12
|
-
expect(SpecificLengthContract.
|
10
|
+
expect(SpecificLengthContract.fulfilled_by?("Hello")).to eq true
|
11
|
+
expect(SpecificLengthContract.fulfilled_by?("Yello")).to eq false
|
12
|
+
expect(SpecificLengthContract.fulfilled_by?("Goodbye")).to eq false
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
describe SpecificLengthBehaviourContract do
|
17
17
|
it 'checks the given block against the subjects method repsonse' do
|
18
|
-
expect(SpecificLengthBehaviourContract.
|
19
|
-
expect(SpecificLengthBehaviourContract.
|
18
|
+
expect(SpecificLengthBehaviourContract.fulfilled_by?('Hello')).to eq true
|
19
|
+
expect(SpecificLengthBehaviourContract.fulfilled_by?('Goodbye')).to eq false
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
describe SpecificIncludeBehaviourContract do
|
24
24
|
it 'checks the given block against the subjects method response' do
|
25
|
-
expect(SpecificIncludeBehaviourContract.
|
26
|
-
expect(SpecificLengthBehaviourContract.
|
25
|
+
expect(SpecificIncludeBehaviourContract.fulfilled_by?('Hello')).to eq true
|
26
|
+
expect(SpecificLengthBehaviourContract.fulfilled_by?('Goodbye')).to eq false
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
data/spec/contract_spec.rb
CHANGED
@@ -15,28 +15,28 @@ module DuckPond
|
|
15
15
|
#
|
16
16
|
# see spec/classes/length_contract.rb
|
17
17
|
#
|
18
|
-
describe '
|
18
|
+
describe 'fulfilled_by?' do
|
19
19
|
context 'when the object is fulfilled by the contract' do
|
20
20
|
it 'returns true' do
|
21
|
-
expect(LengthContract.
|
21
|
+
expect(LengthContract.fulfilled_by?("Hello")).to eq true
|
22
22
|
end
|
23
23
|
end
|
24
24
|
context 'when the object is not fulfilled by the contract' do
|
25
25
|
it 'returns false' do
|
26
|
-
expect(LengthContract.
|
26
|
+
expect(LengthContract.fulfilled_by?(2)).to eq false
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
describe '
|
31
|
+
describe 'fulfilled_by!' do
|
32
32
|
context 'when the object is fulfilled by the contract' do
|
33
33
|
it 'returns true' do
|
34
|
-
expect{LengthContract.
|
34
|
+
expect{LengthContract.fulfilled_by!("Hello")}.to_not raise_error
|
35
35
|
end
|
36
36
|
end
|
37
37
|
context 'when the object is not fulfilled by the contract' do
|
38
38
|
it 'returns false' do
|
39
|
-
expect{LengthContract.
|
39
|
+
expect{LengthContract.fulfilled_by!(2)}.to raise_error DuckPond::Contract::ContractInfringementError
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -56,7 +56,7 @@ module DuckPond
|
|
56
56
|
describe CompositeContract do
|
57
57
|
it 'retains its parents quackings' do
|
58
58
|
clauses = CompositeContract.clauses
|
59
|
-
expect(clauses.length).to eq 2
|
59
|
+
expect(clauses.length).to eq 2
|
60
60
|
clauses.map {|c|c.options[:method_name]}.tap do |method_names|
|
61
61
|
expect(method_names).to include :length
|
62
62
|
expect(method_names).to include :chunky_bacon
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duckpond
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikey Hogarth
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -96,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
96
|
version: '0'
|
97
97
|
requirements: []
|
98
98
|
rubyforge_project:
|
99
|
-
rubygems_version: 2.
|
99
|
+
rubygems_version: 2.5.1
|
100
100
|
signing_key:
|
101
101
|
specification_version: 4
|
102
102
|
summary: Explicit duck-typing for ruby
|