rspec-contracts 0.0.1 → 0.0.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/History.md +5 -0
- data/README.md +5 -2
- data/lib/rspec/contracts/core_syntax.rb +5 -3
- data/lib/rspec/contracts/double.rb +6 -5
- data/lib/rspec/contracts/fulfillment.rb +17 -9
- data/lib/rspec/contracts/fulfillment_view.rb +13 -13
- data/lib/rspec/contracts/implementor.rb +28 -0
- data/lib/rspec/contracts/interface.rb +30 -0
- data/lib/rspec/contracts/interface_fulfillment.rb +34 -0
- data/lib/rspec/contracts/interface_group.rb +21 -0
- data/lib/rspec/contracts/interface_proxy.rb +5 -2
- data/lib/rspec/contracts/message.rb +30 -0
- data/lib/rspec/contracts/message_arguments.rb +19 -0
- data/lib/rspec/contracts/message_return.rb +19 -0
- data/lib/rspec/contracts/message_view.rb +16 -0
- data/lib/rspec/contracts/method_proxy.rb +16 -3
- data/lib/rspec/contracts/mock_proxy.rb +51 -0
- data/lib/rspec/contracts/mocks_syntax.rb +1 -0
- data/lib/rspec/contracts/version.rb +1 -1
- data/lib/rspec/contracts.rb +5 -3
- metadata +15 -10
- data/lib/rspec/contracts/proxy.rb +0 -32
- data/lib/rspec/contracts/requirement.rb +0 -31
- data/lib/rspec/contracts/requirement_group.rb +0 -19
- data/lib/rspec/contracts/requirement_view.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87b15ff10f754beb89ee5b1d4243b8aea51ca5c3
|
4
|
+
data.tar.gz: b28190904c6dc5fd3c909ee73cdbb7c9dd4df3ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27e3827e0404171952cdc793c8032caf74182e1621b2ad932c1d33cbf116ab63fd4ea8fcbbb4bde6bc8493f08c4ce4b9912341a02780b6d8e1eb2cb79cefe738
|
7
|
+
data.tar.gz: f3f091d6f3f01819b6122727b678992068ef2304f59e7036777ef4ce49200d43c9352ce106a9b95e12d5c8b0e71da657037da8ba921aece444f346db428246ec
|
data/History.md
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
-
##
|
1
|
+
## rspec-contracts
|
2
|
+
[](http://badge.fury.io/rb/rspec-contracts)
|
3
|
+
[](https://travis-ci.org/brianauton/rspec-contracts)
|
4
|
+
[](https://codeclimate.com/github/brianauton/rspec-contracts)
|
2
5
|
|
3
|
-
Automatic contract
|
6
|
+
Automatic contract verification for your RSpec suite
|
4
7
|
|
5
8
|
### Requirements
|
6
9
|
|
@@ -1,12 +1,14 @@
|
|
1
|
-
require "rspec/core
|
1
|
+
require "rspec/core"
|
2
|
+
require "rspec/contracts/interface"
|
2
3
|
require "rspec/contracts/interface_proxy"
|
3
4
|
|
4
5
|
module RSpec
|
5
6
|
module Core
|
6
7
|
class ExampleGroup
|
7
8
|
def self.fulfill_contract(*interface_names)
|
8
|
-
interface_names.each do |
|
9
|
-
Contracts::
|
9
|
+
interface_names.each do |name|
|
10
|
+
interface = Contracts::Interface.find_or_create name
|
11
|
+
Contracts::InterfaceProxy.create interface, described_class
|
10
12
|
end
|
11
13
|
end
|
12
14
|
end
|
@@ -1,5 +1,6 @@
|
|
1
|
-
require "rspec/mocks
|
2
|
-
require "rspec/contracts/
|
1
|
+
require "rspec/mocks"
|
2
|
+
require "rspec/contracts/interface"
|
3
|
+
require "rspec/contracts/mock_proxy"
|
3
4
|
|
4
5
|
module RSpec
|
5
6
|
module Contracts
|
@@ -7,12 +8,12 @@ module RSpec
|
|
7
8
|
include Mocks::TestDouble
|
8
9
|
|
9
10
|
def initialize(interface_name, *args)
|
10
|
-
@
|
11
|
-
|
11
|
+
@interface = Interface.find_or_create interface_name
|
12
|
+
super
|
12
13
|
end
|
13
14
|
|
14
15
|
def __build_mock_proxy(order_group)
|
15
|
-
|
16
|
+
MockProxy.new self, order_group, @interface
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
@@ -1,23 +1,31 @@
|
|
1
|
-
require "rspec/contracts/
|
2
|
-
require "rspec/contracts/requirement_view"
|
1
|
+
require "rspec/contracts/interface_fulfillment"
|
3
2
|
|
4
3
|
module RSpec
|
5
4
|
module Contracts
|
6
5
|
class Fulfillment
|
7
|
-
|
8
|
-
|
6
|
+
attr_reader :interface_fulfillments
|
7
|
+
|
8
|
+
def initialize(interfaces, implementors)
|
9
|
+
@implementors = implementors
|
10
|
+
@interface_fulfillments = interfaces.map do |interface|
|
11
|
+
InterfaceFulfillment.new interface, implementors_for(interface)
|
12
|
+
end
|
9
13
|
end
|
10
14
|
|
11
15
|
def complete?
|
12
|
-
|
16
|
+
incomplete_interfaces.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
def incomplete_interfaces
|
20
|
+
interface_fulfillments.reject(&:complete?)
|
13
21
|
end
|
14
22
|
|
15
|
-
def
|
16
|
-
|
23
|
+
def messages_count
|
24
|
+
interface_fulfillments.map(&:messages_count).inject(&:+) || 0
|
17
25
|
end
|
18
26
|
|
19
|
-
def
|
20
|
-
@
|
27
|
+
def implementors_for(interface)
|
28
|
+
@implementors.select{ |i| i.interface_names.include? interface.name }
|
21
29
|
end
|
22
30
|
end
|
23
31
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "rspec/contracts/message_view"
|
2
|
+
|
1
3
|
module RSpec
|
2
4
|
module Contracts
|
3
5
|
class FulfillmentView
|
@@ -6,27 +8,25 @@ module RSpec
|
|
6
8
|
end
|
7
9
|
|
8
10
|
def render
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
def render_complete
|
13
|
-
"#{contracts_count} verified."
|
11
|
+
([summary] + unfulfilled_views).join "\n"
|
14
12
|
end
|
15
13
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
def summary
|
15
|
+
unverified = unfulfilled_views.count
|
16
|
+
verified = @fulfillment.messages_count - unverified
|
17
|
+
"#{contracts_count}, #{verified} verified, #{unverified} unverified"
|
20
18
|
end
|
21
19
|
|
22
20
|
def unfulfilled_views
|
23
|
-
@fulfillment.
|
24
|
-
|
25
|
-
|
21
|
+
@fulfillment.incomplete_interfaces.map do |fulfillment|
|
22
|
+
fulfillment.unfulfilled_messages.map do |message|
|
23
|
+
RSpec::Contracts::MessageView.new(fulfillment.interface.name, message).render
|
24
|
+
end
|
25
|
+
end.flatten
|
26
26
|
end
|
27
27
|
|
28
28
|
def contracts_count
|
29
|
-
pluralize @fulfillment.
|
29
|
+
pluralize @fulfillment.messages_count, "contract"
|
30
30
|
end
|
31
31
|
|
32
32
|
def pluralize(number, noun)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Contracts
|
3
|
+
class Implementor
|
4
|
+
attr_reader :interface_names, :messages
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@interface_names = []
|
8
|
+
@messages = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_message(message)
|
12
|
+
messages << message
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.collection
|
16
|
+
@collection ||= {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.all
|
20
|
+
collection.values
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.find_or_create(subject)
|
24
|
+
collection[subject] ||= new
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "rspec/contracts/interface_group"
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Contracts
|
5
|
+
class Interface
|
6
|
+
attr_reader :name, :messages
|
7
|
+
|
8
|
+
def initialize(name)
|
9
|
+
@name = name
|
10
|
+
@messages = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_message(message)
|
14
|
+
@messages << message
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.all
|
18
|
+
@all ||= InterfaceGroup.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.find_or_create(name)
|
22
|
+
all.find_or_create name
|
23
|
+
end
|
24
|
+
|
25
|
+
def unique_messages
|
26
|
+
messages.uniq(&:to_hash)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Contracts
|
3
|
+
class InterfaceFulfillment
|
4
|
+
attr_reader :interface
|
5
|
+
|
6
|
+
def initialize(interface, implementors)
|
7
|
+
@interface = interface
|
8
|
+
@implementors = implementors
|
9
|
+
end
|
10
|
+
|
11
|
+
def complete?
|
12
|
+
unfulfilled_messages.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
def unfulfilled_messages
|
16
|
+
interface.unique_messages.reject{ |r| fulfilled_by_all? r }
|
17
|
+
end
|
18
|
+
|
19
|
+
def messages_count
|
20
|
+
interface.unique_messages.count
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def fulfilled_by_all?(message)
|
26
|
+
@implementors.all?{ |i| fulfilled_by? message, i }
|
27
|
+
end
|
28
|
+
|
29
|
+
def fulfilled_by?(message, implementor)
|
30
|
+
implementor.messages.any? { |m| message.fully_described_by? m }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "rspec/contracts/interface"
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Contracts
|
5
|
+
class InterfaceGroup
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@collection = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def find_or_create(name)
|
13
|
+
@collection[name] ||= Interface.new(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def each(&block)
|
17
|
+
@collection.values.each(&block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,11 +1,14 @@
|
|
1
|
+
require "rspec/contracts/implementor"
|
1
2
|
require "rspec/contracts/method_proxy"
|
2
3
|
|
3
4
|
module RSpec
|
4
5
|
module Contracts
|
5
6
|
class InterfaceProxy
|
6
|
-
def initialize(
|
7
|
+
def initialize(interface, proxied_class)
|
8
|
+
@implementor = Implementor.find_or_create proxied_class
|
9
|
+
@implementor.interface_names << interface.name
|
7
10
|
proxied_class.instance_methods.select{|m| proxyable_method? m}.each do |method_name|
|
8
|
-
MethodProxy.create
|
11
|
+
MethodProxy.create @implementor, proxied_class, method_name
|
9
12
|
end
|
10
13
|
end
|
11
14
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Contracts
|
3
|
+
class Message
|
4
|
+
attr_reader :method_name
|
5
|
+
attr_accessor :specifications
|
6
|
+
|
7
|
+
def initialize(method_name, specifications = {})
|
8
|
+
@method_name = method_name
|
9
|
+
@specifications = specifications
|
10
|
+
end
|
11
|
+
|
12
|
+
def fully_described_by?(message)
|
13
|
+
return false if message.method_name != method_name
|
14
|
+
@specifications.each do |name, specification|
|
15
|
+
unless specification.fully_described_by? message.specifications[name]
|
16
|
+
return false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_hash
|
23
|
+
{
|
24
|
+
:method_name => method_name,
|
25
|
+
:specifications => specifications.values.map(&:to_hash),
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Contracts
|
3
|
+
class MessageArguments
|
4
|
+
attr_reader :arguments
|
5
|
+
|
6
|
+
def initialize(arguments)
|
7
|
+
@arguments = arguments
|
8
|
+
end
|
9
|
+
|
10
|
+
def fully_described_by?(other)
|
11
|
+
other && (arguments == other.arguments)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_hash
|
15
|
+
{:arguments => arguments}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Contracts
|
3
|
+
class MessageReturn
|
4
|
+
attr_reader :value
|
5
|
+
|
6
|
+
def initialize(value)
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def fully_described_by?(other)
|
11
|
+
other && (value == other.value)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_hash
|
15
|
+
{:value => value}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Contracts
|
3
|
+
class MessageView
|
4
|
+
def initialize(interface_name, message)
|
5
|
+
@interface_name = interface_name
|
6
|
+
@message = message
|
7
|
+
end
|
8
|
+
|
9
|
+
def render
|
10
|
+
arg_string = @message.specifications[:arguments] ? "()" : ""
|
11
|
+
return_string = @message.specifications[:return_value] ? "and return #{@message.specifications[:return_value].value.inspect}" : ""
|
12
|
+
"Interface '#{@interface_name}' must respond to '#{@message.method_name}#{arg_string}' #{return_string}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,3 +1,6 @@
|
|
1
|
+
require "rspec/contracts/message"
|
2
|
+
require "rspec/contracts/message_arguments"
|
3
|
+
|
1
4
|
module RSpec
|
2
5
|
module Contracts
|
3
6
|
class MethodProxy
|
@@ -5,10 +8,16 @@ module RSpec
|
|
5
8
|
new(*args)
|
6
9
|
end
|
7
10
|
|
11
|
+
def add_message(options)
|
12
|
+
message = Message.new(@method_name, options)
|
13
|
+
@implementor.add_message message
|
14
|
+
message
|
15
|
+
end
|
16
|
+
|
8
17
|
private
|
9
18
|
|
10
|
-
def initialize(
|
11
|
-
@
|
19
|
+
def initialize(implementor, proxied_class, method_name)
|
20
|
+
@implementor = implementor
|
12
21
|
@proxied_class = proxied_class
|
13
22
|
@method_name = method_name
|
14
23
|
install
|
@@ -16,8 +25,12 @@ module RSpec
|
|
16
25
|
|
17
26
|
def install
|
18
27
|
original_method = @proxied_class.instance_method @method_name
|
28
|
+
method_proxy = self
|
19
29
|
@proxied_class.send :define_method, @method_name do |*args|
|
20
|
-
|
30
|
+
message = method_proxy.add_message :arguments => MessageArguments.new(args)
|
31
|
+
return_value = original_method.bind(self).call(*args)
|
32
|
+
message.specifications[:return_value] = MessageReturn.new(return_value)
|
33
|
+
return_value
|
21
34
|
end
|
22
35
|
end
|
23
36
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "rspec/mocks"
|
2
|
+
require "rspec/contracts/message"
|
3
|
+
require "rspec/contracts/message_return"
|
4
|
+
|
5
|
+
module RSpec
|
6
|
+
module Contracts
|
7
|
+
class MockProxy < Mocks::Proxy
|
8
|
+
def initialize(object, order_group, interface)
|
9
|
+
super(object, order_group)
|
10
|
+
@method_doubles = Hash.new do |h, k|
|
11
|
+
h[k] = ContractMethodDouble.new(interface, object, k, self)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class ContractMethodDouble < Mocks::MethodDouble
|
17
|
+
attr_reader :message
|
18
|
+
|
19
|
+
def initialize(interface, object, method_name, proxy)
|
20
|
+
@message = Message.new method_name
|
21
|
+
interface.add_message @message
|
22
|
+
super(object, method_name, proxy)
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_simple_stub(method_name, return_value)
|
26
|
+
@message.specifications[:return_value] = MessageReturn.new(return_value)
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
def message_expectation_class
|
31
|
+
ContractMessageExpectation
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class ContractMessageExpectation < Mocks::MessageExpectation
|
36
|
+
def contract_message
|
37
|
+
@method_double.message
|
38
|
+
end
|
39
|
+
|
40
|
+
def with(*args)
|
41
|
+
contract_message.specifications[:arguments] = MessageArguments.new(args)
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
def and_return(*args)
|
46
|
+
contract_message.specifications[:return_value] = MessageReturn.new(args.first)
|
47
|
+
super
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/rspec/contracts.rb
CHANGED
@@ -2,13 +2,15 @@ require "rspec/contracts/core_syntax"
|
|
2
2
|
require "rspec/contracts/mocks_syntax"
|
3
3
|
require "rspec/contracts/fulfillment"
|
4
4
|
require "rspec/contracts/fulfillment_view"
|
5
|
-
require "rspec/contracts/
|
5
|
+
require "rspec/contracts/implementor"
|
6
|
+
require "rspec/contracts/interface"
|
6
7
|
require "rspec/core"
|
7
8
|
|
8
9
|
RSpec.configure do |c|
|
9
10
|
c.after(:suite) do
|
10
|
-
|
11
|
-
|
11
|
+
interfaces = RSpec::Contracts::Interface.all
|
12
|
+
implementors = RSpec::Contracts::Implementor.all
|
13
|
+
fulfillment = RSpec::Contracts::Fulfillment.new interfaces, implementors
|
12
14
|
print "\n" + RSpec::Contracts::FulfillmentView.new(fulfillment).render
|
13
15
|
end
|
14
16
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-contracts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Auton
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -28,28 +28,28 @@ dependencies:
|
|
28
28
|
name: guard-rspec
|
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
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
description:
|
@@ -67,13 +67,18 @@ files:
|
|
67
67
|
- lib/rspec/contracts/double.rb
|
68
68
|
- lib/rspec/contracts/fulfillment.rb
|
69
69
|
- lib/rspec/contracts/fulfillment_view.rb
|
70
|
+
- lib/rspec/contracts/implementor.rb
|
71
|
+
- lib/rspec/contracts/interface.rb
|
72
|
+
- lib/rspec/contracts/interface_fulfillment.rb
|
73
|
+
- lib/rspec/contracts/interface_group.rb
|
70
74
|
- lib/rspec/contracts/interface_proxy.rb
|
75
|
+
- lib/rspec/contracts/message.rb
|
76
|
+
- lib/rspec/contracts/message_arguments.rb
|
77
|
+
- lib/rspec/contracts/message_return.rb
|
78
|
+
- lib/rspec/contracts/message_view.rb
|
71
79
|
- lib/rspec/contracts/method_proxy.rb
|
80
|
+
- lib/rspec/contracts/mock_proxy.rb
|
72
81
|
- lib/rspec/contracts/mocks_syntax.rb
|
73
|
-
- lib/rspec/contracts/proxy.rb
|
74
|
-
- lib/rspec/contracts/requirement.rb
|
75
|
-
- lib/rspec/contracts/requirement_group.rb
|
76
|
-
- lib/rspec/contracts/requirement_view.rb
|
77
82
|
- lib/rspec/contracts/version.rb
|
78
83
|
homepage: http://github.com/brianauton/rspec-contracts
|
79
84
|
licenses:
|
@@ -1,32 +0,0 @@
|
|
1
|
-
require "rspec/mocks/proxy"
|
2
|
-
require "rspec/contracts/requirement"
|
3
|
-
|
4
|
-
module RSpec
|
5
|
-
module Contracts
|
6
|
-
class Proxy < Mocks::Proxy
|
7
|
-
def initialize(object, order_group, interface_name)
|
8
|
-
@interface_name = interface_name
|
9
|
-
super(object, order_group)
|
10
|
-
end
|
11
|
-
|
12
|
-
def add_stub(location, method_name, opts={}, &implementation)
|
13
|
-
create_requirement method_name
|
14
|
-
super
|
15
|
-
end
|
16
|
-
|
17
|
-
def add_simple_stub(method_name, *args)
|
18
|
-
create_requirement method_name, :return_value => args.first
|
19
|
-
super
|
20
|
-
end
|
21
|
-
|
22
|
-
def add_message_expectation(location, method_name, opts={}, &block)
|
23
|
-
create_requirement method_name
|
24
|
-
super
|
25
|
-
end
|
26
|
-
|
27
|
-
def create_requirement(method_name, options = {})
|
28
|
-
Requirement.create @interface_name, method_name, options
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require "rspec/contracts/requirement_group"
|
2
|
-
require "rspec/contracts/requirement_view"
|
3
|
-
|
4
|
-
module RSpec
|
5
|
-
module Contracts
|
6
|
-
class Requirement
|
7
|
-
attr_reader :interface_name, :method_name, :arguments, :return_value
|
8
|
-
|
9
|
-
def initialize(interface_name, method_name, options = {})
|
10
|
-
@interface_name = interface_name
|
11
|
-
@method_name = method_name
|
12
|
-
@arguments = options[:arguments]
|
13
|
-
@return_value = options[:return_value]
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.group
|
17
|
-
@group ||= RequirementGroup.new
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.create(*args)
|
21
|
-
group.add new(*args)
|
22
|
-
end
|
23
|
-
|
24
|
-
def matches?(requirement)
|
25
|
-
[:interface_name, :method_name, :arguments, :return_value].select do |attribute|
|
26
|
-
requirement.send(attribute) != send(attribute)
|
27
|
-
end.empty?
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module RSpec
|
2
|
-
module Contracts
|
3
|
-
class RequirementGroup
|
4
|
-
attr_accessor :requirements
|
5
|
-
|
6
|
-
def initialize
|
7
|
-
@requirements = []
|
8
|
-
end
|
9
|
-
|
10
|
-
def exists?(requirement)
|
11
|
-
@requirements.any?{|r| r.matches? requirement}
|
12
|
-
end
|
13
|
-
|
14
|
-
def add(requirement)
|
15
|
-
requirements << requirement unless exists? requirement
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module RSpec
|
2
|
-
module Contracts
|
3
|
-
class RequirementView
|
4
|
-
def initialize(requirement)
|
5
|
-
@requirement = requirement
|
6
|
-
end
|
7
|
-
|
8
|
-
def render
|
9
|
-
arg_string = @requirement.arguments ? "()" : ""
|
10
|
-
return_string = @requirement.return_value ? "and return #{@requirement.return_value.inspect}" : ""
|
11
|
-
"Interface '#{@requirement.interface_name}' must respond to '#{@requirement.method_name}#{arg_string}' #{return_string}"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|