valuedate 0.0.3 → 0.0.4

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.3
1
+ 0.0.4
data/lib/valuedate.rb CHANGED
@@ -1,5 +1,22 @@
1
1
  class Valuedate
2
2
 
3
+ class ValidationFailed < StandardError
4
+ attr_reader :errors
5
+
6
+ def initialize(errors)
7
+ super("validation failed with #{errors.size} errors")
8
+ @errors = errors
9
+ end
10
+ end
11
+
12
+ class Error
13
+ attr_reader :options
14
+
15
+ def initialize(options={})
16
+ @options = options
17
+ end
18
+ end
19
+
3
20
  class Scope
4
21
  def value
5
22
  Value.new
@@ -19,8 +36,10 @@ class Valuedate
19
36
  end
20
37
  end
21
38
 
39
+ attr_reader :errors
22
40
 
23
41
  def initialize(&block)
42
+ @errors = []
24
43
  @validators = []
25
44
  if block
26
45
  validator = Scope.new.instance_eval(&block)
@@ -32,13 +51,18 @@ class Valuedate
32
51
  valid? do |value|
33
52
  value ||= {}
34
53
  schema.all? do |(key, validator)|
35
- validator.validate(value[key])
54
+ validator.call(value[key]) || collect_errors!(validator, :key => key)
36
55
  end
37
56
  end
38
57
  end
39
58
 
40
59
  def validate(value = nil)
41
- @validators.all? { |validator| validator.call(value) }
60
+ @errors.clear
61
+ @validators.all? { |validator| validator.call(value) || collect_errors!(validator) }
62
+ end
63
+
64
+ def validate!(value = nil)
65
+ validate(value) or raise ValidationFailed.new(@errors)
42
66
  end
43
67
 
44
68
  def call(value)
@@ -50,9 +74,28 @@ class Valuedate
50
74
  self
51
75
  end
52
76
 
77
+ def collect_errors!(validator, options = {})
78
+ case validator
79
+ when Valuedate
80
+ @errors.concat(validator.errors.map { |error| error.options.update(options); error })
81
+ end
82
+ false
83
+ end
84
+
85
+ def errors
86
+ @errors.uniq
87
+ end
88
+
89
+ def error(options={})
90
+ @errors << Error.new(options)
91
+ false
92
+ end
93
+
53
94
  def method_missing(method, *args, &block)
54
95
  if matcher = Valuedate.matchers[method]
55
- valid? { |value| matcher.call(value, *args, &block) }
96
+ valid? do |value|
97
+ matcher.call(value, *args, &block) || error(:matcher => method, :value => value, :args => args)
98
+ end
56
99
  else
57
100
  super
58
101
  end
@@ -6,6 +6,22 @@ class Riot::Situation
6
6
  end
7
7
  end
8
8
 
9
+ class Riot::Context
10
+ def asserts_validation_error(options={}, &block)
11
+ asserts("validation_error with #{options.inspect}") do
12
+ begin
13
+ instance_eval(&block)
14
+ false
15
+ rescue Valuedate::ValidationFailed => e
16
+ error = e.errors.first
17
+ options.all? do |key, value|
18
+ error.options[key] == value
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+
9
25
  context "Valuedate" do
10
26
 
11
27
  asserts(:class) { Valuedate.schema }.equals(Valuedate)
@@ -179,4 +195,38 @@ context "Valuedate" do
179
195
  asserts("valid array size") { v([1,2]) { value.is { |value| value.size == 2 } } }
180
196
  asserts("invalid array size") { !v([1,2]) { value.not { |value| value.size == 2 } } }
181
197
  end
198
+
199
+ context "errors" do
200
+ setup do
201
+ Valuedate.schema {}
202
+ end
203
+
204
+ asserts("empty") { topic.errors.empty? }
205
+ asserts("with error") do
206
+ topic.error(:value => "value")
207
+ topic.errors.first.options[:value]
208
+ end.equals("value")
209
+
210
+ context "aggregate" do
211
+ setup do
212
+ Valuedate.schema do
213
+ value.hash(
214
+ :key1 => value.is_a(String).equals("key"),
215
+ :key2 => value.hash(
216
+ :key3 => value.is_a(Fixnum)
217
+ )
218
+ )
219
+ end
220
+ end
221
+
222
+ asserts("fails") { !topic.validate({}) }
223
+ asserts_validation_error(:key => :key1, :matcher => :is_a) { topic.validate!({}) }
224
+ asserts_validation_error(:key => :key1, :matcher => :is_a) { topic.validate!(:key1 => 23) }
225
+ asserts_validation_error(:key => :key1, :matcher => :equals) { topic.validate!(:key1 => "value") }
226
+ asserts_validation_error(:key => :key2, :matcher => :is_a) { topic.validate!(:key1 => "key") }
227
+ asserts_validation_error(:key => :key2, :matcher => :is_a) { topic.validate!(:key1 => "key", :key2 => {}) }
228
+ asserts_validation_error(:key => :key2, :matcher => :is_a) { topic.validate!(:key1 => "key", :key2 => {:key3 => 0.0}) }
229
+ asserts("passes") { topic.validate(:key1 => "key", :key2 => {:key3 => 23}) }
230
+ end
231
+ end
182
232
  end
data/valuedate.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{valuedate}
8
- s.version = "0.0.3"
8
+ s.version = "0.0.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Peter Suschlik"]
12
- s.date = %q{2010-01-28}
12
+ s.date = %q{2010-01-30}
13
13
  s.email = %q{peter-valuedate@suschlik.de}
14
14
  s.extra_rdoc_files = [
15
15
  "README.rdoc"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: valuedate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Suschlik
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-28 00:00:00 +01:00
12
+ date: 2010-01-30 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency