Skip to content

Commit

Permalink
1.8-WIP ... still needs to be further reduced and cleaned
Browse files Browse the repository at this point in the history
  • Loading branch information
jashkenas committed Feb 19, 2015
1 parent 3d77868 commit 4f771e0
Show file tree
Hide file tree
Showing 17 changed files with 1,261 additions and 887 deletions.
2 changes: 1 addition & 1 deletion bower.json
@@ -1,6 +1,6 @@
{
"name": "underscore",
"version": "1.7.0",
"version": "1.8.0",
"main": "underscore.js",
"keywords": ["util", "functional", "server", "client", "browser"],
"ignore" : ["docs", "test", "*.yml", "CNAME", "index.html", "favicon.ico", "CONTRIBUTING.md"]
Expand Down
2 changes: 1 addition & 1 deletion component.json
Expand Up @@ -5,6 +5,6 @@
"repo" : "jashkenas/underscore",
"main" : "underscore.js",
"scripts" : ["underscore.js"],
"version" : "1.7.0",
"version" : "1.8.0",
"license" : "MIT"
}
15 changes: 9 additions & 6 deletions docs/docco.css
Expand Up @@ -21,11 +21,11 @@
}

@font-face {
font-family: 'novecento-bold';
src: url('public/fonts/novecento-bold.eot');
src: url('public/fonts/novecento-bold.eot?#iefix') format('embedded-opentype'),
url('public/fonts/novecento-bold.woff') format('woff'),
url('public/fonts/novecento-bold.ttf') format('truetype');
font-family: 'roboto-black';
src: url('public/fonts/roboto-black.eot');
src: url('public/fonts/roboto-black.eot?#iefix') format('embedded-opentype'),
url('public/fonts/roboto-black.woff') format('woff'),
url('public/fonts/roboto-black.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
Expand Down Expand Up @@ -67,14 +67,17 @@ h1, h2, h3, h4, h5, h6 {
color: #112233;
line-height: 1em;
font-weight: normal;
font-family: "novecento-bold";
font-family: "roboto-black";
text-transform: uppercase;
margin: 30px 0 15px 0;
}

h1 {
margin-top: 40px;
}
h2 {
font-size: 1.26em;
}

hr {
border: 0;
Expand Down
Binary file removed docs/public/fonts/novecento-bold.eot
Binary file not shown.
Binary file removed docs/public/fonts/novecento-bold.ttf
Binary file not shown.
Binary file removed docs/public/fonts/novecento-bold.woff
Binary file not shown.
Binary file added docs/public/fonts/roboto-black.eot
Binary file not shown.
Binary file added docs/public/fonts/roboto-black.ttf
Binary file not shown.
Binary file added docs/public/fonts/roboto-black.woff
Binary file not shown.
1,882 changes: 1,159 additions & 723 deletions docs/underscore.html

Large diffs are not rendered by default.

59 changes: 54 additions & 5 deletions index.html
Expand Up @@ -180,7 +180,7 @@
<div id="sidebar" class="interface">

<a class="toc_title" href="#">
Underscore.js <span class="version">(1.7.0)</span>
Underscore.js <span class="version">(1.8.0)</span>
</a>
<ul class="toc_section">
<li>&raquo; <a href="https://github.com/jashkenas/underscore">GitHub Repository</a></li>
Expand Down Expand Up @@ -239,6 +239,7 @@
<li>- <a href="#difference">difference</a></li>
<li>- <a href="#uniq">uniq</a></li>
<li>- <a href="#zip">zip</a></li>
<li>- <a href="#unzip">unzip</a></li>
<li>- <a href="#object">object</a></li>
<li>- <a href="#indexOf">indexOf</a></li>
<li>- <a href="#lastIndexOf">lastIndexOf</a></li>
Expand Down Expand Up @@ -393,13 +394,13 @@ <h2>Downloads <i style="padding-left: 12px; font-size:12px;">(Right-click, and u

<table>
<tr>
<td><a href="underscore.js">Development Version (1.7.0)</a></td>
<td><i>46kb, Uncompressed with Plentiful Comments</i></td>
<td><a href="underscore.js">Development Version (1.8.0)</a></td>
<td><i>52kb, Uncompressed with Plentiful Comments</i></td>
</tr>
<tr>
<td><a href="underscore-min.js">Production Version (1.7.0)</a></td>
<td><a href="underscore-min.js">Production Version (1.8.0)</a></td>
<td>
<i>5.2kb, Minified and Gzipped</i>
<i>5.8kb, Minified and Gzipped</i>
&nbsp;<small>(<a href="underscore-min.map">Source Map</a>)</small>
</td>
</tr>
Expand Down Expand Up @@ -954,6 +955,19 @@ <h2 id="arrays">Array Functions</h2>

_.zip.apply(_, arrayOfRowsOfData);
=&gt; arrayOfColumnsOfData
</pre>

<p id="unzip">
<b class="header">unzip</b><code>_.unzip(*arrays)</code>
<br>
The opposite of <a href="#zip">zip</a>. Given a number of <b>arrays</b>, returns a
series of new arrays, the first of which contains all of the first elements
in the input arrays, the second of which contains all of the second elements,
and so on. Use with <tt>apply</tt> to pass in an array of arrays.
</p>
<pre>
_.unzip(["moe", 30, true], ["larry", 40, false], ["curly", 50, false]);
+=&gt; [['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]]
</pre>

<p id="object">
Expand Down Expand Up @@ -2049,6 +2063,41 @@ <h2 id="links">Links &amp; Suggested Reading</h2>

<h2 id="changelog">Change Log</h2>

<p id="1.8.0">
<b class="header">1.8.0</b> &mdash; <small><i>Feb. 19, 2015</i></small> &mdash; <a href="https://github.com/jashkenas/underscore/compare/1.7.0...1.8.0">Diff</a> &mdash; <a href="https://cdn.rawgit.com/jashkenas/underscore/1.8.0/index.html">Docs</a><br />
<ul>
<li>
Added <tt>_.allKeys</tt> which returns <i>all</i> the enumerable property
names on an object.
</li>
<li>
Reverted a 1.7.0 change where <tt>_.extend</tt> only copied "own" properties.
</li>
<li>
Added <tt>_.extendOwn</tt> &mdash; a form of <tt>_.extend</tt> that
only copies over "own" properties.
</li>
<li>
Added an <tt>_.isError</tt> function.
</li>
<li>
Restored the <tt>_.unzip</tt> function as the inverse of <tt>zip</tt>.
</li>
<li>
<tt>_.result</tt> now takes an optional <b>fallback</b> value (or function
that provides a default value).
</li>
<li>
Added <tt>_.propertyOf</tt> wrapper as a mirror-world version
of <tt>_.property</tt>.
</li>
<li>
Various and diverse code simplifications, changes for improved
cross-platform compatibility, and edge case bug fixes.
</li>
</ul>
</p>

<p id="1.7.0">
<b class="header">1.7.0</b> &mdash; <small><i>August 26, 2014</i></small> &mdash; <a href="https://github.com/jashkenas/underscore/compare/1.6.0...1.7.0">Diff</a> &mdash; <a href="https://cdn.rawgit.com/jashkenas/underscore/1.7.0/index.html">Docs</a><br />
<ul>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -15,7 +15,7 @@
"url": "git://github.com/jashkenas/underscore.git"
},
"main": "underscore.js",
"version": "1.7.0",
"version": "1.8.0",
"devDependencies": {
"docco": "0.6.x",
"eslint": "0.6.x",
Expand Down
57 changes: 1 addition & 56 deletions test/collections.js
Expand Up @@ -100,7 +100,7 @@
'each', 'map', 'filter', 'find',
'some', 'every', 'max', 'min', 'reject',
'groupBy', 'countBy', 'partition', 'indexBy',
'transform', 'reduce', 'reduceRight'
'reduce', 'reduceRight'
];
var array = [
'findIndex', 'findLastIndex'
Expand Down Expand Up @@ -252,53 +252,6 @@
strictEqual(_.reduceRight, _.foldr, 'alias for reduceRight');
});

test('transform', function() {
var list = _.transform(['foo', 'bar', 'baz'], function(accumulator, value, index){ accumulator[index] = value + '2'; });
deepEqual(list, ['foo2', 'bar2', 'baz2'], 'handles arrays with no accumulator');

list = _.transform(['foo', 'bar', 'baz'], function(accumulator, value, index){ accumulator[index] = value + '2'; }, []);
deepEqual(list, ['foo2', 'bar2', 'baz2'], 'handles arrays with array accumulator');

list = _.transform(['foo', 'bar', 'baz'], function(accumulator, value, index){ accumulator[index] = value + '2'; }, {});
deepEqual(list, {0: 'foo2', 1: 'bar2', 2: 'baz2'}, 'handles arrays with object accumulator');

var obj = _.transform({foo: 1, bar: 2, baz: 3}, function(accumulator, value, key){ accumulator[key] = value + 1; });
deepEqual(obj, {foo: 2, bar: 3, baz: 4}, 'handles objects with no accumulator');

obj = _.transform({foo: 1, bar: 2, baz: 3}, function(accumulator, value, key){ accumulator[key] = value + 1; }, {});
deepEqual(obj, {foo: 2, bar: 3, baz: 4}, 'handles objects with array accumulator');

obj = _.transform({0: 'foo', 1: 'bar', 2: 'baz'}, function(accumulator, value, key){ accumulator[key] = value + '2'; }, []);
deepEqual(obj, ['foo2', 'bar2', 'baz2'], 'handles objects with object accumulator');

function Obj(props) { _.extend(this, props); }
var instance = new Obj({foo: 1, bar: 2, baz: 3});
obj = _.transform(instance, function(accumulator, value, key){ accumulator[key] = value + 1; });
ok(obj !== instance && obj instanceof Obj, 'creates a new instance of the object');
deepEqual(obj, new Obj({foo: 2, bar: 3, baz: 4}), 'handles instances with no accumulator');

var context = {}, actualContext;
_.transform([1], function() { actualContext = this; }, {}, context);
strictEqual(actualContext, context, 'iterates with the correct context');

obj = {foo: 1};
var accumulator = {};
var args = [accumulator, 'foo', obj.foo, obj], actualArgs;
_.transform(obj, function() { actualArgs = _.toArray(args); }, accumulator);
deepEqual(args, actualArgs, 'iterates with the correct arguments');

accumulator = {};
strictEqual(_.transform([1], function() {}, accumulator), accumulator);

deepEqual(_.transform(), {}, 'should return an empty object when no obj or accumulator is passed');

accumulator = [];
strictEqual(_.transform(null, null, accumulator), accumulator, 'should return the accumulator when no obj is passed');

list = _.transform([1, 2, 3, 4], function(accumulator, value) { return value < 3 && accumulator.push(value); });
deepEqual(list, [1, 2], 'transform should stop when false is returned.');
});

test('find', function() {
var array = [1, 2, 3, 4];
strictEqual(_.find(array, function(n) { return n > 2; }), 3, 'should return first found `value`');
Expand Down Expand Up @@ -453,14 +406,6 @@
strictEqual(_.includes([1, 2, 3], 2), true, 'two is in the array');
ok(!_.includes([1, 3, 9], 2), 'two is not in the array');

var numbers = [1, 2, 3, 1, 2, 3, 1, 2, 3];
strictEqual(_.includes(numbers, 1, 1), true);
strictEqual(_.includes(numbers, 1, -1), false);
strictEqual(_.includes(numbers, 1, -2), false);
strictEqual(_.includes(numbers, 1, -3), true);
strictEqual(_.includes(numbers, 1, 6), true);
strictEqual(_.includes(numbers, 1, 7), false);

strictEqual(_.includes([5, 4, 3, 2, 1], 5, true), true, 'doesn\'t delegate to binary search');

ok(_.includes({moe: 1, larry: 3, curly: 9}, 3) === true, '_.includes on objects checks their values');
Expand Down
68 changes: 21 additions & 47 deletions test/objects.js
Expand Up @@ -35,20 +35,20 @@
deepEqual(_.keys(trouble).sort(), troubleKeys, 'matches non-enumerable properties');
});

test('keysIn', function() {
deepEqual(_.keysIn({one : 1, two : 2}), ['one', 'two'], 'can extract the keysIn from an object');
test('allKeys', function() {
deepEqual(_.allKeys({one : 1, two : 2}), ['one', 'two'], 'can extract the allKeys from an object');
// the test above is not safe because it relies on for-in enumeration order
var a = []; a[1] = 0;
deepEqual(_.keysIn(a), ['1'], 'is not fooled by sparse arrays; see issue #95');
deepEqual(_.allKeys(a), ['1'], 'is not fooled by sparse arrays; see issue #95');

a.a = a;
deepEqual(_.keysIn(a), ['1', 'a'], 'is not fooled by sparse arrays with additional properties');
deepEqual(_.allKeys(a), ['1', 'a'], 'is not fooled by sparse arrays with additional properties');

_.each([null, void 0, 1, 'a', true, NaN, {}, [], new Number(5), new Date(0)], function(val) {
deepEqual(_.keysIn(val), []);
deepEqual(_.allKeys(val), []);
});

// keysIn that may be missed if the implementation isn't careful
// allKeys that may be missed if the implementation isn't careful
var trouble = {
constructor: Object,
valueOf: _.noop,
Expand All @@ -60,17 +60,17 @@
};
var troubleKeys = ['constructor', 'valueOf', 'hasOwnProperty', 'toString', 'toLocaleString', 'propertyIsEnumerable',
'isPrototypeOf'].sort();
deepEqual(_.keysIn(trouble).sort(), troubleKeys, 'matches non-enumerable properties');
deepEqual(_.allKeys(trouble).sort(), troubleKeys, 'matches non-enumerable properties');

function A() {}
A.prototype.foo = 'foo';
var b = new A();
b.bar = 'bar';
deepEqual(_.keysIn(b), ['bar', 'foo'], 'should include inherited keys');
deepEqual(_.allKeys(b), ['bar', 'foo'], 'should include inherited keys');

function y() {}
y.x = 'z';
deepEqual(_.keysIn(y), ['x'], 'should get keys from constructor');
deepEqual(_.allKeys(y), ['x'], 'should get keys from constructor');
});

test('values', function() {
Expand Down Expand Up @@ -136,33 +136,33 @@
strictEqual(_.extend(undefined, {a: 1}), undefined, 'extending undefined results in undefined');
});

test('assign', function() {
test('extendOwn', function() {
var result;
equal(_.assign({}, {a: 'b'}).a, 'b', 'can assign an object with the attributes of another');
equal(_.assign({a: 'x'}, {a: 'b'}).a, 'b', 'properties in source override destination');
equal(_.assign({x: 'x'}, {a: 'b'}).x, 'x', "properties not in source don't get overriden");
result = _.assign({x: 'x'}, {a: 'a'}, {b: 'b'});
equal(_.extendOwn({}, {a: 'b'}).a, 'b', 'can assign an object with the attributes of another');
equal(_.extendOwn({a: 'x'}, {a: 'b'}).a, 'b', 'properties in source override destination');
equal(_.extendOwn({x: 'x'}, {a: 'b'}).x, 'x', "properties not in source don't get overriden");
result = _.extendOwn({x: 'x'}, {a: 'a'}, {b: 'b'});
deepEqual(result, {x: 'x', a: 'a', b: 'b'}, 'can assign from multiple source objects');
result = _.assign({x: 'x'}, {a: 'a', x: 2}, {a: 'b'});
result = _.extendOwn({x: 'x'}, {a: 'a', x: 2}, {a: 'b'});
deepEqual(result, {x: 2, a: 'b'}, 'assigning from multiple source objects last property trumps');
deepEqual(_.assign({}, {a: void 0, b: null}), {a: void 0, b: null}, 'assign copies undefined values');
deepEqual(_.extendOwn({}, {a: void 0, b: null}), {a: void 0, b: null}, 'assign copies undefined values');

var F = function() {};
F.prototype = {a: 'b'};
var subObj = new F();
subObj.c = 'd';
deepEqual(_.assign({}, subObj), {c: 'd'}, 'assign copies own properties from source');
deepEqual(_.extendOwn({}, subObj), {c: 'd'}, 'assign copies own properties from source');

result = {};
deepEqual(_.assign(result, null, undefined, {a: 1}), {a: 1}, 'should not error on `null` or `undefined` sources');
deepEqual(_.extendOwn(result, null, undefined, {a: 1}), {a: 1}, 'should not error on `null` or `undefined` sources');

_.each(['a', 5, null, false], function(val) {
strictEqual(_.assign(val, {a: 1}), val, 'assigning non-objects results in returning the non-object value');
strictEqual(_.extendOwn(val, {a: 1}), val, 'assigning non-objects results in returning the non-object value');
});

strictEqual(_.assign(undefined, {a: 1}), undefined, 'assigning undefined results in undefined');
strictEqual(_.extendOwn(undefined, {a: 1}), undefined, 'assigning undefined results in undefined');

result = _.assign({a: 1, 0: 2, 1: '5', length: 6}, {0: 1, 1: 2, length: 2});
result = _.extendOwn({a: 1, 0: 2, 1: '5', length: 6}, {0: 1, 1: 2, length: 2});
deepEqual(result, {a: 1, 0: 1, 1: 2, length: 2}, 'assign should treat array-like objects like normal objects');
});

Expand Down Expand Up @@ -277,32 +277,6 @@
equal(_.clone(null), null, 'non objects should not be changed by clone');
});

test('create', function() {
var Parent = function() {};
Parent.prototype = {foo: function() {}, bar: 2};

_.each(['foo', null, undefined, 1], function(val) {
deepEqual(_.create(val), {}, 'should return empty object when a non-object is provided');
});

ok(_.create([]) instanceof Array, 'should return new instance of array when array is provided');

var Child = function() {};
Child.prototype = _.create(Parent.prototype);
ok(new Child instanceof Parent, 'object should inherit prototype');

var func = function() {};
Child.prototype = _.create(Parent.prototype, {func: func});
strictEqual(Child.prototype.func, func, 'properties should be added to object');

Child.prototype = _.create(Parent.prototype, {constructor: Child});
strictEqual(Child.prototype.constructor, Child);

Child.prototype.foo = 'foo';
var created = _.create(Child.prototype, new Child);
ok(!created.hasOwnProperty('foo'), 'should only add own properties');
});

test('isEqual', function() {
function First() {
this.value = 1;
Expand Down

0 comments on commit 4f771e0

Please sign in to comment.