judge 1.4.0 → 1.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.
@@ -0,0 +1,41 @@
1
+ module Judge
2
+
3
+ module MessageConfig
4
+
5
+ ALLOW_BLANK = [
6
+ :format,
7
+ :exclusion,
8
+ :inclusion,
9
+ :length
10
+ ]
11
+
12
+ MESSAGE_MAP = {
13
+ :confirmation => { :base => :confirmation },
14
+ :acceptance => { :base => :accepted },
15
+ :presence => { :base => :blank },
16
+ :length => { :base => nil,
17
+ :options => {
18
+ :minimum => :too_short,
19
+ :maximum => :too_long,
20
+ :is => :wrong_length
21
+ }
22
+ },
23
+ :format => { :base => :invalid },
24
+ :inclusion => { :base => :inclusion },
25
+ :exclusion => { :base => :exclusion },
26
+ :numericality => { :base => :not_a_number,
27
+ :options => {
28
+ :greater_than => :greater_than,
29
+ :greater_than_or_equal_to => :greater_than_or_equal_to,
30
+ :equal_to => :equal_to,
31
+ :less_than => :less_than,
32
+ :less_than_or_equal_to => :less_than_or_equal_to,
33
+ :odd => :odd,
34
+ :even => :even
35
+ }
36
+ }
37
+ }
38
+
39
+ end
40
+
41
+ end
@@ -4,16 +4,19 @@ module Judge
4
4
 
5
5
  attr_reader :active_model_validator, :kind, :options, :method, :messages
6
6
 
7
- def initialize(amv, method, message_collection)
8
- @active_model_validator = amv
9
- @kind = @active_model_validator.kind
10
- @options = @active_model_validator.options.reject { |key| [:if, :on, :unless, :tokenizer].include?(key) }
11
- @method = method
12
- @messages = message_collection
7
+ def initialize(object, method, amv)
8
+ @kind = amv.kind
9
+ @options = amv.options.reject { |key| [:if, :on, :unless, :tokenizer].include?(key) }
10
+ @method = method
11
+ @messages = Judge::MessageCollection.new(object, method, amv)
13
12
  end
14
13
 
15
14
  def to_hash
16
- { :kind => kind, :options => options, :messages => messages.to_hash }
15
+ {
16
+ :kind => kind,
17
+ :options => options,
18
+ :messages => messages.to_hash
19
+ }
17
20
  end
18
21
 
19
22
  end
@@ -7,10 +7,8 @@ module Judge
7
7
  attr_reader :validators
8
8
 
9
9
  def initialize(object, method)
10
- active_model_validators = object.class.validators_on(method).reject { |amv| amv.kind == :uniqueness }
11
- @validators = active_model_validators.map do |amv|
12
- Judge::Validator.new(amv, method, Judge::MessageCollection.new(object, method, amv))
13
- end
10
+ amvs = object.class.validators_on(method).reject { |amv| amv.kind == :uniqueness }
11
+ @validators = amvs.map { |amv| Judge::Validator.new(object, method, amv) }
14
12
  end
15
13
 
16
14
  def each(&block)
data/lib/judge/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Judge
2
- VERSION = "1.4.0"
2
+ VERSION = "1.5.0"
3
3
  end
@@ -0,0 +1,17 @@
1
+ require "support/spec_helper"
2
+
3
+ describe Judge::EachValidator do
4
+
5
+ let(:amv) { User.validators_on(:city).first }
6
+
7
+ specify "custom validators include Judge::EachValidator" do
8
+ CityValidator.include?(Judge::EachValidator).should be_true
9
+ end
10
+
11
+ specify "#messages_to_lookup method should return array of messages" do
12
+ amv.should respond_to :messages_to_lookup
13
+ amv.messages_to_lookup.should be_an Array
14
+ amv.messages_to_lookup.should include :not_valid_city
15
+ end
16
+
17
+ end
@@ -1,4 +1,4 @@
1
- require "spec_helper"
1
+ require "support/spec_helper"
2
2
 
3
3
  describe Judge::FormBuilder do
4
4
 
data/spec/html_spec.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "spec_helper"
1
+ require "support/spec_helper"
2
2
 
3
3
  describe Judge::HTML do
4
4
 
@@ -1,4 +1,5 @@
1
- // Underscore.js 1.3.1
1
+
2
+ // Underscore.js 1.3.2
2
3
  // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
3
4
  // Underscore is freely distributable under the MIT license.
4
5
  // Portions of Underscore are inspired or borrowed from Prototype,
@@ -62,7 +63,7 @@
62
63
  }
63
64
 
64
65
  // Current version.
65
- _.VERSION = '1.3.1';
66
+ _.VERSION = '1.3.2';
66
67
 
67
68
  // Collection Functions
68
69
  // --------------------
@@ -180,7 +181,7 @@
180
181
  each(obj, function(value, index, list) {
181
182
  if (!(result = result && iterator.call(context, value, index, list))) return breaker;
182
183
  });
183
- return result;
184
+ return !!result;
184
185
  };
185
186
 
186
187
  // Determine if at least one element in the object matches a truth test.
@@ -224,7 +225,7 @@
224
225
 
225
226
  // Return the maximum element or (element-based computation).
226
227
  _.max = function(obj, iterator, context) {
227
- if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
228
+ if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.max.apply(Math, obj);
228
229
  if (!iterator && _.isEmpty(obj)) return -Infinity;
229
230
  var result = {computed : -Infinity};
230
231
  each(obj, function(value, index, list) {
@@ -236,7 +237,7 @@
236
237
 
237
238
  // Return the minimum element (or element-based computation).
238
239
  _.min = function(obj, iterator, context) {
239
- if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
240
+ if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.min.apply(Math, obj);
240
241
  if (!iterator && _.isEmpty(obj)) return Infinity;
241
242
  var result = {computed : Infinity};
242
243
  each(obj, function(value, index, list) {
@@ -250,19 +251,16 @@
250
251
  _.shuffle = function(obj) {
251
252
  var shuffled = [], rand;
252
253
  each(obj, function(value, index, list) {
253
- if (index == 0) {
254
- shuffled[0] = value;
255
- } else {
256
- rand = Math.floor(Math.random() * (index + 1));
257
- shuffled[index] = shuffled[rand];
258
- shuffled[rand] = value;
259
- }
254
+ rand = Math.floor(Math.random() * (index + 1));
255
+ shuffled[index] = shuffled[rand];
256
+ shuffled[rand] = value;
260
257
  });
261
258
  return shuffled;
262
259
  };
263
260
 
264
261
  // Sort the object's values by a criterion produced by an iterator.
265
- _.sortBy = function(obj, iterator, context) {
262
+ _.sortBy = function(obj, val, context) {
263
+ var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
266
264
  return _.pluck(_.map(obj, function(value, index, list) {
267
265
  return {
268
266
  value : value,
@@ -270,6 +268,8 @@
270
268
  };
271
269
  }).sort(function(left, right) {
272
270
  var a = left.criteria, b = right.criteria;
271
+ if (a === void 0) return 1;
272
+ if (b === void 0) return -1;
273
273
  return a < b ? -1 : a > b ? 1 : 0;
274
274
  }), 'value');
275
275
  };
@@ -299,26 +299,26 @@
299
299
  };
300
300
 
301
301
  // Safely convert anything iterable into a real, live array.
302
- _.toArray = function(iterable) {
303
- if (!iterable) return [];
304
- if (iterable.toArray) return iterable.toArray();
305
- if (_.isArray(iterable)) return slice.call(iterable);
306
- if (_.isArguments(iterable)) return slice.call(iterable);
307
- return _.values(iterable);
302
+ _.toArray = function(obj) {
303
+ if (!obj) return [];
304
+ if (_.isArray(obj)) return slice.call(obj);
305
+ if (_.isArguments(obj)) return slice.call(obj);
306
+ if (obj.toArray && _.isFunction(obj.toArray)) return obj.toArray();
307
+ return _.values(obj);
308
308
  };
309
309
 
310
310
  // Return the number of elements in an object.
311
311
  _.size = function(obj) {
312
- return _.toArray(obj).length;
312
+ return _.isArray(obj) ? obj.length : _.keys(obj).length;
313
313
  };
314
314
 
315
315
  // Array Functions
316
316
  // ---------------
317
317
 
318
318
  // Get the first element of an array. Passing **n** will return the first N
319
- // values in the array. Aliased as `head`. The **guard** check allows it to work
320
- // with `_.map`.
321
- _.first = _.head = function(array, n, guard) {
319
+ // values in the array. Aliased as `head` and `take`. The **guard** check
320
+ // allows it to work with `_.map`.
321
+ _.first = _.head = _.take = function(array, n, guard) {
322
322
  return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
323
323
  };
324
324
 
@@ -372,15 +372,17 @@
372
372
  // Aliased as `unique`.
373
373
  _.uniq = _.unique = function(array, isSorted, iterator) {
374
374
  var initial = iterator ? _.map(array, iterator) : array;
375
- var result = [];
376
- _.reduce(initial, function(memo, el, i) {
377
- if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) {
378
- memo[memo.length] = el;
379
- result[result.length] = array[i];
375
+ var results = [];
376
+ // The `isSorted` flag is irrelevant if the array only contains two elements.
377
+ if (array.length < 3) isSorted = true;
378
+ _.reduce(initial, function (memo, value, index) {
379
+ if (isSorted ? _.last(memo) !== value || !memo.length : !_.include(memo, value)) {
380
+ memo.push(value);
381
+ results.push(array[index]);
380
382
  }
381
383
  return memo;
382
384
  }, []);
383
- return result;
385
+ return results;
384
386
  };
385
387
 
386
388
  // Produce an array that contains the union: each distinct element from all of
@@ -403,7 +405,7 @@
403
405
  // Take the difference between one array and a number of other arrays.
404
406
  // Only the elements present in just the first array will remain.
405
407
  _.difference = function(array) {
406
- var rest = _.flatten(slice.call(arguments, 1));
408
+ var rest = _.flatten(slice.call(arguments, 1), true);
407
409
  return _.filter(array, function(value){ return !_.include(rest, value); });
408
410
  };
409
411
 
@@ -514,7 +516,7 @@
514
516
  // it with the arguments supplied.
515
517
  _.delay = function(func, wait) {
516
518
  var args = slice.call(arguments, 2);
517
- return setTimeout(function(){ return func.apply(func, args); }, wait);
519
+ return setTimeout(function(){ return func.apply(null, args); }, wait);
518
520
  };
519
521
 
520
522
  // Defers a function, scheduling it to run after the current call stack has
@@ -526,7 +528,7 @@
526
528
  // Returns a function, that, when invoked, will only be triggered at most once
527
529
  // during a given window of time.
528
530
  _.throttle = function(func, wait) {
529
- var context, args, timeout, throttling, more;
531
+ var context, args, timeout, throttling, more, result;
530
532
  var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
531
533
  return function() {
532
534
  context = this; args = arguments;
@@ -539,24 +541,27 @@
539
541
  if (throttling) {
540
542
  more = true;
541
543
  } else {
542
- func.apply(context, args);
544
+ result = func.apply(context, args);
543
545
  }
544
546
  whenDone();
545
547
  throttling = true;
548
+ return result;
546
549
  };
547
550
  };
548
551
 
549
552
  // Returns a function, that, as long as it continues to be invoked, will not
550
553
  // be triggered. The function will be called after it stops being called for
551
- // N milliseconds.
552
- _.debounce = function(func, wait) {
554
+ // N milliseconds. If `immediate` is passed, trigger the function on the
555
+ // leading edge, instead of the trailing.
556
+ _.debounce = function(func, wait, immediate) {
553
557
  var timeout;
554
558
  return function() {
555
559
  var context = this, args = arguments;
556
560
  var later = function() {
557
561
  timeout = null;
558
- func.apply(context, args);
562
+ if (!immediate) func.apply(context, args);
559
563
  };
564
+ if (immediate && !timeout) func.apply(context, args);
560
565
  clearTimeout(timeout);
561
566
  timeout = setTimeout(later, wait);
562
567
  };
@@ -641,6 +646,15 @@
641
646
  return obj;
642
647
  };
643
648
 
649
+ // Return a copy of the object only containing the whitelisted properties.
650
+ _.pick = function(obj) {
651
+ var result = {};
652
+ each(_.flatten(slice.call(arguments, 1)), function(key) {
653
+ if (key in obj) result[key] = obj[key];
654
+ });
655
+ return result;
656
+ };
657
+
644
658
  // Fill in a given object with default properties.
645
659
  _.defaults = function(obj) {
646
660
  each(slice.call(arguments, 1), function(source) {
@@ -761,6 +775,7 @@
761
775
  // Is a given array, string, or object empty?
762
776
  // An "empty" object has no enumerable own-properties.
763
777
  _.isEmpty = function(obj) {
778
+ if (obj == null) return true;
764
779
  if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
765
780
  for (var key in obj) if (_.has(obj, key)) return false;
766
781
  return true;
@@ -807,6 +822,11 @@
807
822
  return toString.call(obj) == '[object Number]';
808
823
  };
809
824
 
825
+ // Is a given object a finite number?
826
+ _.isFinite = function(obj) {
827
+ return _.isNumber(obj) && isFinite(obj);
828
+ };
829
+
810
830
  // Is the given value `NaN`?
811
831
  _.isNaN = function(obj) {
812
832
  // `NaN` is the only value for which `===` is not reflexive.
@@ -868,6 +888,14 @@
868
888
  return (''+string).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
869
889
  };
870
890
 
891
+ // If the value of the named property is a function then invoke it;
892
+ // otherwise, return it.
893
+ _.result = function(object, property) {
894
+ if (object == null) return null;
895
+ var value = object[property];
896
+ return _.isFunction(value) ? value.call(object) : value;
897
+ };
898
+
871
899
  // Add your own custom functions to the Underscore object, ensuring that
872
900
  // they're correctly added to the OOP wrapper as well.
873
901
  _.mixin = function(obj) {
@@ -897,39 +925,72 @@
897
925
  // guaranteed not to match.
898
926
  var noMatch = /.^/;
899
927
 
928
+ // Certain characters need to be escaped so that they can be put into a
929
+ // string literal.
930
+ var escapes = {
931
+ '\\': '\\',
932
+ "'": "'",
933
+ 'r': '\r',
934
+ 'n': '\n',
935
+ 't': '\t',
936
+ 'u2028': '\u2028',
937
+ 'u2029': '\u2029'
938
+ };
939
+
940
+ for (var p in escapes) escapes[escapes[p]] = p;
941
+ var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
942
+ var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g;
943
+
900
944
  // Within an interpolation, evaluation, or escaping, remove HTML escaping
901
945
  // that had been previously added.
902
946
  var unescape = function(code) {
903
- return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'");
947
+ return code.replace(unescaper, function(match, escape) {
948
+ return escapes[escape];
949
+ });
904
950
  };
905
951
 
906
952
  // JavaScript micro-templating, similar to John Resig's implementation.
907
953
  // Underscore templating handles arbitrary delimiters, preserves whitespace,
908
954
  // and correctly escapes quotes within interpolated code.
909
- _.template = function(str, data) {
910
- var c = _.templateSettings;
911
- var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
912
- 'with(obj||{}){__p.push(\'' +
913
- str.replace(/\\/g, '\\\\')
914
- .replace(/'/g, "\\'")
915
- .replace(c.escape || noMatch, function(match, code) {
916
- return "',_.escape(" + unescape(code) + "),'";
917
- })
918
- .replace(c.interpolate || noMatch, function(match, code) {
919
- return "'," + unescape(code) + ",'";
920
- })
921
- .replace(c.evaluate || noMatch, function(match, code) {
922
- return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('";
923
- })
924
- .replace(/\r/g, '\\r')
925
- .replace(/\n/g, '\\n')
926
- .replace(/\t/g, '\\t')
927
- + "');}return __p.join('');";
928
- var func = new Function('obj', '_', tmpl);
929
- if (data) return func(data, _);
930
- return function(data) {
931
- return func.call(this, data, _);
955
+ _.template = function(text, data, settings) {
956
+ settings = _.extend(_.templateSettings, settings);
957
+
958
+ // Compile the template source, taking care to escape characters that
959
+ // cannot be included in a string literal and then unescape them in code
960
+ // blocks.
961
+ var source = "__p+='" + text
962
+ .replace(escaper, function(match) {
963
+ return '\\' + escapes[match];
964
+ })
965
+ .replace(settings.escape || noMatch, function(match, code) {
966
+ return "'+\n_.escape(" + unescape(code) + ")+\n'";
967
+ })
968
+ .replace(settings.interpolate || noMatch, function(match, code) {
969
+ return "'+\n(" + unescape(code) + ")+\n'";
970
+ })
971
+ .replace(settings.evaluate || noMatch, function(match, code) {
972
+ return "';\n" + unescape(code) + "\n;__p+='";
973
+ }) + "';\n";
974
+
975
+ // If a variable is not specified, place data values in local scope.
976
+ if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
977
+
978
+ source = "var __p='';" +
979
+ "var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n" +
980
+ source + "return __p;\n";
981
+
982
+ var render = new Function(settings.variable || 'obj', '_', source);
983
+ if (data) return render(data, _);
984
+ var template = function(data) {
985
+ return render.call(this, data, _);
932
986
  };
987
+
988
+ // Provide the compiled function source as a convenience for build time
989
+ // precompilation.
990
+ template.source = 'function(' + (settings.variable || 'obj') + '){\n' +
991
+ source + '}';
992
+
993
+ return template;
933
994
  };
934
995
 
935
996
  // Add a "chain" function, which will delegate to the wrapper.