judge 0.4.3 → 0.5.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/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