lawyer 0.0.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 +7 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +141 -0
- data/Rakefile +8 -0
- data/lawyer.gemspec +23 -0
- data/lib/lawyer/broken_contract.rb +38 -0
- data/lib/lawyer/clause.rb +72 -0
- data/lib/lawyer/contract.rb +28 -0
- data/lib/lawyer/method_missing_violation.rb +11 -0
- data/lib/lawyer/rspec/contract_double.rb +13 -0
- data/lib/lawyer/rspec/matchers.rb +25 -0
- data/lib/lawyer/rspec.rb +2 -0
- data/lib/lawyer/version.rb +3 -0
- data/lib/lawyer/wrong_arity_violation.rb +13 -0
- data/lib/lawyer/wrong_signature_violation.rb +16 -0
- data/lib/lawyer.rb +8 -0
- data/lib/monkey_patch/module.rb +5 -0
- data/spec/lib/lawyer/contract_spec.rb +73 -0
- data/spec/lib/lawyer/rspec/contract_double_spec.rb +15 -0
- data/spec/lib/lawyer/rspec/matchers_spec.rb +28 -0
- data/spec/module_spec.rb +11 -0
- data/spec/spec_helper.rb +9 -0
- metadata +115 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e99be433808f11cb424f36b57b3ac474f2cd810e
|
4
|
+
data.tar.gz: 9eeebb6c71f45d45e054aa3a66a310409de86587
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6c2f4dd3603a8dd235adfd3efb6c7ad08a075f2410cb7b835e7c9b78a876e0194ed00c9bb2c6c9359b64d3fbc1764d982bc1e962c081a852d08452b93630f4df
|
7
|
+
data.tar.gz: 681467aa0759581e4410d1524ce7c67e6c0fc1148cb736417d057478d2b28910dbc7a50c850e6caa9bbf8efcfb881267724361aabf23369286494a660d5d107f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 John Cinnamond
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
# Lawyer
|
2
|
+
|
3
|
+
Strong Duck Typing for Ruby.
|
4
|
+
|
5
|
+
Lawyer allows you to create contracts that specify how an object behaves.
|
6
|
+
|
7
|
+
require 'lawyer'
|
8
|
+
|
9
|
+
class Pingable < Lawyer::Contract
|
10
|
+
confirm :ping
|
11
|
+
end
|
12
|
+
|
13
|
+
You can then ensure that your class implements the contract:
|
14
|
+
|
15
|
+
require 'pingable'
|
16
|
+
|
17
|
+
class Foo
|
18
|
+
def ping
|
19
|
+
puts "ping"
|
20
|
+
end
|
21
|
+
|
22
|
+
def pong
|
23
|
+
puts "pong"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Foo.implements(Pingable)
|
28
|
+
|
29
|
+
...but this works best when you write loosely coupled objects and then define the
|
30
|
+
interfaces between them. You can then write specs to check that a class implements
|
31
|
+
a particular contract:
|
32
|
+
|
33
|
+
require 'foo'
|
34
|
+
require 'pingable'
|
35
|
+
|
36
|
+
describe Foo do
|
37
|
+
it { should implement(Pingable) }
|
38
|
+
end
|
39
|
+
|
40
|
+
...and use mocks to test methods that expect to receive objects that conform to
|
41
|
+
a particular contract:
|
42
|
+
|
43
|
+
describe Pinger do
|
44
|
+
let(:pingable) { contract_double(Pingable) }
|
45
|
+
subject(:pinger) { Pinger.new(pingable) }
|
46
|
+
|
47
|
+
it "pings the pingable" do
|
48
|
+
subject.run
|
49
|
+
expect(:pingable).to have_received(:ping)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "can't call methods that aren't part of the contract" do
|
53
|
+
expect { pingable.pong }.to raise_error(NoMethodError)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
...all based off a single definition of the contract.
|
58
|
+
|
59
|
+
This helps you to write loosely coupled code that relies on well defined interfaces.
|
60
|
+
By declaring the contract up front and then using that in your tests you can ensure
|
61
|
+
that any mismatches between the expected interface and the actual impelmentations are
|
62
|
+
caught as you modify your codebase.
|
63
|
+
|
64
|
+
## Installation
|
65
|
+
|
66
|
+
Add this line to your application's Gemfile:
|
67
|
+
|
68
|
+
gem 'lawyer'
|
69
|
+
|
70
|
+
And then execute:
|
71
|
+
|
72
|
+
$ bundle
|
73
|
+
|
74
|
+
Or install it yourself as:
|
75
|
+
|
76
|
+
$ gem install laywer
|
77
|
+
|
78
|
+
## Usage
|
79
|
+
|
80
|
+
First up, create a contract that specifies the methods available in an interface:
|
81
|
+
|
82
|
+
require 'lawyer'
|
83
|
+
|
84
|
+
module Contracts
|
85
|
+
class Person < Lawyer::Contract
|
86
|
+
check :name # check that the method exists
|
87
|
+
check :name= => 1 # check the method arity
|
88
|
+
check :rename => [:firstname, :lastname] # check required named parameters (ruby 2.1 only)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
Add Laywer to your spec_helper:
|
94
|
+
|
95
|
+
require 'lawyer/rspec'
|
96
|
+
|
97
|
+
RSpec.configure do |config|
|
98
|
+
config.include Lawyer::RSpec::Matchers
|
99
|
+
config.include Lawyer::RSpec::ContractDouble
|
100
|
+
|
101
|
+
# ...
|
102
|
+
end
|
103
|
+
|
104
|
+
Test an implementation:
|
105
|
+
|
106
|
+
require 'contracts/person'
|
107
|
+
require 'person_record'
|
108
|
+
|
109
|
+
describe PersonRecord do
|
110
|
+
it { should implement(Contracts::Person) }
|
111
|
+
|
112
|
+
# test the implementation
|
113
|
+
end
|
114
|
+
|
115
|
+
And test a receiver:
|
116
|
+
|
117
|
+
require 'contracts/person'
|
118
|
+
require 'namer'
|
119
|
+
|
120
|
+
describe Namer do
|
121
|
+
let(:person) { contract_double(Contracts::Person) }
|
122
|
+
subject(:namer) { Namer.new(person) }
|
123
|
+
|
124
|
+
it "sets the name" do
|
125
|
+
expect(person).to receive(:name=).with("John Smith")
|
126
|
+
namer.set_name("John Smith")
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
## Credits
|
131
|
+
|
132
|
+
Many thanks to Jakub Oboza (http://lambdacu.be) for suggesting an original
|
133
|
+
implementation of this idea and for discussing the motivations behind it.
|
134
|
+
|
135
|
+
## Contributing
|
136
|
+
|
137
|
+
1. Fork it ( http://github.com/jcinnamond/lawyer/fork )
|
138
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
139
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
140
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
141
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lawyer.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'lawyer/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "lawyer"
|
8
|
+
spec.version = Lawyer::VERSION
|
9
|
+
spec.authors = ["John Cinnamond"]
|
10
|
+
spec.email = ["jc@panagile.com"]
|
11
|
+
spec.summary = %q{Strong Duck Typing for Ruby}
|
12
|
+
spec.homepage = "http://github.com/jcinnamond/lawyer"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(spec)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "rspec", "~> 2.14.1"
|
23
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Lawyer
|
2
|
+
class BrokenContract < StandardError
|
3
|
+
def initialize(subject, contract, violations)
|
4
|
+
@subject = subject.name
|
5
|
+
@contract = contract.name
|
6
|
+
@method_missing_violations = violations.select { |v| v.is_a?(MethodMissingViolation) }
|
7
|
+
@wrong_arity_violations = violations.select { |v| v.is_a?(WrongArityViolation) }
|
8
|
+
@wrong_signature_violations = violations.select { |v| v.is_a?(WrongSignatureViolation) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
str = "#{@subject} does not implement <#{@contract}>\n"
|
13
|
+
str << explain_violations(@method_missing_violations, "missing")
|
14
|
+
str << "\n" if @method_missing_violations &&
|
15
|
+
(@wrong_arity_violations || @wrong_signature_violations)
|
16
|
+
str << explain_violations(@wrong_arity_violations, "with the wrong arity")
|
17
|
+
str << "\n" if (@method_missing_violations || @wrong_arity_violations) &&
|
18
|
+
@wrong_signature_violations
|
19
|
+
str << explain_violations(@wrong_signature_violations, "with the wrong signature")
|
20
|
+
str
|
21
|
+
end
|
22
|
+
|
23
|
+
def explain_violations(violations, type)
|
24
|
+
str = ""
|
25
|
+
if violations.any?
|
26
|
+
count = violations.count
|
27
|
+
str << "\t(#{count} #{methods(count)} #{type})\n"
|
28
|
+
str << violations.map(&:to_s).join("\n")
|
29
|
+
str << "\n"
|
30
|
+
end
|
31
|
+
str
|
32
|
+
end
|
33
|
+
|
34
|
+
def methods(count)
|
35
|
+
count == 1 ? "method" : "methods"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'lawyer/method_missing_violation'
|
2
|
+
require 'lawyer/wrong_arity_violation'
|
3
|
+
require 'lawyer/wrong_signature_violation'
|
4
|
+
|
5
|
+
module Lawyer
|
6
|
+
class Clause
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
def initialize(params)
|
10
|
+
@arity = nil
|
11
|
+
@signature = nil
|
12
|
+
|
13
|
+
if params.is_a?(Hash)
|
14
|
+
(@name, details) = params.first
|
15
|
+
case details
|
16
|
+
when Fixnum
|
17
|
+
@arity = details
|
18
|
+
when Array
|
19
|
+
@signature = details
|
20
|
+
end
|
21
|
+
else
|
22
|
+
@name = params.to_sym
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def check(subject)
|
27
|
+
if missing_method?(subject)
|
28
|
+
Lawyer::MethodMissingViolation.new(@name)
|
29
|
+
elsif wrong_arity?(subject)
|
30
|
+
Lawyer::WrongArityViolation.new(@name, expected: @arity, actual: actual_arity(subject))
|
31
|
+
elsif wrong_signature?(subject)
|
32
|
+
Lawyer::WrongSignatureViolation.new(@name,
|
33
|
+
missing: missing_parameters(subject),
|
34
|
+
extra: extra_parameters(subject))
|
35
|
+
else
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def missing_method?(subject)
|
41
|
+
!subject.instance_methods.include?(@name)
|
42
|
+
end
|
43
|
+
|
44
|
+
def wrong_arity?(subject)
|
45
|
+
@arity && @arity != actual_arity(subject)
|
46
|
+
end
|
47
|
+
|
48
|
+
def actual_arity(subject)
|
49
|
+
method_from(subject).arity
|
50
|
+
end
|
51
|
+
|
52
|
+
def wrong_signature?(subject)
|
53
|
+
@signature && (missing_parameters(subject).any? || extra_parameters(subject).any?)
|
54
|
+
end
|
55
|
+
|
56
|
+
def missing_parameters(subject)
|
57
|
+
@signature - actual_signature(subject)
|
58
|
+
end
|
59
|
+
|
60
|
+
def extra_parameters(subject)
|
61
|
+
actual_signature(subject) - @signature
|
62
|
+
end
|
63
|
+
|
64
|
+
def actual_signature(subject)
|
65
|
+
method_from(subject).parameters.select { |p| p[0] == :keyreq }.map(&:last) || []
|
66
|
+
end
|
67
|
+
|
68
|
+
def method_from(subject)
|
69
|
+
subject.instance_method(@name)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'lawyer/clause'
|
2
|
+
|
3
|
+
module Lawyer
|
4
|
+
class Contract
|
5
|
+
class << self
|
6
|
+
def clauses
|
7
|
+
@clauses ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
def confirm(clause)
|
11
|
+
self.clauses << Lawyer::Clause.new(clause)
|
12
|
+
end
|
13
|
+
|
14
|
+
def check!(subject)
|
15
|
+
klass = subject.is_a?(Class) ? subject : subject.class
|
16
|
+
|
17
|
+
violations = self.clauses.map do |clause|
|
18
|
+
clause.check(klass)
|
19
|
+
end
|
20
|
+
violations.compact!
|
21
|
+
|
22
|
+
if violations.any?
|
23
|
+
raise Lawyer::BrokenContract.new(klass, self, violations)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rspec/expectations'
|
2
|
+
|
3
|
+
module Lawyer
|
4
|
+
module RSpec
|
5
|
+
module Matchers
|
6
|
+
extend ::RSpec::Matchers::DSL
|
7
|
+
|
8
|
+
matcher :implement do |contract|
|
9
|
+
match do |implementation|
|
10
|
+
begin
|
11
|
+
contract.check!(implementation)
|
12
|
+
true
|
13
|
+
rescue Lawyer::BrokenContract => e
|
14
|
+
@exception = e
|
15
|
+
false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
failure_message_for_should do |actual|
|
20
|
+
@expectation.to_s
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/lawyer/rspec.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Lawyer
|
2
|
+
class WrongSignatureViolation
|
3
|
+
def initialize(name, missing:, extra:)
|
4
|
+
@name = name
|
5
|
+
@missing = missing
|
6
|
+
@extra = extra
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
details = []
|
11
|
+
details << "missing #{@missing}" if @missing.any?
|
12
|
+
details << "extra #{@extra}" if @extra.any?
|
13
|
+
"\t[wrong signature] #{@name} (#{details.join(', ')})"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/lawyer.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
class TestContract < Lawyer::Contract
|
2
|
+
confirm :ping
|
3
|
+
confirm :pong => 2
|
4
|
+
confirm :pung => [:name, :size]
|
5
|
+
end
|
6
|
+
|
7
|
+
describe TestContract do
|
8
|
+
before :each do
|
9
|
+
# Stop modifications to the TestObject from leaking into other specs.
|
10
|
+
Object.send(:remove_const, :TestObject) if Object.const_defined?(:TestObject)
|
11
|
+
class TestObject;
|
12
|
+
def pong(a1); end
|
13
|
+
def pung(name:, hats:); end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#check!" do
|
18
|
+
context "with a compliant object" do
|
19
|
+
before :each do
|
20
|
+
# Reopen the class and define the required methods
|
21
|
+
class TestObject;
|
22
|
+
def ping; end
|
23
|
+
def pong(a1, a2); end
|
24
|
+
def pung(name:, size:); end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "does not raise an exception when checking a class" do
|
29
|
+
expect { TestContract.check!(TestObject) }.not_to raise_error
|
30
|
+
end
|
31
|
+
|
32
|
+
it "does not raise an exception when checking an object" do
|
33
|
+
expect { TestContract.check!(TestObject.new) }.not_to raise_error
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "with a non-compliant object" do
|
38
|
+
it "raises a BrokenContract exception when checking a class" do
|
39
|
+
expect { TestContract.check!(TestObject) }.to raise_error(Lawyer::BrokenContract)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "raises a BrokenContract exception when checking an object" do
|
43
|
+
expect { TestContract.check!(TestObject.new) }.to raise_error(Lawyer::BrokenContract)
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "the exception" do
|
47
|
+
before :each do
|
48
|
+
begin
|
49
|
+
TestContract.check!(TestObject)
|
50
|
+
rescue Lawyer::BrokenContract => e
|
51
|
+
@exception = e
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "includes the offending class and contract" do
|
56
|
+
expect(@exception.to_s).to include("TestObject does not implement <TestContract>\n")
|
57
|
+
end
|
58
|
+
|
59
|
+
it "includes the missing method details in the exception" do
|
60
|
+
expect(@exception.to_s).to include("\t(1 method missing)\n\t[missing] ping\n")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "includes the incorrect arity details in the exception" do
|
64
|
+
expect(@exception.to_s).to include("\t(1 method with the wrong arity)\n\t[wrong arity] pong (takes 1, requires 2)\n")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "includes required argument mismatch details in the exception" do
|
68
|
+
expect(@exception.to_s).to include("\t(1 method with the wrong signature)\n\t[wrong signature] pung (missing [:size], extra [:hats])\n")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'lawyer/rspec'
|
2
|
+
|
3
|
+
class DoublableContract < Lawyer::Contract
|
4
|
+
confirm :ping
|
5
|
+
end
|
6
|
+
|
7
|
+
describe Lawyer::RSpec::ContractDouble do
|
8
|
+
include Lawyer::RSpec::ContractDouble
|
9
|
+
|
10
|
+
subject { contract_double(DoublableContract) }
|
11
|
+
|
12
|
+
it { should be_a(RSpec::Mocks::Mock) }
|
13
|
+
it { should respond_to(:ping) }
|
14
|
+
it { should_not respond_to(:pong) }
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'lawyer/rspec'
|
2
|
+
|
3
|
+
describe Lawyer::RSpec::Matchers do
|
4
|
+
include Lawyer::RSpec::Matchers
|
5
|
+
let(:subject) { double("Module", name: "Module") }
|
6
|
+
let(:contract) { double("contract", check!: true, name: "Contract") }
|
7
|
+
|
8
|
+
it "defines 'implement'" do
|
9
|
+
expect(subject).to implement(contract)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "calls checks the subject against the contract" do
|
13
|
+
expect(contract).to receive(:check!).with(subject)
|
14
|
+
expect(subject).to implement(contract)
|
15
|
+
end
|
16
|
+
|
17
|
+
context "with violations" do
|
18
|
+
let(:broken_contract) { Lawyer::BrokenContract.new(subject, contract, []) }
|
19
|
+
|
20
|
+
before :each do
|
21
|
+
allow(contract).to receive(:check!).and_raise(broken_contract)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "fails the matcher" do
|
25
|
+
expect(subject).not_to implement(contract)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/spec/module_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lawyer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Cinnamond
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.14.1
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.14.1
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- jc@panagile.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- lawyer.gemspec
|
69
|
+
- lib/lawyer.rb
|
70
|
+
- lib/lawyer/broken_contract.rb
|
71
|
+
- lib/lawyer/clause.rb
|
72
|
+
- lib/lawyer/contract.rb
|
73
|
+
- lib/lawyer/method_missing_violation.rb
|
74
|
+
- lib/lawyer/rspec.rb
|
75
|
+
- lib/lawyer/rspec/contract_double.rb
|
76
|
+
- lib/lawyer/rspec/matchers.rb
|
77
|
+
- lib/lawyer/version.rb
|
78
|
+
- lib/lawyer/wrong_arity_violation.rb
|
79
|
+
- lib/lawyer/wrong_signature_violation.rb
|
80
|
+
- lib/monkey_patch/module.rb
|
81
|
+
- spec/lib/lawyer/contract_spec.rb
|
82
|
+
- spec/lib/lawyer/rspec/contract_double_spec.rb
|
83
|
+
- spec/lib/lawyer/rspec/matchers_spec.rb
|
84
|
+
- spec/module_spec.rb
|
85
|
+
- spec/spec_helper.rb
|
86
|
+
homepage: http://github.com/jcinnamond/lawyer
|
87
|
+
licenses:
|
88
|
+
- MIT
|
89
|
+
metadata: {}
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
requirements: []
|
105
|
+
rubyforge_project:
|
106
|
+
rubygems_version: 2.2.0
|
107
|
+
signing_key:
|
108
|
+
specification_version: 4
|
109
|
+
summary: Strong Duck Typing for Ruby
|
110
|
+
test_files:
|
111
|
+
- spec/lib/lawyer/contract_spec.rb
|
112
|
+
- spec/lib/lawyer/rspec/contract_double_spec.rb
|
113
|
+
- spec/lib/lawyer/rspec/matchers_spec.rb
|
114
|
+
- spec/module_spec.rb
|
115
|
+
- spec/spec_helper.rb
|