duckpond 1.2 → 1.2.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/.travis.yml +3 -3
- data/Gemfile.lock +30 -29
- data/README.md +13 -8
- data/duckpond.gemspec +1 -1
- data/lib/duckpond/clause/method_clause.rb +40 -25
- data/lib/duckpond/clause.rb +14 -2
- data/lib/duckpond/contract/contract_infringement_error.rb +19 -0
- data/lib/duckpond/contract/convinience_methods.rb +24 -0
- data/lib/duckpond/contract.rb +20 -21
- data/lib/duckpond/inspection.rb +18 -3
- data/lib/duckpond/lawyer.rb +30 -0
- data/lib/duckpond/version.rb +1 -1
- data/lib/duckpond.rb +1 -0
- data/spec/clauses/{method_clause_spec.rb → method_clause/method_clause_spec.rb} +3 -3
- data/spec/clauses/method_clause/method_clause_usage_spec.rb +30 -0
- data/spec/contract_spec.rb +7 -29
- data/spec/lawyer_spec.rb +24 -0
- metadata +24 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c635271dca4ed930b071dc968a417b806c7cfb1
|
4
|
+
data.tar.gz: 4a8da65e653dadfac684a2204199d9f9acd3d9c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52973252980ae5be14a152965de3f0faffc8cc0de46489ee3002a07f4f457b30cf92298e453c37d79d4e80911a42f90ccd37aecfc58cc460966f87a6e337f822
|
7
|
+
data.tar.gz: d426f2173a3cc9baae657ddb8782d1f9749870a1f2ddfbd1350fba3af971e1ba043bedc53341e7f53506f28208249fd078e76425da321191c1dbacb59e944677
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,52 +1,53 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
duckpond (1.
|
4
|
+
duckpond (1.2)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
coveralls (0.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
coveralls (0.8.13)
|
10
|
+
json (~> 1.8)
|
11
|
+
simplecov (~> 0.11.0)
|
12
|
+
term-ansicolor (~> 1.3)
|
13
|
+
thor (~> 0.19.1)
|
14
|
+
tins (~> 1.6.0)
|
15
15
|
diff-lcs (1.2.5)
|
16
16
|
docile (1.1.5)
|
17
|
-
|
18
|
-
multi_json (1.10.1)
|
17
|
+
json (1.8.3)
|
19
18
|
rake (0.9.6)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
rspec-
|
24
|
-
|
25
|
-
rspec-
|
26
|
-
rspec-
|
27
|
-
rspec-support (~> 3.0.0)
|
28
|
-
rspec-expectations (3.0.1)
|
19
|
+
rspec (3.4.0)
|
20
|
+
rspec-core (~> 3.4.0)
|
21
|
+
rspec-expectations (~> 3.4.0)
|
22
|
+
rspec-mocks (~> 3.4.0)
|
23
|
+
rspec-core (3.4.3)
|
24
|
+
rspec-support (~> 3.4.0)
|
25
|
+
rspec-expectations (3.4.0)
|
29
26
|
diff-lcs (>= 1.2.0, < 2.0)
|
30
|
-
rspec-support (~> 3.
|
31
|
-
rspec-mocks (3.
|
32
|
-
|
33
|
-
|
34
|
-
|
27
|
+
rspec-support (~> 3.4.0)
|
28
|
+
rspec-mocks (3.4.1)
|
29
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
30
|
+
rspec-support (~> 3.4.0)
|
31
|
+
rspec-support (3.4.1)
|
32
|
+
simplecov (0.11.2)
|
35
33
|
docile (~> 1.1.0)
|
36
|
-
|
37
|
-
simplecov-html (~> 0.
|
38
|
-
simplecov-html (0.
|
39
|
-
term-ansicolor (1.3.
|
34
|
+
json (~> 1.8)
|
35
|
+
simplecov-html (~> 0.10.0)
|
36
|
+
simplecov-html (0.10.0)
|
37
|
+
term-ansicolor (1.3.2)
|
40
38
|
tins (~> 1.0)
|
41
39
|
thor (0.19.1)
|
42
|
-
tins (1.
|
40
|
+
tins (1.6.0)
|
43
41
|
|
44
42
|
PLATFORMS
|
45
43
|
ruby
|
46
44
|
|
47
45
|
DEPENDENCIES
|
48
|
-
bundler (~> 1.
|
46
|
+
bundler (~> 1.10)
|
49
47
|
coveralls
|
50
48
|
duckpond!
|
51
49
|
rake (~> 0)
|
52
50
|
rspec
|
51
|
+
|
52
|
+
BUNDLED WITH
|
53
|
+
1.10.6
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
Explicit duck typing for ruby.
|
8
8
|
|
9
9
|
|
10
|
-
##
|
10
|
+
## Introduction
|
11
11
|
|
12
12
|
Duck Typing can make code confusing and unreadable, particularly
|
13
13
|
when multiple developers are working on the same project or when
|
@@ -35,6 +35,8 @@ 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!
|
39
|
+
|
38
40
|
Usage is demonstrated in '[the_solution](docs/the_solution.txt)', but in a nutshell you
|
39
41
|
create "contract" classes by inheriting from DuckPond::Contract. These classes should
|
40
42
|
be commented extensively.
|
@@ -56,10 +58,13 @@ fulfilled by the object:
|
|
56
58
|
=> false
|
57
59
|
|
58
60
|
There is also a "bang" version of the #fulfills method, that raises an error instead
|
59
|
-
of returning false.
|
61
|
+
of returning false. The error message details why it got raised.
|
62
|
+
|
63
|
+
MyContract.fulfills! :foo
|
64
|
+
=> DuckPond::Contract::ContractInfringementError:
|
65
|
+
One or more clauses from MyContract were not fulfilled by :foo (Symbol)
|
66
|
+
Expected subject to respond to method 'length'
|
60
67
|
|
61
|
-
MyContract.fulfills! 12
|
62
|
-
=> RAISES ERROR!!
|
63
68
|
|
64
69
|
Contracts can be combined into composite "super contracts" - contracts which are made up of
|
65
70
|
various other contracts. This ties in with the reccomendation of preferring composition over inheritance:
|
@@ -127,11 +132,11 @@ And then be implemented in a method like this:
|
|
127
132
|
|
128
133
|
## Compatibility
|
129
134
|
|
130
|
-
CI tests exist for the following rubies,
|
135
|
+
CI tests exist for the following rubies, other versions are not supported but should still work;
|
131
136
|
|
132
|
-
-
|
133
|
-
- 2.
|
134
|
-
- 2.1.
|
137
|
+
- 2.3.0
|
138
|
+
- 2.2.4
|
139
|
+
- 2.1.8
|
135
140
|
- jruby-19mode
|
136
141
|
|
137
142
|
|
data/duckpond.gemspec
CHANGED
@@ -18,6 +18,6 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(spec)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_development_dependency "bundler", "~> 1.
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
22
22
|
spec.add_development_dependency "rake", "~> 0"
|
23
23
|
end
|
@@ -4,43 +4,58 @@
|
|
4
4
|
# Satisfied if the subject responds to the method represented
|
5
5
|
# by this clause.
|
6
6
|
#
|
7
|
+
# Available Options:
|
8
|
+
#
|
9
|
+
# :method_name => The name of the method to check for / call
|
10
|
+
# :given_args => Arguments to pass into the method
|
11
|
+
# :responds_with => What you would expect the method to respond with
|
12
|
+
#
|
13
|
+
#
|
7
14
|
module DuckPond
|
8
15
|
class MethodClause < Clause
|
9
16
|
|
10
|
-
def method_name
|
11
|
-
@options[:method_name]
|
12
|
-
end
|
13
|
-
|
14
|
-
#
|
15
|
-
# satisfied_by?
|
16
17
|
#
|
17
|
-
#
|
18
|
+
# legal_assesment
|
18
19
|
#
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
# Unless a block was given, or a response is required, we're done!
|
25
|
-
return true unless @options[:block] || @options[:responds_with]
|
26
|
-
|
27
|
-
# If we get this far, we need to tap into the result of the method
|
28
|
-
# call, as the user is interrogating it somehow.
|
29
|
-
response_when_called(subject, method_name, @options[:given_args])
|
30
|
-
.tap do |response_when_called|
|
31
|
-
if @options[:block]
|
32
|
-
return false unless @options[:block].call(response_when_called)
|
20
|
+
def legal_assesment(subject)
|
21
|
+
Lawyer.new do |lawyer|
|
22
|
+
unless subject.respond_to? method
|
23
|
+
lawyer.unsatisfied! "Expected subject to respond to method '#{method}'"
|
33
24
|
end
|
34
|
-
|
35
|
-
|
25
|
+
|
26
|
+
if @block || expected_response
|
27
|
+
response_when_called(subject, method, args).tap do |response_when_called|
|
28
|
+
if @block
|
29
|
+
unless @block.call(response_when_called)
|
30
|
+
lawyer.unsatisfied! "Block did not respond with 'true' for method #{method}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if expected_response
|
35
|
+
unless response_when_called == expected_response
|
36
|
+
lawyer.unsatisfied! "Expected method #{method} to return #{expected_response} but got #{response_when_called}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
36
40
|
end
|
37
41
|
end
|
38
|
-
true
|
39
42
|
end
|
40
43
|
|
41
44
|
private
|
42
45
|
def response_when_called(subject, method, args = [])
|
43
|
-
subject.send(
|
46
|
+
subject.send(method, *args)
|
47
|
+
end
|
48
|
+
|
49
|
+
def method
|
50
|
+
@options[:method_name]
|
51
|
+
end
|
52
|
+
|
53
|
+
def expected_response
|
54
|
+
@options[:responds_with]
|
55
|
+
end
|
56
|
+
|
57
|
+
def args
|
58
|
+
@options[:given_args]
|
44
59
|
end
|
45
60
|
|
46
61
|
end
|
data/lib/duckpond/clause.rb
CHANGED
@@ -6,14 +6,26 @@
|
|
6
6
|
module DuckPond
|
7
7
|
class Clause
|
8
8
|
|
9
|
-
attr_reader :options
|
9
|
+
attr_reader :options, :block
|
10
10
|
|
11
11
|
#
|
12
12
|
# initialize
|
13
13
|
#
|
14
14
|
def initialize(opts={}, block)
|
15
15
|
@options = opts
|
16
|
-
@
|
16
|
+
@block = block
|
17
17
|
end
|
18
|
+
|
19
|
+
def satisfied_by?(subject)
|
20
|
+
self.legal_assesment(subject).satisfied?
|
21
|
+
end
|
22
|
+
|
23
|
+
def legal_assesment
|
24
|
+
# it is the responsibility of clauses to provide a #legal_assesment
|
25
|
+
# method - this should return a lawyer who is either satisfied or
|
26
|
+
# not satisfied that the subject fulfills the clause.
|
27
|
+
raise NotImplementedError
|
28
|
+
end
|
29
|
+
|
18
30
|
end
|
19
31
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module DuckPond
|
2
|
+
class Contract
|
3
|
+
class ContractInfringementError < TypeError
|
4
|
+
def initialize(contract, subject, inspection = nil)
|
5
|
+
@contract = contract
|
6
|
+
@subject = subject
|
7
|
+
@messages = inspection.messages
|
8
|
+
end
|
9
|
+
|
10
|
+
def message
|
11
|
+
%Q{
|
12
|
+
One or more clauses from #{@contract} were not fulfilled by #{@subject} (#{@subject.class})
|
13
|
+
#{@messages.join(', ') if @messages.any?}
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#
|
2
|
+
# Contract::ConvinienceMethods
|
3
|
+
#
|
4
|
+
# A set of methods used to make adding clauses easier for the user.
|
5
|
+
#
|
6
|
+
module DuckPond
|
7
|
+
class Contract
|
8
|
+
module ConvinienceMethods
|
9
|
+
#
|
10
|
+
# has_method
|
11
|
+
#
|
12
|
+
# Adds a method clause to the contract
|
13
|
+
#
|
14
|
+
def has_method(method_name, opts = {})
|
15
|
+
if block_given?
|
16
|
+
has_clause(MethodClause, opts.merge(:method_name => method_name), &Proc.new)
|
17
|
+
else
|
18
|
+
has_clause(MethodClause, opts.merge(:method_name => method_name))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/duckpond/contract.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'duckpond/contract/convinience_methods'
|
2
|
+
require 'duckpond/contract/contract_infringement_error'
|
3
|
+
|
1
4
|
#
|
2
5
|
# DuckPond::Contract
|
3
6
|
#
|
@@ -7,7 +10,7 @@
|
|
7
10
|
#
|
8
11
|
module DuckPond
|
9
12
|
class Contract
|
10
|
-
|
13
|
+
extend DuckPond::Contract::ConvinienceMethods
|
11
14
|
|
12
15
|
class << self
|
13
16
|
|
@@ -41,20 +44,6 @@ module DuckPond
|
|
41
44
|
clauses << clause_klass.new(opts, block)
|
42
45
|
end
|
43
46
|
|
44
|
-
|
45
|
-
#
|
46
|
-
# has_method
|
47
|
-
#
|
48
|
-
# Adds a method clause to the contract
|
49
|
-
#
|
50
|
-
def has_method(method_name, opts = {})
|
51
|
-
if block_given?
|
52
|
-
has_clause(MethodClause, opts.merge(:method_name => method_name), &Proc.new)
|
53
|
-
else
|
54
|
-
has_clause(MethodClause, opts.merge(:method_name => method_name))
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
47
|
#
|
59
48
|
# include_clauses_from
|
60
49
|
#
|
@@ -62,7 +51,7 @@ module DuckPond
|
|
62
51
|
#
|
63
52
|
def include_clauses_from(other_contract)
|
64
53
|
other_contract.each_clause do |other_clause|
|
65
|
-
|
54
|
+
has_clause other_clause.class, other_clause.options, &other_clause.block
|
66
55
|
end
|
67
56
|
end
|
68
57
|
|
@@ -73,11 +62,13 @@ module DuckPond
|
|
73
62
|
# otherwise false.
|
74
63
|
#
|
75
64
|
def fulfills?(obj)
|
76
|
-
|
77
|
-
|
78
|
-
|
65
|
+
DuckPond::Inspection.new(obj).tap do |inspection|
|
66
|
+
return inspection.fulfilled_by? self
|
67
|
+
end
|
79
68
|
end
|
80
69
|
|
70
|
+
alias_method :fulfilled_by?, :fulfills?
|
71
|
+
|
81
72
|
#
|
82
73
|
# fulfills!
|
83
74
|
#
|
@@ -85,9 +76,17 @@ module DuckPond
|
|
85
76
|
# the passed in object, otherwise returns true.
|
86
77
|
#
|
87
78
|
def fulfills!(obj)
|
88
|
-
|
89
|
-
|
79
|
+
DuckPond::Inspection.new(obj).tap do |inspection|
|
80
|
+
unless inspection.fulfilled_by? self
|
81
|
+
raise ContractInfringementError.new(self, obj, inspection)
|
82
|
+
else
|
83
|
+
return true
|
84
|
+
end
|
85
|
+
end
|
90
86
|
end
|
87
|
+
|
88
|
+
alias_method :fulfilled_by!, :fulfills!
|
89
|
+
|
91
90
|
end
|
92
91
|
end
|
93
92
|
end
|
data/lib/duckpond/inspection.rb
CHANGED
@@ -16,7 +16,13 @@ module DuckPond
|
|
16
16
|
# Construct with any ruby object.
|
17
17
|
#
|
18
18
|
def initialize(subject)
|
19
|
-
@subject
|
19
|
+
@subject = subject
|
20
|
+
@satisfied = true
|
21
|
+
@messages = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def messages
|
25
|
+
@messages.flatten.uniq
|
20
26
|
end
|
21
27
|
|
22
28
|
#
|
@@ -28,9 +34,18 @@ module DuckPond
|
|
28
34
|
#
|
29
35
|
def fulfilled_by?(contract)
|
30
36
|
contract.each_clause do |clause|
|
31
|
-
|
37
|
+
clause.legal_assesment(@subject).tap do |lawyer|
|
38
|
+
unless lawyer.satisfied?
|
39
|
+
@satisfied = false
|
40
|
+
@messages << lawyer.messages
|
41
|
+
end
|
42
|
+
end
|
32
43
|
end
|
33
|
-
|
44
|
+
@satisfied
|
45
|
+
end
|
46
|
+
|
47
|
+
def satisfied?
|
48
|
+
@satisfied
|
34
49
|
end
|
35
50
|
end
|
36
51
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#
|
2
|
+
# DuckPond::Lawyer
|
3
|
+
#
|
4
|
+
# The lawyer class is responsible for maintaining the sate of satisfaction
|
5
|
+
# between a subject and its contract. Typically these are used in clauses.
|
6
|
+
#
|
7
|
+
module DuckPond
|
8
|
+
class Lawyer
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@satisfied = true
|
12
|
+
@messages = []
|
13
|
+
yield self if block_given?
|
14
|
+
end
|
15
|
+
|
16
|
+
def satisfied?
|
17
|
+
@satisfied
|
18
|
+
end
|
19
|
+
|
20
|
+
def messages
|
21
|
+
@messages
|
22
|
+
end
|
23
|
+
|
24
|
+
def unsatisfied!(msg = nil)
|
25
|
+
@satisfied = false
|
26
|
+
@messages << msg unless msg.nil?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/lib/duckpond/version.rb
CHANGED
data/lib/duckpond.rb
CHANGED
@@ -12,7 +12,7 @@ module DuckPond
|
|
12
12
|
context 'when constructed with a method name option' do
|
13
13
|
it 'adds that method name as an attribute' do
|
14
14
|
clause = MethodClause.new({:method_name => :foo}, nil)
|
15
|
-
expect(clause.method_name).to eq :foo
|
15
|
+
expect(clause.options[:method_name]).to eq :foo
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -24,12 +24,12 @@ module DuckPond
|
|
24
24
|
|
25
25
|
context 'when the subject responds to the clauses method' do
|
26
26
|
it 'returns true' do
|
27
|
-
expect(clause.satisfied_by?
|
27
|
+
expect(clause.satisfied_by?('Hello')).to eq true
|
28
28
|
end
|
29
29
|
end
|
30
30
|
context 'when the subject responds to the clauses method' do
|
31
31
|
it 'returns false' do
|
32
|
-
expect(clause.satisfied_by?
|
32
|
+
expect(clause.satisfied_by?(42)).to eq false
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'MethodClause usage' do
|
4
|
+
|
5
|
+
#
|
6
|
+
# see spec/classes/specific_length_contract.rb
|
7
|
+
#
|
8
|
+
describe SpecificLengthContract do
|
9
|
+
it 'checks a methods response is correct' do
|
10
|
+
expect(SpecificLengthContract.fulfills?("Hello")).to eq true
|
11
|
+
expect(SpecificLengthContract.fulfills?("Yello")).to eq false
|
12
|
+
expect(SpecificLengthContract.fulfills?("Goodbye")).to eq false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe SpecificLengthBehaviourContract do
|
17
|
+
it 'checks the given block against the subjects method repsonse' do
|
18
|
+
expect(SpecificLengthBehaviourContract.fulfills?('Hello')).to eq true
|
19
|
+
expect(SpecificLengthBehaviourContract.fulfills?('Goodbye')).to eq false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe SpecificIncludeBehaviourContract do
|
24
|
+
it 'checks the given block against the subjects method response' do
|
25
|
+
expect(SpecificIncludeBehaviourContract.fulfills?('Hello')).to eq true
|
26
|
+
expect(SpecificLengthBehaviourContract.fulfills?('Goodbye')).to eq false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/spec/contract_spec.rb
CHANGED
@@ -36,7 +36,7 @@ module DuckPond
|
|
36
36
|
end
|
37
37
|
context 'when the object is not fulfilled by the contract' do
|
38
38
|
it 'returns false' do
|
39
|
-
|
39
|
+
expect{LengthContract.fulfills!(2)}.to raise_error DuckPond::Contract::ContractInfringementError
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -45,36 +45,11 @@ module DuckPond
|
|
45
45
|
it 'returns the clauses for this contract' do
|
46
46
|
clauses = LengthContract.clauses
|
47
47
|
expect(clauses.length).to eq 1
|
48
|
-
expect(clauses.
|
48
|
+
expect(clauses.first.options[:method_name]).to eq :length
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
#
|
54
|
-
# see spec/classes/specific_length_contract.rb
|
55
|
-
#
|
56
|
-
describe SpecificLengthContract do
|
57
|
-
it 'checks a methods response is correct' do
|
58
|
-
expect(SpecificLengthContract.fulfills?("Hello")).to eq true
|
59
|
-
expect(SpecificLengthContract.fulfills?("Yello")).to eq false
|
60
|
-
expect(SpecificLengthContract.fulfills?("Goodbye")).to eq false
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
describe SpecificLengthBehaviourContract do
|
65
|
-
it 'checks the given block against the subjects method repsonse' do
|
66
|
-
expect(SpecificLengthBehaviourContract.fulfills?('Hello')).to eq true
|
67
|
-
expect(SpecificLengthBehaviourContract.fulfills?('Goodbye')).to eq false
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
describe SpecificIncludeBehaviourContract do
|
72
|
-
it 'checks the given block against the subjects method response' do
|
73
|
-
expect(SpecificIncludeBehaviourContract.fulfills?('Hello')).to eq true
|
74
|
-
expect(SpecificLengthBehaviourContract.fulfills?('Goodbye')).to eq false
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
53
|
#
|
79
54
|
# See spec/classes/composite_contract.rb
|
80
55
|
#
|
@@ -82,8 +57,11 @@ module DuckPond
|
|
82
57
|
it 'retains its parents quackings' do
|
83
58
|
clauses = CompositeContract.clauses
|
84
59
|
expect(clauses.length).to eq 2
|
85
|
-
|
86
|
-
|
60
|
+
clauses.map {|c|c.options[:method_name]}.tap do |method_names|
|
61
|
+
expect(method_names).to include :length
|
62
|
+
expect(method_names).to include :chunky_bacon
|
63
|
+
end
|
87
64
|
end
|
88
65
|
end
|
66
|
+
|
89
67
|
end
|
data/spec/lawyer_spec.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module DuckPond
|
4
|
+
describe Lawyer do
|
5
|
+
describe 'constructor' do
|
6
|
+
it 'yields itself if passed a block' do
|
7
|
+
oid_1 = nil
|
8
|
+
oid_2 = Lawyer.new do |lawyer|
|
9
|
+
oid_1 = lawyer.object_id
|
10
|
+
end.object_id
|
11
|
+
expect(oid_1).to eq oid_2
|
12
|
+
end
|
13
|
+
end
|
14
|
+
describe 'unsatisified!' do
|
15
|
+
it 'sets the lawyers satisfied flag to false' do
|
16
|
+
lawyer = Lawyer.new
|
17
|
+
expect(lawyer.satisfied?).to be true
|
18
|
+
|
19
|
+
lawyer.unsatisfied!
|
20
|
+
expect(lawyer.satisfied?).to be false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duckpond
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.2.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:
|
11
|
+
date: 2016-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.10'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.10'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
description: Explicit duck-typing for ruby
|
@@ -45,9 +45,9 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
-
- .gitignore
|
49
|
-
- .rspec
|
50
|
-
- .travis.yml
|
48
|
+
- ".gitignore"
|
49
|
+
- ".rspec"
|
50
|
+
- ".travis.yml"
|
51
51
|
- Gemfile
|
52
52
|
- Gemfile.lock
|
53
53
|
- LICENSE
|
@@ -60,16 +60,21 @@ files:
|
|
60
60
|
- lib/duckpond/clause.rb
|
61
61
|
- lib/duckpond/clause/method_clause.rb
|
62
62
|
- lib/duckpond/contract.rb
|
63
|
+
- lib/duckpond/contract/contract_infringement_error.rb
|
64
|
+
- lib/duckpond/contract/convinience_methods.rb
|
63
65
|
- lib/duckpond/inspection.rb
|
66
|
+
- lib/duckpond/lawyer.rb
|
64
67
|
- lib/duckpond/version.rb
|
65
68
|
- spec/classes/contracts/composite_contract.rb
|
66
69
|
- spec/classes/contracts/length_contract.rb
|
67
70
|
- spec/classes/contracts/specific_include_behaviour_contract.rb
|
68
71
|
- spec/classes/contracts/specific_length_behaviour_contract.rb
|
69
72
|
- spec/classes/contracts/specific_length_contract.rb
|
70
|
-
- spec/clauses/method_clause_spec.rb
|
73
|
+
- spec/clauses/method_clause/method_clause_spec.rb
|
74
|
+
- spec/clauses/method_clause/method_clause_usage_spec.rb
|
71
75
|
- spec/contract_spec.rb
|
72
76
|
- spec/inspection_spec.rb
|
77
|
+
- spec/lawyer_spec.rb
|
73
78
|
- spec/spec_helper.rb
|
74
79
|
homepage: https://github.com/mikeyhogarth/duckpond
|
75
80
|
licenses:
|
@@ -81,17 +86,17 @@ require_paths:
|
|
81
86
|
- lib
|
82
87
|
required_ruby_version: !ruby/object:Gem::Requirement
|
83
88
|
requirements:
|
84
|
-
- -
|
89
|
+
- - ">="
|
85
90
|
- !ruby/object:Gem::Version
|
86
91
|
version: '0'
|
87
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
93
|
requirements:
|
89
|
-
- -
|
94
|
+
- - ">="
|
90
95
|
- !ruby/object:Gem::Version
|
91
96
|
version: '0'
|
92
97
|
requirements: []
|
93
98
|
rubyforge_project:
|
94
|
-
rubygems_version: 2.
|
99
|
+
rubygems_version: 2.4.5.1
|
95
100
|
signing_key:
|
96
101
|
specification_version: 4
|
97
102
|
summary: Explicit duck-typing for ruby
|
@@ -101,7 +106,10 @@ test_files:
|
|
101
106
|
- spec/classes/contracts/specific_include_behaviour_contract.rb
|
102
107
|
- spec/classes/contracts/specific_length_behaviour_contract.rb
|
103
108
|
- spec/classes/contracts/specific_length_contract.rb
|
104
|
-
- spec/clauses/method_clause_spec.rb
|
109
|
+
- spec/clauses/method_clause/method_clause_spec.rb
|
110
|
+
- spec/clauses/method_clause/method_clause_usage_spec.rb
|
105
111
|
- spec/contract_spec.rb
|
106
112
|
- spec/inspection_spec.rb
|
113
|
+
- spec/lawyer_spec.rb
|
107
114
|
- spec/spec_helper.rb
|
115
|
+
has_rdoc:
|