duckpond 1.1.0 → 1.1.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +8 -8
- data/docs/the_solution.txt +3 -3
- data/lib/duckpond/contract.rb +31 -7
- data/lib/duckpond/inspection.rb +3 -3
- data/lib/duckpond/version.rb +1 -1
- data/spec/classes/contracts/composite_contract.rb +6 -0
- data/spec/classes/contracts/length_contract.rb +5 -0
- data/spec/contract_spec.rb +22 -34
- data/spec/inspection_spec.rb +6 -11
- data/spec/spec_helper.rb +2 -1
- metadata +8 -5
- data/spec/classes/fooinator.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb40e8e7d8b6bdc3292b4ddfb0bc5548af7df234
|
4
|
+
data.tar.gz: 4ecca5d9961fc6accd02237c9cd136d8b3c729eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6665633fd874275fbcef6e1e292966849e5e558ac65230cc7fa78dbb26430b88ad8c0c0eb6e23730c2b397532fb31debbf02c493908f5e21143baf6b4553619f
|
7
|
+
data.tar.gz: 7d9d32e81cf6fd3fbb0b20986c552c0a3d37dd0b6a9ee9de266a427f3672455640f4c25cff2991ce16a93173cbff92a847980e1b38b297dc5d0186bcd1c6b8ff
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -50,16 +50,16 @@ following contract describes classes which respond to #length and #to_s
|
|
50
50
|
Once you've declared a contract, you can compare objects to it to see if the contract is
|
51
51
|
fulfilled by the object:
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
MyContract.fulfills? "Hello"
|
54
|
+
=> true
|
55
|
+
MyContract.fulfills? 12
|
56
|
+
=> false
|
57
57
|
|
58
|
-
There is also a "bang" version of the
|
58
|
+
There is also a "bang" version of the #fulfills method, that raises an error instead
|
59
59
|
of returning false.
|
60
60
|
|
61
|
-
|
62
|
-
|
61
|
+
MyContract.fulfills! 12
|
62
|
+
=> RAISES ERROR!!
|
63
63
|
|
64
64
|
Contracts can be combined into composite "super contracts" - contracts which are made up of
|
65
65
|
various other contracts. This ties in with the reccomendation of preferring composition over inheritance:
|
@@ -87,7 +87,7 @@ And then be implemented in a method like this:
|
|
87
87
|
|
88
88
|
class Emailer
|
89
89
|
def send(email)
|
90
|
-
IEmailable.
|
90
|
+
IEmailable.fulfills! email
|
91
91
|
email.send
|
92
92
|
end
|
93
93
|
end
|
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.fulfills? "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.fulfills! "Hello"
|
22
22
|
=> true (or error if not fulfilled)
|
23
23
|
|
24
24
|
#
|
@@ -27,7 +27,7 @@ ObjContract.fulfilled_by! "Hello"
|
|
27
27
|
|
28
28
|
class Foo
|
29
29
|
def self.bar(obj)
|
30
|
-
ObjContract.
|
30
|
+
ObjContract.fulfills! obj
|
31
31
|
|
32
32
|
obj.foo!
|
33
33
|
fooinator = Test::Fooinator.new
|
data/lib/duckpond/contract.rb
CHANGED
@@ -11,10 +11,27 @@ module DuckPond
|
|
11
11
|
|
12
12
|
class << self
|
13
13
|
|
14
|
+
#
|
15
|
+
# clauses
|
16
|
+
#
|
17
|
+
# Gets this contract's list of clauses or returns
|
18
|
+
# an empty array if uninitialized.
|
19
|
+
#
|
14
20
|
def clauses
|
15
21
|
@clauses ||= []
|
16
22
|
end
|
17
23
|
|
24
|
+
#
|
25
|
+
# each_clause
|
26
|
+
#
|
27
|
+
# Iterator for clauses
|
28
|
+
#
|
29
|
+
def each_clause
|
30
|
+
0.upto(clauses.size-1) do |i|
|
31
|
+
yield @clauses[i]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
18
35
|
#
|
19
36
|
# has_method
|
20
37
|
#
|
@@ -30,25 +47,32 @@ module DuckPond
|
|
30
47
|
# Facilitates composition of multiple contracts
|
31
48
|
#
|
32
49
|
def include_clauses_from(other_contract)
|
33
|
-
other_contract.
|
34
|
-
has_method
|
50
|
+
other_contract.each_clause do |other_clause|
|
51
|
+
has_method other_clause
|
35
52
|
end
|
36
53
|
end
|
37
54
|
|
38
55
|
#
|
39
|
-
#
|
56
|
+
# fulfills?
|
40
57
|
#
|
41
|
-
|
58
|
+
# Returns true if this contract fulfills the passed-in object,
|
59
|
+
# otherwise false.
|
60
|
+
#
|
61
|
+
def fulfills?(obj)
|
42
62
|
inspection = DuckPond::Inspection.new(obj)
|
43
63
|
return false unless inspection.fulfilled_by? self
|
44
64
|
true
|
45
65
|
end
|
46
66
|
|
47
67
|
#
|
48
|
-
#
|
68
|
+
# fulfills!
|
69
|
+
#
|
70
|
+
# Raises a ContractInfringementError unless this contract fulfills
|
71
|
+
# the passed in object, otherwise returns true.
|
49
72
|
#
|
50
|
-
def
|
51
|
-
raise ContractInfringementError unless
|
73
|
+
def fulfills!(obj)
|
74
|
+
raise ContractInfringementError unless fulfills?(obj)
|
75
|
+
true
|
52
76
|
end
|
53
77
|
end
|
54
78
|
end
|
data/lib/duckpond/inspection.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#
|
2
2
|
# DuckPond::Inspection
|
3
3
|
#
|
4
|
-
# The duckpond
|
5
|
-
# object
|
4
|
+
# The duckpond inspection class is essentially just a wrapper for an inspected
|
5
|
+
# object (the subject).
|
6
6
|
#
|
7
7
|
module DuckPond
|
8
8
|
class Inspection
|
@@ -27,7 +27,7 @@ module DuckPond
|
|
27
27
|
# by the contract's clauses.
|
28
28
|
#
|
29
29
|
def fulfilled_by?(contract)
|
30
|
-
contract.
|
30
|
+
contract.each_clause do |clause|
|
31
31
|
return false unless @subject.respond_to? clause
|
32
32
|
end
|
33
33
|
true
|
data/lib/duckpond/version.rb
CHANGED
data/spec/contract_spec.rb
CHANGED
@@ -12,64 +12,52 @@ module DuckPond
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
describe '
|
15
|
+
|
16
|
+
#
|
17
|
+
# see spec/classes/length_contract.rb
|
18
|
+
#
|
19
|
+
describe 'fulfills?' do
|
20
20
|
context 'when the object is fulfilled by the contract' do
|
21
21
|
it 'returns true' do
|
22
|
-
expect(LengthContract.
|
22
|
+
expect(LengthContract.fulfills?("Hello")).to eq true
|
23
23
|
end
|
24
24
|
end
|
25
25
|
context 'when the object is not fulfilled by the contract' do
|
26
26
|
it 'returns false' do
|
27
|
-
expect(LengthContract.
|
27
|
+
expect(LengthContract.fulfills?(2)).to eq false
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
32
|
-
describe 'fulfilled_by!' do
|
31
|
+
describe 'fulfills!' do
|
33
32
|
context 'when the object is fulfilled by the contract' do
|
34
33
|
it 'returns true' do
|
35
|
-
expect{LengthContract.
|
34
|
+
expect{LengthContract.fulfills!("Hello")}.to_not raise_error
|
36
35
|
end
|
37
36
|
end
|
38
37
|
context 'when the object is not fulfilled by the contract' do
|
39
38
|
it 'returns false' do
|
40
|
-
expect{LengthContract.
|
39
|
+
expect{LengthContract.fulfills!(2)}.to raise_error
|
41
40
|
end
|
42
41
|
end
|
43
42
|
end
|
44
|
-
end
|
45
43
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
describe MyContract do
|
52
|
-
context '.clauses' do
|
53
|
-
it 'quacks like foo and bar' do
|
54
|
-
clauses = MyContract.clauses
|
55
|
-
expect(clauses.length).to eq 2
|
56
|
-
expect(clauses).to include :foo
|
57
|
-
expect(clauses).to include :bar
|
44
|
+
describe '.clauses' do
|
45
|
+
it 'returns the clauses for this contract' do
|
46
|
+
clauses = LengthContract.clauses
|
47
|
+
expect(clauses.length).to eq 1
|
48
|
+
expect(clauses).to include :length
|
58
49
|
end
|
59
50
|
end
|
60
51
|
end
|
61
52
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
describe MySimilarContract do
|
53
|
+
#
|
54
|
+
# See spec/classes/composite_contract.rb
|
55
|
+
#
|
56
|
+
describe CompositeContract do
|
68
57
|
it 'retains its parents quackings' do
|
69
|
-
clauses =
|
70
|
-
expect(clauses.length).to eq
|
71
|
-
expect(clauses).to include :
|
72
|
-
expect(clauses).to include :bar
|
58
|
+
clauses = CompositeContract.clauses
|
59
|
+
expect(clauses.length).to eq 2
|
60
|
+
expect(clauses).to include :length
|
73
61
|
expect(clauses).to include :chunky_bacon
|
74
62
|
end
|
75
63
|
end
|
data/spec/inspection_spec.rb
CHANGED
@@ -11,24 +11,19 @@ module DuckPond
|
|
11
11
|
end
|
12
12
|
|
13
13
|
describe '#fulfilled_by?' do
|
14
|
-
|
15
|
-
class MyChunkyBaconContract < Contract
|
16
|
-
has_method :chunky_bacon
|
17
|
-
end
|
18
|
-
|
19
|
-
context 'when the sighted object quacks like the duck' do
|
14
|
+
context 'when the inspected object is fulfilled by the contract' do
|
20
15
|
it 'returns true' do
|
21
|
-
obj = OpenStruct.new(:
|
16
|
+
obj = OpenStruct.new(:length => 2)
|
22
17
|
inspection = Inspection.new(obj)
|
23
|
-
expect(inspection.fulfilled_by?
|
18
|
+
expect(inspection.fulfilled_by? LengthContract).to be true
|
24
19
|
end
|
25
20
|
end
|
26
21
|
|
27
|
-
context 'when the
|
22
|
+
context 'when the inspected object is not fulfilled by the contract' do
|
28
23
|
it 'returns false' do
|
29
|
-
obj = OpenStruct.new(:
|
24
|
+
obj = OpenStruct.new(:size => 2)
|
30
25
|
inspection = Inspection.new(obj)
|
31
|
-
expect(inspection.fulfilled_by?
|
26
|
+
expect(inspection.fulfilled_by? LengthContract).to be false
|
32
27
|
end
|
33
28
|
end
|
34
29
|
|
data/spec/spec_helper.rb
CHANGED
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.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikey Hogarth
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -61,7 +61,8 @@ files:
|
|
61
61
|
- lib/duckpond/contract.rb
|
62
62
|
- lib/duckpond/inspection.rb
|
63
63
|
- lib/duckpond/version.rb
|
64
|
-
- spec/classes/
|
64
|
+
- spec/classes/contracts/composite_contract.rb
|
65
|
+
- spec/classes/contracts/length_contract.rb
|
65
66
|
- spec/contract_spec.rb
|
66
67
|
- spec/inspection_spec.rb
|
67
68
|
- spec/spec_helper.rb
|
@@ -85,12 +86,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
86
|
version: '0'
|
86
87
|
requirements: []
|
87
88
|
rubyforge_project:
|
88
|
-
rubygems_version: 2.
|
89
|
+
rubygems_version: 2.1.10
|
89
90
|
signing_key:
|
90
91
|
specification_version: 4
|
91
92
|
summary: Explicit duck-typing for ruby
|
92
93
|
test_files:
|
93
|
-
- spec/classes/
|
94
|
+
- spec/classes/contracts/composite_contract.rb
|
95
|
+
- spec/classes/contracts/length_contract.rb
|
94
96
|
- spec/contract_spec.rb
|
95
97
|
- spec/inspection_spec.rb
|
96
98
|
- spec/spec_helper.rb
|
99
|
+
has_rdoc:
|