judge 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +5 -1
- data/README.md +11 -4
- data/judge.gemspec +8 -9
- data/lib/generators/judge/templates/judge.js +142 -196
- data/lib/generators/judge/templates/underscore.js +138 -101
- data/lib/judge/version.rb +1 -1
- data/spec/javascripts/JudgeSpec.js +6 -5
- data/spec/javascripts/helpers/json2.js +46 -41
- data/spec/javascripts/helpers/underscore.js +305 -130
- data/spec/javascripts/support/jasmine_runner.rb +4 -15
- metadata +22 -23
@@ -1,5 +1,5 @@
|
|
1
|
-
// Underscore.js 1.
|
2
|
-
// (c)
|
1
|
+
// Underscore.js 1.3.1
|
2
|
+
// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
|
3
3
|
// Underscore is freely distributable under the MIT license.
|
4
4
|
// Portions of Underscore are inspired or borrowed from Prototype,
|
5
5
|
// Oliver Steele's Functional, and John Resig's Micro-Templating.
|
@@ -48,26 +48,21 @@
|
|
48
48
|
// Create a safe reference to the Underscore object for use below.
|
49
49
|
var _ = function(obj) { return new wrapper(obj); };
|
50
50
|
|
51
|
-
// Export the Underscore object for **Node.js
|
52
|
-
// backwards-compatibility for the old `require()` API. If we're
|
53
|
-
//
|
51
|
+
// Export the Underscore object for **Node.js**, with
|
52
|
+
// backwards-compatibility for the old `require()` API. If we're in
|
53
|
+
// the browser, add `_` as a global object via a string identifier,
|
54
|
+
// for Closure Compiler "advanced" mode.
|
54
55
|
if (typeof exports !== 'undefined') {
|
55
56
|
if (typeof module !== 'undefined' && module.exports) {
|
56
57
|
exports = module.exports = _;
|
57
58
|
}
|
58
59
|
exports._ = _;
|
59
|
-
} else if (typeof define === 'function' && define.amd) {
|
60
|
-
// Register as a named module with AMD.
|
61
|
-
define('underscore', function() {
|
62
|
-
return _;
|
63
|
-
});
|
64
60
|
} else {
|
65
|
-
// Exported as a string, for Closure Compiler "advanced" mode.
|
66
61
|
root['_'] = _;
|
67
62
|
}
|
68
63
|
|
69
64
|
// Current version.
|
70
|
-
_.VERSION = '1.
|
65
|
+
_.VERSION = '1.3.1';
|
71
66
|
|
72
67
|
// Collection Functions
|
73
68
|
// --------------------
|
@@ -85,7 +80,7 @@
|
|
85
80
|
}
|
86
81
|
} else {
|
87
82
|
for (var key in obj) {
|
88
|
-
if (
|
83
|
+
if (_.has(obj, key)) {
|
89
84
|
if (iterator.call(context, obj[key], key, obj) === breaker) return;
|
90
85
|
}
|
91
86
|
}
|
@@ -94,20 +89,21 @@
|
|
94
89
|
|
95
90
|
// Return the results of applying the iterator to each element.
|
96
91
|
// Delegates to **ECMAScript 5**'s native `map` if available.
|
97
|
-
_.map = function(obj, iterator, context) {
|
92
|
+
_.map = _.collect = function(obj, iterator, context) {
|
98
93
|
var results = [];
|
99
94
|
if (obj == null) return results;
|
100
95
|
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
|
101
96
|
each(obj, function(value, index, list) {
|
102
97
|
results[results.length] = iterator.call(context, value, index, list);
|
103
98
|
});
|
99
|
+
if (obj.length === +obj.length) results.length = obj.length;
|
104
100
|
return results;
|
105
101
|
};
|
106
102
|
|
107
103
|
// **Reduce** builds up a single result from a list of values, aka `inject`,
|
108
104
|
// or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
|
109
105
|
_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
|
110
|
-
var initial =
|
106
|
+
var initial = arguments.length > 2;
|
111
107
|
if (obj == null) obj = [];
|
112
108
|
if (nativeReduce && obj.reduce === nativeReduce) {
|
113
109
|
if (context) iterator = _.bind(iterator, context);
|
@@ -121,20 +117,22 @@
|
|
121
117
|
memo = iterator.call(context, memo, value, index, list);
|
122
118
|
}
|
123
119
|
});
|
124
|
-
if (!initial) throw new TypeError(
|
120
|
+
if (!initial) throw new TypeError('Reduce of empty array with no initial value');
|
125
121
|
return memo;
|
126
122
|
};
|
127
123
|
|
128
124
|
// The right-associative version of reduce, also known as `foldr`.
|
129
125
|
// Delegates to **ECMAScript 5**'s native `reduceRight` if available.
|
130
126
|
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
|
127
|
+
var initial = arguments.length > 2;
|
131
128
|
if (obj == null) obj = [];
|
132
129
|
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
|
133
130
|
if (context) iterator = _.bind(iterator, context);
|
134
|
-
return
|
131
|
+
return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
|
135
132
|
}
|
136
|
-
var reversed =
|
137
|
-
|
133
|
+
var reversed = _.toArray(obj).reverse();
|
134
|
+
if (context && !initial) iterator = _.bind(iterator, context);
|
135
|
+
return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator);
|
138
136
|
};
|
139
137
|
|
140
138
|
// Return the first value which passes a truth test. Aliased as `detect`.
|
@@ -189,12 +187,12 @@
|
|
189
187
|
// Delegates to **ECMAScript 5**'s native `some` if available.
|
190
188
|
// Aliased as `any`.
|
191
189
|
var any = _.some = _.any = function(obj, iterator, context) {
|
192
|
-
iterator
|
190
|
+
iterator || (iterator = _.identity);
|
193
191
|
var result = false;
|
194
192
|
if (obj == null) return result;
|
195
193
|
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
|
196
194
|
each(obj, function(value, index, list) {
|
197
|
-
if (result
|
195
|
+
if (result || (result = iterator.call(context, value, index, list))) return breaker;
|
198
196
|
});
|
199
197
|
return !!result;
|
200
198
|
};
|
@@ -215,7 +213,7 @@
|
|
215
213
|
_.invoke = function(obj, method) {
|
216
214
|
var args = slice.call(arguments, 2);
|
217
215
|
return _.map(obj, function(value) {
|
218
|
-
return (method
|
216
|
+
return (_.isFunction(method) ? method || value : value[method]).apply(value, args);
|
219
217
|
});
|
220
218
|
};
|
221
219
|
|
@@ -335,7 +333,11 @@
|
|
335
333
|
// Get the last element of an array. Passing **n** will return the last N
|
336
334
|
// values in the array. The **guard** check allows it to work with `_.map`.
|
337
335
|
_.last = function(array, n, guard) {
|
338
|
-
|
336
|
+
if ((n != null) && !guard) {
|
337
|
+
return slice.call(array, Math.max(array.length - n, 0));
|
338
|
+
} else {
|
339
|
+
return array[array.length - 1];
|
340
|
+
}
|
339
341
|
};
|
340
342
|
|
341
343
|
// Returns everything but the first entry of the array. Aliased as `tail`.
|
@@ -398,10 +400,11 @@
|
|
398
400
|
});
|
399
401
|
};
|
400
402
|
|
401
|
-
// Take the difference between one array and
|
403
|
+
// Take the difference between one array and a number of other arrays.
|
402
404
|
// Only the elements present in just the first array will remain.
|
403
|
-
_.difference = function(array
|
404
|
-
|
405
|
+
_.difference = function(array) {
|
406
|
+
var rest = _.flatten(slice.call(arguments, 1));
|
407
|
+
return _.filter(array, function(value){ return !_.include(rest, value); });
|
405
408
|
};
|
406
409
|
|
407
410
|
// Zip together multiple lists into a single array -- elements that share
|
@@ -428,7 +431,7 @@
|
|
428
431
|
return array[i] === item ? i : -1;
|
429
432
|
}
|
430
433
|
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
|
431
|
-
for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
|
434
|
+
for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i;
|
432
435
|
return -1;
|
433
436
|
};
|
434
437
|
|
@@ -437,7 +440,7 @@
|
|
437
440
|
if (array == null) return -1;
|
438
441
|
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
|
439
442
|
var i = array.length;
|
440
|
-
while (i--) if (array[i] === item) return i;
|
443
|
+
while (i--) if (i in array && array[i] === item) return i;
|
441
444
|
return -1;
|
442
445
|
};
|
443
446
|
|
@@ -503,7 +506,7 @@
|
|
503
506
|
hasher || (hasher = _.identity);
|
504
507
|
return function() {
|
505
508
|
var key = hasher.apply(this, arguments);
|
506
|
-
return
|
509
|
+
return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
|
507
510
|
};
|
508
511
|
};
|
509
512
|
|
@@ -575,7 +578,7 @@
|
|
575
578
|
// conditionally execute the original function.
|
576
579
|
_.wrap = function(func, wrapper) {
|
577
580
|
return function() {
|
578
|
-
var args = [func].concat(slice.call(arguments));
|
581
|
+
var args = [func].concat(slice.call(arguments, 0));
|
579
582
|
return wrapper.apply(this, args);
|
580
583
|
};
|
581
584
|
};
|
@@ -583,9 +586,9 @@
|
|
583
586
|
// Returns a function that is the composition of a list of functions, each
|
584
587
|
// consuming the return value of the function that follows.
|
585
588
|
_.compose = function() {
|
586
|
-
var funcs =
|
589
|
+
var funcs = arguments;
|
587
590
|
return function() {
|
588
|
-
var args =
|
591
|
+
var args = arguments;
|
589
592
|
for (var i = funcs.length - 1; i >= 0; i--) {
|
590
593
|
args = [funcs[i].apply(this, args)];
|
591
594
|
}
|
@@ -595,6 +598,7 @@
|
|
595
598
|
|
596
599
|
// Returns a function that will only be executed after being called N times.
|
597
600
|
_.after = function(times, func) {
|
601
|
+
if (times <= 0) return func();
|
598
602
|
return function() {
|
599
603
|
if (--times < 1) { return func.apply(this, arguments); }
|
600
604
|
};
|
@@ -608,7 +612,7 @@
|
|
608
612
|
_.keys = nativeKeys || function(obj) {
|
609
613
|
if (obj !== Object(obj)) throw new TypeError('Invalid object');
|
610
614
|
var keys = [];
|
611
|
-
for (var key in obj) if (
|
615
|
+
for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
|
612
616
|
return keys;
|
613
617
|
};
|
614
618
|
|
@@ -631,7 +635,7 @@
|
|
631
635
|
_.extend = function(obj) {
|
632
636
|
each(slice.call(arguments, 1), function(source) {
|
633
637
|
for (var prop in source) {
|
634
|
-
|
638
|
+
obj[prop] = source[prop];
|
635
639
|
}
|
636
640
|
});
|
637
641
|
return obj;
|
@@ -667,48 +671,40 @@
|
|
667
671
|
// See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
|
668
672
|
if (a === b) return a !== 0 || 1 / a == 1 / b;
|
669
673
|
// A strict comparison is necessary because `null == undefined`.
|
670
|
-
if (
|
674
|
+
if (a == null || b == null) return a === b;
|
671
675
|
// Unwrap any wrapped objects.
|
672
676
|
if (a._chain) a = a._wrapped;
|
673
677
|
if (b._chain) b = b._wrapped;
|
674
678
|
// Invoke a custom `isEqual` method if one is provided.
|
675
|
-
if (_.isFunction(a.isEqual)) return a.isEqual(b);
|
676
|
-
if (_.isFunction(b.isEqual)) return b.isEqual(a);
|
677
|
-
// Compare
|
678
|
-
var
|
679
|
-
if (
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
a.global == b.global &&
|
703
|
-
a.multiline == b.multiline &&
|
704
|
-
a.ignoreCase == b.ignoreCase;
|
679
|
+
if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b);
|
680
|
+
if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a);
|
681
|
+
// Compare `[[Class]]` names.
|
682
|
+
var className = toString.call(a);
|
683
|
+
if (className != toString.call(b)) return false;
|
684
|
+
switch (className) {
|
685
|
+
// Strings, numbers, dates, and booleans are compared by value.
|
686
|
+
case '[object String]':
|
687
|
+
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
|
688
|
+
// equivalent to `new String("5")`.
|
689
|
+
return a == String(b);
|
690
|
+
case '[object Number]':
|
691
|
+
// `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
|
692
|
+
// other numeric values.
|
693
|
+
return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
|
694
|
+
case '[object Date]':
|
695
|
+
case '[object Boolean]':
|
696
|
+
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
|
697
|
+
// millisecond representations. Note that invalid dates with millisecond representations
|
698
|
+
// of `NaN` are not equivalent.
|
699
|
+
return +a == +b;
|
700
|
+
// RegExps are compared by their source patterns and flags.
|
701
|
+
case '[object RegExp]':
|
702
|
+
return a.source == b.source &&
|
703
|
+
a.global == b.global &&
|
704
|
+
a.multiline == b.multiline &&
|
705
|
+
a.ignoreCase == b.ignoreCase;
|
705
706
|
}
|
706
|
-
|
707
|
-
if (typeA != 'object') return false;
|
708
|
-
// Arrays or Arraylikes with different lengths are not equal.
|
709
|
-
if (a.length !== b.length) return false;
|
710
|
-
// Objects with different constructors are not equal.
|
711
|
-
if (a.constructor !== b.constructor) return false;
|
707
|
+
if (typeof a != 'object' || typeof b != 'object') return false;
|
712
708
|
// Assume equality for cyclic structures. The algorithm for detecting cyclic
|
713
709
|
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
714
710
|
var length = stack.length;
|
@@ -720,21 +716,37 @@
|
|
720
716
|
// Add the first object to the stack of traversed objects.
|
721
717
|
stack.push(a);
|
722
718
|
var size = 0, result = true;
|
723
|
-
//
|
724
|
-
|
725
|
-
if
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
719
|
+
// Recursively compare objects and arrays.
|
720
|
+
if (className == '[object Array]') {
|
721
|
+
// Compare array lengths to determine if a deep comparison is necessary.
|
722
|
+
size = a.length;
|
723
|
+
result = size == b.length;
|
724
|
+
if (result) {
|
725
|
+
// Deep compare the contents, ignoring non-numeric properties.
|
726
|
+
while (size--) {
|
727
|
+
// Ensure commutative equality for sparse arrays.
|
728
|
+
if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;
|
729
|
+
}
|
730
730
|
}
|
731
|
-
}
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
731
|
+
} else {
|
732
|
+
// Objects with different constructors are not equivalent.
|
733
|
+
if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false;
|
734
|
+
// Deep compare objects.
|
735
|
+
for (var key in a) {
|
736
|
+
if (_.has(a, key)) {
|
737
|
+
// Count the expected number of properties.
|
738
|
+
size++;
|
739
|
+
// Deep compare each member.
|
740
|
+
if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break;
|
741
|
+
}
|
742
|
+
}
|
743
|
+
// Ensure that both objects contain the same number of properties.
|
744
|
+
if (result) {
|
745
|
+
for (key in b) {
|
746
|
+
if (_.has(b, key) && !(size--)) break;
|
747
|
+
}
|
748
|
+
result = !size;
|
736
749
|
}
|
737
|
-
result = !size;
|
738
750
|
}
|
739
751
|
// Remove the first object from the stack of traversed objects.
|
740
752
|
stack.pop();
|
@@ -750,7 +762,7 @@
|
|
750
762
|
// An "empty" object has no enumerable own-properties.
|
751
763
|
_.isEmpty = function(obj) {
|
752
764
|
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
|
753
|
-
for (var key in obj) if (
|
765
|
+
for (var key in obj) if (_.has(obj, key)) return false;
|
754
766
|
return true;
|
755
767
|
};
|
756
768
|
|
@@ -771,13 +783,12 @@
|
|
771
783
|
};
|
772
784
|
|
773
785
|
// Is a given variable an arguments object?
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
} else {
|
786
|
+
_.isArguments = function(obj) {
|
787
|
+
return toString.call(obj) == '[object Arguments]';
|
788
|
+
};
|
789
|
+
if (!_.isArguments(arguments)) {
|
779
790
|
_.isArguments = function(obj) {
|
780
|
-
return !!(obj &&
|
791
|
+
return !!(obj && _.has(obj, 'callee'));
|
781
792
|
};
|
782
793
|
}
|
783
794
|
|
@@ -827,6 +838,11 @@
|
|
827
838
|
return obj === void 0;
|
828
839
|
};
|
829
840
|
|
841
|
+
// Has own property?
|
842
|
+
_.has = function(obj, key) {
|
843
|
+
return hasOwnProperty.call(obj, key);
|
844
|
+
};
|
845
|
+
|
830
846
|
// Utility Functions
|
831
847
|
// -----------------
|
832
848
|
|
@@ -876,6 +892,17 @@
|
|
876
892
|
escape : /<%-([\s\S]+?)%>/g
|
877
893
|
};
|
878
894
|
|
895
|
+
// When customizing `templateSettings`, if you don't want to define an
|
896
|
+
// interpolation, evaluation or escaping regex, we need one that is
|
897
|
+
// guaranteed not to match.
|
898
|
+
var noMatch = /.^/;
|
899
|
+
|
900
|
+
// Within an interpolation, evaluation, or escaping, remove HTML escaping
|
901
|
+
// that had been previously added.
|
902
|
+
var unescape = function(code) {
|
903
|
+
return code.replace(/\\\\/g, '\\').replace(/\\'/g, "'");
|
904
|
+
};
|
905
|
+
|
879
906
|
// JavaScript micro-templating, similar to John Resig's implementation.
|
880
907
|
// Underscore templating handles arbitrary delimiters, preserves whitespace,
|
881
908
|
// and correctly escapes quotes within interpolated code.
|
@@ -885,22 +912,29 @@
|
|
885
912
|
'with(obj||{}){__p.push(\'' +
|
886
913
|
str.replace(/\\/g, '\\\\')
|
887
914
|
.replace(/'/g, "\\'")
|
888
|
-
.replace(c.escape, function(match, code) {
|
889
|
-
return "',_.escape(" + code
|
915
|
+
.replace(c.escape || noMatch, function(match, code) {
|
916
|
+
return "',_.escape(" + unescape(code) + "),'";
|
890
917
|
})
|
891
|
-
.replace(c.interpolate, function(match, code) {
|
892
|
-
return "'," + code
|
918
|
+
.replace(c.interpolate || noMatch, function(match, code) {
|
919
|
+
return "'," + unescape(code) + ",'";
|
893
920
|
})
|
894
|
-
.replace(c.evaluate ||
|
895
|
-
return "');" + code.replace(
|
896
|
-
.replace(/[\r\n\t]/g, ' ') + "__p.push('";
|
921
|
+
.replace(c.evaluate || noMatch, function(match, code) {
|
922
|
+
return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('";
|
897
923
|
})
|
898
924
|
.replace(/\r/g, '\\r')
|
899
925
|
.replace(/\n/g, '\\n')
|
900
926
|
.replace(/\t/g, '\\t')
|
901
927
|
+ "');}return __p.join('');";
|
902
928
|
var func = new Function('obj', '_', tmpl);
|
903
|
-
|
929
|
+
if (data) return func(data, _);
|
930
|
+
return function(data) {
|
931
|
+
return func.call(this, data, _);
|
932
|
+
};
|
933
|
+
};
|
934
|
+
|
935
|
+
// Add a "chain" function, which will delegate to the wrapper.
|
936
|
+
_.chain = function(obj) {
|
937
|
+
return _(obj).chain();
|
904
938
|
};
|
905
939
|
|
906
940
|
// The OOP Wrapper
|
@@ -935,8 +969,11 @@
|
|
935
969
|
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
|
936
970
|
var method = ArrayProto[name];
|
937
971
|
wrapper.prototype[name] = function() {
|
938
|
-
|
939
|
-
|
972
|
+
var wrapped = this._wrapped;
|
973
|
+
method.apply(wrapped, arguments);
|
974
|
+
var length = wrapped.length;
|
975
|
+
if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0];
|
976
|
+
return result(wrapped, this._chain);
|
940
977
|
};
|
941
978
|
});
|
942
979
|
|
data/lib/judge/version.rb
CHANGED
@@ -58,7 +58,7 @@ describe('judge', function() {
|
|
58
58
|
});
|
59
59
|
|
60
60
|
it('has custom validation methods when defined by user', function() {
|
61
|
-
judge.customValidators.phatness = function(
|
61
|
+
judge.customValidators.phatness = function() {};
|
62
62
|
expect(_(j.validates()).keys()).toContain('phatness');
|
63
63
|
});
|
64
64
|
|
@@ -649,13 +649,14 @@ describe('judge', function() {
|
|
649
649
|
describe('convertFlags', function() {
|
650
650
|
|
651
651
|
it('returns m if present in options string without negation', function() {
|
652
|
-
expect(judge.utils.convertFlags('
|
652
|
+
expect(judge.utils.convertFlags('mix')).toEqual('m');
|
653
|
+
expect(judge.utils.convertFlags('m-ix')).toEqual('m');
|
654
|
+
expect(judge.utils.convertFlags('mx-i')).toEqual('m');
|
653
655
|
});
|
654
656
|
|
655
657
|
it('returns empty string otherwise', function() {
|
656
|
-
expect(judge.utils.convertFlags('-
|
657
|
-
expect(judge.utils.convertFlags('
|
658
|
-
expect(judge.utils.convertFlags('-m')).toEqual('');
|
658
|
+
expect(judge.utils.convertFlags('ix-m')).toEqual('');
|
659
|
+
expect(judge.utils.convertFlags('x-mi')).toEqual('');
|
659
660
|
});
|
660
661
|
|
661
662
|
});
|