ward 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/.document +5 -0
  2. data/.gitignore +28 -0
  3. data/LICENSE +19 -0
  4. data/README.markdown +99 -0
  5. data/Rakefile +47 -0
  6. data/VERSION +1 -0
  7. data/features/acceptance_matcher.feature +78 -0
  8. data/features/attribute_keyword.feature +13 -0
  9. data/features/close_to_matcher.feature +130 -0
  10. data/features/context_arguments.feature +47 -0
  11. data/features/equal_to_matcher.feature +25 -0
  12. data/features/error_messages.feature +69 -0
  13. data/features/external_validation.feature +15 -0
  14. data/features/has_matcher.feature +72 -0
  15. data/features/has_matcher_initialized_with_expectation.feature +94 -0
  16. data/features/has_matcher_relativities.feature +171 -0
  17. data/features/include_matcher.feature +28 -0
  18. data/features/is_keyword.feature +42 -0
  19. data/features/is_not_keyword.feature +62 -0
  20. data/features/match_matcher.feature +49 -0
  21. data/features/multiple_validators.feature +29 -0
  22. data/features/nil_matcher.feature +25 -0
  23. data/features/predicate_matcher.feature +23 -0
  24. data/features/present_matcher.feature +59 -0
  25. data/features/satisfy_matcher.feature +80 -0
  26. data/features/scenario_validation.feature +81 -0
  27. data/features/step_definitions/external_validation_steps.rb +69 -0
  28. data/features/step_definitions/generic_validation_steps.rb +33 -0
  29. data/features/step_definitions/object_definition_steps.rb +43 -0
  30. data/features/support/env.rb +12 -0
  31. data/features/support/object_builder.rb +33 -0
  32. data/features/support/struct.rb +38 -0
  33. data/lang/en.yml +56 -0
  34. data/lib/ward.rb +26 -0
  35. data/lib/ward/context.rb +70 -0
  36. data/lib/ward/context_chain.rb +87 -0
  37. data/lib/ward/dsl.rb +7 -0
  38. data/lib/ward/dsl/validation_block.rb +73 -0
  39. data/lib/ward/dsl/validation_builder.rb +190 -0
  40. data/lib/ward/errors.rb +213 -0
  41. data/lib/ward/matchers.rb +97 -0
  42. data/lib/ward/matchers/acceptance.rb +43 -0
  43. data/lib/ward/matchers/close_to.rb +60 -0
  44. data/lib/ward/matchers/equal_to.rb +33 -0
  45. data/lib/ward/matchers/has.rb +283 -0
  46. data/lib/ward/matchers/include.rb +54 -0
  47. data/lib/ward/matchers/match.rb +29 -0
  48. data/lib/ward/matchers/matcher.rb +68 -0
  49. data/lib/ward/matchers/nil.rb +30 -0
  50. data/lib/ward/matchers/predicate.rb +31 -0
  51. data/lib/ward/matchers/present.rb +56 -0
  52. data/lib/ward/matchers/satisfy.rb +65 -0
  53. data/lib/ward/spec.rb +17 -0
  54. data/lib/ward/spec/matcher_matcher.rb +114 -0
  55. data/lib/ward/support.rb +7 -0
  56. data/lib/ward/support/basic_object.rb +55 -0
  57. data/lib/ward/support/result.rb +49 -0
  58. data/lib/ward/validator.rb +147 -0
  59. data/lib/ward/validator_set.rb +115 -0
  60. data/lib/ward/version.rb +3 -0
  61. data/spec/lib/has_matcher_relativity_examples.rb +15 -0
  62. data/spec/lib/have_public_method_defined.rb +22 -0
  63. data/spec/rcov.opts +8 -0
  64. data/spec/spec.opts +4 -0
  65. data/spec/spec_helper.rb +19 -0
  66. data/spec/ward/context_chain_spec.rb +178 -0
  67. data/spec/ward/context_spec.rb +57 -0
  68. data/spec/ward/dsl/validation_block_spec.rb +27 -0
  69. data/spec/ward/dsl/validation_builder_spec.rb +212 -0
  70. data/spec/ward/errors_spec.rb +149 -0
  71. data/spec/ward/matchers/acceptance_spec.rb +16 -0
  72. data/spec/ward/matchers/close_to_spec.rb +57 -0
  73. data/spec/ward/matchers/equal_to_spec.rb +16 -0
  74. data/spec/ward/matchers/has_spec.rb +175 -0
  75. data/spec/ward/matchers/include_spec.rb +41 -0
  76. data/spec/ward/matchers/match_spec.rb +21 -0
  77. data/spec/ward/matchers/matcher_spec.rb +54 -0
  78. data/spec/ward/matchers/nil_spec.rb +16 -0
  79. data/spec/ward/matchers/predicate_spec.rb +19 -0
  80. data/spec/ward/matchers/present_spec.rb +16 -0
  81. data/spec/ward/matchers/satisfy_spec.rb +68 -0
  82. data/spec/ward/matchers_spec.rb +51 -0
  83. data/spec/ward/spec/have_public_method_defined_spec.rb +31 -0
  84. data/spec/ward/spec/matcher_matcher_spec.rb +217 -0
  85. data/spec/ward/validator_set_spec.rb +178 -0
  86. data/spec/ward/validator_spec.rb +264 -0
  87. data/tasks/features.rake +15 -0
  88. data/tasks/rcov.rake +24 -0
  89. data/tasks/spec.rake +18 -0
  90. data/tasks/yard.rake +9 -0
  91. data/ward.gemspec +176 -0
  92. metadata +239 -0
@@ -0,0 +1,178 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe Ward::ContextChain do
4
+ subject { Ward::ContextChain }
5
+
6
+ #
7
+ # attribute
8
+ #
9
+
10
+ it { should have_public_method_defined(:attribute) }
11
+
12
+ describe '#attribute' do
13
+ before(:all) do
14
+ @chain = Ward::ContextChain.new
15
+ @chain.push(Ward::Context.new(:name))
16
+ @chain.push(Ward::Context.new(:length))
17
+ end
18
+
19
+ it 'should return a symbol' do
20
+ @chain.attribute.should be_a(Symbol)
21
+ end
22
+
23
+ it "should return the first Context's attribute" do
24
+ @chain.attribute.should == :name
25
+ end
26
+
27
+ it 'should return :base when there are no contexts contained' do
28
+ Ward::ContextChain.new.attribute.should == :base
29
+ end
30
+ end
31
+
32
+ #
33
+ # to_a
34
+ #
35
+
36
+ it { should have_public_method_defined(:to_a) }
37
+
38
+ #
39
+ # push
40
+ #
41
+
42
+ it { should have_public_method_defined(:push) }
43
+ it { should have_public_method_defined(:<<) }
44
+
45
+ describe '#push' do
46
+ it 'should add a context to the end of the chain' do
47
+ chain = Ward::ContextChain.new
48
+ new_context = Ward::Context.new(:length)
49
+ chain.to_a.should be_empty
50
+ chain.push(new_context)
51
+ chain.to_a.should eql([new_context])
52
+ end
53
+ end
54
+
55
+ #
56
+ # natural name
57
+ #
58
+
59
+ it { should have_public_method_defined(:natural_name) }
60
+
61
+ describe '#natural_name' do
62
+ describe 'when the chain contains no contexts' do
63
+ it 'should return a blank string' do
64
+ Ward::ContextChain.new.natural_name.should eql('')
65
+ end
66
+ end
67
+
68
+ describe 'when the chain contains a single context' do
69
+ before(:all) do
70
+ @chain = Ward::ContextChain.new
71
+ @chain << Ward::Context.new(:length)
72
+ end
73
+
74
+ it 'should return the context natural name' do
75
+ @chain.natural_name.should eql('length')
76
+ end
77
+ end
78
+
79
+ describe 'when the chain contains a two (or more) contexts' do
80
+ before(:all) do
81
+ @chain = Ward::ContextChain.new
82
+ @chain << Ward::Context.new(:post)
83
+ @chain << Ward::Context.new(:name)
84
+ end
85
+
86
+ it 'should join the natural names of each context' do
87
+ @chain.natural_name.should eql('post name')
88
+ end
89
+ end
90
+ end
91
+
92
+ #
93
+ # value
94
+ #
95
+
96
+ it { should have_public_method_defined(:value) }
97
+
98
+ describe '#value' do
99
+ describe 'when the chain contains no context' do
100
+ before(:all) do
101
+ @chain = Ward::ContextChain.new
102
+ end
103
+
104
+ it 'should return the given object' do
105
+ @chain.value('this').should == 'this'
106
+ end
107
+ end
108
+
109
+ describe 'when the chain contains a single context' do
110
+ before(:all) do
111
+ @chain = Ward::ContextChain.new
112
+ @chain << Ward::Context.new(:length)
113
+ end
114
+
115
+ it 'should retrieve the value when set' do
116
+ @chain.value('abc').should eql(3)
117
+ end
118
+
119
+ it 'should retrieve a nil value without an error' do
120
+ @chain.value(Struct.new(:length).new(nil)).should be_nil
121
+ end
122
+ end # when the chain contains a single context
123
+
124
+ describe 'when the chain contains two contexts' do
125
+ before(:all) do
126
+ @chain = Ward::ContextChain.new
127
+ @chain << Ward::Context.new(:post)
128
+ @chain << Ward::Context.new(:name)
129
+ end
130
+
131
+ it 'should retrieve the value when set' do
132
+ target = Struct.new(:post).new(Struct.new(:name).new('Hello!'))
133
+ @chain.value(target).should eql('Hello!')
134
+ end
135
+
136
+ it 'should raise an error if the first context value is nil' do
137
+ lambda { @chain.value(nil) }.should raise_error
138
+ end
139
+
140
+ it 'should not raise an error if the second context value is nil' do
141
+ target = Struct.new(:post).new(Struct.new(:name).new(nil))
142
+ @chain.value(target).should be_nil
143
+ end
144
+ end # when the chain contains two contexts
145
+
146
+ describe 'when the chain contains three (or more) contexts' do
147
+ before(:all) do
148
+ @chain = Ward::ContextChain.new
149
+ @chain << Ward::Context.new(:post)
150
+ @chain << Ward::Context.new(:name)
151
+ @chain << Ward::Context.new(:length)
152
+ end
153
+
154
+ it 'should retrieve the value when set' do
155
+ target = Struct.new(:post).new(Struct.new(:name).new('abc'))
156
+ @chain.value(target).should eql(3)
157
+ end
158
+
159
+ it 'should raise an error if the first context value is nil' do
160
+ lambda { @chain.value(nil) }.should raise_error
161
+ end
162
+
163
+ it 'should raise an error if the second context value is nil' do
164
+ target = Struct.new(:post).new(Struct.new(:name).new(nil))
165
+ lambda { @chain.value(target) }.should raise_error
166
+ end
167
+
168
+ it 'should not raise an error if the second context value is nil' do
169
+ target = Struct.new(:post).new(
170
+ Struct.new(:name).new(Struct.new(:length).new(nil))
171
+ )
172
+
173
+ @chain.value(target).should be_nil
174
+ end
175
+ end # when the chain contains three (or more) contexts
176
+ end # value
177
+
178
+ end
@@ -0,0 +1,57 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe Ward::Context do
4
+ subject { Ward::Context }
5
+
6
+ #
7
+ # attribute
8
+ #
9
+
10
+ it { should have_public_method_defined(:attribute) }
11
+
12
+ describe '#attribute' do
13
+ subject do
14
+ @attribute = Ward::Context.new('full_name').attribute
15
+ end
16
+
17
+ it { should be_a(Symbol) }
18
+ it { should eql(:full_name) }
19
+ end
20
+
21
+ #
22
+ # natural name
23
+ #
24
+
25
+ it { should have_public_method_defined(:natural_name) }
26
+
27
+ describe '#natural_name' do
28
+ subject do
29
+ @attribute = Ward::Context.new('full_name').natural_name
30
+ end
31
+
32
+ it { should be_a(String) }
33
+ it { should eql('full name') }
34
+ end
35
+
36
+ #
37
+ # value
38
+ #
39
+
40
+ it { should have_public_method_defined(:value) }
41
+
42
+ describe '#value' do
43
+ before(:all) do
44
+ @matcher = Ward::Context.new(:length)
45
+ end
46
+
47
+ it 'should retrieve the target value' do
48
+ @matcher.value('abc').should == 3
49
+ end
50
+
51
+ it 'should raise an error when the target does not respond to the ' \
52
+ 'target method' do
53
+ lambda { @matcher.value(nil) }.should raise_exception(NoMethodError)
54
+ end
55
+ end # value
56
+
57
+ end # Ward::Context
@@ -0,0 +1,27 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ describe Ward::DSL::ValidationBlock do
4
+
5
+ #
6
+ # to_validator_set
7
+ #
8
+
9
+ describe '#to_validator_set' do
10
+ it 'should return a Ward::ValidatorSet' do
11
+ set = Ward::DSL::ValidationBlock.new.to_validator_set
12
+ set.should be_a(Ward::ValidatorSet)
13
+ end
14
+ end # to_validator_set
15
+
16
+ #
17
+ # method_missing
18
+ #
19
+
20
+ describe '#method_missing' do
21
+ it 'should raise an exception when used outside of a run block' do
22
+ running = lambda { Ward::DSL::ValidationBlock.new.name }
23
+ running.should raise_error(RuntimeError, /a block/)
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,212 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ describe Ward::DSL::ValidationBuilder do
4
+ subject { Ward::DSL::ValidationBuilder }
5
+
6
+ #
7
+ # when setting a matcher
8
+ #
9
+
10
+ describe 'when setting a matcher' do
11
+ before(:each) do
12
+ @builder = Ward::DSL::ValidationBuilder.new
13
+ end
14
+
15
+ it "should set an Acceptance matcher when calling #accepted" do
16
+ validator = @builder.is.accepted.to_validator
17
+ validator.matcher.should be_a(Ward::Matchers::Acceptance)
18
+ end
19
+
20
+ it "should set a CloseTo matcher when calling #close_to" do
21
+ validator = @builder.is.close_to(1, 1).to_validator
22
+ validator.matcher.should be_a(Ward::Matchers::CloseTo)
23
+ end
24
+
25
+ it "should set an EqualTo matcher when calling #equal_to" do
26
+ validator = @builder.is.equal_to(1).to_validator
27
+ validator.matcher.should be_a(Ward::Matchers::EqualTo)
28
+ end
29
+
30
+ it "should set a Has matcher when calling #has" do
31
+ validator = @builder.has.to_validator
32
+ validator.matcher.should be_a(Ward::Matchers::Has)
33
+ end
34
+
35
+ it "should set a Has matcher when calling #have" do
36
+ validator = @builder.have(1, 1).to_validator
37
+ validator.matcher.should be_a(Ward::Matchers::Has)
38
+ end
39
+
40
+ it "should set an Include matcher when calling #included_in" do
41
+ validator = @builder.is.included_in([]).to_validator
42
+ validator.matcher.should be_a(Ward::Matchers::Include)
43
+ end
44
+
45
+ it "should set a Match matcher when calling #matches" do
46
+ validator = @builder.matches(//).to_validator
47
+ validator.matcher.should be_a(Ward::Matchers::Match)
48
+ end
49
+
50
+ it "should set a Match matcher when calling #match" do
51
+ validator = @builder.match(//).to_validator
52
+ validator.matcher.should be_a(Ward::Matchers::Match)
53
+ end
54
+
55
+ it "should set a Nil matcher when calling #nil" do
56
+ validator = @builder.is.nil.to_validator
57
+ validator.matcher.should be_a(Ward::Matchers::Nil)
58
+ end
59
+
60
+ it "should set a Present matcher when calling #present" do
61
+ validator = @builder.is.present.to_validator
62
+ validator.matcher.should be_a(Ward::Matchers::Present)
63
+ end
64
+
65
+ it "should set a Satisfy matcher when calling #satisfies" do
66
+ validator = @builder.satisfies.to_validator
67
+ validator.matcher.should be_a(Ward::Matchers::Satisfy)
68
+ end
69
+
70
+ it "should set a Satisfy matcher when calling #satisfy" do
71
+ validator = @builder.satisfy.to_validator
72
+ validator.matcher.should be_a(Ward::Matchers::Satisfy)
73
+ end
74
+ end
75
+
76
+ #
77
+ # customising a matcher
78
+ #
79
+
80
+ describe 'calling a missing method when a matcher is set' do
81
+ it 'should call methods on the matcher' do
82
+ builder = Ward::DSL::ValidationBuilder.new.has
83
+ builder.to_validator.matcher.expected.should == 1 # default
84
+ builder.at_least(5)
85
+ builder.to_validator.matcher.expected.should == 5
86
+ end
87
+ end
88
+
89
+ #
90
+ # when setting a context name
91
+ #
92
+
93
+ describe '#attribute' do
94
+ before(:each) do
95
+ @builder = Ward::DSL::ValidationBuilder.new
96
+ end
97
+
98
+ it 'should return the builder' do
99
+ @builder.attribute(:name).should be(@builder)
100
+ end
101
+ end
102
+
103
+ #
104
+ # when setting a message
105
+ #
106
+
107
+ describe '#message' do
108
+ before(:each) do
109
+ @builder = Ward::DSL::ValidationBuilder.new.is.present
110
+ end
111
+
112
+ it 'should return the builder' do
113
+ @builder.message('A validation error message').should be(@builder)
114
+ end
115
+
116
+ it 'should set the validation message' do
117
+ validator = @builder.message('A validation error message').to_validator
118
+ validator.message.should == 'A validation error message'
119
+ end
120
+ end
121
+
122
+ describe 'with no message' do
123
+ before(:each) do
124
+ @builder = Ward::DSL::ValidationBuilder.new.is.present
125
+ end
126
+
127
+ it 'should set the validation message' do
128
+ validator = @builder.to_validator
129
+ validator.message.should be_nil
130
+ end
131
+ end
132
+
133
+ #
134
+ # when setting a scenario
135
+ #
136
+
137
+ describe '#scenario' do
138
+ before(:each) do
139
+ @builder = Ward::DSL::ValidationBuilder.new.is.present
140
+ end
141
+
142
+ it 'should return the builder' do
143
+ @builder.scenario(:scenario).should be(@builder)
144
+ end
145
+
146
+ it 'should set the validation scenario' do
147
+ validator = @builder.scenario(:scenario).to_validator
148
+ validator.scenarios.should == [:scenario]
149
+ end
150
+ end
151
+
152
+ describe '#scenarios' do
153
+ before(:each) do
154
+ @builder = Ward::DSL::ValidationBuilder.new.is.present
155
+ end
156
+
157
+ it 'should return the builder' do
158
+ @builder.scenarios([:scenario]).should be(@builder)
159
+ end
160
+
161
+ it 'should set multiple scenarios when given an array' do
162
+ validator = @builder.scenarios([:one, :two]).to_validator
163
+ validator.scenarios.should == [:one, :two]
164
+ end
165
+
166
+ it 'should set multiple scenarios when given a multiple arguments' do
167
+ validator = @builder.scenarios(:one, :two).to_validator
168
+ validator.scenarios.should == [:one, :two]
169
+ end
170
+ end
171
+
172
+ #
173
+ # to_validator
174
+ #
175
+
176
+ it { should have_public_method_defined(:to_validator) }
177
+
178
+ describe '#to_validator' do
179
+ describe 'when no matcher is defined' do
180
+ it 'should raise an IncompleteValidator exception' do
181
+ running = lambda { Ward::DSL::ValidationBuilder.new.to_validator }
182
+ running.should raise_exception(Ward::IncompleteValidator)
183
+ end
184
+ end
185
+
186
+ describe 'when a matcher is defined' do
187
+ before(:all) do
188
+ builder = Ward::DSL::ValidationBuilder.new.author.name
189
+ builder.is.equal_to(1)
190
+ @validator = builder.to_validator
191
+ end
192
+
193
+ it 'should return a Ward::Validator' do
194
+ @validator.should be_a(Ward::Validator)
195
+ end
196
+
197
+ it 'should set the matcher' do
198
+ @validator.matcher.should be_a(Ward::Matchers::Matcher)
199
+ end
200
+
201
+ it 'should set the matcher expectation' do
202
+ @validator.matcher.expected.should == 1
203
+ end
204
+
205
+ it 'should set the context' do
206
+ attributes = @validator.context.to_a.map { |c| c.attribute }
207
+ attributes.should == [:author, :name]
208
+ end
209
+ end
210
+ end
211
+
212
+ end