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.
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