judge 0.4.3 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/judge.rb CHANGED
@@ -2,7 +2,3 @@ require File.dirname(__FILE__) + '/judge/utils'
2
2
  require File.dirname(__FILE__) + '/judge/form'
3
3
 
4
4
  ::ActionView::Helpers::FormBuilder.send(:include, Judge::FormBuilder)
5
-
6
- module ApplicationHelper
7
- include Judge::FormHelper
8
- end
data/lib/judge/form.rb CHANGED
@@ -7,7 +7,7 @@ module Judge
7
7
  %w{text_field text_area password_field}.each do |type|
8
8
  helper = <<-END
9
9
  def validated_#{type}(method, options = {})
10
- options = { "data-validate" => Judge::Utils.jsonify_validators(self.object, method) }.merge(options)
10
+ options = { "data-validate" => Judge::Utils.validators_to_json(self.object, method) }.merge(options)
11
11
  @template.#{type}(self.object_name, method, options)
12
12
  end
13
13
  END
@@ -15,34 +15,34 @@ module Judge
15
15
  end
16
16
 
17
17
  def validated_radio_button(method, tag_value, options = {})
18
- options = { "data-validate" => Judge::Utils.jsonify_validators(self.object, method) }.merge(options)
18
+ options = { "data-validate" => Judge::Utils.validators_to_json(self.object, method) }.merge(options)
19
19
  @template.radio_button(@object_name, method, tag_value, objectify_options(options))
20
20
  end
21
21
 
22
22
  def validated_check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
23
- options = { "data-validate" => Judge::Utils.jsonify_validators(self.object, method) }.merge(options)
23
+ options = { "data-validate" => Judge::Utils.validators_to_json(self.object, method) }.merge(options)
24
24
  @template.check_box(self.object_name, method, objectify_options(options), checked_value, unchecked_value)
25
25
  end
26
26
 
27
27
  def validated_select(method, choices, options = {}, html_options = {})
28
- html_options = { "data-validate" => Judge::Utils.jsonify_validators(self.object, method) }.merge(html_options)
28
+ html_options = { "data-validate" => Judge::Utils.validators_to_json(self.object, method) }.merge(html_options)
29
29
  @template.select(self.object_name, method, choices, objectify_options(options), @default_options.merge(html_options))
30
30
  end
31
31
 
32
32
  def validated_collection_select(method, collection, value_method, text_method, options = {}, html_options = {})
33
- html_options = { "data-validate" => Judge::Utils.jsonify_validators(self.object, method) }.merge(html_options)
33
+ html_options = { "data-validate" => Judge::Utils.validators_to_json(self.object, method) }.merge(html_options)
34
34
  @template.collection_select(self.object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options))
35
35
  end
36
36
 
37
37
  def validated_grouped_collection_select(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
38
- html_options = { "data-validate" => Judge::Utils.jsonify_validators(self.object, method) }.merge(html_options)
38
+ html_options = { "data-validate" => Judge::Utils.validators_to_json(self.object, method) }.merge(html_options)
39
39
  @template.grouped_collection_select(self.object_name, method, collection, group_method, group_label_method, option_key_method, option_value_method, objectify_options(options), @default_options.merge(html_options))
40
40
  end
41
41
 
42
42
  %w{date_select datetime_select time_select}.each do |type|
43
43
  helper = <<-END
44
44
  def validated_#{type}(method, options = {}, html_options = {})
45
- html_options = { "data-validate" => Judge::Utils.jsonify_validators(self.object, method) }.merge(html_options)
45
+ html_options = { "data-validate" => Judge::Utils.validators_to_json(self.object, method) }.merge(html_options)
46
46
  @template.#{type}(self.object_name, method, objectify_options(options), html_options)
47
47
  end
48
48
  END
@@ -50,22 +50,10 @@ module Judge
50
50
  end
51
51
 
52
52
  def validated_time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
53
- html_options = { "data-validate" => Judge::Utils.jsonify_validators(self.object, method) }.merge(html_options)
53
+ html_options = { "data-validate" => Judge::Utils.validators_to_json(self.object, method) }.merge(html_options)
54
54
  @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_options.merge(html_options))
55
55
  end
56
56
 
57
-
58
- end
59
-
60
- module FormHelper
61
-
62
- def validated_form_for(record_or_name_or_array, *args, &proc)
63
- options = args.extract_options!
64
- options[:html] ||= {}
65
- options[:html]["data-error-messages"] = I18n.t("errors.messages").to_json
66
- form_for(record_or_name_or_array, *(args << options), &proc)
67
- end
68
-
69
57
  end
70
58
 
71
59
  end
data/lib/judge/utils.rb CHANGED
@@ -1,15 +1,79 @@
1
1
  module Judge
2
+
2
3
  module Utils
3
4
 
4
- def self.jsonify_validators(object, method)
5
- validators = object.class.validators_on(method)
6
- validators = validators.collect do |validator|
7
- {
8
- :kind => validator.kind.to_s,
9
- :options => validator.options.reject{ |key| [:if, :on, :unless, :tokenizer].include?(key) }
10
- }
5
+ extend self
6
+
7
+ MESSAGE_MAP = {
8
+ :confirmation => { :base => :confirmation },
9
+ :acceptance => { :base => :accepted },
10
+ :presence => { :base => :blank },
11
+ :length => { :base => nil,
12
+ :options => {
13
+ :minimum => :too_short,
14
+ :maximum => :too_long,
15
+ :is => :wrong_length
16
+ }
17
+ },
18
+ :format => { :base => :invalid },
19
+ :inclusion => { :base => :inclusion },
20
+ :exclusion => { :base => :exclusion },
21
+ :numericality => { :base => :not_a_number,
22
+ :options => {
23
+ :greater_than => :greater_than,
24
+ :greater_than_or_equal_to => :greater_than_or_equal_to,
25
+ :equal_to => :equal_to,
26
+ :less_than => :less_than,
27
+ :less_than_or_equal_to => :less_than_or_equal_to,
28
+ :odd => :odd,
29
+ :even => :even
30
+ }
31
+ }
32
+ }
33
+
34
+ ALLOW_BLANK = [:format, :exclusion, :inclusion, :length]
35
+
36
+ # Returns all decorated validators for an object's method, as JSON
37
+ # Judge::Utils.validators_to_json(@user, :name)
38
+ def validators_to_json(object, method)
39
+ validators = object.class.validators_on(method).reject { |validator| validator.kind == :uniqueness }
40
+ validators.collect! do |validator|
41
+ Judge::Utils.decorate_validator(validator, object, method)
42
+ end
43
+ validators.to_json
44
+ end
45
+
46
+ # Convert validator to hash, removing all parts we don't support and adding all possible error messages
47
+ # Judge::Utils.decorate_validator(validator_instance, @user, :name)
48
+ def decorate_validator(validator, object, method)
49
+ kind = validator.kind
50
+ mm = MESSAGE_MAP
51
+
52
+ # remove callbacks and tokenizer, which we don't support
53
+ validator_options = validator.options.reject { |key| [:if, :on, :unless, :tokenizer].include?(key) }
54
+
55
+ messages = {}
56
+ if mm.has_key?(kind) && mm[kind][:base].present?
57
+ base_message = mm[kind][:base]
58
+ messages[base_message] = object.errors.generate_message(method, base_message, validator_options)
59
+ end
60
+ if mm.has_key?(kind) && mm[kind][:options].present?
61
+ opt_messages = mm[kind][:options]
62
+ opt_messages.each do |opt, opt_message|
63
+ if validator_options.has_key?(opt)
64
+ options_for_interpolation = { :count => validator_options[opt] }.merge(validator_options)
65
+ messages[opt_message] = object.errors.generate_message(method, opt_message, options_for_interpolation)
66
+ end
67
+ end
68
+ end
69
+ if ALLOW_BLANK.include?(kind) && validator_options[:allow_blank].blank? && messages[:blank].blank?
70
+ messages[:blank] = object.errors.generate_message(method, :blank)
11
71
  end
12
- validators.reject{ |validator| validator[:kind] == "uniqueness" }.to_json
72
+ if kind == :numericality && validator_options[:only_integer].present?
73
+ messages[:not_an_integer] = object.errors.generate_message(method, :not_an_integer)
74
+ end
75
+
76
+ { :kind => kind, :options => validator_options, :messages => messages }
13
77
  end
14
78
 
15
79
  end
@@ -17,9 +17,9 @@ describe('judge', function() {
17
17
  });
18
18
 
19
19
  it('validates a collection of elements', function() {
20
- var e = document.querySelectorAll('.field input'),
20
+ var e = document.querySelectorAll('input[type=radio]'),
21
21
  v = judge.validate(e);
22
- expect(v.length).toBeGreaterThan(1);
22
+ expect(v.length).toEqual(1);
23
23
  });
24
24
 
25
25
  });
@@ -47,8 +47,9 @@ describe('judge', function() {
47
47
  expect(_(j.validators).isEmpty()).toEqual(false);
48
48
  });
49
49
 
50
- it('holds default messages', function() {
51
- expect(j.defaultMessages).toBeInstanceOf(Object);
50
+ it('holds messages inside validators', function() {
51
+ expect(_(j.validators).first().hasOwnProperty('messages')).toBe(true);
52
+ expect(_(j.validators).first().messages).toBeInstanceOf(Object);
52
53
  });
53
54
 
54
55
  it('has validation methods in prototype', function() {
@@ -67,14 +68,6 @@ describe('judge', function() {
67
68
  expect(function() { new judge.Watcher(e); }).toThrow();
68
69
  });
69
70
 
70
- it('throws error if element.form has no data-error-messages attribute', function() {
71
- var e = document.createElement('input'),
72
- f = document.createElement('form');
73
- e.type = 'text';
74
- f.appendChild(e);
75
- expect(function() { new judge.Watcher(e); }).toThrow();
76
- });
77
-
78
71
  it('throws error if no element is passed', function() {
79
72
  expect(function() { new judge.Watcher(); }).toThrow();
80
73
  });
@@ -118,20 +111,21 @@ describe('judge', function() {
118
111
 
119
112
  it('returns DOM elements from stored Watchers', function() {
120
113
  judge.store.save('mykey', e);
121
- judge.store.save('mykey', document.getElementById('foo_two'));
114
+ judge.store.save('mykey', document.getElementById('foo_two_foobar'));
122
115
  var d = judge.store.getDOM('mykey');
123
116
  expect(d.length).toEqual(2);
124
- expect(Object.prototype.toString.call(d[0])).toEqual('[object HTMLInputElement]');
117
+ console.log(d);
118
+ expect(Object.prototype.toString.call(d[0])).toEqual('[object HTMLSelectElement]');
125
119
  });
126
120
 
127
121
  it('returns store object with watchers converted to elements if no key given', function() {
128
122
  judge.store.save('mykey', e);
129
- judge.store.save('mykey2', document.getElementById('foo_two'));
123
+ judge.store.save('mykey2', document.getElementById('foo_two_foobar'));
130
124
  judge.store.save('mykey2', document.getElementById('foo_three'));
131
125
  var d = judge.store.getDOM();
132
126
  expect(d.mykey.length).toEqual(1);
133
127
  expect(d.mykey2.length).toEqual(2);
134
- expect(Object.prototype.toString.call(d.mykey[0])).toEqual('[object HTMLInputElement]');
128
+ expect(Object.prototype.toString.call(d.mykey[0])).toEqual('[object HTMLSelectElement]');
135
129
  });
136
130
 
137
131
  it('returns null if key not found', function() {
@@ -220,17 +214,12 @@ describe('judge', function() {
220
214
  expect(j.validate().valid).toEqual(false);
221
215
  });
222
216
 
223
- it('returns custom message when present', function() {
224
- _(j.validators).first().options.message = 'hello';
225
- expect(j.validate().messages).toContain('hello');
226
- });
227
-
228
- it('returns default message', function() {
229
- expect(j.validate().messages).toContain(j.defaultMessages.blank);
217
+ it('returns message', function() {
218
+ expect(j.validate().messages).not.toBeEmpty();
230
219
  });
231
220
 
232
221
  it('validates non-empty input', function() {
233
- j.element.value = 'abcde';
222
+ j.element.children[1].selected = true;
234
223
  expect(j.validate().valid).toEqual(true);
235
224
  });
236
225
 
@@ -238,11 +227,10 @@ describe('judge', function() {
238
227
 
239
228
  describe('length', function() {
240
229
 
241
- var j, jIs;
230
+ var j;
242
231
 
243
232
  beforeEach(function() {
244
- j = new judge.Watcher(document.getElementById('foo_two'));
245
- jIs = new judge.Watcher(document.getElementById('foo_two_is'));
233
+ j = new judge.Watcher(document.getElementById('foo_two_foobar'));
246
234
  });
247
235
 
248
236
  it('validates valid input', function() {
@@ -255,15 +243,9 @@ describe('judge', function() {
255
243
  expect(j.validate().valid).toEqual(true);
256
244
  });
257
245
 
258
- it('returns custom message when present', function() {
259
- j.element.value = 'abc';
260
- _(j.validators).first().options.too_short = 'oh dear';
261
- expect(j.validate().messages).toContain('oh dear');
262
- });
263
-
264
- it('returns default message', function() {
246
+ it('returns message', function() {
265
247
  j.element.value = 'abc';
266
- expect(j.validate().messages).toContain(judge.utils.countMsg(j.defaultMessages.too_short, 5));
248
+ expect(j.validate().messages).not.toBeEmpty();
267
249
  });
268
250
 
269
251
  it('invalidates when value is under minimum', function() {
@@ -276,10 +258,10 @@ describe('judge', function() {
276
258
  expect(j.validate().valid).toEqual(false);
277
259
  });
278
260
 
279
- it('invalidates when value is not equal to is', function() {
280
- jIs.element.value = 'abc';
281
- expect(jIs.validate().valid).toEqual(false);
282
- });
261
+ //it('invalidates when value is not equal to is', function() {
262
+ // jIs.element.value = 'abc';
263
+ // expect(jIs.validate().valid).toEqual(false);
264
+ //});
283
265
  });
284
266
 
285
267
  describe('exclusion', function() {
@@ -291,24 +273,16 @@ describe('judge', function() {
291
273
  });
292
274
 
293
275
  it('validates when value is not in array', function() {
294
- j.element.value = 'abc';
295
276
  expect(j.validate().valid).toEqual(true);
296
277
  });
297
278
 
298
279
  it('invalidates when value is in array', function() {
299
- j.element.value = 'foo';
280
+ j.element.children[1].selected = true;
300
281
  expect(j.validate().valid).toEqual(false);
301
- });
302
-
303
- it('returns default message', function() {
304
- j.element.value = 'foo';
305
- expect(j.validate().messages).toContain(j.defaultMessages.exclusion);
306
- });
282
+ });
307
283
 
308
- it('returns default message', function() {
309
- _(j.validators).first().options.message = 'restricted';
310
- j.element.value = 'foo';
311
- expect(j.validate().messages).toContain('restricted');
284
+ it('returns message', function() {
285
+ expect(j.validate().messages).not.toBeEmpty();
312
286
  });
313
287
 
314
288
  });
@@ -322,24 +296,16 @@ describe('judge', function() {
322
296
  });
323
297
 
324
298
  it('validates when value is in array', function() {
325
- j.element.value = '3';
299
+ j.element.children[1].selected = true;
326
300
  expect(j.validate().valid).toEqual(true);
327
301
  });
328
302
 
329
303
  it('invalidates when value is not in array', function() {
330
- j.element.value = '10';
331
304
  expect(j.validate().valid).toEqual(false);
332
305
  });
333
306
 
334
- it('returns default message', function() {
335
- j.element.value = '10';
336
- expect(j.validate().messages).toContain(j.defaultMessages.inclusion);
337
- });
338
-
339
- it('returns default message', function() {
340
- _(j.validators).first().options.message = 'must be one of defined values';
341
- j.element.value = 'foo';
342
- expect(j.validate().messages).toContain('must be one of defined values');
307
+ it('returns message', function() {
308
+ expect(j.validate().messages).not.toBeEmpty();
343
309
  });
344
310
 
345
311
  });
@@ -358,13 +324,13 @@ describe('judge', function() {
358
324
  it('invalidates when value is not a number', function() {
359
325
  j.element.value = 'foo bar';
360
326
  expect(j.validate().valid).toEqual(false);
361
- expect(j.validate().messages).toContain(j.defaultMessages.not_a_number);
327
+ expect(j.validate().messages).not.toBeEmpty();
362
328
  });
363
329
 
364
330
  it('validates odd / invalidates not odd', function() {
365
331
  j.element.value = '2';
366
332
  expect(j.validate().valid).toEqual(false);
367
- expect(j.validate().messages).toContain(j.defaultMessages.odd);
333
+ expect(j.validate().messages).not.toBeEmpty();
368
334
  j.element.value = '1';
369
335
  expect(j.validate().valid).toEqual(true);
370
336
  });
@@ -372,7 +338,7 @@ describe('judge', function() {
372
338
  it('validates even / invalidates not even', function() {
373
339
  jEven.element.value = '1';
374
340
  expect(jEven.validate().valid).toEqual(false);
375
- expect(jEven.validate().messages).toContain(jEven.defaultMessages.even);
341
+ expect(jEven.validate().messages).not.toBeEmpty();
376
342
  jEven.element.value = '2';
377
343
  expect(jEven.validate().valid).toEqual(true);
378
344
  });
@@ -387,7 +353,7 @@ describe('judge', function() {
387
353
  it('invalidates float', function() {
388
354
  j.element.value = '1.1';
389
355
  expect(j.validate().valid).toEqual(false);
390
- expect(j.validate().messages).toContain(j.defaultMessages.not_an_integer);
356
+ expect(j.validate().messages).not.toBeEmpty();
391
357
  });
392
358
 
393
359
  });
@@ -397,10 +363,10 @@ describe('judge', function() {
397
363
  it('invalidates not greater than', function() {
398
364
  jGt.element.value = '6';
399
365
  expect(jGt.validate().valid).toEqual(false);
400
- expect(jGt.validate().messages).toContain(judge.utils.countMsg(jGt.defaultMessages.greater_than, 7));
366
+ expect(jGt.validate().messages).not.toBeEmpty();
401
367
  jGt.element.value = '7';
402
368
  expect(jGt.validate().valid).toEqual(false);
403
- expect(jGt.validate().messages).toContain(judge.utils.countMsg(jGt.defaultMessages.greater_than, 7));
369
+ expect(jGt.validate().messages).not.toBeEmpty();
404
370
  });
405
371
 
406
372
  it('validates greater than', function() {
@@ -426,30 +392,30 @@ describe('judge', function() {
426
392
 
427
393
  });
428
394
 
429
- it('validates equal to', function() {
430
- jLt.element.value = '5';
431
- expect(jLt.validate().valid).toEqual(false);
432
- jLt.element.value = '6';
433
- expect(jLt.validate().valid).toEqual(true);
434
- });
395
+ //it('validates equal to', function() {
396
+ // jLt.element.value = '5';
397
+ // expect(jLt.validate().valid).toEqual(false);
398
+ // jLt.element.value = '6';
399
+ // expect(jLt.validate().valid).toEqual(true);
400
+ //});
435
401
 
436
- it('validates less than or equal to', function() {
437
- j.element.value = '5';
438
- expect(j.validate().valid).toEqual(true);
439
- j.element.value = '7';
440
- expect(j.validate().valid).toEqual(true);
441
- j.element.value = '9';
442
- expect(j.validate().valid).toEqual(false);
443
- });
402
+ //it('validates less than or equal to', function() {
403
+ // j.element.value = '5';
404
+ // expect(j.validate().valid).toEqual(true);
405
+ // j.element.value = '7';
406
+ // expect(j.validate().valid).toEqual(true);
407
+ // j.element.value = '9';
408
+ // expect(j.validate().valid).toEqual(false);
409
+ //});
444
410
 
445
- it('validates greater than or equal to', function() {
446
- jEven.element.value = '20';
447
- expect(jEven.validate().valid).toEqual(true);
448
- jEven.element.value = '2';
449
- expect(jEven.validate().valid).toEqual(true);
450
- jEven.element.value = '1';
451
- expect(jEven.validate().valid).toEqual(false);
452
- });
411
+ //it('validates greater than or equal to', function() {
412
+ // jEven.element.value = '20';
413
+ // expect(jEven.validate().valid).toEqual(true);
414
+ // jEven.element.value = '2';
415
+ // expect(jEven.validate().valid).toEqual(true);
416
+ // jEven.element.value = '1';
417
+ // expect(jEven.validate().valid).toEqual(false);
418
+ //});
453
419
 
454
420
  });
455
421
 
@@ -460,18 +426,17 @@ describe('judge', function() {
460
426
  var j;
461
427
 
462
428
  beforeEach(function() {
463
- j = new judge.Watcher(document.getElementById('foo_five'));
429
+ j = new judge.Watcher(document.getElementById('foo_five_wi'));
464
430
  });
465
431
 
466
- it('validates value matching with', function() {
467
- j.element.value = 'ABCabc123';
468
- expect(j.validate().valid).toEqual(true);
432
+ it('invalidates value matching with', function() {
433
+ expect(j.validate().valid).toEqual(false);
434
+ expect(j.validate().messages).not.toBeEmpty();
469
435
  });
470
436
 
471
437
  it('invalidates value not matching with', function() {
472
- j.element.value = '123';
473
- expect(j.validate().valid).toEqual(false);
474
- expect(j.validate().messages).toContain(j.defaultMessages.invalid);
438
+ j.element.children[1].selected = true;
439
+ expect(j.validate().valid).toEqual(true);
475
440
  });
476
441
 
477
442
  });
@@ -484,15 +449,14 @@ describe('judge', function() {
484
449
  j = new judge.Watcher(document.getElementById('foo_five_wo'));
485
450
  });
486
451
 
487
- it('validates value matching with', function() {
488
- j.element.value = '12345';
452
+ it('validates value not matching with', function() {
489
453
  expect(j.validate().valid).toEqual(true);
490
454
  });
491
455
 
492
- it('invalidates value not matching with', function() {
493
- j.element.value = 'AbC123';
456
+ it('invalidates value matching with', function() {
457
+ j.element.children[1].selected = true;
494
458
  expect(j.validate().valid).toEqual(false);
495
- expect(j.validate().messages).toContain(j.defaultMessages.invalid);
459
+ expect(j.validate().messages).not.toBeEmpty();
496
460
  });
497
461
 
498
462
  });
@@ -516,11 +480,6 @@ describe('judge', function() {
516
480
  expect(j.validate().valid).toEqual(false);
517
481
  });
518
482
 
519
- it('invalidates with custom message when present', function() {
520
- _(j.validators).first().options.message = 'must be ticked';
521
- expect(j.validate().messages).toContain('must be ticked');
522
- });
523
-
524
483
  });
525
484
 
526
485
  describe('confirmation', function() {
@@ -544,13 +503,6 @@ describe('judge', function() {
544
503
  expect(j.validate().valid).toEqual(false);
545
504
  });
546
505
 
547
- it('invalidates with custom message when present', function() {
548
- _(j.validators).first().options.message = 'must be same';
549
- j.element.value = 'password';
550
- c.value = 'wrongpassword';
551
- expect(j.validate().messages).toContain('must be same');
552
- });
553
-
554
506
  });
555
507
 
556
508
  });
@@ -605,14 +557,6 @@ describe('judge', function() {
605
557
  });
606
558
 
607
559
  });
608
-
609
- describe('countMsg', function() {
610
-
611
- it('subs string', function() {
612
- expect(judge.utils.countMsg('should be less than %{count}', 5)).toEqual('should be less than 5');
613
- });
614
-
615
- });
616
560
 
617
561
  describe('isInt', function() {
618
562