ward 0.1.0
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/.document +5 -0
- data/.gitignore +28 -0
- data/LICENSE +19 -0
- data/README.markdown +99 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/features/acceptance_matcher.feature +78 -0
- data/features/attribute_keyword.feature +13 -0
- data/features/close_to_matcher.feature +130 -0
- data/features/context_arguments.feature +47 -0
- data/features/equal_to_matcher.feature +25 -0
- data/features/error_messages.feature +69 -0
- data/features/external_validation.feature +15 -0
- data/features/has_matcher.feature +72 -0
- data/features/has_matcher_initialized_with_expectation.feature +94 -0
- data/features/has_matcher_relativities.feature +171 -0
- data/features/include_matcher.feature +28 -0
- data/features/is_keyword.feature +42 -0
- data/features/is_not_keyword.feature +62 -0
- data/features/match_matcher.feature +49 -0
- data/features/multiple_validators.feature +29 -0
- data/features/nil_matcher.feature +25 -0
- data/features/predicate_matcher.feature +23 -0
- data/features/present_matcher.feature +59 -0
- data/features/satisfy_matcher.feature +80 -0
- data/features/scenario_validation.feature +81 -0
- data/features/step_definitions/external_validation_steps.rb +69 -0
- data/features/step_definitions/generic_validation_steps.rb +33 -0
- data/features/step_definitions/object_definition_steps.rb +43 -0
- data/features/support/env.rb +12 -0
- data/features/support/object_builder.rb +33 -0
- data/features/support/struct.rb +38 -0
- data/lang/en.yml +56 -0
- data/lib/ward.rb +26 -0
- data/lib/ward/context.rb +70 -0
- data/lib/ward/context_chain.rb +87 -0
- data/lib/ward/dsl.rb +7 -0
- data/lib/ward/dsl/validation_block.rb +73 -0
- data/lib/ward/dsl/validation_builder.rb +190 -0
- data/lib/ward/errors.rb +213 -0
- data/lib/ward/matchers.rb +97 -0
- data/lib/ward/matchers/acceptance.rb +43 -0
- data/lib/ward/matchers/close_to.rb +60 -0
- data/lib/ward/matchers/equal_to.rb +33 -0
- data/lib/ward/matchers/has.rb +283 -0
- data/lib/ward/matchers/include.rb +54 -0
- data/lib/ward/matchers/match.rb +29 -0
- data/lib/ward/matchers/matcher.rb +68 -0
- data/lib/ward/matchers/nil.rb +30 -0
- data/lib/ward/matchers/predicate.rb +31 -0
- data/lib/ward/matchers/present.rb +56 -0
- data/lib/ward/matchers/satisfy.rb +65 -0
- data/lib/ward/spec.rb +17 -0
- data/lib/ward/spec/matcher_matcher.rb +114 -0
- data/lib/ward/support.rb +7 -0
- data/lib/ward/support/basic_object.rb +55 -0
- data/lib/ward/support/result.rb +49 -0
- data/lib/ward/validator.rb +147 -0
- data/lib/ward/validator_set.rb +115 -0
- data/lib/ward/version.rb +3 -0
- data/spec/lib/has_matcher_relativity_examples.rb +15 -0
- data/spec/lib/have_public_method_defined.rb +22 -0
- data/spec/rcov.opts +8 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/ward/context_chain_spec.rb +178 -0
- data/spec/ward/context_spec.rb +57 -0
- data/spec/ward/dsl/validation_block_spec.rb +27 -0
- data/spec/ward/dsl/validation_builder_spec.rb +212 -0
- data/spec/ward/errors_spec.rb +149 -0
- data/spec/ward/matchers/acceptance_spec.rb +16 -0
- data/spec/ward/matchers/close_to_spec.rb +57 -0
- data/spec/ward/matchers/equal_to_spec.rb +16 -0
- data/spec/ward/matchers/has_spec.rb +175 -0
- data/spec/ward/matchers/include_spec.rb +41 -0
- data/spec/ward/matchers/match_spec.rb +21 -0
- data/spec/ward/matchers/matcher_spec.rb +54 -0
- data/spec/ward/matchers/nil_spec.rb +16 -0
- data/spec/ward/matchers/predicate_spec.rb +19 -0
- data/spec/ward/matchers/present_spec.rb +16 -0
- data/spec/ward/matchers/satisfy_spec.rb +68 -0
- data/spec/ward/matchers_spec.rb +51 -0
- data/spec/ward/spec/have_public_method_defined_spec.rb +31 -0
- data/spec/ward/spec/matcher_matcher_spec.rb +217 -0
- data/spec/ward/validator_set_spec.rb +178 -0
- data/spec/ward/validator_spec.rb +264 -0
- data/tasks/features.rake +15 -0
- data/tasks/rcov.rake +24 -0
- data/tasks/spec.rake +18 -0
- data/tasks/yard.rake +9 -0
- data/ward.gemspec +176 -0
- metadata +239 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'ward/matchers/matcher'
|
2
|
+
require 'ward/matchers/acceptance'
|
3
|
+
require 'ward/matchers/close_to'
|
4
|
+
require 'ward/matchers/equal_to'
|
5
|
+
require 'ward/matchers/has'
|
6
|
+
require 'ward/matchers/include'
|
7
|
+
require 'ward/matchers/match'
|
8
|
+
require 'ward/matchers/nil'
|
9
|
+
require 'ward/matchers/predicate'
|
10
|
+
require 'ward/matchers/present'
|
11
|
+
require 'ward/matchers/satisfy'
|
12
|
+
|
13
|
+
module Ward
|
14
|
+
# Matchers are used to determine whether a particular value is valid.
|
15
|
+
#
|
16
|
+
# Any class instance can be a validator so long as it responds to #matches?;
|
17
|
+
# the #matches? method should take at least one argument which will be the
|
18
|
+
# value of the object being validated. The matcher should then return a
|
19
|
+
# true-like value if the match is successful or either nil, false, or an
|
20
|
+
# array whose first member is false, if the match was not successful.
|
21
|
+
#
|
22
|
+
# In the event that your matcher returns an array, the second member will be
|
23
|
+
# used as the error message.
|
24
|
+
#
|
25
|
+
module Matchers
|
26
|
+
|
27
|
+
# Registers a matcher and it's slug.
|
28
|
+
#
|
29
|
+
# A matcher can be registered with as many slugs as desired.
|
30
|
+
#
|
31
|
+
# @param [Symbol, #to_sym] slug
|
32
|
+
# A slug which will be used by the DSL in order to assign a context to
|
33
|
+
# a matcher.
|
34
|
+
# @param [Ward::Matchers::Matcher] matcher
|
35
|
+
# The matcher to be registered.
|
36
|
+
#
|
37
|
+
# @example Registering the Acceptance handler to be used with :accepted
|
38
|
+
#
|
39
|
+
# Matchers.register(:accepted, Matchers::Acceptance)
|
40
|
+
#
|
41
|
+
# # The Acceptance matcher can now be used like so...
|
42
|
+
#
|
43
|
+
# validate do |form|
|
44
|
+
# form.acceptable_use_policy.is.accepted
|
45
|
+
# form.acceptable_use_policy.is_not.accepted
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# @example Registering the Has matcher twice.
|
49
|
+
#
|
50
|
+
# Matchers.register(:has, Matchers::Acceptance)
|
51
|
+
#
|
52
|
+
# validate do |post|
|
53
|
+
# post.has(1).author
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# # This provides access to the Has matcher, but "does_not.has" doesn't
|
57
|
+
# # make much sense. So, we register the Has matcher a second time with
|
58
|
+
# # a slug which make sense when used in the negative.
|
59
|
+
#
|
60
|
+
# Matchers.register(:have, Matchers::Acceptance)
|
61
|
+
#
|
62
|
+
# validate do |post|
|
63
|
+
# form.does_not.have(1).author
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# # Much better.
|
67
|
+
#
|
68
|
+
def self.register(slug, matcher)
|
69
|
+
matchers[slug.to_sym] = matcher
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns the registered matchers.
|
73
|
+
#
|
74
|
+
# @return [Hash{Symbol => Ward::Matchers::Matcher}]
|
75
|
+
#
|
76
|
+
def self.matchers
|
77
|
+
@matchers ||= {}
|
78
|
+
end
|
79
|
+
|
80
|
+
# Register the built-in matchers.
|
81
|
+
|
82
|
+
register :accepted, Acceptance
|
83
|
+
register :close_to, CloseTo
|
84
|
+
register :equal_to, EqualTo
|
85
|
+
register :has, Has
|
86
|
+
register :have, Has
|
87
|
+
register :included_in, Include
|
88
|
+
register :matches, Match
|
89
|
+
register :match, Match
|
90
|
+
register :nil, Nil
|
91
|
+
register :one_of, Include
|
92
|
+
register :present, Present
|
93
|
+
register :satisfies, Satisfy
|
94
|
+
register :satisfy, Satisfy
|
95
|
+
|
96
|
+
end # Matchers
|
97
|
+
end # Ward
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Ward
|
2
|
+
module Matchers
|
3
|
+
# Tests whether the validation value is accepted.
|
4
|
+
#
|
5
|
+
# An "accepted" value one which is exactly true, "t", "true", "1", "y",
|
6
|
+
# or "yes".
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# class Person
|
11
|
+
# validate do |person|
|
12
|
+
# person.name.is.accepted
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
class Acceptance < Matcher
|
17
|
+
|
18
|
+
# Creates a new matcher instance.
|
19
|
+
#
|
20
|
+
# @param [Object] expected
|
21
|
+
# The expected value for the matcher.
|
22
|
+
#
|
23
|
+
def initialize(expected = nil, *extra_args)
|
24
|
+
expected = Array(expected || %w( t true y yes 1 ) + [1])
|
25
|
+
@include_matcher = Include.new(expected)
|
26
|
+
|
27
|
+
super(expected, *extra_args)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns whether the given value is accepted.
|
31
|
+
#
|
32
|
+
# @param [Object] actual
|
33
|
+
# The validation value.
|
34
|
+
#
|
35
|
+
# @return [Boolean]
|
36
|
+
#
|
37
|
+
def matches?(actual)
|
38
|
+
actual == true or @include_matcher.matches?(actual)
|
39
|
+
end
|
40
|
+
|
41
|
+
end # Acceptance
|
42
|
+
end # Matchers
|
43
|
+
end # Ward
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Ward
|
2
|
+
module Matchers
|
3
|
+
# Tests whether the validation value is within the delta of the expected
|
4
|
+
# value.
|
5
|
+
#
|
6
|
+
# @example Validating that the estimate attribute is 10 (+- 5).
|
7
|
+
#
|
8
|
+
# class Price
|
9
|
+
# validate do |price|
|
10
|
+
# price.estimate.is.close_to(10, 5)
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
class CloseTo < Matcher
|
15
|
+
|
16
|
+
# Creates a new CloseTo matcher instance.
|
17
|
+
#
|
18
|
+
# @param [Numeric] expected
|
19
|
+
# The expected value for the matcher.
|
20
|
+
# @param [Numeric] delta
|
21
|
+
# The the acceptable range by which the actual value can deviate.
|
22
|
+
#
|
23
|
+
def initialize(expected, delta, *extra_args)
|
24
|
+
raise ArgumentError,
|
25
|
+
'The CloseTo matcher requires that the +expected+ value ' \
|
26
|
+
'responds to +-+' unless expected.respond_to?(:-)
|
27
|
+
|
28
|
+
raise ArgumentError,
|
29
|
+
'The CloseTo matcher requires that a Numeric +delta+ value ' \
|
30
|
+
'is supplied' unless delta.kind_of?(Numeric)
|
31
|
+
|
32
|
+
super(expected, *extra_args)
|
33
|
+
|
34
|
+
@delta = delta
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns whether the given value is close to the expected value.
|
38
|
+
#
|
39
|
+
# @param [Object] actual
|
40
|
+
# The validation value.
|
41
|
+
#
|
42
|
+
# @return [Boolean]
|
43
|
+
#
|
44
|
+
def matches?(actual)
|
45
|
+
(actual - @expected).abs <= @delta
|
46
|
+
end
|
47
|
+
|
48
|
+
# Adds extra information to the error message.
|
49
|
+
#
|
50
|
+
# @param [String] error
|
51
|
+
# @return [String]
|
52
|
+
#
|
53
|
+
def customise_error_values(values)
|
54
|
+
values[:delta] = @delta
|
55
|
+
values
|
56
|
+
end
|
57
|
+
|
58
|
+
end # CloseTo
|
59
|
+
end # Matchers
|
60
|
+
end # Ward
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Ward
|
2
|
+
module Matchers
|
3
|
+
# Tests whether the validation value is equal in value to -- but not
|
4
|
+
# necessarily the same object as -- the expected value.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
#
|
8
|
+
# class Person
|
9
|
+
# validate do |person|
|
10
|
+
# person.name.is.equal_to('Michael Scarn')
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# @todo
|
15
|
+
# Once the validator DSL is is available, amend the class documentation
|
16
|
+
# to provide an example of how to call +is+ and +is_not+ with a value.
|
17
|
+
#
|
18
|
+
class EqualTo < Matcher
|
19
|
+
|
20
|
+
# Returns whether the given value is equal to the expected value.
|
21
|
+
#
|
22
|
+
# @param [Object] actual
|
23
|
+
# The validation value.
|
24
|
+
#
|
25
|
+
# @return [Boolean]
|
26
|
+
#
|
27
|
+
def matches?(actual)
|
28
|
+
actual.eql?(@expected)
|
29
|
+
end
|
30
|
+
|
31
|
+
end # EqualTo
|
32
|
+
end # Matchers
|
33
|
+
end # Ward
|
@@ -0,0 +1,283 @@
|
|
1
|
+
module Ward
|
2
|
+
module Matchers
|
3
|
+
# Tests whether the actual value is a collection with the expected number
|
4
|
+
# of members, or contains a collection with the expected number of
|
5
|
+
# members.
|
6
|
+
#
|
7
|
+
# @example Setting the exact size for a collection
|
8
|
+
#
|
9
|
+
# class Author
|
10
|
+
# validate do |author|
|
11
|
+
# # All mean the same thing.
|
12
|
+
# author.has(5).posts
|
13
|
+
# author.has.exactly(5).posts
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# @example Setting the minimum size for a collection
|
18
|
+
#
|
19
|
+
# class Author
|
20
|
+
# validate do |author|
|
21
|
+
# # All mean the same thing.
|
22
|
+
# author.has.at_least(5).posts
|
23
|
+
# author.has.gte(5).posts
|
24
|
+
#
|
25
|
+
# author.has.greater_than(4).posts
|
26
|
+
# author.has.more_than(4).posts
|
27
|
+
# author.has.gt(4).posts
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# @example Setting the maximum size for a collection
|
32
|
+
#
|
33
|
+
# class Author
|
34
|
+
# validate do |author|
|
35
|
+
# # All mean the same thing.
|
36
|
+
# author.has.at_most(5).posts
|
37
|
+
# author.has.lte(5).posts
|
38
|
+
#
|
39
|
+
# author.has.less_than(6).posts
|
40
|
+
# author.has.fewer_than(6).posts
|
41
|
+
# author.has.lt(6).posts
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# @example Setting a range of acceptable sizes for a collection
|
46
|
+
#
|
47
|
+
# class Author
|
48
|
+
# validate do |author|
|
49
|
+
# # All mean the same thing.
|
50
|
+
# author.has.between(1..5).posts
|
51
|
+
# author.has.between(1, 5).posts
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
class Has < Matcher
|
56
|
+
|
57
|
+
# The name of the collection whose size is being checked.
|
58
|
+
#
|
59
|
+
# @return [Symbol, nil]
|
60
|
+
# nil indicates that no collection name has been set, and the matcher
|
61
|
+
# will attempt to call +size+ or +length+ on the collection owner.
|
62
|
+
#
|
63
|
+
attr_reader :collection_name
|
64
|
+
|
65
|
+
# Returns how to test the length of the collection.
|
66
|
+
#
|
67
|
+
# @return [Symbol]
|
68
|
+
#
|
69
|
+
attr_reader :relativity
|
70
|
+
|
71
|
+
# Creates a new matcher instance.
|
72
|
+
#
|
73
|
+
# If no expected value is provided, the matcher will default to
|
74
|
+
# expecting that the collection has at_least(1).
|
75
|
+
#
|
76
|
+
# @param [Object] expected
|
77
|
+
# The expected value for the matcher.
|
78
|
+
#
|
79
|
+
def initialize(expected = nil, *extra_args)
|
80
|
+
case expected
|
81
|
+
when Range then super ; between(expected)
|
82
|
+
when Numeric then super ; eql(expected)
|
83
|
+
when :no then super ; eql(0)
|
84
|
+
else super(1, *extra_args) ; @relativity = :gte
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns whether the given value is satisfied by the expected block.
|
89
|
+
#
|
90
|
+
# @param [Object] collection
|
91
|
+
# The collection or the collection owner.
|
92
|
+
#
|
93
|
+
# @return [Boolean]
|
94
|
+
#
|
95
|
+
def matches?(collection)
|
96
|
+
unless @collection_name.nil?
|
97
|
+
if collection.respond_to?(@collection_name)
|
98
|
+
collection = collection.__send__(@collection_name)
|
99
|
+
elsif collection.respond_to?(@plural_collection_name)
|
100
|
+
collection = collection.__send__(@plural_collection_name)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
if collection.respond_to?(:length)
|
105
|
+
actual = collection.length
|
106
|
+
elsif collection.respond_to?(:size)
|
107
|
+
actual = collection.size
|
108
|
+
else
|
109
|
+
raise RuntimeError,
|
110
|
+
'The given value is not a collection (it does not respond to ' \
|
111
|
+
'#length or #size)'
|
112
|
+
end
|
113
|
+
|
114
|
+
result = case @relativity
|
115
|
+
when :eql, nil then actual == (@expected == :no ? 0 : @expected)
|
116
|
+
when :lte then actual <= @expected
|
117
|
+
when :gte then actual >= @expected
|
118
|
+
when :between then @expected.include?(actual)
|
119
|
+
end
|
120
|
+
|
121
|
+
[result, @relativity || :eql]
|
122
|
+
end
|
123
|
+
|
124
|
+
# Sets that the collection should be smaller than the expected value.
|
125
|
+
#
|
126
|
+
# @param [Numeric] n
|
127
|
+
# The maximum size of the collection + 1.
|
128
|
+
#
|
129
|
+
# @return [Ward::Matchers::Has]
|
130
|
+
# Returns self.
|
131
|
+
#
|
132
|
+
def lt(n)
|
133
|
+
set_relativity(:lte, n - 1)
|
134
|
+
end
|
135
|
+
|
136
|
+
alias_method :fewer_than, :lt
|
137
|
+
alias_method :less_than, :lt
|
138
|
+
|
139
|
+
# Sets that the collection should be no larger than the expected value.
|
140
|
+
#
|
141
|
+
# @param [Numeric] n
|
142
|
+
# The maximum size of the collection.
|
143
|
+
#
|
144
|
+
# @return [Ward::Matchers::Has]
|
145
|
+
# Returns self.
|
146
|
+
#
|
147
|
+
def lte(n)
|
148
|
+
set_relativity(:lte, n)
|
149
|
+
end
|
150
|
+
|
151
|
+
alias_method :at_most, :lte
|
152
|
+
|
153
|
+
# Sets that the collection should be the exact size of the expectation.
|
154
|
+
#
|
155
|
+
# @param [Numeric] n
|
156
|
+
# The exact expected size of the collection.
|
157
|
+
#
|
158
|
+
# @return [Ward::Matchers::Has]
|
159
|
+
# Returns self.
|
160
|
+
#
|
161
|
+
def eql(n)
|
162
|
+
set_relativity(:eql, n)
|
163
|
+
end
|
164
|
+
|
165
|
+
alias_method :exactly, :eql
|
166
|
+
|
167
|
+
# Sets that the collection should be no smaller than the expected value.
|
168
|
+
#
|
169
|
+
# @param [Numeric] n
|
170
|
+
# The minimum size of the collection.
|
171
|
+
#
|
172
|
+
# @return [Ward::Matchers::Has]
|
173
|
+
# Returns self.
|
174
|
+
#
|
175
|
+
def gte(n)
|
176
|
+
set_relativity(:gte, n)
|
177
|
+
end
|
178
|
+
|
179
|
+
alias_method :at_least, :gte
|
180
|
+
|
181
|
+
# Sets that the collection should be greater than the expected value.
|
182
|
+
#
|
183
|
+
# @param [Numeric] n
|
184
|
+
# The minimum size of the collection - 1.
|
185
|
+
#
|
186
|
+
# @return [Ward::Matchers::Has]
|
187
|
+
# Returns self.
|
188
|
+
#
|
189
|
+
def gt(n)
|
190
|
+
set_relativity(:gte, n + 1)
|
191
|
+
end
|
192
|
+
|
193
|
+
alias_method :greater_than, :gt
|
194
|
+
alias_method :more_than, :gt
|
195
|
+
|
196
|
+
# Sets that the collection size should be between two values.
|
197
|
+
#
|
198
|
+
# @param [Range, Numeric] n
|
199
|
+
# The lowest boundary for the collection size. Alternatively, a range
|
200
|
+
# specifying the acceptable size of the collection.
|
201
|
+
# @param [Numeric] upper
|
202
|
+
# The lowest boundary for the collection size. Omit if a range is
|
203
|
+
# supplied as the first argument.
|
204
|
+
#
|
205
|
+
# @return [Ward::Matchers::Has]
|
206
|
+
# Returns self.
|
207
|
+
#
|
208
|
+
def between(n, upper = nil)
|
209
|
+
if n.kind_of?(Range)
|
210
|
+
set_relativity(:between, n)
|
211
|
+
elsif upper.nil?
|
212
|
+
raise ArgumentError,
|
213
|
+
'You must supply an upper boundary for the collection size'
|
214
|
+
else
|
215
|
+
set_relativity(:between, (n..upper))
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# Adds extra information to the error message.
|
220
|
+
#
|
221
|
+
# @param [String] error
|
222
|
+
# @return [String]
|
223
|
+
#
|
224
|
+
def customise_error_values(values)
|
225
|
+
values[:collection] = @collection_desc || 'items'
|
226
|
+
|
227
|
+
if @relativity == :between
|
228
|
+
values[:lower] = @expected.first
|
229
|
+
values[:upper] = @expected.last
|
230
|
+
end
|
231
|
+
|
232
|
+
values
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
|
237
|
+
# Sets the collection name to be used by the matcher.
|
238
|
+
#
|
239
|
+
# @return [Ward::Matchers::Has]
|
240
|
+
# Returns self.
|
241
|
+
#
|
242
|
+
# @todo
|
243
|
+
# Capture args and block to be used when fetching the collection.
|
244
|
+
#
|
245
|
+
def method_missing(method, *args, &block)
|
246
|
+
@collection_desc = ActiveSupport::Inflector.humanize(method).downcase
|
247
|
+
|
248
|
+
@collection_desc = ActiveSupport::Inflector.singularize(
|
249
|
+
@collection_desc) if @expected == 1
|
250
|
+
|
251
|
+
unless method == :characters and ''.respond_to?(:characters)
|
252
|
+
@collection_name, @plural_collection_name =
|
253
|
+
method, ActiveSupport::Inflector.pluralize(method.to_s).to_sym
|
254
|
+
end
|
255
|
+
|
256
|
+
self
|
257
|
+
end
|
258
|
+
|
259
|
+
# Sets the relativity and the expected value.
|
260
|
+
#
|
261
|
+
# Also marks that a relativity has been set, preventing another one from
|
262
|
+
# being set in the future.
|
263
|
+
#
|
264
|
+
# @param [Symbol] relativity
|
265
|
+
# The relativity to set.
|
266
|
+
# @param [Numeric] expected
|
267
|
+
# The expected value to set.
|
268
|
+
#
|
269
|
+
# @return [Ward::Matchers::Has]
|
270
|
+
# Returns self.
|
271
|
+
#
|
272
|
+
def set_relativity(relativity, expected)
|
273
|
+
raise RuntimeError,
|
274
|
+
"A relativity (#{@relativity}) was already set; you cannot " \
|
275
|
+
"set another" if @relativity_set
|
276
|
+
|
277
|
+
@relativity, @expected, @relativity_set = relativity, expected, true
|
278
|
+
self
|
279
|
+
end
|
280
|
+
|
281
|
+
end # Has
|
282
|
+
end # Matchers
|
283
|
+
end # Ward
|