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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 49a48ab6dd27f5acfb06ff204a3679299aabab0d
4
- data.tar.gz: adeae633ba2f56c289cff8b0f3ae902e2f63e2d2
3
+ metadata.gz: bb40e8e7d8b6bdc3292b4ddfb0bc5548af7df234
4
+ data.tar.gz: 4ecca5d9961fc6accd02237c9cd136d8b3c729eb
5
5
  SHA512:
6
- metadata.gz: 21d67910df3b44f7aac195706ab565b3e20b23549d73251f8ba7dba36f31d033c2e293333d3c17b33b83555b23a345b6b73e97be7ba3cf49b9c19338d64b6c3a
7
- data.tar.gz: 2cbf35d78a704430210fff5e7fe78aea5da7c04aba15d484e420501a8b5e4ec26948f6682e019687fed20fd32ed04964d9ea5d7615dcfd5b091b8f5a32184c36
6
+ metadata.gz: 6665633fd874275fbcef6e1e292966849e5e558ac65230cc7fa78dbb26430b88ad8c0c0eb6e23730c2b397532fb31debbf02c493908f5e21143baf6b4553619f
7
+ data.tar.gz: 7d9d32e81cf6fd3fbb0b20986c552c0a3d37dd0b6a9ee9de266a427f3672455640f4c25cff2991ce16a93173cbff92a847980e1b38b297dc5d0186bcd1c6b8ff
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- duckpond (1.0.2)
4
+ duckpond (1.1.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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
- MyContract.fulfilled_by? "Hello"
54
- => true
55
- MyContract.fulfilled_by? 12
56
- => false
53
+ MyContract.fulfills? "Hello"
54
+ => true
55
+ MyContract.fulfills? 12
56
+ => false
57
57
 
58
- There is also a "bang" version of the fulfilled_by method, that raises an error instead
58
+ There is also a "bang" version of the #fulfills method, that raises an error instead
59
59
  of returning false.
60
60
 
61
- MyContract.fulfilled_by! 12
62
- => RAISES ERROR!!
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.fulfilled_by! email
90
+ IEmailable.fulfills! email
91
91
  email.send
92
92
  end
93
93
  end
@@ -11,14 +11,14 @@ end
11
11
  # Then use it to check stuff!
12
12
  #
13
13
 
14
- ObjContract.fulfilled_by? "Hello"
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.fulfilled_by! "Hello"
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.fulfilled_by! obj
30
+ ObjContract.fulfills! obj
31
31
 
32
32
  obj.foo!
33
33
  fooinator = Test::Fooinator.new
@@ -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.clauses.each do |other_contracts_quacking|
34
- has_method other_contracts_quacking
50
+ other_contract.each_clause do |other_clause|
51
+ has_method other_clause
35
52
  end
36
53
  end
37
54
 
38
55
  #
39
- # fulfilled_by?
56
+ # fulfills?
40
57
  #
41
- def fulfilled_by?(obj)
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
- # fulfilled_by!
68
+ # fulfills!
69
+ #
70
+ # Raises a ContractInfringementError unless this contract fulfills
71
+ # the passed in object, otherwise returns true.
49
72
  #
50
- def fulfilled_by!(obj)
51
- raise ContractInfringementError unless fulfilled_by?(obj)
73
+ def fulfills!(obj)
74
+ raise ContractInfringementError unless fulfills?(obj)
75
+ true
52
76
  end
53
77
  end
54
78
  end
@@ -1,8 +1,8 @@
1
1
  #
2
2
  # DuckPond::Inspection
3
3
  #
4
- # The duckpond analysis class is essentially just a wrapper for the inspected
5
- # object, used here to avoid un-nessecary monkey patching.
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.clauses.each do |clause|
30
+ contract.each_clause do |clause|
31
31
  return false unless @subject.respond_to? clause
32
32
  end
33
33
  true
@@ -1,3 +1,3 @@
1
1
  module DuckPond
2
- VERSION = "1.1.0"
2
+ VERSION = "1.1.1"
3
3
  end
@@ -0,0 +1,6 @@
1
+ module DuckPond
2
+ class CompositeContract < Contract
3
+ include_clauses_from LengthContract
4
+ has_method :chunky_bacon
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module DuckPond
2
+ class LengthContract < DuckPond::Contract
3
+ has_method :length
4
+ end
5
+ end
@@ -12,64 +12,52 @@ module DuckPond
12
12
  end
13
13
  end
14
14
 
15
- class LengthContract < DuckPond::Contract
16
- has_method :length
17
- end
18
-
19
- describe 'fulfilled_by?' do
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.fulfilled_by?("Hello")).to eq true
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.fulfilled_by?(2)).to eq false
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.fulfilled_by!("Hello")}.to_not raise_error
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.fulfilled_by!(2)}.to raise_error
39
+ expect{LengthContract.fulfills!(2)}.to raise_error
41
40
  end
42
41
  end
43
42
  end
44
- end
45
43
 
46
- class MyContract < Contract
47
- has_method :foo
48
- has_method :bar
49
- end
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
- class MySimilarContract < Contract
63
- include_clauses_from MyContract
64
- has_method :chunky_bacon
65
- end
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 = MySimilarContract.clauses
70
- expect(clauses.length).to eq 3
71
- expect(clauses).to include :foo
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
@@ -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(:chunky_bacon => :mmm)
16
+ obj = OpenStruct.new(:length => 2)
22
17
  inspection = Inspection.new(obj)
23
- expect(inspection.fulfilled_by? MyChunkyBaconContract).to be true
18
+ expect(inspection.fulfilled_by? LengthContract).to be true
24
19
  end
25
20
  end
26
21
 
27
- context 'when the sighted object does not quack like the duck' do
22
+ context 'when the inspected object is not fulfilled by the contract' do
28
23
  it 'returns false' do
29
- obj = OpenStruct.new(:vegan_fallafal => :yuck)
24
+ obj = OpenStruct.new(:size => 2)
30
25
  inspection = Inspection.new(obj)
31
- expect(inspection.fulfilled_by? MyChunkyBaconContract).to be false
26
+ expect(inspection.fulfilled_by? LengthContract).to be false
32
27
  end
33
28
  end
34
29
 
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'duckpond'
2
- require 'classes/fooinator'
2
+ require 'classes/contracts/length_contract'
3
+ require 'classes/contracts/composite_contract'
3
4
  require 'coveralls'
4
5
 
5
6
  Coveralls.wear!
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.0
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-18 00:00:00.000000000 Z
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/fooinator.rb
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.2.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/fooinator.rb
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:
@@ -1,10 +0,0 @@
1
- module Duckpond
2
- module Test
3
- class Fooinator
4
- def bar(obj)
5
- obj
6
- end
7
- end
8
- end
9
- end
10
-