judge 0.2.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 (71) hide show
  1. data/.document +5 -0
  2. data/.travis.yml +18 -0
  3. data/Gemfile +12 -0
  4. data/Gemfile.lock +112 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +20 -0
  7. data/Rakefile +51 -0
  8. data/VERSION +1 -0
  9. data/judge.gemspec +155 -0
  10. data/lib/generators/judge/judge_generator.rb +21 -0
  11. data/lib/generators/judge/templates/json2.js +483 -0
  12. data/lib/generators/judge/templates/judge.js +295 -0
  13. data/lib/generators/judge/templates/underscore.js +840 -0
  14. data/lib/judge.rb +4 -0
  15. data/lib/judge/helpers.rb +31 -0
  16. data/lib/tasks/js_tests.rake +27 -0
  17. data/spec/javascripts/JudgeSpec.js +670 -0
  18. data/spec/javascripts/fixtures/form.html +50 -0
  19. data/spec/javascripts/helpers/customMatchers.js +20 -0
  20. data/spec/javascripts/helpers/jasmine-jquery.js +204 -0
  21. data/spec/javascripts/helpers/jquery-1.5.1.min.js +18 -0
  22. data/spec/javascripts/helpers/json2.js +482 -0
  23. data/spec/javascripts/helpers/underscore.js +824 -0
  24. data/spec/javascripts/support/jasmine.yml +79 -0
  25. data/spec/javascripts/support/jasmine_config.rb +6 -0
  26. data/spec/javascripts/support/jasmine_runner.rb +32 -0
  27. data/spec/javascripts/support/phantomRunner.js +28 -0
  28. data/test/dummy/Rakefile +7 -0
  29. data/test/dummy/app/controllers/application_controller.rb +3 -0
  30. data/test/dummy/app/controllers/foos_controller.rb +5 -0
  31. data/test/dummy/app/helpers/application_helper.rb +2 -0
  32. data/test/dummy/app/models/foo.rb +11 -0
  33. data/test/dummy/app/views/foos/new.html.erb +42 -0
  34. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  35. data/test/dummy/config.ru +4 -0
  36. data/test/dummy/config/application.rb +45 -0
  37. data/test/dummy/config/boot.rb +10 -0
  38. data/test/dummy/config/database.yml +22 -0
  39. data/test/dummy/config/environment.rb +5 -0
  40. data/test/dummy/config/environments/development.rb +26 -0
  41. data/test/dummy/config/environments/production.rb +49 -0
  42. data/test/dummy/config/environments/test.rb +35 -0
  43. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  44. data/test/dummy/config/initializers/inflections.rb +10 -0
  45. data/test/dummy/config/initializers/mime_types.rb +5 -0
  46. data/test/dummy/config/initializers/secret_token.rb +7 -0
  47. data/test/dummy/config/initializers/session_store.rb +8 -0
  48. data/test/dummy/config/locales/en.yml +5 -0
  49. data/test/dummy/config/routes.rb +3 -0
  50. data/test/dummy/db/development.sqlite3 +0 -0
  51. data/test/dummy/db/migrate/20110624115516_create_foos.rb +26 -0
  52. data/test/dummy/db/schema.rb +34 -0
  53. data/test/dummy/db/test.sqlite3 +0 -0
  54. data/test/dummy/log/development.log +59 -0
  55. data/test/dummy/log/production.log +0 -0
  56. data/test/dummy/log/server.log +0 -0
  57. data/test/dummy/public/404.html +26 -0
  58. data/test/dummy/public/422.html +26 -0
  59. data/test/dummy/public/500.html +26 -0
  60. data/test/dummy/public/favicon.ico +0 -0
  61. data/test/dummy/public/javascripts/application.js +2 -0
  62. data/test/dummy/public/javascripts/controls.js +965 -0
  63. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  64. data/test/dummy/public/javascripts/effects.js +1123 -0
  65. data/test/dummy/public/javascripts/prototype.js +6001 -0
  66. data/test/dummy/public/javascripts/rails.js +175 -0
  67. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  68. data/test/dummy/script/rails +6 -0
  69. data/test/judge_test.rb +73 -0
  70. data/test/test_helper.rb +23 -0
  71. metadata +275 -0
data/lib/judge.rb ADDED
@@ -0,0 +1,4 @@
1
+ require File.dirname(__FILE__) + '/judge/helpers'
2
+
3
+ ::ActionView::Helpers::FormBuilder.send(:include, Judge::FieldHelpers)
4
+ ::ActionView::Helpers::FormHelper.send(:include, Judge::FormHelpers)
@@ -0,0 +1,31 @@
1
+ module Judge
2
+
3
+ module FieldHelpers
4
+
5
+ include ActionView::Helpers::TagHelper
6
+
7
+ %w{text_field text_area}.each do |type|
8
+ helper = <<-END
9
+ def validated_#{type}(method, options = {})
10
+ validators = self.object.class.validators_on(method).collect{ |v| { :kind => v.kind.to_s, :options => v.options } }
11
+ options = { "data-validate" => validators.to_json }.merge(options)
12
+ @template.#{type}(self.object_name, method, options)
13
+ end
14
+ END
15
+ class_eval helper, __FILE__, __LINE__
16
+ end
17
+
18
+ end
19
+
20
+ module FormHelpers
21
+
22
+ def validated_form_for(record_or_name_or_array, *args, &proc)
23
+ options = args.extract_options!
24
+ options[:html] ||= {}
25
+ options[:html]["data-error-messages"] = I18n.t("errors.messages").to_json
26
+ form_for(record_or_name_or_array, *(args << options), &proc)
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,27 @@
1
+ namespace :jasmine do
2
+ task :require_phantom_js do
3
+ sh "which phantomjs" do |ok, res|
4
+ fail 'Cannot find phantomjs on $PATH' unless ok
5
+ end
6
+ end
7
+
8
+ desc "Run continuous integration tests headlessly with phantom.js"
9
+ task :phantom => ['jasmine:require', 'jasmine:require_phantom_js'] do
10
+ support_dir = File.expand_path('../../spec/javascripts/support', File.dirname(__FILE__))
11
+ config_overrides = File.join(support_dir, 'jasmine_config.rb')
12
+ require config_overrides if File.exists?(config_overrides)
13
+ phantom_js_runner = File.join(support_dir, 'phantomRunner.js')
14
+
15
+ config = Jasmine::Config.new
16
+
17
+ # start the Jasmine server and wait up to 10 seconds for it to be running:
18
+ config.start_jasmine_server
19
+
20
+ jasmine_url = "#{config.jasmine_host}:#{config.jasmine_server_port}"
21
+ puts "Running tests against #{jasmine_url}"
22
+ sh "phantomjs #{phantom_js_runner} #{jasmine_url}" do |ok, res|
23
+ fail "jasmine suite failed" unless ok
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,670 @@
1
+ describe('judge', function() {
2
+
3
+ beforeEach(function() {
4
+ this.addMatchers(customMatchers);
5
+ });
6
+
7
+ describe('judge.validate', function() {
8
+
9
+ beforeEach(function() {
10
+ loadFixtures('spec/javascripts/fixtures/form.html');
11
+ });
12
+
13
+ it('validates a single element', function() {
14
+ var e = document.getElementById('foo_one'),
15
+ v = judge.validate(e);
16
+ expect(v.length).toEqual(1);
17
+ });
18
+
19
+ it('validates a collection of elements', function() {
20
+ var e = document.querySelectorAll('.field input'),
21
+ v = judge.validate(e);
22
+ expect(v.length).toBeGreaterThan(1);
23
+ });
24
+
25
+ });
26
+
27
+ describe('judge.Watcher', function() {
28
+
29
+ var j;
30
+
31
+ beforeEach(function() {
32
+ loadFixtures('spec/javascripts/fixtures/form.html');
33
+ j = new judge.Watcher(document.getElementById('foo_one'));
34
+ });
35
+
36
+ it('returns new instance of judge', function() {
37
+ expect(typeof j).toEqual('object');
38
+ expect(j.constructor).toEqual(judge.Watcher);
39
+ });
40
+
41
+ it('associates with element', function() {
42
+ expect(j.element).toEqual(document.getElementById('foo_one'));
43
+ });
44
+
45
+ it('holds validators', function() {
46
+ expect(_(j.validators).isArray()).toEqual(true);
47
+ expect(_(j.validators).isEmpty()).toEqual(false);
48
+ });
49
+
50
+ it('holds default messages', function() {
51
+ expect(j.defaultMessages).toBeInstanceOf(Object);
52
+ });
53
+
54
+ it('has validation methods in prototype', function() {
55
+ expect(j.validates()).not.toBeEmpty();
56
+ expect(_(j.validates()).keys()).toContain('presence');
57
+ });
58
+
59
+ it('has custom validation methods when defined by user', function() {
60
+ judge.customValidators.phatness = function(options) { return { valid: true }; };
61
+ expect(_(j.validates()).keys()).toContain('phatness');
62
+ });
63
+
64
+ it('throws error if element has no data-validate attribute', function() {
65
+ var e = document.createElement('input');
66
+ e.type = 'text';
67
+ expect(function() { new judge.Watcher(e); }).toThrow();
68
+ });
69
+
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
+ it('throws error if no element is passed', function() {
79
+ expect(function() { new judge.Watcher(); }).toThrow();
80
+ });
81
+
82
+ it('throws error if element is not validatable', function() {
83
+ var e = document.createElement('p');
84
+ expect(function() { new judge.Watcher(e); }).toThrow();
85
+ });
86
+
87
+ });
88
+
89
+ describe('judge.store', function() {
90
+
91
+ var e;
92
+
93
+ beforeEach(function() {
94
+ loadFixtures('spec/javascripts/fixtures/form.html');
95
+ judge.store.clear();
96
+ e = document.getElementById('foo_one');
97
+ });
98
+
99
+ describe('save / get', function() {
100
+
101
+ it('saves Watcher against key', function() {
102
+ judge.store.save('mykey', e);
103
+ expect(_(judge.store.get('mykey')).first().constructor).toEqual(judge.Watcher);
104
+ expect(_(judge.store.get('mykey')).first().element).toBe(e);
105
+ });
106
+
107
+ it('does not save Watcher if element has already been stored against same key', function() {
108
+ judge.store.save('mykey', e);
109
+ judge.store.save('mykey', e);
110
+ expect(judge.store.get('mykey').length).toEqual(1);
111
+ });
112
+
113
+ it('does save Watcher again if key is different', function() {
114
+ judge.store.save('mykey', e);
115
+ judge.store.save('mykey2', e);
116
+ expect(judge.store.get('mykey').length).toEqual(1);
117
+ expect(judge.store.get('mykey2').length).toEqual(1);
118
+ });
119
+
120
+ });
121
+
122
+ describe('getDOM', function() {
123
+
124
+ it('returns DOM elements from stored Watchers', function() {
125
+ judge.store.save('mykey', e);
126
+ judge.store.save('mykey', document.getElementById('foo_two'));
127
+ var d = judge.store.getDOM('mykey');
128
+ expect(d.length).toEqual(2);
129
+ expect(Object.prototype.toString.call(d[0])).toEqual('[object HTMLInputElement]');
130
+ });
131
+
132
+ it('returns store object with watchers converted to elements if no key given', function() {
133
+ judge.store.save('mykey', e);
134
+ judge.store.save('mykey2', document.getElementById('foo_two'));
135
+ judge.store.save('mykey2', document.getElementById('foo_three'));
136
+ var d = judge.store.getDOM();
137
+ expect(d.mykey.length).toEqual(1);
138
+ expect(d.mykey2.length).toEqual(2);
139
+ expect(Object.prototype.toString.call(d.mykey[0])).toEqual('[object HTMLInputElement]');
140
+ });
141
+
142
+ it('returns null if key not found', function() {
143
+ expect(judge.store.getDOM('notakey')).toEqual(null);
144
+ });
145
+
146
+ });
147
+
148
+ describe('remove', function() {
149
+
150
+ it('removes Watcher from store', function() {
151
+ judge.store.save('mykey', e);
152
+ expect(judge.store.remove('mykey', e)).not.toEqual(null);
153
+ expect(judge.store.get('mykey').length).toEqual(0);
154
+ });
155
+
156
+ it('returns null if key not found', function() {
157
+ judge.store.save('mykey', e);
158
+ expect(judge.store.remove('notakey', e)).toEqual(null);
159
+ });
160
+
161
+ });
162
+
163
+ describe('clear', function() {
164
+
165
+ it('clears entire store if no key is passed', function() {
166
+ judge.store.save('mykey', e);
167
+ judge.store.clear();
168
+ expect(judge.store.get()).toEqual({});
169
+ });
170
+
171
+ it('clears all Watchers against key', function() {
172
+ judge.store.save('mykey', e);
173
+ judge.store.save('mykey2', e);
174
+ judge.store.clear('mykey');
175
+ expect(judge.store.get('mykey')).toEqual([]);
176
+ expect(judge.store.get('mykey2').length).toEqual(1);
177
+ });
178
+
179
+ it('returns null if key not found', function() {
180
+ expect(judge.store.clear('notakey')).toEqual(null);
181
+ });
182
+
183
+ });
184
+
185
+ });
186
+
187
+ describe('judge.Watcher instance methods', function() {
188
+
189
+ beforeEach(function() {
190
+ loadFixtures('spec/javascripts/fixtures/form.html');
191
+ });
192
+
193
+ describe('validate method', function() {
194
+
195
+ var j, r;
196
+
197
+ beforeEach(function() {
198
+ j = new judge.Watcher(document.getElementById('foo_one'));
199
+ r = j.validate();
200
+ });
201
+
202
+ it('returns element', function() {
203
+ expect(r.element).toBeInstanceOf(Object);
204
+ });
205
+
206
+ it('returns validity', function() {
207
+ expect(typeof r.valid).toEqual('boolean');
208
+ });
209
+
210
+ it('returns messages', function() {
211
+ expect(r.messages).toBeInstanceOf(Array);
212
+ });
213
+
214
+ });
215
+
216
+ describe('presence', function() {
217
+
218
+ var j;
219
+
220
+ beforeEach(function() {
221
+ j = new judge.Watcher(document.getElementById('foo_one'));
222
+ });
223
+
224
+ it('invalidates empty input', function() {
225
+ expect(j.validate().valid).toEqual(false);
226
+ });
227
+
228
+ it('returns custom message when present', function() {
229
+ _(j.validators).first().options.message = 'hello';
230
+ expect(j.validate().messages).toContain('hello');
231
+ });
232
+
233
+ it('returns default message', function() {
234
+ expect(j.validate().messages).toContain(j.defaultMessages.blank);
235
+ });
236
+
237
+ it('validates non-empty input', function() {
238
+ j.element.value = 'abcde';
239
+ expect(j.validate().valid).toEqual(true);
240
+ });
241
+
242
+ });
243
+
244
+ describe('length', function() {
245
+
246
+ var j, jIs;
247
+
248
+ beforeEach(function() {
249
+ j = new judge.Watcher(document.getElementById('foo_two'));
250
+ jIs = new judge.Watcher(document.getElementById('foo_two_is'));
251
+ });
252
+
253
+ it('validates valid input', function() {
254
+ j.element.value = 'abcdef';
255
+ expect(j.validate().valid).toEqual(true);
256
+ });
257
+
258
+ it('validates allow_blank', function() {
259
+ j.element.value = '';
260
+ expect(j.validate().valid).toEqual(true);
261
+ });
262
+
263
+ it('returns custom message when present', function() {
264
+ j.element.value = 'abc';
265
+ _(j.validators).first().options.too_short = 'oh dear';
266
+ expect(j.validate().messages).toContain('oh dear');
267
+ });
268
+
269
+ it('returns default message', function() {
270
+ j.element.value = 'abc';
271
+ expect(j.validate().messages).toContain(judge.utils.countMsg(j.defaultMessages.too_short, 5));
272
+ });
273
+
274
+ it('invalidates when value is under minimum', function() {
275
+ j.element.value = 'abc';
276
+ expect(j.validate().valid).toEqual(false);
277
+ });
278
+
279
+ it('invalidates when value is over maximum', function() {
280
+ j.element.value = 'abcdefghijkl';
281
+ expect(j.validate().valid).toEqual(false);
282
+ });
283
+
284
+ it('invalidates when value is not equal to is', function() {
285
+ jIs.element.value = 'abc';
286
+ expect(jIs.validate().valid).toEqual(false);
287
+ });
288
+ });
289
+
290
+ describe('exclusion', function() {
291
+
292
+ var j;
293
+
294
+ beforeEach(function() {
295
+ j = new judge.Watcher(document.getElementById('foo_three'));
296
+ });
297
+
298
+ it('validates when value is not in array', function() {
299
+ j.element.value = 'abc';
300
+ expect(j.validate().valid).toEqual(true);
301
+ });
302
+
303
+ it('invalidates when value is in array', function() {
304
+ j.element.value = 'foo';
305
+ expect(j.validate().valid).toEqual(false);
306
+ });
307
+
308
+ it('returns default message', function() {
309
+ j.element.value = 'foo';
310
+ expect(j.validate().messages).toContain(j.defaultMessages.exclusion);
311
+ });
312
+
313
+ it('returns default message', function() {
314
+ _(j.validators).first().options.message = 'restricted';
315
+ j.element.value = 'foo';
316
+ expect(j.validate().messages).toContain('restricted');
317
+ });
318
+
319
+ });
320
+
321
+ describe('inclusion', function() {
322
+
323
+ var j;
324
+
325
+ beforeEach(function() {
326
+ j = new judge.Watcher(document.getElementById('foo_three_inc'));
327
+ });
328
+
329
+ it('validates when value is in array', function() {
330
+ j.element.value = '3';
331
+ expect(j.validate().valid).toEqual(true);
332
+ });
333
+
334
+ it('invalidates when value is not in array', function() {
335
+ j.element.value = '10';
336
+ expect(j.validate().valid).toEqual(false);
337
+ });
338
+
339
+ it('returns default message', function() {
340
+ j.element.value = '10';
341
+ expect(j.validate().messages).toContain(j.defaultMessages.inclusion);
342
+ });
343
+
344
+ it('returns default message', function() {
345
+ _(j.validators).first().options.message = 'must be one of defined values';
346
+ j.element.value = 'foo';
347
+ expect(j.validate().messages).toContain('must be one of defined values');
348
+ });
349
+
350
+ });
351
+
352
+ describe('numericality', function() {
353
+
354
+ var j, jEven, jGt, jLt;
355
+
356
+ beforeEach(function() {
357
+ j = new judge.Watcher(document.getElementById('foo_four'));
358
+ jEven = new judge.Watcher(document.getElementById('foo_four_even'));
359
+ jGt = new judge.Watcher(document.getElementById('foo_four_gt'));
360
+ jLt = new judge.Watcher(document.getElementById('foo_four_lt'));
361
+ });
362
+
363
+ it('invalidates when value is not a number', function() {
364
+ j.element.value = 'foo bar';
365
+ expect(j.validate().valid).toEqual(false);
366
+ expect(j.validate().messages).toContain(j.defaultMessages.not_a_number);
367
+ });
368
+
369
+ it('validates odd / invalidates not odd', function() {
370
+ j.element.value = '2';
371
+ expect(j.validate().valid).toEqual(false);
372
+ expect(j.validate().messages).toContain(j.defaultMessages.odd);
373
+ j.element.value = '1';
374
+ expect(j.validate().valid).toEqual(true);
375
+ });
376
+
377
+ it('validates even / invalidates not even', function() {
378
+ jEven.element.value = '1';
379
+ expect(jEven.validate().valid).toEqual(false);
380
+ expect(jEven.validate().messages).toContain(jEven.defaultMessages.even);
381
+ jEven.element.value = '2';
382
+ expect(jEven.validate().valid).toEqual(true);
383
+ });
384
+
385
+ describe('integer', function() {
386
+
387
+ it('validates int', function() {
388
+ j.element.value = '1';
389
+ expect(j.validate().valid).toEqual(true);
390
+ });
391
+
392
+ it('invalidates float', function() {
393
+ j.element.value = '1.1';
394
+ expect(j.validate().valid).toEqual(false);
395
+ expect(j.validate().messages).toContain(j.defaultMessages.not_an_integer);
396
+ });
397
+
398
+ });
399
+
400
+ describe('greater than', function() {
401
+
402
+ it('invalidates not greater than', function() {
403
+ jGt.element.value = '6';
404
+ expect(jGt.validate().valid).toEqual(false);
405
+ expect(jGt.validate().messages).toContain(judge.utils.countMsg(jGt.defaultMessages.greater_than, 7));
406
+ jGt.element.value = '7';
407
+ expect(jGt.validate().valid).toEqual(false);
408
+ expect(jGt.validate().messages).toContain(judge.utils.countMsg(jGt.defaultMessages.greater_than, 7));
409
+ });
410
+
411
+ it('validates greater than', function() {
412
+ jGt.element.value = '8';
413
+ expect(jGt.validate().valid).toEqual(true);
414
+ });
415
+
416
+ });
417
+
418
+ describe('less than', function() {
419
+
420
+ it('invalidates not less than', function() {
421
+ jLt.element.value = '8';
422
+ expect(jLt.validate().valid).toEqual(false);
423
+ jLt.element.value = '7';
424
+ expect(jLt.validate().valid).toEqual(false);
425
+ });
426
+
427
+ it('validates less than', function() {
428
+ jLt.element.value = '6';
429
+ expect(jLt.validate().valid).toEqual(true);
430
+ });
431
+
432
+ });
433
+
434
+ it('validates equal to', function() {
435
+ jLt.element.value = '5';
436
+ expect(jLt.validate().valid).toEqual(false);
437
+ jLt.element.value = '6';
438
+ expect(jLt.validate().valid).toEqual(true);
439
+ });
440
+
441
+ it('validates less than or equal to', function() {
442
+ j.element.value = '5';
443
+ expect(j.validate().valid).toEqual(true);
444
+ j.element.value = '7';
445
+ expect(j.validate().valid).toEqual(true);
446
+ j.element.value = '9';
447
+ expect(j.validate().valid).toEqual(false);
448
+ });
449
+
450
+ it('validates greater than or equal to', function() {
451
+ jEven.element.value = '20';
452
+ expect(jEven.validate().valid).toEqual(true);
453
+ jEven.element.value = '2';
454
+ expect(jEven.validate().valid).toEqual(true);
455
+ jEven.element.value = '1';
456
+ expect(jEven.validate().valid).toEqual(false);
457
+ });
458
+
459
+ });
460
+
461
+ describe('format', function() {
462
+
463
+ describe('with', function() {
464
+
465
+ var j;
466
+
467
+ beforeEach(function() {
468
+ j = new judge.Watcher(document.getElementById('foo_five'));
469
+ });
470
+
471
+ it('validates value matching with', function() {
472
+ j.element.value = 'ABCabc123';
473
+ expect(j.validate().valid).toEqual(true);
474
+ });
475
+
476
+ it('invalidates value not matching with', function() {
477
+ j.element.value = '123';
478
+ expect(j.validate().valid).toEqual(false);
479
+ expect(j.validate().messages).toContain(j.defaultMessages.invalid);
480
+ });
481
+
482
+ });
483
+
484
+ describe('without', function() {
485
+
486
+ var j;
487
+
488
+ beforeEach(function() {
489
+ j = new judge.Watcher(document.getElementById('foo_five_wo'));
490
+ });
491
+
492
+ it('validates value matching with', function() {
493
+ j.element.value = '12345';
494
+ expect(j.validate().valid).toEqual(true);
495
+ });
496
+
497
+ it('invalidates value not matching with', function() {
498
+ j.element.value = 'AbC123';
499
+ expect(j.validate().valid).toEqual(false);
500
+ expect(j.validate().messages).toContain(j.defaultMessages.invalid);
501
+ });
502
+
503
+ });
504
+
505
+ });
506
+
507
+ });
508
+
509
+ describe('utils', function() {
510
+
511
+ describe('isValidatable', function() {
512
+
513
+ it('returns true if judge can validate object', function() {
514
+ var i = document.createElement('input'),
515
+ s = document.createElement('select'),
516
+ t = document.createElement('textarea');
517
+ expect(judge.utils.isValidatable(i)).toEqual(true);
518
+ expect(judge.utils.isValidatable(s)).toEqual(true);
519
+ expect(judge.utils.isValidatable(t)).toEqual(true);
520
+ });
521
+
522
+ it('returns false otherwise', function() {
523
+ var p = document.createElement('p');
524
+ expect(judge.utils.isValidatable(p)).toEqual(false);
525
+ });
526
+
527
+ });
528
+
529
+ describe('isCollection', function() {
530
+
531
+ beforeEach(function() {
532
+ loadFixtures('spec/javascripts/fixtures/form.html');
533
+ });
534
+
535
+ it('returns true if judge can treat object as collection', function() {
536
+ var a = [],
537
+ n = document.getElementsByTagName('input');
538
+ expect(judge.utils.isCollection(a)).toEqual(true);
539
+ expect(judge.utils.isCollection(n)).toEqual(true);
540
+ });
541
+
542
+ it('returns false otherwise', function() {
543
+ var o = { a:1, b:2 };
544
+ expect(judge.utils.isCollection(o)).toEqual(false);
545
+ });
546
+
547
+ });
548
+
549
+ describe('getObjectString', function() {
550
+
551
+ it('returns type as represented in Object.prototype.toString', function() {
552
+ var i = document.createElement('input'),
553
+ s = document.createElement('select');
554
+ expect(judge.utils.getObjectString(i)).toEqual('HTMLInputElement');
555
+ expect(judge.utils.getObjectString(s)).toEqual('HTMLSelectElement');
556
+ });
557
+
558
+ });
559
+
560
+ describe('countMsg', function() {
561
+
562
+ it('subs string', function() {
563
+ expect(judge.utils.countMsg('should be less than %{count}', 5)).toEqual('should be less than 5');
564
+ });
565
+
566
+ });
567
+
568
+ describe('isInt', function() {
569
+
570
+ it('returns true when int', function() {
571
+ expect(judge.utils.isInt(1)).toEqual(true);
572
+ expect(judge.utils.isInt(1.)).toEqual(true);
573
+ expect(judge.utils.isInt(1.0)).toEqual(true);
574
+ expect(judge.utils.isInt(0)).toEqual(true);
575
+ expect(judge.utils.isInt(-1)).toEqual(true);
576
+ });
577
+
578
+ it('returns false when not int', function() {
579
+ expect(judge.utils.isInt(1.1)).toEqual(false);
580
+ expect(judge.utils.isInt(-1.1)).toEqual(false);
581
+ });
582
+
583
+ });
584
+
585
+ describe('isFloat', function() {
586
+
587
+ it('returns true when float', function() {
588
+ expect(judge.utils.isFloat(1.1)).toEqual(true);
589
+ expect(judge.utils.isFloat(-1.1)).toEqual(true);
590
+ });
591
+
592
+ it('returns false when not float', function() {
593
+ expect(judge.utils.isFloat(1)).toEqual(false);
594
+ expect(judge.utils.isFloat(1.)).toEqual(false);
595
+ expect(judge.utils.isFloat(1.0)).toEqual(false);
596
+ expect(judge.utils.isFloat(0)).toEqual(false);
597
+ expect(judge.utils.isFloat(-1)).toEqual(false);
598
+ });
599
+
600
+ });
601
+
602
+ describe('isEven', function() {
603
+
604
+ it('returns true when even', function() {
605
+ expect(judge.utils.isEven(2)).toEqual(true);
606
+ expect(judge.utils.isEven(0)).toEqual(true);
607
+ expect(judge.utils.isEven(-2)).toEqual(true);
608
+ });
609
+
610
+ it('returns false when odd', function() {
611
+ expect(judge.utils.isEven(1)).toEqual(false);
612
+ expect(judge.utils.isEven(-1)).toEqual(false);
613
+ });
614
+
615
+ });
616
+
617
+ describe('isOdd', function() {
618
+
619
+ it('returns true when odd', function() {
620
+ expect(judge.utils.isOdd(1)).toEqual(true);
621
+ expect(judge.utils.isOdd(-1)).toEqual(true);
622
+ });
623
+
624
+ it('returns false when even', function() {
625
+ expect(judge.utils.isOdd(2)).toEqual(false);
626
+ expect(judge.utils.isOdd(0)).toEqual(false);
627
+ expect(judge.utils.isOdd(-2)).toEqual(false);
628
+ });
629
+
630
+ });
631
+
632
+ describe('operate', function() {
633
+
634
+ it('evaluates and returns true or false', function() {
635
+ expect(judge.utils.operate(1, '<', 4)).toEqual(true);
636
+ expect(judge.utils.operate(1, '==', 1)).toEqual(true);
637
+ expect(judge.utils.operate(1, '>=', 4)).toEqual(false);
638
+ });
639
+
640
+ });
641
+
642
+ describe('convertRegExp', function() {
643
+
644
+ it('converts string format options-first ruby regexp into RegExp object', function() {
645
+ var re = judge.utils.convertRegExp('(?mix:[A-Z0-9])');
646
+ expect(re).toBeInstanceOf(RegExp);
647
+ expect(re.source).toEqual('[A-Z0-9]');
648
+ expect(re.multiline).toEqual(true);
649
+ expect(re.global).toEqual(false);
650
+ });
651
+
652
+ });
653
+
654
+ describe('convertFlags', function() {
655
+
656
+ it('returns m if present in options string without negation', function() {
657
+ expect(judge.utils.convertFlags('imx')).toEqual('m');
658
+ });
659
+
660
+ it('returns empty string otherwise', function() {
661
+ expect(judge.utils.convertFlags('-imx')).toEqual('');
662
+ expect(judge.utils.convertFlags('ix')).toEqual('');
663
+ expect(judge.utils.convertFlags('-m')).toEqual('');
664
+ });
665
+
666
+ });
667
+
668
+ });
669
+
670
+ });