judge 1.1.0 → 1.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.
data/.travis.yml CHANGED
@@ -2,7 +2,11 @@ rvm:
2
2
  - 1.9.2
3
3
  - 1.9.3
4
4
 
5
- script: "bundle exec rake spec"
5
+ before_script:
6
+ - "export DISPLAY=:99.0"
7
+ - "sh -e /etc/init.d/xvfb start"
8
+
9
+ script: "bundle exec rake"
6
10
 
7
11
  notifications:
8
12
  recipients:
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  judge
2
2
  =====
3
3
 
4
+ [![Build status](https://secure.travis-ci.org/joecorcoran/judge.png?branch=master)](http://travis-ci.org/joecorcoran/judge)
5
+
4
6
  Client-side form validation in Rails 3.
5
7
 
6
8
  Usage
@@ -8,12 +10,17 @@ Usage
8
10
 
9
11
  See http://judge.joecorcoran.co.uk for documentation.
10
12
 
13
+ Extensions
14
+ ----------
15
+
16
+ Use Judge with your favourite form building tool.
17
+
18
+ * http://github.com/joecorcoran/judge-formtastic
19
+ * http://github.com/joecorcoran/judge-simple_form
20
+
11
21
  License
12
22
  -------
13
23
 
14
24
  Released under an MIT license (see LICENSE.txt).
15
25
 
16
- http://tribesports.com
17
- http://blog.joecorcoran.co.uk
18
-
19
-
26
+ http://blog.joecorcoran.co.uk
data/judge.gemspec CHANGED
@@ -6,19 +6,18 @@ Gem::Specification.new do |s|
6
6
  s.name = "judge"
7
7
  s.version = Judge::VERSION
8
8
  s.homepage = "http://github.com/joecorcoran/judge"
9
- s.license = "MIT"
10
- s.summary = %Q{Simple client side ActiveModel::Validators}
11
- s.description = %Q{Validate forms on the client side, cleanly}
9
+ s.summary = "Simple client side ActiveModel::Validators"
10
+ s.description = "Validate Rails 3 forms on the client side, cleanly"
12
11
  s.email = "joe@tribesports.com"
13
12
  s.authors = ["Joe Corcoran"]
14
13
 
15
14
  s.files = `git ls-files`.split("\n")
16
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.test_files = `git ls-files -- spec/*`.split("\n")
17
16
  s.require_paths = ["lib"]
18
17
 
19
- s.add_development_dependency "jasmine", "~> 1.0.2"
20
- s.add_development_dependency "rails", "~> 3.0.10"
21
- s.add_development_dependency "rspec", "~> 2.8.0"
22
- s.add_development_dependency "sqlite3-ruby", "~> 1.3.2"
23
- s.add_development_dependency "factory_girl_rails", "~> 1.7.0"
18
+ s.add_development_dependency "jasmine", "~> 1.1.2"
19
+ s.add_development_dependency "rails", "~> 3.2"
20
+ s.add_development_dependency "rspec", "~> 2.8"
21
+ s.add_development_dependency "sqlite3-ruby", "~> 1.3.3"
22
+ s.add_development_dependency "factory_girl", "~> 2.6"
24
23
  end
@@ -1,14 +1,17 @@
1
+ // Judge 1.2.0
2
+ // (c) 2011–2012 Joe Corcoran
3
+ // http://raw.github.com/joecorcoran/judge/master/LICENSE.txt
1
4
  // This is the JavaScript part of Judge, a client-side validation gem for Rails 3.
2
5
  // You can find a guide and some more traditional API documentation at <http://joecorcoran.github.com/judge/>.
3
- // Hopefully this page will help you understand what's happening under the hood.
4
-
5
- /* http://raw.github.com/joecorcoran/judge/master/LICENSE.txt */
6
+ // Hopefully the comments here will help you understand what's happening under the hood.
6
7
 
7
8
  /*jshint curly: true, evil: true, newcap: true, noarg: true, strict: false */
8
9
  /*global _: false, JSON: false */
9
10
 
10
11
  // The judge namespace.
11
- var judge = judge || {};
12
+ var judge = {};
13
+
14
+ judge.VERSION = '1.2.0';
12
15
 
13
16
  // A judge.Watcher is a DOM element wrapper that judge uses to store validation info and instance methods.
14
17
  judge.Watcher = function (element) {
@@ -34,7 +37,6 @@ judge.Watcher = function (element) {
34
37
  message: '[judge][constructor] No DOM element passed to constructor'
35
38
  };
36
39
  }
37
-
38
40
  if (element.getAttribute('data-validate') === null) {
39
41
  throw {
40
42
  name: 'ReferenceError',
@@ -42,199 +44,149 @@ judge.Watcher = function (element) {
42
44
  };
43
45
  }
44
46
 
45
- // Convenient access to this Watcher.
46
- var watcher = this;
47
-
48
47
  // Watcher instance properties.
49
48
  this.element = element;
50
49
  this.validators = JSON.parse(this.element.getAttribute('data-validate'));
51
-
52
- // The `validate` instance method returns the validity of the watched element,
53
- // represented as an object containing the element itself and some validity information.
54
- this.validate = function() {
55
- watcher.errorMessages = [];
56
- var validators = watcher.validators,
57
- validity = true,
58
- messages = [];
59
- _(validators).each(function(validator) {
60
- var options = validator.options,
61
- msgs = validator.messages;
62
- if (watcher.element.value.length || options.allow_blank !== true) {
63
- var result = watcher.validates()[validator.kind](options, msgs);
64
- if (!result.valid && result.hasOwnProperty('messages')) {
65
- validity = false;
66
- messages.push(result.messages);
67
- }
50
+ };
51
+
52
+ // The `validate` method returns an object which describes the current validity of the
53
+ // value of the watched element.
54
+ judge.Watcher.prototype.validate = function() {
55
+ var allMessages = [];
56
+ _(this.validators).each(function(v) {
57
+ if (this.element.value.length || v.options.allow_blank !== true) {
58
+ var messages = this.validates()[v.kind](this.element.value, v.options, v.messages);
59
+ if (messages.length) {
60
+ allMessages.push(messages);
68
61
  }
69
- });
70
- return {
71
- valid: validity,
72
- messages: _(messages).flatten(),
73
- element: watcher.element
74
- };
62
+ }
63
+ }, this);
64
+ allMessages = _(allMessages).flatten();
65
+ return {
66
+ valid: (allMessages.length < 1),
67
+ messages: allMessages,
68
+ element: this.element
75
69
  };
76
-
77
70
  };
78
71
 
79
- // Watcher prototype methods.
80
- judge.Watcher.prototype.validates = function() {
81
- var watcher = this,
82
- extendedMethods = judge.customValidators,
83
- methods = {
84
-
85
- // Presence validator ported as closely as possible
86
- // from [ActiveModel::Validations::PresenceValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/PresenceValidator.html).
87
- presence: function(options, messages) {
88
- if (watcher.element.value.length) {
89
- return { valid:true };
90
- } else{
91
- return { valid:false, messages:[messages.blank] };
92
- }
93
- },
94
-
95
- // Length validator ported as closely as possible
96
- // from [ActiveModel::Validations::LengthValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/LengthValidator.html).
97
- length: function(options, messages) {
98
- var msgs = [],
99
- length = watcher.element.value.length,
100
- types = {
101
- minimum: { operator: '<', message: 'too_short' },
102
- maximum: { operator: '>', message: 'too_long' },
103
- is: { operator: '!=', message: 'wrong_length' }
104
- };
105
- _(types).each(function(properties, type) {
106
- var invalid = judge.utils.operate(length, properties.operator, options[type]);
107
- if (options.hasOwnProperty(type) && invalid) {
108
- msgs.push(messages[properties.message]);
109
- }
110
- });
111
- return msgs.length ? { valid:false, messages:msgs } : { valid:true };
112
- },
113
-
114
- // Exclusion validator ported as closely as possible
115
- // from [ActiveModel::Validations::ExclusionValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/ExclusionValidator.html).
116
- exclusion: function(options, messages) {
117
- var stringIn = _(options['in']).map(function(o) { return o.toString(); });
118
- if (_(stringIn).include(watcher.element.value)) {
119
- return {
120
- valid:false,
121
- messages:[messages.exclusion]
122
- };
123
- } else {
124
- return { valid:true };
125
- }
126
- },
127
-
128
- // Inclusion validator ported as closely as possible
129
- // from [ActiveModel::Validations::InclusionValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/InclusionValidator.html).
130
- inclusion: function(options, messages) {
131
- var stringIn = _(options['in']).map(function(o) { return o.toString(); });
132
- if (!_(stringIn).include(watcher.element.value)) {
133
- return {
134
- valid:false,
135
- messages:[messages.inclusion]
136
- };
137
- } else {
138
- return { valid:true };
139
- }
140
- },
141
-
142
- // Numericality validator ported as closely as possible
143
- // from [ActiveModel::Validations::NumericalityValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/NumericalityValidator.html).
144
- numericality: function(options, messages) {
145
- var operators = {
146
- greater_than: '>',
147
- greater_than_or_equal_to: '>=',
148
- equal_to: '==',
149
- less_than: '<',
150
- less_than_or_equal_to: '<='
151
- },
152
- msgs = [],
153
- value = watcher.element.value,
154
- parsedValue = parseFloat(value, 10);
72
+ // Ported ActiveModel validators.
73
+ // See <http://api.rubyonrails.org/classes/ActiveModel/Validations.html> for the originals.
74
+ judge.eachValidators = (function() {
75
+ return {
76
+ // ActiveModel::Validations::PresenceValidator
77
+ presence: function(value, options, messages) {
78
+ return (value.length) ? [] : [messages.blank];
79
+ },
80
+
81
+ // ActiveModel::Validations::LengthValidator
82
+ length: function(value, options, messages) {
83
+ var msgs = [],
84
+ types = {
85
+ minimum: { operator: '<', message: 'too_short' },
86
+ maximum: { operator: '>', message: 'too_long' },
87
+ is: { operator: '!=', message: 'wrong_length' }
88
+ };
89
+ _(types).each(function(properties, type) {
90
+ var invalid = judge.utils.operate(value.length, properties.operator, options[type]);
91
+ if (options.hasOwnProperty(type) && invalid) {
92
+ msgs.push(messages[properties.message]);
93
+ }
94
+ });
95
+ return msgs;
96
+ },
97
+
98
+ // ActiveModel::Validations::ExclusionValidator
99
+ exclusion: function(value, options, messages) {
100
+ var stringIn = _(options['in']).map(function(o) { return o.toString(); });
101
+ return (_(stringIn).include(value)) ? [messages.exclusion] : [];
102
+ },
103
+
104
+ // ActiveModel::Validations::InclusionValidator
105
+ inclusion: function(value, options, messages) {
106
+ var stringIn = _(options['in']).map(function(o) { return o.toString(); });
107
+ return (!_(stringIn).include(value)) ? [messages.inclusion] : [];
108
+ },
109
+
110
+ // ActiveModel::Validations::NumericalityValidator
111
+ numericality: function(value, options, messages) {
112
+ var operators = {
113
+ greater_than: '>',
114
+ greater_than_or_equal_to: '>=',
115
+ equal_to: '==',
116
+ less_than: '<',
117
+ less_than_or_equal_to: '<='
118
+ },
119
+ msgs = [],
120
+ parsedValue = parseFloat(value, 10);
155
121
 
156
- if (isNaN(Number(value))) {
157
- msgs.push(messages.not_a_number);
158
- } else {
159
- if (options.odd && judge.utils.isEven(parsedValue)) {
160
- msgs.push(messages.odd);
161
- }
162
- if (options.even && judge.utils.isOdd(parsedValue)) {
163
- msgs.push(messages.even);
164
- }
165
- if (options.only_integer && !judge.utils.isInt(parsedValue)) {
166
- msgs.push(messages.not_an_integer);
167
- }
168
- _(operators).each(function(operator, key) {
169
- var valid = judge.utils.operate(parsedValue, operators[key], parseFloat(options[key], 10));
170
- if (options.hasOwnProperty(key) && !valid) {
171
- msgs.push(messages[key]);
172
- }
173
- });
174
- }
175
- return msgs.length ? { valid:false, messages:msgs } : { valid:true };
176
- },
177
-
178
- // Format validator ported as closely as possible
179
- // from [ActiveModel::Validations::FormatValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/FormatValidator.html).
180
- format: function(options, messages) {
181
- var msgs = [],
182
- value = watcher.element.value;
183
- if (options.hasOwnProperty('with')) {
184
- var withReg = judge.utils.convertRegExp(options['with']);
185
- if (!withReg.test(value)) {
186
- msgs.push(messages.invalid);
187
- }
188
- }
189
- if (options.hasOwnProperty('without')) {
190
- var withoutReg = judge.utils.convertRegExp(options.without);
191
- if (withoutReg.test(value)) {
192
- msgs.push(messages.invalid);
193
- }
194
- }
195
- return msgs.length ? { valid:false, messages:msgs } : { valid:true };
196
- },
197
-
198
- // Acceptance validator ported as closely as possible
199
- // from [ActiveModel::Validations::AcceptanceValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/AcceptanceValidator.html).
200
- acceptance: function(options, messages) {
201
- if (watcher.element.checked === true) {
202
- return { valid:true };
203
- } else {
204
- return {
205
- valid:false,
206
- messages:[messages.accepted]
207
- };
208
- }
209
- },
210
-
211
- // Confirmation validator ported as closely as possible
212
- // from [ActiveModel::Validations::ConfirmationValidator](http://api.rubyonrails.org/classes/ActiveModel/Validations/ConfirmationValidator.html).
213
- confirmation: function(options, messages) {
214
- var id = watcher.element.getAttribute('id'),
215
- confId = id + '_confirmation',
216
- confElem = document.getElementById(confId);
217
- if (watcher.element.value === confElem.value) {
218
- return { valid:true };
219
- } else {
220
- return {
221
- valid:false,
222
- messages:[messages.confirmation]
223
- };
122
+ if (isNaN(Number(value))) {
123
+ msgs.push(messages.not_a_number);
124
+ } else {
125
+ if (options.odd && judge.utils.isEven(parsedValue)) {
126
+ msgs.push(messages.odd);
127
+ }
128
+ if (options.even && judge.utils.isOdd(parsedValue)) {
129
+ msgs.push(messages.even);
130
+ }
131
+ if (options.only_integer && !judge.utils.isInt(parsedValue)) {
132
+ msgs.push(messages.not_an_integer);
133
+ }
134
+ _(operators).each(function(operator, key) {
135
+ var valid = judge.utils.operate(parsedValue, operators[key], parseFloat(options[key], 10));
136
+ if (options.hasOwnProperty(key) && !valid) {
137
+ msgs.push(messages[key]);
224
138
  }
139
+ });
140
+ }
141
+ return msgs;
142
+ },
143
+
144
+ // ActiveModel::Validations::FormatValidator
145
+ format: function(value, options, messages) {
146
+ var msgs = [];
147
+ if (options.hasOwnProperty('with')) {
148
+ var withReg = judge.utils.convertRegExp(options['with']);
149
+ if (!withReg.test(value)) {
150
+ msgs.push(messages.invalid);
225
151
  }
226
- };
227
- // Return all validation methods, including those found in judge.customValidators.
228
- // If you name a custom validation method the same as a default one, for example
229
- // `judge.customValidators.presence = function() {};`
230
- // then the custom method _will overwrite_ the default one, so be careful!
231
- return _.extend(methods, extendedMethods);
232
- };
152
+ }
153
+ if (options.hasOwnProperty('without')) {
154
+ var withoutReg = judge.utils.convertRegExp(options.without);
155
+ if (withoutReg.test(value)) {
156
+ msgs.push(messages.invalid);
157
+ }
158
+ }
159
+ return msgs;
160
+ },
161
+
162
+ // ActiveModel::Validations::AcceptanceValidator
163
+ acceptance: function(value, options, messages) {
164
+ return (this._element.checked === true) ? [] : [messages.accepted];
165
+ },
166
+
167
+ // ActiveModel::Validations::ConfirmationValidator
168
+ confirmation: function(value, options, messages) {
169
+ var id = this._element.getAttribute('id'),
170
+ confId = id + '_confirmation',
171
+ confElem = document.getElementById(confId);
172
+ return (value === confElem.value) ? [] : [messages.confirmation];
173
+ }
174
+ };
175
+
176
+ }());
233
177
 
234
178
  // This object should contain any judge validation methods
235
179
  // that correspond to custom validators used in the model.
236
180
  judge.customValidators = {};
237
181
 
182
+ // Return all validation methods, including those found in judge.customValidators.
183
+ // If you name a custom validation method the same as a default one, for example
184
+ // `judge.customValidators.presence = function() {};`
185
+ // then the custom method _will overwrite_ the default one, so be careful!
186
+ judge.Watcher.prototype.validates = function() {
187
+ return _.extend({_element: this.element}, judge.eachValidators, judge.customValidators);
188
+ };
189
+
238
190
  // The judge store is now open :)
239
191
  judge.store = (function() {
240
192
  var store = {};
@@ -365,19 +317,13 @@ judge.utils = {
365
317
  // If you know of a better way (or an existing library) to convert regular expressions
366
318
  // from Ruby to JavaScript, I would really love to hear from you.
367
319
  convertRegExp: function(string) {
368
- var p = string.slice(1, -1).split(':'),
369
- o = p.shift(),
370
- r = p.join(':').replace(/\\\\/g, '\\');
371
- return new RegExp(r, judge.utils.convertFlags(o));
320
+ var parts = string.slice(1, -1).split(':'),
321
+ flags = parts.shift().replace('?', ''),
322
+ source = parts.join(':').replace(/\\\\/g, '\\');
323
+ return new RegExp(source, judge.utils.convertFlags(flags));
372
324
  },
373
325
  convertFlags: function(string) {
374
- var off = new RegExp('-'),
375
- multi = new RegExp('m');
376
- string = string.replace('?', '');
377
- if (off.test(string) || !multi.test(string)) {
378
- return '';
379
- } else {
380
- return 'm';
381
- }
326
+ var on = string.split('-')[0];
327
+ return (/m/.test(on)) ? 'm' : '';
382
328
  }
383
- };
329
+ };