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 +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
|
});
|