duckpond 1.2 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|