spicycode-micronaut 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.
- data/LICENSE +20 -0
- data/README +17 -0
- data/Rakefile +55 -0
- data/examples/example_helper.rb +19 -0
- data/examples/lib/micronaut/example_group_example.rb +116 -0
- data/examples/lib/micronaut/example_runner_example.rb +5 -0
- data/examples/lib/micronaut/expectations/differs/default_example.rb +126 -0
- data/examples/lib/micronaut/expectations/extensions/object_example.rb +78 -0
- data/examples/lib/micronaut/expectations/fail_with_example.rb +71 -0
- data/examples/lib/micronaut/expectations/wrap_expectation_example.rb +30 -0
- data/examples/lib/micronaut_example.rb +8 -0
- data/lib/autotest/discover.rb +3 -0
- data/lib/autotest/micronaut.rb +43 -0
- data/lib/micronaut/example_group.rb +100 -0
- data/lib/micronaut/example_runner.rb +108 -0
- data/lib/micronaut/example_world.rb +13 -0
- data/lib/micronaut/exceptions.rb +7 -0
- data/lib/micronaut/expectations/differs/default.rb +67 -0
- data/lib/micronaut/expectations/handler.rb +52 -0
- data/lib/micronaut/expectations/object_extensions.rb +62 -0
- data/lib/micronaut/expectations/string_and_symbol_extensions.rb +17 -0
- data/lib/micronaut/expectations/wrap_expectation.rb +51 -0
- data/lib/micronaut/expectations.rb +57 -0
- data/lib/micronaut/extensions/kernel.rb +15 -0
- data/lib/micronaut/matchers/be.rb +203 -0
- data/lib/micronaut/matchers/be_close.rb +37 -0
- data/lib/micronaut/matchers/change.rb +148 -0
- data/lib/micronaut/matchers/eql.rb +43 -0
- data/lib/micronaut/matchers/equal.rb +43 -0
- data/lib/micronaut/matchers/errors.rb +5 -0
- data/lib/micronaut/matchers/exist.rb +22 -0
- data/lib/micronaut/matchers/generated_descriptions.rb +36 -0
- data/lib/micronaut/matchers/has.rb +34 -0
- data/lib/micronaut/matchers/have.rb +150 -0
- data/lib/micronaut/matchers/include.rb +77 -0
- data/lib/micronaut/matchers/match.rb +41 -0
- data/lib/micronaut/matchers/method_missing.rb +9 -0
- data/lib/micronaut/matchers/operator_matcher.rb +72 -0
- data/lib/micronaut/matchers/raise_error.rb +132 -0
- data/lib/micronaut/matchers/respond_to.rb +46 -0
- data/lib/micronaut/matchers/satisfy.rb +47 -0
- data/lib/micronaut/matchers/simple_matcher.rb +132 -0
- data/lib/micronaut/matchers/throw_symbol.rb +100 -0
- data/lib/micronaut/matchers.rb +141 -0
- data/lib/micronaut/mocking/with_mocha.rb +23 -0
- data/lib/micronaut.rb +42 -0
- metadata +120 -0
@@ -0,0 +1,203 @@
|
|
1
|
+
module Micronaut
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class Be #:nodoc:
|
5
|
+
def initialize(*args)
|
6
|
+
@expected = args.empty? ? true : set_expected(args.shift)
|
7
|
+
@args = args
|
8
|
+
end
|
9
|
+
|
10
|
+
def matches?(actual)
|
11
|
+
@actual = actual
|
12
|
+
handling_predicate? ? run_predicate_on(actual) : match_or_compare(actual)
|
13
|
+
end
|
14
|
+
|
15
|
+
def run_predicate_on(actual)
|
16
|
+
begin
|
17
|
+
return @result = actual.__send__(predicate, *@args)
|
18
|
+
rescue NameError => predicate_missing_error
|
19
|
+
"this needs to be here or rcov will not count this branch even though it's executed in a code example"
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
return @result = actual.__send__(present_tense_predicate, *@args)
|
24
|
+
rescue NameError
|
25
|
+
raise predicate_missing_error
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def failure_message
|
30
|
+
handling_predicate? ?
|
31
|
+
"expected #{predicate}#{args_to_s} to return true, got #{@result.inspect}" :
|
32
|
+
"expected #{@comparison_method} #{expected}, got #{@actual.inspect}".gsub(' ',' ')
|
33
|
+
end
|
34
|
+
|
35
|
+
def negative_failure_message
|
36
|
+
if handling_predicate?
|
37
|
+
"expected #{predicate}#{args_to_s} to return false, got #{@result.inspect}"
|
38
|
+
else
|
39
|
+
message = <<-MESSAGE
|
40
|
+
'should_not be #{@comparison_method} #{expected}' not only FAILED,
|
41
|
+
it reads really poorly.
|
42
|
+
MESSAGE
|
43
|
+
|
44
|
+
raise message << ([:===,:==].include?(@comparison_method) ?
|
45
|
+
"Why don't you try expressing it without the \"be\"?" :
|
46
|
+
"Why don't you try expressing it in the positive?")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def description
|
51
|
+
"#{prefix_to_sentence}#{comparison} #{expected_to_sentence}#{args_to_sentence}".gsub(/\s+/,' ')
|
52
|
+
end
|
53
|
+
|
54
|
+
[:==, :<, :<=, :>=, :>, :===].each do |method|
|
55
|
+
define_method method do |expected|
|
56
|
+
compare_to(expected, :using => method)
|
57
|
+
self
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def match_or_compare(actual)
|
63
|
+
case @expected
|
64
|
+
when TrueClass
|
65
|
+
@actual
|
66
|
+
else
|
67
|
+
@actual.__send__(comparison_method, @expected)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def comparison_method
|
72
|
+
@comparison_method || :equal?
|
73
|
+
end
|
74
|
+
|
75
|
+
def expected
|
76
|
+
@expected
|
77
|
+
end
|
78
|
+
|
79
|
+
def compare_to(expected, opts)
|
80
|
+
@expected, @comparison_method = expected, opts[:using]
|
81
|
+
end
|
82
|
+
|
83
|
+
def set_expected(expected)
|
84
|
+
Symbol === expected ? parse_expected(expected) : expected
|
85
|
+
end
|
86
|
+
|
87
|
+
def parse_expected(expected)
|
88
|
+
["be_an_","be_a_","be_"].each do |prefix|
|
89
|
+
handling_predicate!
|
90
|
+
if expected.starts_with?(prefix)
|
91
|
+
set_prefix(prefix)
|
92
|
+
expected = expected.to_s.sub(prefix,"")
|
93
|
+
[true, false, nil].each do |val|
|
94
|
+
return val if val.to_s == expected
|
95
|
+
end
|
96
|
+
return expected.to_sym
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def set_prefix(prefix)
|
102
|
+
@prefix = prefix
|
103
|
+
end
|
104
|
+
|
105
|
+
def prefix
|
106
|
+
@prefix
|
107
|
+
end
|
108
|
+
|
109
|
+
def handling_predicate!
|
110
|
+
@handling_predicate = true
|
111
|
+
end
|
112
|
+
|
113
|
+
def handling_predicate?
|
114
|
+
return false if [true, false, nil].include?(expected)
|
115
|
+
return @handling_predicate
|
116
|
+
end
|
117
|
+
|
118
|
+
def predicate
|
119
|
+
"#{@expected.to_s}?".to_sym
|
120
|
+
end
|
121
|
+
|
122
|
+
def present_tense_predicate
|
123
|
+
"#{@expected.to_s}s?".to_sym
|
124
|
+
end
|
125
|
+
|
126
|
+
def args_to_s
|
127
|
+
@args.empty? ? "" : parenthesize(inspected_args.join(', '))
|
128
|
+
end
|
129
|
+
|
130
|
+
def parenthesize(string)
|
131
|
+
return "(#{string})"
|
132
|
+
end
|
133
|
+
|
134
|
+
def inspected_args
|
135
|
+
@args.collect{|a| a.inspect}
|
136
|
+
end
|
137
|
+
|
138
|
+
def comparison
|
139
|
+
@comparison_method.nil? ? " " : "be #{@comparison_method.to_s} "
|
140
|
+
end
|
141
|
+
|
142
|
+
def expected_to_sentence
|
143
|
+
split_words(expected)
|
144
|
+
end
|
145
|
+
|
146
|
+
def prefix_to_sentence
|
147
|
+
split_words(prefix)
|
148
|
+
end
|
149
|
+
|
150
|
+
def split_words(sym)
|
151
|
+
sym.to_s.gsub(/_/,' ')
|
152
|
+
end
|
153
|
+
|
154
|
+
def args_to_sentence
|
155
|
+
case @args.length
|
156
|
+
when 0
|
157
|
+
""
|
158
|
+
when 1
|
159
|
+
" #{@args[0]}"
|
160
|
+
else
|
161
|
+
" #{@args[0...-1].join(', ')} and #{@args[-1]}"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
# :call-seq:
|
168
|
+
# should be_true
|
169
|
+
# should be_false
|
170
|
+
# should be_nil
|
171
|
+
# should be_arbitrary_predicate(*args)
|
172
|
+
# should_not be_nil
|
173
|
+
# should_not be_arbitrary_predicate(*args)
|
174
|
+
#
|
175
|
+
# Given true, false, or nil, will pass if actual value is
|
176
|
+
# true, false or nil (respectively). Given no args means
|
177
|
+
# the caller should satisfy an if condition (to be or not to be).
|
178
|
+
#
|
179
|
+
# Predicates are any Ruby method that ends in a "?" and returns true or false.
|
180
|
+
# Given be_ followed by arbitrary_predicate (without the "?"), we will match
|
181
|
+
# convert that into a query against the target object.
|
182
|
+
#
|
183
|
+
# The arbitrary_predicate feature will handle any predicate
|
184
|
+
# prefixed with "be_an_" (e.g. be_an_instance_of), "be_a_" (e.g. be_a_kind_of)
|
185
|
+
# or "be_" (e.g. be_empty), letting you choose the prefix that best suits the predicate.
|
186
|
+
#
|
187
|
+
# == Examples
|
188
|
+
#
|
189
|
+
# target.should be_true
|
190
|
+
# target.should be_false
|
191
|
+
# target.should be_nil
|
192
|
+
# target.should_not be_nil
|
193
|
+
#
|
194
|
+
# collection.should be_empty #passes if target.empty?
|
195
|
+
# "this string".should be_an_intance_of(String)
|
196
|
+
#
|
197
|
+
# target.should_not be_empty #passes unless target.empty?
|
198
|
+
# target.should_not be_old_enough(16) #passes unless target.old_enough?(16)
|
199
|
+
def be(*args)
|
200
|
+
Matchers::Be.new(*args)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Micronaut
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class BeClose #:nodoc:
|
5
|
+
def initialize(expected, delta)
|
6
|
+
@expected = expected
|
7
|
+
@delta = delta
|
8
|
+
end
|
9
|
+
|
10
|
+
def matches?(given)
|
11
|
+
@given = given
|
12
|
+
(@given - @expected).abs < @delta
|
13
|
+
end
|
14
|
+
|
15
|
+
def failure_message
|
16
|
+
"expected #{@expected} +/- (< #{@delta}), got #{@given}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def description
|
20
|
+
"be close to #{@expected} (within +- #{@delta})"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# :call-seq:
|
25
|
+
# should be_close(expected, delta)
|
26
|
+
# should_not be_close(expected, delta)
|
27
|
+
#
|
28
|
+
# Passes if given == expected +/- delta
|
29
|
+
#
|
30
|
+
# == Example
|
31
|
+
#
|
32
|
+
# result.should be_close(3.0, 0.5)
|
33
|
+
def be_close(expected, delta)
|
34
|
+
Matchers::BeClose.new(expected, delta)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
module Micronaut
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
#Based on patch from Wilson Bilkovich
|
5
|
+
class Change #:nodoc:
|
6
|
+
def initialize(receiver=nil, message=nil, &block)
|
7
|
+
@message = message || "result"
|
8
|
+
@value_proc = block || lambda {
|
9
|
+
receiver.__send__(message)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def matches?(event_proc)
|
14
|
+
raise_block_syntax_error if block_given?
|
15
|
+
|
16
|
+
@before = evaluate_value_proc
|
17
|
+
event_proc.call
|
18
|
+
@after = evaluate_value_proc
|
19
|
+
|
20
|
+
return false if @from unless @from == @before
|
21
|
+
return false if @to unless @to == @after
|
22
|
+
return (@before + @amount == @after) if @amount
|
23
|
+
return ((@after - @before) >= @minimum) if @minimum
|
24
|
+
return ((@after - @before) <= @maximum) if @maximum
|
25
|
+
return @before != @after
|
26
|
+
end
|
27
|
+
|
28
|
+
def raise_block_syntax_error
|
29
|
+
raise MatcherError.new(<<-MESSAGE
|
30
|
+
block passed to should or should_not change must use {} instead of do/end
|
31
|
+
MESSAGE
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def evaluate_value_proc
|
36
|
+
@value_proc.call
|
37
|
+
end
|
38
|
+
|
39
|
+
def failure_message
|
40
|
+
if @to
|
41
|
+
"#{@message} should have been changed to #{@to.inspect}, but is now #{@after.inspect}"
|
42
|
+
elsif @from
|
43
|
+
"#{@message} should have initially been #{@from.inspect}, but was #{@before.inspect}"
|
44
|
+
elsif @amount
|
45
|
+
"#{@message} should have been changed by #{@amount.inspect}, but was changed by #{actual_delta.inspect}"
|
46
|
+
elsif @minimum
|
47
|
+
"#{@message} should have been changed by at least #{@minimum.inspect}, but was changed by #{actual_delta.inspect}"
|
48
|
+
elsif @maximum
|
49
|
+
"#{@message} should have been changed by at most #{@maximum.inspect}, but was changed by #{actual_delta.inspect}"
|
50
|
+
else
|
51
|
+
"#{@message} should have changed, but is still #{@before.inspect}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def actual_delta
|
56
|
+
@after - @before
|
57
|
+
end
|
58
|
+
|
59
|
+
def negative_failure_message
|
60
|
+
"#{@message} should not have changed, but did change from #{@before.inspect} to #{@after.inspect}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def by(amount)
|
64
|
+
@amount = amount
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
def by_at_least(minimum)
|
69
|
+
@minimum = minimum
|
70
|
+
self
|
71
|
+
end
|
72
|
+
|
73
|
+
def by_at_most(maximum)
|
74
|
+
@maximum = maximum
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
def to(to)
|
79
|
+
@to = to
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
def from (from)
|
84
|
+
@from = from
|
85
|
+
self
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# :call-seq:
|
90
|
+
# should change(receiver, message, &block)
|
91
|
+
# should change(receiver, message, &block).by(value)
|
92
|
+
# should change(receiver, message, &block).from(old).to(new)
|
93
|
+
# should_not change(receiver, message, &block)
|
94
|
+
#
|
95
|
+
# Allows you to specify that a Proc will cause some value to change.
|
96
|
+
#
|
97
|
+
# == Examples
|
98
|
+
#
|
99
|
+
# lambda {
|
100
|
+
# team.add_player(player)
|
101
|
+
# }.should change(roster, :count)
|
102
|
+
#
|
103
|
+
# lambda {
|
104
|
+
# team.add_player(player)
|
105
|
+
# }.should change(roster, :count).by(1)
|
106
|
+
#
|
107
|
+
# lambda {
|
108
|
+
# team.add_player(player)
|
109
|
+
# }.should change(roster, :count).by_at_least(1)
|
110
|
+
#
|
111
|
+
# lambda {
|
112
|
+
# team.add_player(player)
|
113
|
+
# }.should change(roster, :count).by_at_most(1)
|
114
|
+
#
|
115
|
+
# string = "string"
|
116
|
+
# lambda {
|
117
|
+
# string.reverse!
|
118
|
+
# }.should change { string }.from("string").to("gnirts")
|
119
|
+
#
|
120
|
+
# lambda {
|
121
|
+
# person.happy_birthday
|
122
|
+
# }.should change(person, :birthday).from(32).to(33)
|
123
|
+
#
|
124
|
+
# lambda {
|
125
|
+
# employee.develop_great_new_social_networking_app
|
126
|
+
# }.should change(employee, :title).from("Mail Clerk").to("CEO")
|
127
|
+
#
|
128
|
+
# Evaluates <tt>receiver.message</tt> or <tt>block</tt> before and after
|
129
|
+
# it evaluates the c object (generated by the lambdas in the examples
|
130
|
+
# above).
|
131
|
+
#
|
132
|
+
# Then compares the values before and after the <tt>receiver.message</tt>
|
133
|
+
# and evaluates the difference compared to the expected difference.
|
134
|
+
#
|
135
|
+
# == WARNING
|
136
|
+
# <tt>should_not change</tt> only supports the form with no
|
137
|
+
# subsequent calls to <tt>by</tt>, <tt>by_at_least</tt>,
|
138
|
+
# <tt>by_at_most</tt>, <tt>to</tt> or <tt>from</tt>.
|
139
|
+
#
|
140
|
+
# blocks passed to <tt>should</tt> <tt>change</tt> and <tt>should_not</tt>
|
141
|
+
# <tt>change</tt> must use the <tt>{}</tt> form (<tt>do/end</tt> is not
|
142
|
+
# supported).
|
143
|
+
#
|
144
|
+
def change(receiver=nil, message=nil, &block)
|
145
|
+
Matchers::Change.new(receiver, message, &block)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Micronaut
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class Eql #:nodoc:
|
5
|
+
def initialize(expected)
|
6
|
+
@expected = expected
|
7
|
+
end
|
8
|
+
|
9
|
+
def matches?(given)
|
10
|
+
@given = given
|
11
|
+
@given.eql?(@expected)
|
12
|
+
end
|
13
|
+
|
14
|
+
def failure_message
|
15
|
+
return "expected #{@expected.inspect}, got #{@given.inspect} (using .eql?)", @expected, @given
|
16
|
+
end
|
17
|
+
|
18
|
+
def negative_failure_message
|
19
|
+
return "expected #{@given.inspect} not to equal #{@expected.inspect} (using .eql?)", @expected, @given
|
20
|
+
end
|
21
|
+
|
22
|
+
def description
|
23
|
+
"eql #{@expected.inspect}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# :call-seq:
|
28
|
+
# should eql(expected)
|
29
|
+
# should_not eql(expected)
|
30
|
+
#
|
31
|
+
# Passes if given and expected are of equal value, but not necessarily the same object.
|
32
|
+
#
|
33
|
+
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more information about equality in Ruby.
|
34
|
+
#
|
35
|
+
# == Examples
|
36
|
+
#
|
37
|
+
# 5.should eql(5)
|
38
|
+
# 5.should_not eql(3)
|
39
|
+
def eql(expected)
|
40
|
+
Matchers::Eql.new(expected)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Micronaut
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class Equal #:nodoc:
|
5
|
+
def initialize(expected)
|
6
|
+
@expected = expected
|
7
|
+
end
|
8
|
+
|
9
|
+
def matches?(given)
|
10
|
+
@given = given
|
11
|
+
@given.equal?(@expected)
|
12
|
+
end
|
13
|
+
|
14
|
+
def failure_message
|
15
|
+
return "expected #{@expected.inspect}, got #{@given.inspect} (using .equal?)", @expected, @given
|
16
|
+
end
|
17
|
+
|
18
|
+
def negative_failure_message
|
19
|
+
return "expected #{@given.inspect} not to equal #{@expected.inspect} (using .equal?)", @expected, @given
|
20
|
+
end
|
21
|
+
|
22
|
+
def description
|
23
|
+
"equal #{@expected.inspect}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# :call-seq:
|
28
|
+
# should equal(expected)
|
29
|
+
# should_not equal(expected)
|
30
|
+
#
|
31
|
+
# Passes if given and expected are the same object (object identity).
|
32
|
+
#
|
33
|
+
# See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more information about equality in Ruby.
|
34
|
+
#
|
35
|
+
# == Examples
|
36
|
+
#
|
37
|
+
# 5.should equal(5) #Fixnums are equal
|
38
|
+
# "5".should_not equal("5") #Strings that look the same are not the same object
|
39
|
+
def equal(expected)
|
40
|
+
Matchers::Equal.new(expected)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Micronaut
|
2
|
+
module Matchers
|
3
|
+
class Exist
|
4
|
+
def matches?(given)
|
5
|
+
@given = given
|
6
|
+
@given.exist?
|
7
|
+
end
|
8
|
+
def failure_message
|
9
|
+
"expected #{@given.inspect} to exist, but it doesn't."
|
10
|
+
end
|
11
|
+
def negative_failure_message
|
12
|
+
"expected #{@given.inspect} to not exist, but it does."
|
13
|
+
end
|
14
|
+
end
|
15
|
+
# :call-seq:
|
16
|
+
# should exist
|
17
|
+
# should_not exist
|
18
|
+
#
|
19
|
+
# Passes if given.exist?
|
20
|
+
def exist; Exist.new; end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Micronaut
|
2
|
+
module Matchers
|
3
|
+
class << self
|
4
|
+
attr_accessor :last_matcher, :last_should
|
5
|
+
|
6
|
+
def clear_generated_description
|
7
|
+
self.last_matcher = nil
|
8
|
+
self.last_should = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def generated_description
|
12
|
+
return nil if last_should.nil?
|
13
|
+
"#{last_should} #{last_description}"
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def last_description
|
19
|
+
last_matcher.respond_to?(:description) ? last_matcher.description : <<-MESSAGE
|
20
|
+
When you call a matcher in an example without a String, like this:
|
21
|
+
|
22
|
+
specify { object.should matcher }
|
23
|
+
|
24
|
+
or this:
|
25
|
+
|
26
|
+
it { should matcher }
|
27
|
+
|
28
|
+
the runner expects the matcher to have a #describe method. You should either
|
29
|
+
add a String to the example this matcher is being used in, or give it a
|
30
|
+
description method. Then you won't have to suffer this lengthy warning again.
|
31
|
+
MESSAGE
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Micronaut
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class Has #:nodoc:
|
5
|
+
def initialize(sym, *args)
|
6
|
+
@sym = sym
|
7
|
+
@args = args
|
8
|
+
end
|
9
|
+
|
10
|
+
def matches?(given)
|
11
|
+
given.__send__(predicate, *@args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def failure_message
|
15
|
+
"expected ##{predicate}(#{@args[0].inspect}) to return true, got false"
|
16
|
+
end
|
17
|
+
|
18
|
+
def negative_failure_message
|
19
|
+
"expected ##{predicate}(#{@args[0].inspect}) to return false, got true"
|
20
|
+
end
|
21
|
+
|
22
|
+
def description
|
23
|
+
"have key #{@args[0].inspect}"
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def predicate
|
28
|
+
"#{@sym.to_s.sub("have_","has_")}?".to_sym
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|