diff --git a/.gitmodules b/.gitmodules index 566bd4f..289ca75 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "lib/es5-shim"] - path = lib/es5-shim - url = git://github.com/kriskowal/es5-shim.git [submodule "build/html"] path = build/html url = git://github.com/quadroid/clonejs.git diff --git a/.version b/.version index 4c9c442..d0a68ee 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -v0.7.4-beta \ No newline at end of file +v1.0.0-alpha \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d87146..428adf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### Build v0.7.4-beta (2013-04-14 09:06) +##### Build v0.7.4 (2013-04-14 09:06) * add ability to inject into Object.prototype, update module interface * change namespace interface * add RequireJS support @@ -7,21 +7,21 @@ * improve documentation * refactor tests -### Build v0.7.3-beta (2013-04-12 06:00) +##### Build v0.7.3 (2013-04-12 06:00) * improve documentation * fix bug: first call applySuper() on sealed object * optimize `for` * deploy scripts: add comments -### Build v0.7.2-05-beta (2013-04-06 15:35) +###### Build v0.7.2-05 (2013-04-06 15:35) * reverse changelog items order * deploy scripts: fix new line in build message * fix cdn src -### Build v0.7.2-04-beta (2013-04-06 14:35) +###### Build v0.7.2-04 (2013-04-06 14:35) * update documentation -### Build v0.7.2-03-beta (2013-04-01 12:06) +###### Build v0.7.2-03 (2013-04-01 12:06) * fix bug in getKeys(), forEach() * add getValues() test * add getSuper() @@ -31,11 +31,11 @@ * update describe() test * fix applySuper() bug -### Build v0.7.2-02-beta (2013-03-30 22:06) +###### Build v0.7.2-02 (2013-03-30 22:06) * fix home page nav * incrase CI speed -### Build 0.7.2.01 (2013-03-30 15:32) +###### Build v0.7.2-01 (2013-03-30 15:32) * fix deploy scripts * jsdoc template: update DL's formatting * edit readme diff --git a/README.md b/README.md index a9315d9..9eed8bb 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,42 @@ -## [clone.js](http://clonejs.org) [![Build Status](https://travis-ci.org/quadroid/clonejs.png?branch=master "travis-ci.org")](https://travis-ci.org/quadroid/clonejs) -[API documentation](http://clonejs.org/symbols/%24object.html) +## CloneJS [![Build Status](https://travis-ci.org/quadroid/clonejs.png?branch=master "travis-ci.org")](https://travis-ci.org/quadroid/clonejs) [![NPM version](https://badge.fury.io/js/clonejs.png)](http://badge.fury.io/js/clonejs) +[**CloneJS.org**](http://clonejs.org) +| [API documentation](http://clonejs.org/symbols/clone.html) | [ChangeLog](https://github.com/quadroid/clonejs/blob/master/CHANGELOG.md) -| [GitHub](http://github.com/quadroid/clonejs) +*| [GitHub](http://github.com/quadroid/clonejs) | [NPM package](http://npmjs.org/package/clonejs) -| [Travis CI](http://travis-ci.org/quadroid/clonejs) +| [Travis CI](http://travis-ci.org/quadroid/clonejs)* + +**This framework provides:** -This is the micro-framework that based on the ECMA Script 5 features like [Object.create⠙][] and [property descriptors⠙][Object.defineProperty⠙]. +* Speed! It's extrimerly fast! +* Class-less, the pure prototype-oriented paradigm. +* Separate all your objects and classes to state (data) and behavior (methods). +* [Lazy initialization⠙][] support (by `__inits__` behavior). +* IE6+ support! Shims `Object.create` and `Object.getPrototypeOf` methods. -##### Try the true [prototype-based OOP⠙](http://en.wikipedia.org/wiki/Prototype-based_programming) +[Lazy initialization⠙]: http://en.wikipedia.org/wiki/Lazy_initialization -**It's trivial to create new "classes"** - just clone the prototype and change a couple of properties and voila... new "class". +The main code of the framework: -**It's really class-free**: do you know the difference between js constructor-functions and classes in other languages? -`$object.clone` produces prototype objects, not function-constructors, unlike other class-producing tools (`Backbone.Model.extend`, `Ext.define`, `dojo.declare`). + function clone(/** Object! */obj, /** object! */state, /** object= */behavior$){ + if( behavior$ ){ + behavior$.__proto__ = obj; + state.__proto__ = behavior$; + }else{ + state.__proto__ = obj; + } + return state; + } + +Thats it! + +#### Try the true [prototype-based OOP⠙](http://en.wikipedia.org/wiki/Prototype-based_programming) + +**It's trivial to create new "classes"** - just clone the object and change a couple of properties and voila... new "class". + +**It's really class-free**: `clone` produces prototype objects, not function-constructors, unlike other class-producing tools (`Ext.define`, `dojo.declare`). In this framework you can easilly create and manipulate objects without constructors, instead of classic js way, where you should define a constructor for every object (that you want to use as prototype), even if you didn't need it. @@ -31,207 +53,75 @@ Node.js: npm install clonejs -[CDN⠙][] for client-side (~3 KB gzipped): +[CDN⠙][] for client-side: ### Usage - // - var clonejs = require('clonejs'), - $object = clonejs.$object; - //or: var $object = require('clonejs').$object; - //or: require('clonejs').inject(); - // + var clone = require('clonejs');// /// Forget about classes. // Instead of creating class (function), create prototype (object): - var $duck = $object.clone({ - name: 'Unnamed', + + var duck$ = { quack: function(){ - console.log( this.name +' Duck: Quack-quack!'); + console.log( this.name +" Duck: Quack-quack!"); } - }); - $duck.quack();//Unnamed Duck: Quack-quack! - - /// Inheritance is simple: - var $talkingDuck = $duck.clone({ + }; + + /// Inheritance is simple (talkingDuck$ extends duck$): + + var talkingDuck$ = clone(duck$, { quack: function(){ - this.applySuper('quack'); - console.log('My name is '+ this.name +'!'); - } + duck$.quack.call(this); + console.log("My name is "+ this.name +"!"); + } }); - /// Forget about the `new` operator, use .create() method instead: - var donald = $talkingDuck.create({name: 'Donald'}); - donald.quack();// Donald Duck: Quack-quack! My name is Donald! + /// Forget about the `new` operator, use clone to create instances: + + var donald = clone(talkingDuck$, {name: "Donald"}); + donald.quack();// Donald Duck: Quack-quack! + // My name is Donald! + var daffy = clone(talkingDuck$, {name: "Daffy"}); + daffy.quack(); // Daffy Duck: Quack-quack! + // My name is Daffy! /// Forget about the `instanceof` operator, use JS native // .isPrototypeOf() method instead: - $duck.isPrototypeOf(donald);// true - - - -###### Cloning objects: - - var $proto = $object.clone({a:1, b:2, c:3}); - - /// clone: - var clone = $proto.clone(); - clone.a = 11; // $proto.a not changed - $proto.b = 22; // clone.b will be also changed to 22 - - /// copy: - var copy = $proto.copy(); - copy.a = 111;// $proto.a not changed - $proto.b = 222;// copy.b not changed - /// create: - var instance = $proto.create({d: 4444}); - instance.a = 1111;// $proto.a not changed - $proto.b = 2222;// like clone, instance.b will be also changed to 2222 - assert( instance.a === 1111 ); - assert( instance.d === 4444 ); - -See: [clone][], [copy][], [create][], [deepCopy][], [deepClone][]. - -###### Property modificators: - - var $myType = $object.clone({ - '(final) property1': "not configurable and not writable", - '(writable final) property2': "not configurable only", - '(hidden) property3': "not enumerable", - '(const) constant': "not writable", - property4 : "simple property", - '(get) property3alias': 'property3',// automatically create getter - _item : "private property (not enumerable)", - '(get) item': function() { return this._item }, - '(set) item': function(v){ this._item = v }, - constructor : 'MyType' - }); - assert( $myType.property3alias === $myType.property3 ); - -See: [describe][]. - -###### Inheritance & constructors: - - var $parent = $object.clone({ - constructor: function Parent(){ - this.applySuper(); - console.log('$parent constructor arguments:', arguments); - } - }); - - var $child = $parent.clone({ - constructor: function Child(arg1, arg2){ - this.callSuper('constructor', arg1, arg2); - console.log('$child constructor arguments:', arguments); - } - }); - - var $grandchild = $child.clone({ - constructor: function Grandchild(){ - this.applySuper(arguments); - console.log('$grandchild constructor arguments:', arguments); - } - }); - - var myBoy = $grandchild.create(1,2,3); - /// console log: - // $parent constructor arguments: [1,2] - // $child constructor arguments: [1,2,3] - // $grandchild constructor arguments: [1,2,3] - - assert( $child.isPrototypeOf(myBoy) ); + duck$.isPrototypeOf(donald);// true -See: [constructor][], [create][], [applySuper][], [callSuper][], [createSuperSafeCallback][]. - -###### Properties iteration: - - var $obj = $object.clone({a: 11, b: 22, c: 33}), - obj = $obj.create({d: 44}); - - /// Map only own properties (default): - - var mappedObj1 = obj.map(function(value){return 100 + value}); - // mappedObj1 == {d: 144} - /// Map all properties, replace default (`$object`) prototype of returned object: - - var proto = {e: 55}; - var mappedObj2 = obj.map(function(value){return 100 + value}, obj, false, proto); - // mappedObj2 == {a: 111, b: 122, c: 133, d: 144, e: 155} - proto.f = 66; - // mappedObj2 == {a: 111, b: 122, c: 133, d: 144, e: 155, f: 66} - -See: [forEach][], [map][], [filter][], [every][], [some][]. - -###### Namespaces: - - var app = clonejs.$namespace.create(); - - /// create namespace item `app.collections` - - app.extend('collections', { - $item: {}, - _items: {} - }); +###### Lazy initialization: - /// create namespace item `app.collections.arrayCollections` +Instead of defining in constructor, you can initialize your properties separetly. +Lazy initialization is the tactic, that will initialize property in first use of them. - app.collections.extend('arrayCollections', {_items: []}); - - /// create namespace item `app.models.users` - - var $users = app.collections.$arrayCollections.clone({ - $item: {name: '', isAdmin: false}, - constructor: function Users(items){ - items.forEach(function(item){ - var newItem = $object.create.call(this.$item, item); - this._items.push(newItem); - }, this); + var obj = clone.create({ + name: "Default Name" + },{ + __inits__: { + lazy: function(){ + console.log("Lazy initialization..."); + return this.name +": Lazy initiated.": + } } }); - app.put('models.users', $users); - - /// use namespace: - - var users = app.models.$users.create([{name: 'User1'}]); - -See: [$namespace][], [$namespace.extend][], [$namespace.put][]. - - + console.log( obj.lazy ); + // Lazy initialization... + // Default Name: Lazy initiated. + + console.log( obj.lazy );// initializer don't run again + // Default Name: Lazy initiated. [Object.create⠙]: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create [Object.defineProperty⠙]: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty +[property descriptors⠙]: http://ejohn.org/blog/ecmascript-5-objects-and-properties/#ig-sh-1 [CDN⠙]: http://code.lancepollard.com/github-as-a-cdn/ -[$object]: http://clonejs.org/symbols/%24object.html - -[clone]: http://clonejs.org/symbols/%24object.html#clone -[create]: http://clonejs.org/symbols/%24object.html#create -[copy]: http://clonejs.org/symbols/%24object.html#copy -[deepCopy]: http://clonejs.org/symbols/%24object.html#deepCopy -[deepClone]: http://clonejs.org/symbols/%24object.html#deepClone - -[describe]: http://clonejs.org/symbols/%24object.html#.describe - -[forEach]: http://clonejs.org/symbols/%24object.html#forEach -[every]: http://clonejs.org/symbols/%24object.html#every -[some]: http://clonejs.org/symbols/%24object.html#some -[map]: http://clonejs.org/symbols/%24object.html#map -[filter]: http://clonejs.org/symbols/%24object.html#filter - -[constructor]: http://clonejs.org/symbols/%24object.html#constructor -[applySuper]: http://clonejs.org/symbols/%24object.html#applySuper -[callSuper]: http://clonejs.org/symbols/%24object.html#callSuper -[createSuperSafeCallback]: http://clonejs.org/symbols/%24object.html#createSuperSafeCallback - -[$namespace]: http://clonejs.org/symbols/$namespace.html -[$namespace.extend]: http://clonejs.org/symbols/$namespace.html#extend -[$namespace.put]: http://clonejs.org/symbols/$namespace.html#put - ![yandex metrika](http://mc.yandex.ru/watch/20738752) [![githalytics.com alpha](https://cruel-carlota.pagodabox.com/3110be9614da5cb337ebd483c187010f "githalytics.com")](http://githalytics.com/quadroid/clonejs) diff --git a/build/clone.min.js b/build/clone.min.js index 054dc86..6763121 100644 --- a/build/clone.min.js +++ b/build/clone.min.js @@ -1,19 +1,6 @@ -'use strict';(function(n){function t(){Object.defineProperties(Object.prototype,f.describe(f));f=Object.prototype;Object.defineProperty(p,"$object",{value:f})}var f={clone:function(k,h){if(arguments.length)var c=f.describe.apply(this,arguments);return Object.create(this,c)},create:function(f,h){var c=this.clone();return c.constructor.apply(c,arguments)||c},constructor:function(f,h){if("object"==typeof f)this.defineProperties(f,h);else if(arguments.length)return Object(f)},describe:function(f,h){var c= -{},a=h?h:{configurable:!0,enumerable:!0,writable:!0},d=!(h&&h.enumerable),b;for(b in f){var e=f[b],g=Object.create(a);if("("==b[0]){var i=b.match(/^\((((get|set|const|hidden|final|writable) *)+)\) +(.+)$/);if(i){var j=i[1].split(" ").sort();b=i[4];c[b]&&(g=c[b]);for(var m in j)switch(j[m]){case "const":g.writable=!1;break;case "final":g.configurable=!1;g.writable=!1;break;case "get":g.get=e;break;case "hidden":g.enumerable=!1;break;case "set":g.set=e;break;case "writable":g.writable=!0}}}if(g.get|| -g.set){if("string"==typeof e){var r=e;"string"==typeof g.get?g.get=function(){return this[r]}:g.set=function(a){this[r]=a}}g.value=void 0;g.get&&(e=void 0)}else g.value=e;if(d&&"function"==typeof e||"_"==b[0])g.enumerable=!1;b.toUpperCase()==b&&(g.writable=!1);c[b]=g}c.hasOwnProperty("constructor")&&(a=c.constructor.value,"string"==typeof a?(d=a,a=Function("return function "+d+"(){return this.applySuper(arguments)}")(),a.typeName=d,c.constructor.value=a):a.typeName||(a.typeName=a.name||"CloneOf"+ -this.constructor.typeName),a.prototype=this,c.constructor.enumerable=!1);return c},applySuper:function(f,h){"string"!=typeof f&&(h=f,f="constructor");"__super__"in this||this.getSuper(!0);var c=this.__super__;this.__super__=Object.getPrototypeOf(c);var a=c[f].apply(this,h);this.__super__=c;return a},callSuper:function(f,h,c){var a=Array.prototype.slice.call(arguments,1);return this.applySuper(f,a)},getSuper:function(f){var h=Object.getPrototypeOf(Object.getPrototypeOf(this));f&&this.defineProperty("__super__", -{value:h,writable:!0,configurable:!0});return h},createSuperSafeCallback:function(f,h){if("string"==typeof f){var c=this[f];"undefined"==typeof h&&(h=this)}else c=f;var a=this,d=this.__super__;return function(){if(a.__super__===d)return c.apply(h||this,arguments);var b=a.__super__;a.__super__=d;var e=c.apply(h||this,arguments);a.__super__=b;return e}},getState:function(k){for(var h=f.create(),k=k?Object.getOwnPropertyNames(this):Object.keys(this),c=0,a=k.length;c boilerplate - -1.2.2 - - Changed reduce to follow the letter of the spec with regard to having and - owning properties. - - Fixed a bug where RegExps pass as Functions in some engines in reduce. - -1.2.1 - - Adding few fixes to make jshint happy. - - Fix for issue #12, function expressions can cause scoping issues in IE. - - NPM will minify on install or when `npm run-script install` is executed. - - Adding .gitignore to avoid publishing dev dependencies. - -1.2.0 - - Making script loadable as AMD module. - - Adding `indexOf` to the list of safe shims. - -1.1.0 - - Added support for accessor properties where possible (which is all browsers - except IE). - - Stop exposing bound function's (that are returned by - `Function.prototype.bind`) internal properties (`bound, boundTo, boundArgs`) - as in some cases (when using facade objects for example) capabilities of the - enclosed functions will be leaked. - - `Object.create` now explicitly sets `__proto__` property to guarantee - correct behavior of `Object.getPrototypeOf`'s on all objects created using - `Object.create`. - - Switched to `===` from `==` where possible as it's slightly faster on older - browsers that are target of this lib. - - Added names to all anonymous functions to have a better stack traces. - -1.0.0 - - fixed Date.toISODate, using UTC accessors, as in - http://code.google.com/p/v8/source/browse/trunk/src/date.js?r=6120#986 - (arian) - -0.0.4 - - Revised Object.getPrototypeOf to work in more cases - in response to http://ejohn.org/blog/objectgetprototypeof/ - [issue #2] (fschaefer) - -0.0.3 - - Fixed typos in Object.keys (samsonjs) - -0.0.2 - Per kangax's recommendations: - - faster Object.create(null) - - fixed a function-scope function declaration statement in Object.create - -0.0.1 - - fixed Object.create(null), in so far as that's possible - - reworked Rhino Object.freeze(Function) bug detector and patcher - -0.0.0 - - forked from narwhal-lib - diff --git a/lib/es5-shim/CONTRIBUTORS.md b/lib/es5-shim/CONTRIBUTORS.md deleted file mode 100644 index 56959a6..0000000 --- a/lib/es5-shim/CONTRIBUTORS.md +++ /dev/null @@ -1,25 +0,0 @@ - -- kriskowal Kris Kowal Copyright (C) 2009-2011 MIT License -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal - Project) -- dantman Daniel Friesen Copyright (C) 2010 XXX TODO License or CLA -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License -- Gozala Irakli Gozalishvili Copyright (C) 2010 MIT License -- kitcambridge Kit Cambridge Copyright (C) 2011 MIT License -- kossnocorp Sasha Koss XXX TODO License or CLA -- bryanforbes Bryan Forbes XXX TODO License or CLA -- killdream Quildreen Motta Copyright (C) 2011 MIT Licence -- michaelficarra Michael Ficarra Copyright (C) 2011 3-clause BSD - License -- sharkbrainguy Gerard Paapu Copyright (C) 2011 MIT License -- bbqsrc Brendan Molloy (C) 2011 Creative Commons Zero (public domain) -- iwyg XXX TODO License or CLA -- DomenicDenicola Domenic Denicola Copyright (C) 2011 MIT License -- xavierm02 Montillet Xavier Copyright (C) 2011 MIT License -- Raynos Jake Verbaten Copyright (C) 2011 MIT Licence -- samsonjs Sami Samhuri Copyright (C) 2010 MIT License -- rwldrn Rick Waldron Copyright (C) 2011 MIT License -- lexer Alexey Zakharov XXX TODO License or CLA -- 280 North Inc. (Now Motorola LLC, a subsidiary of Google Inc.) - Copyright (C) 2009 MIT License - diff --git a/lib/es5-shim/LICENSE b/lib/es5-shim/LICENSE deleted file mode 100644 index fee0825..0000000 --- a/lib/es5-shim/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ - -Copyright 2009, 2010 Kristopher Michael Kowal. All rights reserved. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. diff --git a/lib/es5-shim/README.md b/lib/es5-shim/README.md deleted file mode 100644 index 2972222..0000000 --- a/lib/es5-shim/README.md +++ /dev/null @@ -1,161 +0,0 @@ - -`es5-shim.js` and `es5-shim.min.js` monkey-patch a JavaScript context to -contain all EcmaScript 5 methods that can be faithfully emulated with a -legacy JavaScript engine. - -`es5-sham.js` and `es5-sham.min.js` monkey-patch other ES5 methods as -closely as possible. For these methods, as closely as possible to ES5 -is not very close. Many of these shams are intended only to allow code -to be written to ES5 without causing run-time errors in older engines. -In many cases, this means that these shams cause many ES5 methods to -silently fail. Decide carefully whether this is what you want. - - -## Tests - -The tests are written with the Jasmine BDD test framework. -To run the tests, navigate to /tests/. - -In order to run against the shim-code, the tests attempt to kill the current -implementation of the missing methods. This happens in /tests/helpers/h-kill.js. -So in order to run the tests against the build-in methods, invalidate that file somehow -(comment-out, delete the file, delete the script-tag, etc.). - -## Shims - -### Complete tests ### - -* Array.prototype.every -* Array.prototype.filter -* Array.prototype.forEach -* Array.prototype.indexOf -* Array.prototype.lastIndexOf -* Array.prototype.map -* Array.prototype.some -* Array.prototype.reduce -* Array.prototype.reduceRight -* Array.isArray -* Date.now -* Date.prototype.toJSON -* Function.prototype.bind - * /!\ Caveat: the bound function's length is always 0. - * /!\ Caveat: the bound function has a prototype property. - * /!\ Caveat: bound functions do not try too hard to keep you - from manipulating their ``arguments`` and ``caller`` properties. - * /!\ Caveat: bound functions don't have checks in ``call`` and - ``apply`` to avoid executing as a constructor. -* Object.keys -* String.prototype.trim - -### Untested ### - -* Date.parse (for ISO parsing) -* Date.prototype.toISOString - -## Shams - -* /?\ Object.create - - For the case of simply "begetting" an object that - inherits prototypically from another, this should work - fine across legacy engines. - - /!\ Object.create(null) will work only in browsers that - support prototype assignment. This creates an object - that does not have any properties inherited from - Object.prototype. It will silently fail otherwise. - - /!\ The second argument is passed to - Object.defineProperties which will probably fail - silently. - -* /?\ Object.getPrototypeOf - - This will return "undefined" in some cases. It uses - __proto__ if it's available. Failing that, it uses - constructor.prototype, which depends on the constructor - property of the object's prototype having not been - replaced. If your object was created like this, it - won't work: - - function Foo() { - } - Foo.prototype = {}; - - Because the prototype reassignment destroys the - constructor property. - - This will work for all objects that were created using - `Object.create` implemented with this library. - -* /!\ Object.getOwnPropertyNames - - This method uses Object.keys, so it will not be accurate - on legacy engines. - -* Object.isSealed - - Returns "false" in all legacy engines for all objects, - which is conveniently guaranteed to be accurate. - -* Object.isFrozen - - Returns "false" in all legacy engines for all objects, - which is conveniently guaranteed to be accurate. - -* Object.isExtensible - - Works like a charm, by trying very hard to extend the - object then redacting the extension. - -### Fail silently - -* /!\ Object.getOwnPropertyDescriptor - - The behavior of this shim does not conform to ES5. It - should probably not be used at this time, until its - behavior has been reviewed and been confirmed to be - useful in legacy engines. - -* /!\ Object.defineProperty - - This method will silently fail to set "writable", - "enumerable", and "configurable" properties. - - Providing a getter or setter with "get" or "set" on a - descriptor will silently fail on engines that lack - "__defineGetter__" and "__defineSetter__", which include - all versions of IE up to version 8 so far. - - IE 8 provides a version of this method but it only works - on DOM objects. Thus, the shim will not get installed - and attempts to set "value" properties will fail - silently on non-DOM objects. - - https://github.com/kriskowal/es5-shim/issues#issue/5 - -* /!\ Object.defineProperties - - This uses the Object.defineProperty shim - -* Object.seal - - Silently fails on all legacy engines. This should be - fine unless you are depending on the safety and security - provisions of this method, which you cannot possibly - obtain in legacy engines. - -* Object.freeze - - Silently fails on all legacy engines. This should be - fine unless you are depending on the safety and security - provisions of this method, which you cannot possibly - obtain in legacy engines. - -* Object.preventExtensions - - Silently fails on all legacy engines. This should be - fine unless you are depending on the safety and security - provisions of this method, which you cannot possibly - obtain in legacy engines. - diff --git a/lib/es5-shim/es5-sham.js b/lib/es5-shim/es5-sham.js deleted file mode 100644 index 4602647..0000000 --- a/lib/es5-shim/es5-sham.js +++ /dev/null @@ -1,404 +0,0 @@ -// Copyright 2009-2012 by contributors, MIT License -// vim: ts=4 sts=4 sw=4 expandtab - -// Module systems magic dance -(function (definition) { - // RequireJS - if (typeof define == "function") { - define(definition); - // YUI3 - } else if (typeof YUI == "function") { - YUI.add("es5-sham", definition); - // CommonJS and - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/es5-shim/tests/lib/jasmine-html.js b/lib/es5-shim/tests/lib/jasmine-html.js deleted file mode 100644 index 7383401..0000000 --- a/lib/es5-shim/tests/lib/jasmine-html.js +++ /dev/null @@ -1,190 +0,0 @@ -jasmine.TrivialReporter = function(doc) { - this.document = doc || document; - this.suiteDivs = {}; - this.logRunningSpecs = false; -}; - -jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { - var el = document.createElement(type); - - for (var i = 2; i < arguments.length; i++) { - var child = arguments[i]; - - if (typeof child === 'string') { - el.appendChild(document.createTextNode(child)); - } else { - if (child) { el.appendChild(child); } - } - } - - for (var attr in attrs) { - if (attr == "className") { - el[attr] = attrs[attr]; - } else { - el.setAttribute(attr, attrs[attr]); - } - } - - return el; -}; - -jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { - var showPassed, showSkipped; - - this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' }, - this.createDom('div', { className: 'banner' }, - this.createDom('div', { className: 'logo' }, - this.createDom('span', { className: 'title' }, "Jasmine"), - this.createDom('span', { className: 'version' }, runner.env.versionString())), - this.createDom('div', { className: 'options' }, - "Show ", - showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), - this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), - showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), - this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") - ) - ), - - this.runnerDiv = this.createDom('div', { className: 'runner running' }, - this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), - this.runnerMessageSpan = this.createDom('span', {}, "Running..."), - this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) - ); - - this.document.body.appendChild(this.outerDiv); - - var suites = runner.suites(); - for (var i = 0; i < suites.length; i++) { - var suite = suites[i]; - var suiteDiv = this.createDom('div', { className: 'suite' }, - this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), - this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); - this.suiteDivs[suite.id] = suiteDiv; - var parentDiv = this.outerDiv; - if (suite.parentSuite) { - parentDiv = this.suiteDivs[suite.parentSuite.id]; - } - parentDiv.appendChild(suiteDiv); - } - - this.startedAt = new Date(); - - var self = this; - showPassed.onclick = function(evt) { - if (showPassed.checked) { - self.outerDiv.className += ' show-passed'; - } else { - self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); - } - }; - - showSkipped.onclick = function(evt) { - if (showSkipped.checked) { - self.outerDiv.className += ' show-skipped'; - } else { - self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); - } - }; -}; - -jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { - var results = runner.results(); - var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; - this.runnerDiv.setAttribute("class", className); - //do it twice for IE - this.runnerDiv.setAttribute("className", className); - var specs = runner.specs(); - var specCount = 0; - for (var i = 0; i < specs.length; i++) { - if (this.specFilter(specs[i])) { - specCount++; - } - } - var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); - message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; - this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); - - this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); -}; - -jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { - var results = suite.results(); - var status = results.passed() ? 'passed' : 'failed'; - if (results.totalCount === 0) { // todo: change this to check results.skipped - status = 'skipped'; - } - this.suiteDivs[suite.id].className += " " + status; -}; - -jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { - if (this.logRunningSpecs) { - this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); - } -}; - -jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { - var results = spec.results(); - var status = results.passed() ? 'passed' : 'failed'; - if (results.skipped) { - status = 'skipped'; - } - var specDiv = this.createDom('div', { className: 'spec ' + status }, - this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), - this.createDom('a', { - className: 'description', - href: '?spec=' + encodeURIComponent(spec.getFullName()), - title: spec.getFullName() - }, spec.description)); - - - var resultItems = results.getItems(); - var messagesDiv = this.createDom('div', { className: 'messages' }); - for (var i = 0; i < resultItems.length; i++) { - var result = resultItems[i]; - - if (result.type == 'log') { - messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); - } else if (result.type == 'expect' && result.passed && !result.passed()) { - messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); - - if (result.trace.stack) { - messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); - } - } - } - - if (messagesDiv.childNodes.length > 0) { - specDiv.appendChild(messagesDiv); - } - - this.suiteDivs[spec.suite.id].appendChild(specDiv); -}; - -jasmine.TrivialReporter.prototype.log = function() { - var console = jasmine.getGlobal().console; - if (console && console.log) { - if (console.log.apply) { - console.log.apply(console, arguments); - } else { - console.log(arguments); // ie fix: console.log.apply doesn't exist on ie - } - } -}; - -jasmine.TrivialReporter.prototype.getLocation = function() { - return this.document.location; -}; - -jasmine.TrivialReporter.prototype.specFilter = function(spec) { - var paramMap = {}; - var params = this.getLocation().search.substring(1).split('&'); - for (var i = 0; i < params.length; i++) { - var p = params[i].split('='); - paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); - } - - if (!paramMap.spec) { - return true; - } - return spec.getFullName().indexOf(paramMap.spec) === 0; -}; diff --git a/lib/es5-shim/tests/lib/jasmine.css b/lib/es5-shim/tests/lib/jasmine.css deleted file mode 100644 index 6583fe7..0000000 --- a/lib/es5-shim/tests/lib/jasmine.css +++ /dev/null @@ -1,166 +0,0 @@ -body { - font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; -} - - -.jasmine_reporter a:visited, .jasmine_reporter a { - color: #303; -} - -.jasmine_reporter a:hover, .jasmine_reporter a:active { - color: blue; -} - -.run_spec { - float:right; - padding-right: 5px; - font-size: .8em; - text-decoration: none; -} - -.jasmine_reporter { - margin: 0 5px; -} - -.banner { - color: #303; - background-color: #fef; - padding: 5px; -} - -.logo { - float: left; - font-size: 1.1em; - padding-left: 5px; -} - -.logo .version { - font-size: .6em; - padding-left: 1em; -} - -.runner.running { - background-color: yellow; -} - - -.options { - text-align: right; - font-size: .8em; -} - - - - -.suite { - border: 1px outset gray; - margin: 5px 0; - padding-left: 1em; -} - -.suite .suite { - margin: 5px; -} - -.suite.passed { - background-color: #dfd; -} - -.suite.failed { - background-color: #fdd; -} - -.spec { - margin: 5px; - padding-left: 1em; - clear: both; -} - -.spec.failed, .spec.passed, .spec.skipped { - padding-bottom: 5px; - border: 1px solid gray; -} - -.spec.failed { - background-color: #fbb; - border-color: red; -} - -.spec.passed { - background-color: #bfb; - border-color: green; -} - -.spec.skipped { - background-color: #bbb; -} - -.messages { - border-left: 1px dashed gray; - padding-left: 1em; - padding-right: 1em; -} - -.passed { - background-color: #cfc; - display: none; -} - -.failed { - background-color: #fbb; -} - -.skipped { - color: #777; - background-color: #eee; - display: none; -} - - -/*.resultMessage {*/ - /*white-space: pre;*/ -/*}*/ - -.resultMessage span.result { - display: block; - line-height: 2em; - color: black; -} - -.resultMessage .mismatch { - color: black; -} - -.stackTrace { - white-space: pre; - font-size: .8em; - margin-left: 10px; - max-height: 5em; - overflow: auto; - border: 1px inset red; - padding: 1em; - background: #eef; -} - -.finished-at { - padding-left: 1em; - font-size: .6em; -} - -.show-passed .passed, -.show-skipped .skipped { - display: block; -} - - -#jasmine_content { - position:fixed; - right: 100%; -} - -.runner { - border: 1px solid gray; - display: block; - margin: 5px 0; - padding: 2px 0 2px 10px; -} diff --git a/lib/es5-shim/tests/lib/jasmine.js b/lib/es5-shim/tests/lib/jasmine.js deleted file mode 100644 index 70d7d25..0000000 --- a/lib/es5-shim/tests/lib/jasmine.js +++ /dev/null @@ -1,2477 +0,0 @@ -var isCommonJS = typeof window == "undefined"; - -/** - * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework. - * - * @namespace - */ -var jasmine = {}; -if (isCommonJS) exports.jasmine = jasmine; -/** - * @private - */ -jasmine.unimplementedMethod_ = function() { - throw new Error("unimplemented method"); -}; - -/** - * Use jasmine.undefined instead of undefined, since undefined is just - * a plain old variable and may be redefined by somebody else. - * - * @private - */ -jasmine.undefined = jasmine.___undefined___; - -/** - * Show diagnostic messages in the console if set to true - * - */ -jasmine.VERBOSE = false; - -/** - * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed. - * - */ -jasmine.DEFAULT_UPDATE_INTERVAL = 250; - -/** - * Default timeout interval in milliseconds for waitsFor() blocks. - */ -jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; - -jasmine.getGlobal = function() { - function getGlobal() { - return this; - } - - return getGlobal(); -}; - -/** - * Allows for bound functions to be compared. Internal use only. - * - * @ignore - * @private - * @param base {Object} bound 'this' for the function - * @param name {Function} function to find - */ -jasmine.bindOriginal_ = function(base, name) { - var original = base[name]; - if (original.apply) { - return function() { - return original.apply(base, arguments); - }; - } else { - // IE support - return jasmine.getGlobal()[name]; - } -}; - -jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout'); -jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout'); -jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval'); -jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval'); - -jasmine.MessageResult = function(values) { - this.type = 'log'; - this.values = values; - this.trace = new Error(); // todo: test better -}; - -jasmine.MessageResult.prototype.toString = function() { - var text = ""; - for (var i = 0; i < this.values.length; i++) { - if (i > 0) text += " "; - if (jasmine.isString_(this.values[i])) { - text += this.values[i]; - } else { - text += jasmine.pp(this.values[i]); - } - } - return text; -}; - -jasmine.ExpectationResult = function(params) { - this.type = 'expect'; - this.matcherName = params.matcherName; - this.passed_ = params.passed; - this.expected = params.expected; - this.actual = params.actual; - this.message = this.passed_ ? 'Passed.' : params.message; - - var trace = (params.trace || new Error(this.message)); - this.trace = this.passed_ ? '' : trace; -}; - -jasmine.ExpectationResult.prototype.toString = function () { - return this.message; -}; - -jasmine.ExpectationResult.prototype.passed = function () { - return this.passed_; -}; - -/** - * Getter for the Jasmine environment. Ensures one gets created - */ -jasmine.getEnv = function() { - var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(); - return env; -}; - -/** - * @ignore - * @private - * @param value - * @returns {Boolean} - */ -jasmine.isArray_ = function(value) { - return jasmine.isA_("Array", value); -}; - -/** - * @ignore - * @private - * @param value - * @returns {Boolean} - */ -jasmine.isString_ = function(value) { - return jasmine.isA_("String", value); -}; - -/** - * @ignore - * @private - * @param value - * @returns {Boolean} - */ -jasmine.isNumber_ = function(value) { - return jasmine.isA_("Number", value); -}; - -/** - * @ignore - * @private - * @param {String} typeName - * @param value - * @returns {Boolean} - */ -jasmine.isA_ = function(typeName, value) { - return Object.prototype.toString.apply(value) === '[object ' + typeName + ']'; -}; - -/** - * Pretty printer for expecations. Takes any object and turns it into a human-readable string. - * - * @param value {Object} an object to be outputted - * @returns {String} - */ -jasmine.pp = function(value) { - var stringPrettyPrinter = new jasmine.StringPrettyPrinter(); - stringPrettyPrinter.format(value); - return stringPrettyPrinter.string; -}; - -/** - * Returns true if the object is a DOM Node. - * - * @param {Object} obj object to check - * @returns {Boolean} - */ -jasmine.isDomNode = function(obj) { - return obj.nodeType > 0; -}; - -/** - * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter. - * - * @example - * // don't care about which function is passed in, as long as it's a function - * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function)); - * - * @param {Class} clazz - * @returns matchable object of the type clazz - */ -jasmine.any = function(clazz) { - return new jasmine.Matchers.Any(clazz); -}; - -/** - * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks. - * - * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine - * expectation syntax. Spies can be checked if they were called or not and what the calling params were. - * - * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs). - * - * Spies are torn down at the end of every spec. - * - * Note: Do not call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj. - * - * @example - * // a stub - * var myStub = jasmine.createSpy('myStub'); // can be used anywhere - * - * // spy example - * var foo = { - * not: function(bool) { return !bool; } - * } - * - * // actual foo.not will not be called, execution stops - * spyOn(foo, 'not'); - - // foo.not spied upon, execution will continue to implementation - * spyOn(foo, 'not').andCallThrough(); - * - * // fake example - * var foo = { - * not: function(bool) { return !bool; } - * } - * - * // foo.not(val) will return val - * spyOn(foo, 'not').andCallFake(function(value) {return value;}); - * - * // mock example - * foo.not(7 == 7); - * expect(foo.not).toHaveBeenCalled(); - * expect(foo.not).toHaveBeenCalledWith(true); - * - * @constructor - * @see spyOn, jasmine.createSpy, jasmine.createSpyObj - * @param {String} name - */ -jasmine.Spy = function(name) { - /** - * The name of the spy, if provided. - */ - this.identity = name || 'unknown'; - /** - * Is this Object a spy? - */ - this.isSpy = true; - /** - * The actual function this spy stubs. - */ - this.plan = function() { - }; - /** - * Tracking of the most recent call to the spy. - * @example - * var mySpy = jasmine.createSpy('foo'); - * mySpy(1, 2); - * mySpy.mostRecentCall.args = [1, 2]; - */ - this.mostRecentCall = {}; - - /** - * Holds arguments for each call to the spy, indexed by call count - * @example - * var mySpy = jasmine.createSpy('foo'); - * mySpy(1, 2); - * mySpy(7, 8); - * mySpy.mostRecentCall.args = [7, 8]; - * mySpy.argsForCall[0] = [1, 2]; - * mySpy.argsForCall[1] = [7, 8]; - */ - this.argsForCall = []; - this.calls = []; -}; - -/** - * Tells a spy to call through to the actual implemenatation. - * - * @example - * var foo = { - * bar: function() { // do some stuff } - * } - * - * // defining a spy on an existing property: foo.bar - * spyOn(foo, 'bar').andCallThrough(); - */ -jasmine.Spy.prototype.andCallThrough = function() { - this.plan = this.originalValue; - return this; -}; - -/** - * For setting the return value of a spy. - * - * @example - * // defining a spy from scratch: foo() returns 'baz' - * var foo = jasmine.createSpy('spy on foo').andReturn('baz'); - * - * // defining a spy on an existing property: foo.bar() returns 'baz' - * spyOn(foo, 'bar').andReturn('baz'); - * - * @param {Object} value - */ -jasmine.Spy.prototype.andReturn = function(value) { - this.plan = function() { - return value; - }; - return this; -}; - -/** - * For throwing an exception when a spy is called. - * - * @example - * // defining a spy from scratch: foo() throws an exception w/ message 'ouch' - * var foo = jasmine.createSpy('spy on foo').andThrow('baz'); - * - * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch' - * spyOn(foo, 'bar').andThrow('baz'); - * - * @param {String} exceptionMsg - */ -jasmine.Spy.prototype.andThrow = function(exceptionMsg) { - this.plan = function() { - throw exceptionMsg; - }; - return this; -}; - -/** - * Calls an alternate implementation when a spy is called. - * - * @example - * var baz = function() { - * // do some stuff, return something - * } - * // defining a spy from scratch: foo() calls the function baz - * var foo = jasmine.createSpy('spy on foo').andCall(baz); - * - * // defining a spy on an existing property: foo.bar() calls an anonymnous function - * spyOn(foo, 'bar').andCall(function() { return 'baz';} ); - * - * @param {Function} fakeFunc - */ -jasmine.Spy.prototype.andCallFake = function(fakeFunc) { - this.plan = fakeFunc; - return this; -}; - -/** - * Resets all of a spy's the tracking variables so that it can be used again. - * - * @example - * spyOn(foo, 'bar'); - * - * foo.bar(); - * - * expect(foo.bar.callCount).toEqual(1); - * - * foo.bar.reset(); - * - * expect(foo.bar.callCount).toEqual(0); - */ -jasmine.Spy.prototype.reset = function() { - this.wasCalled = false; - this.callCount = 0; - this.argsForCall = []; - this.calls = []; - this.mostRecentCall = {}; -}; - -jasmine.createSpy = function(name) { - - var spyObj = function() { - spyObj.wasCalled = true; - spyObj.callCount++; - var args = jasmine.util.argsToArray(arguments); - spyObj.mostRecentCall.object = this; - spyObj.mostRecentCall.args = args; - spyObj.argsForCall.push(args); - spyObj.calls.push({object: this, args: args}); - return spyObj.plan.apply(this, arguments); - }; - - var spy = new jasmine.Spy(name); - - for (var prop in spy) { - spyObj[prop] = spy[prop]; - } - - spyObj.reset(); - - return spyObj; -}; - -/** - * Determines whether an object is a spy. - * - * @param {jasmine.Spy|Object} putativeSpy - * @returns {Boolean} - */ -jasmine.isSpy = function(putativeSpy) { - return putativeSpy && putativeSpy.isSpy; -}; - -/** - * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something - * large in one call. - * - * @param {String} baseName name of spy class - * @param {Array} methodNames array of names of methods to make spies - */ -jasmine.createSpyObj = function(baseName, methodNames) { - if (!jasmine.isArray_(methodNames) || methodNames.length === 0) { - throw new Error('createSpyObj requires a non-empty array of method names to create spies for'); - } - var obj = {}; - for (var i = 0; i < methodNames.length; i++) { - obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]); - } - return obj; -}; - -/** - * All parameters are pretty-printed and concatenated together, then written to the current spec's output. - * - * Be careful not to leave calls to jasmine.log in production code. - */ -jasmine.log = function() { - var spec = jasmine.getEnv().currentSpec; - spec.log.apply(spec, arguments); -}; - -/** - * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy. - * - * @example - * // spy example - * var foo = { - * not: function(bool) { return !bool; } - * } - * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops - * - * @see jasmine.createSpy - * @param obj - * @param methodName - * @returns a Jasmine spy that can be chained with all spy methods - */ -var spyOn = function(obj, methodName) { - return jasmine.getEnv().currentSpec.spyOn(obj, methodName); -}; -if (isCommonJS) exports.spyOn = spyOn; - -/** - * Creates a Jasmine spec that will be added to the current suite. - * - * // TODO: pending tests - * - * @example - * it('should be true', function() { - * expect(true).toEqual(true); - * }); - * - * @param {String} desc description of this specification - * @param {Function} func defines the preconditions and expectations of the spec - */ -var it = function(desc, func) { - return jasmine.getEnv().it(desc, func); -}; -if (isCommonJS) exports.it = it; - -/** - * Creates a disabled Jasmine spec. - * - * A convenience method that allows existing specs to be disabled temporarily during development. - * - * @param {String} desc description of this specification - * @param {Function} func defines the preconditions and expectations of the spec - */ -var xit = function(desc, func) { - return jasmine.getEnv().xit(desc, func); -}; -if (isCommonJS) exports.xit = xit; - -/** - * Starts a chain for a Jasmine expectation. - * - * It is passed an Object that is the actual value and should chain to one of the many - * jasmine.Matchers functions. - * - * @param {Object} actual Actual value to test against and expected value - */ -var expect = function(actual) { - return jasmine.getEnv().currentSpec.expect(actual); -}; -if (isCommonJS) exports.expect = expect; - -/** - * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs. - * - * @param {Function} func Function that defines part of a jasmine spec. - */ -var runs = function(func) { - jasmine.getEnv().currentSpec.runs(func); -}; -if (isCommonJS) exports.runs = runs; - -/** - * Waits a fixed time period before moving to the next block. - * - * @deprecated Use waitsFor() instead - * @param {Number} timeout milliseconds to wait - */ -var waits = function(timeout) { - jasmine.getEnv().currentSpec.waits(timeout); -}; -if (isCommonJS) exports.waits = waits; - -/** - * Waits for the latchFunction to return true before proceeding to the next block. - * - * @param {Function} latchFunction - * @param {String} optional_timeoutMessage - * @param {Number} optional_timeout - */ -var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { - jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments); -}; -if (isCommonJS) exports.waitsFor = waitsFor; - -/** - * A function that is called before each spec in a suite. - * - * Used for spec setup, including validating assumptions. - * - * @param {Function} beforeEachFunction - */ -var beforeEach = function(beforeEachFunction) { - jasmine.getEnv().beforeEach(beforeEachFunction); -}; -if (isCommonJS) exports.beforeEach = beforeEach; - -/** - * A function that is called after each spec in a suite. - * - * Used for restoring any state that is hijacked during spec execution. - * - * @param {Function} afterEachFunction - */ -var afterEach = function(afterEachFunction) { - jasmine.getEnv().afterEach(afterEachFunction); -}; -if (isCommonJS) exports.afterEach = afterEach; - -/** - * Defines a suite of specifications. - * - * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared - * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization - * of setup in some tests. - * - * @example - * // TODO: a simple suite - * - * // TODO: a simple suite with a nested describe block - * - * @param {String} description A string, usually the class under test. - * @param {Function} specDefinitions function that defines several specs. - */ -var describe = function(description, specDefinitions) { - return jasmine.getEnv().describe(description, specDefinitions); -}; -if (isCommonJS) exports.describe = describe; - -/** - * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development. - * - * @param {String} description A string, usually the class under test. - * @param {Function} specDefinitions function that defines several specs. - */ -var xdescribe = function(description, specDefinitions) { - return jasmine.getEnv().xdescribe(description, specDefinitions); -}; -if (isCommonJS) exports.xdescribe = xdescribe; - - -// Provide the XMLHttpRequest class for IE 5.x-6.x: -jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() { - function tryIt(f) { - try { - return f(); - } catch(e) { - } - return null; - } - - var xhr = tryIt(function() { - return new ActiveXObject("Msxml2.XMLHTTP.6.0"); - }) || - tryIt(function() { - return new ActiveXObject("Msxml2.XMLHTTP.3.0"); - }) || - tryIt(function() { - return new ActiveXObject("Msxml2.XMLHTTP"); - }) || - tryIt(function() { - return new ActiveXObject("Microsoft.XMLHTTP"); - }); - - if (!xhr) throw new Error("This browser does not support XMLHttpRequest."); - - return xhr; -} : XMLHttpRequest; -/** - * @namespace - */ -jasmine.util = {}; - -/** - * Declare that a child class inherit it's prototype from the parent class. - * - * @private - * @param {Function} childClass - * @param {Function} parentClass - */ -jasmine.util.inherit = function(childClass, parentClass) { - /** - * @private - */ - var subclass = function() { - }; - subclass.prototype = parentClass.prototype; - childClass.prototype = new subclass(); -}; - -jasmine.util.formatException = function(e) { - var lineNumber; - if (e.line) { - lineNumber = e.line; - } - else if (e.lineNumber) { - lineNumber = e.lineNumber; - } - - var file; - - if (e.sourceURL) { - file = e.sourceURL; - } - else if (e.fileName) { - file = e.fileName; - } - - var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString(); - - if (file && lineNumber) { - message += ' in ' + file + ' (line ' + lineNumber + ')'; - } - - return message; -}; - -jasmine.util.htmlEscape = function(str) { - if (!str) return str; - return str.replace(/&/g, '&') - .replace(//g, '>'); -}; - -jasmine.util.argsToArray = function(args) { - var arrayOfArgs = []; - for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); - return arrayOfArgs; -}; - -jasmine.util.extend = function(destination, source) { - for (var property in source) destination[property] = source[property]; - return destination; -}; - -/** - * Environment for Jasmine - * - * @constructor - */ -jasmine.Env = function() { - this.currentSpec = null; - this.currentSuite = null; - this.currentRunner_ = new jasmine.Runner(this); - - this.reporter = new jasmine.MultiReporter(); - - this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; - this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; - this.lastUpdate = 0; - this.specFilter = function() { - return true; - }; - - this.nextSpecId_ = 0; - this.nextSuiteId_ = 0; - this.equalityTesters_ = []; - - // wrap matchers - this.matchersClass = function() { - jasmine.Matchers.apply(this, arguments); - }; - jasmine.util.inherit(this.matchersClass, jasmine.Matchers); - - jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); -}; - - -jasmine.Env.prototype.setTimeout = jasmine.setTimeout; -jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; -jasmine.Env.prototype.setInterval = jasmine.setInterval; -jasmine.Env.prototype.clearInterval = jasmine.clearInterval; - -/** - * @returns an object containing jasmine version build info, if set. - */ -jasmine.Env.prototype.version = function () { - if (jasmine.version_) { - return jasmine.version_; - } else { - throw new Error('Version not set'); - } -}; - -/** - * @returns string containing jasmine version build info, if set. - */ -jasmine.Env.prototype.versionString = function() { - if (!jasmine.version_) { - return "version unknown"; - } - - var version = this.version(); - var versionString = version.major + "." + version.minor + "." + version.build; - if (version.release_candidate) { - versionString += ".rc" + version.release_candidate - } - versionString += " revision " + version.revision; - return versionString; -}; - -/** - * @returns a sequential integer starting at 0 - */ -jasmine.Env.prototype.nextSpecId = function () { - return this.nextSpecId_++; -}; - -/** - * @returns a sequential integer starting at 0 - */ -jasmine.Env.prototype.nextSuiteId = function () { - return this.nextSuiteId_++; -}; - -/** - * Register a reporter to receive status updates from Jasmine. - * @param {jasmine.Reporter} reporter An object which will receive status updates. - */ -jasmine.Env.prototype.addReporter = function(reporter) { - this.reporter.addReporter(reporter); -}; - -jasmine.Env.prototype.execute = function() { - this.currentRunner_.execute(); -}; - -jasmine.Env.prototype.describe = function(description, specDefinitions) { - var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); - - var parentSuite = this.currentSuite; - if (parentSuite) { - parentSuite.add(suite); - } else { - this.currentRunner_.add(suite); - } - - this.currentSuite = suite; - - var declarationError = null; - try { - specDefinitions.call(suite); - } catch(e) { - declarationError = e; - } - - if (declarationError) { - this.it("encountered a declaration exception", function() { - throw declarationError; - }); - } - - this.currentSuite = parentSuite; - - return suite; -}; - -jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { - if (this.currentSuite) { - this.currentSuite.beforeEach(beforeEachFunction); - } else { - this.currentRunner_.beforeEach(beforeEachFunction); - } -}; - -jasmine.Env.prototype.currentRunner = function () { - return this.currentRunner_; -}; - -jasmine.Env.prototype.afterEach = function(afterEachFunction) { - if (this.currentSuite) { - this.currentSuite.afterEach(afterEachFunction); - } else { - this.currentRunner_.afterEach(afterEachFunction); - } - -}; - -jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { - return { - execute: function() { - } - }; -}; - -jasmine.Env.prototype.it = function(description, func) { - var spec = new jasmine.Spec(this, this.currentSuite, description); - this.currentSuite.add(spec); - this.currentSpec = spec; - - if (func) { - spec.runs(func); - } - - return spec; -}; - -jasmine.Env.prototype.xit = function(desc, func) { - return { - id: this.nextSpecId(), - runs: function() { - } - }; -}; - -jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { - if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { - return true; - } - - a.__Jasmine_been_here_before__ = b; - b.__Jasmine_been_here_before__ = a; - - var hasKey = function(obj, keyName) { - return obj !== null && obj[keyName] !== jasmine.undefined; - }; - - for (var property in b) { - if (!hasKey(a, property) && hasKey(b, property)) { - mismatchKeys.push("expected has key '" + property + "', but missing from actual."); - } - } - for (property in a) { - if (!hasKey(b, property) && hasKey(a, property)) { - mismatchKeys.push("expected missing key '" + property + "', but present in actual."); - } - } - for (property in b) { - if (property == '__Jasmine_been_here_before__') continue; - if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { - mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual."); - } - } - - if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { - mismatchValues.push("arrays were not the same length"); - } - - delete a.__Jasmine_been_here_before__; - delete b.__Jasmine_been_here_before__; - return (mismatchKeys.length === 0 && mismatchValues.length === 0); -}; - -jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { - mismatchKeys = mismatchKeys || []; - mismatchValues = mismatchValues || []; - - for (var i = 0; i < this.equalityTesters_.length; i++) { - var equalityTester = this.equalityTesters_[i]; - var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); - if (result !== jasmine.undefined) return result; - } - - if (a === b) return true; - - if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) { - return (a == jasmine.undefined && b == jasmine.undefined); - } - - if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { - return a === b; - } - - if (a instanceof Date && b instanceof Date) { - return a.getTime() == b.getTime(); - } - - if (a instanceof jasmine.Matchers.Any) { - return a.matches(b); - } - - if (b instanceof jasmine.Matchers.Any) { - return b.matches(a); - } - - if (jasmine.isString_(a) && jasmine.isString_(b)) { - return (a == b); - } - - if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) { - return (a == b); - } - - if (typeof a === "object" && typeof b === "object") { - return this.compareObjects_(a, b, mismatchKeys, mismatchValues); - } - - //Straight check - return (a === b); -}; - -jasmine.Env.prototype.contains_ = function(haystack, needle) { - if (jasmine.isArray_(haystack)) { - for (var i = 0; i < haystack.length; i++) { - if (this.equals_(haystack[i], needle)) return true; - } - return false; - } - return haystack.indexOf(needle) >= 0; -}; - -jasmine.Env.prototype.addEqualityTester = function(equalityTester) { - this.equalityTesters_.push(equalityTester); -}; -/** No-op base class for Jasmine reporters. - * - * @constructor - */ -jasmine.Reporter = function() { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportRunnerStarting = function(runner) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportRunnerResults = function(runner) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportSuiteResults = function(suite) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportSpecStarting = function(spec) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.reportSpecResults = function(spec) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.Reporter.prototype.log = function(str) { -}; - -/** - * Blocks are functions with executable code that make up a spec. - * - * @constructor - * @param {jasmine.Env} env - * @param {Function} func - * @param {jasmine.Spec} spec - */ -jasmine.Block = function(env, func, spec) { - this.env = env; - this.func = func; - this.spec = spec; -}; - -jasmine.Block.prototype.execute = function(onComplete) { - try { - this.func.apply(this.spec); - } catch (e) { - this.spec.fail(e); - } - onComplete(); -}; -/** JavaScript API reporter. - * - * @constructor - */ -jasmine.JsApiReporter = function() { - this.started = false; - this.finished = false; - this.suites_ = []; - this.results_ = {}; -}; - -jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { - this.started = true; - var suites = runner.topLevelSuites(); - for (var i = 0; i < suites.length; i++) { - var suite = suites[i]; - this.suites_.push(this.summarize_(suite)); - } -}; - -jasmine.JsApiReporter.prototype.suites = function() { - return this.suites_; -}; - -jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { - var isSuite = suiteOrSpec instanceof jasmine.Suite; - var summary = { - id: suiteOrSpec.id, - name: suiteOrSpec.description, - type: isSuite ? 'suite' : 'spec', - children: [] - }; - - if (isSuite) { - var children = suiteOrSpec.children(); - for (var i = 0; i < children.length; i++) { - summary.children.push(this.summarize_(children[i])); - } - } - return summary; -}; - -jasmine.JsApiReporter.prototype.results = function() { - return this.results_; -}; - -jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) { - return this.results_[specId]; -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) { - this.finished = true; -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) { -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) { - this.results_[spec.id] = { - messages: spec.results().getItems(), - result: spec.results().failedCount > 0 ? "failed" : "passed" - }; -}; - -//noinspection JSUnusedLocalSymbols -jasmine.JsApiReporter.prototype.log = function(str) { -}; - -jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){ - var results = {}; - for (var i = 0; i < specIds.length; i++) { - var specId = specIds[i]; - results[specId] = this.summarizeResult_(this.results_[specId]); - } - return results; -}; - -jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){ - var summaryMessages = []; - var messagesLength = result.messages.length; - for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) { - var resultMessage = result.messages[messageIndex]; - summaryMessages.push({ - text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined, - passed: resultMessage.passed ? resultMessage.passed() : true, - type: resultMessage.type, - message: resultMessage.message, - trace: { - stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined - } - }); - } - - return { - result : result.result, - messages : summaryMessages - }; -}; - -/** - * @constructor - * @param {jasmine.Env} env - * @param actual - * @param {jasmine.Spec} spec - */ -jasmine.Matchers = function(env, actual, spec, opt_isNot) { - this.env = env; - this.actual = actual; - this.spec = spec; - this.isNot = opt_isNot || false; - this.reportWasCalled_ = false; -}; - -// todo: @deprecated as of Jasmine 0.11, remove soon [xw] -jasmine.Matchers.pp = function(str) { - throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!"); -}; - -// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw] -jasmine.Matchers.prototype.report = function(result, failing_message, details) { - throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs"); -}; - -jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) { - for (var methodName in prototype) { - if (methodName == 'report') continue; - var orig = prototype[methodName]; - matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig); - } -}; - -jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { - return function() { - var matcherArgs = jasmine.util.argsToArray(arguments); - var result = matcherFunction.apply(this, arguments); - - if (this.isNot) { - result = !result; - } - - if (this.reportWasCalled_) return result; - - var message; - if (!result) { - if (this.message) { - message = this.message.apply(this, arguments); - if (jasmine.isArray_(message)) { - message = message[this.isNot ? 1 : 0]; - } - } else { - var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); - message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate; - if (matcherArgs.length > 0) { - for (var i = 0; i < matcherArgs.length; i++) { - if (i > 0) message += ","; - message += " " + jasmine.pp(matcherArgs[i]); - } - } - message += "."; - } - } - var expectationResult = new jasmine.ExpectationResult({ - matcherName: matcherName, - passed: result, - expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0], - actual: this.actual, - message: message - }); - this.spec.addMatcherResult(expectationResult); - return jasmine.undefined; - }; -}; - - - - -/** - * toBe: compares the actual to the expected using === - * @param expected - */ -jasmine.Matchers.prototype.toBe = function(expected) { - return this.actual === expected; -}; - -/** - * toNotBe: compares the actual to the expected using !== - * @param expected - * @deprecated as of 1.0. Use not.toBe() instead. - */ -jasmine.Matchers.prototype.toNotBe = function(expected) { - return this.actual !== expected; -}; - -/** - * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc. - * - * @param expected - */ -jasmine.Matchers.prototype.toEqual = function(expected) { - return this.env.equals_(this.actual, expected); -}; - -/** - * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual - * @param expected - * @deprecated as of 1.0. Use not.toNotEqual() instead. - */ -jasmine.Matchers.prototype.toNotEqual = function(expected) { - return !this.env.equals_(this.actual, expected); -}; - -/** - * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes - * a pattern or a String. - * - * @param expected - */ -jasmine.Matchers.prototype.toMatch = function(expected) { - return new RegExp(expected).test(this.actual); -}; - -/** - * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch - * @param expected - * @deprecated as of 1.0. Use not.toMatch() instead. - */ -jasmine.Matchers.prototype.toNotMatch = function(expected) { - return !(new RegExp(expected).test(this.actual)); -}; - -/** - * Matcher that compares the actual to jasmine.undefined. - */ -jasmine.Matchers.prototype.toBeDefined = function() { - return (this.actual !== jasmine.undefined); -}; - -/** - * Matcher that compares the actual to jasmine.undefined. - */ -jasmine.Matchers.prototype.toBeUndefined = function() { - return (this.actual === jasmine.undefined); -}; - -/** - * Matcher that compares the actual to null. - */ -jasmine.Matchers.prototype.toBeNull = function() { - return (this.actual === null); -}; - -/** - * Matcher that boolean not-nots the actual. - */ -jasmine.Matchers.prototype.toBeTruthy = function() { - return !!this.actual; -}; - - -/** - * Matcher that boolean nots the actual. - */ -jasmine.Matchers.prototype.toBeFalsy = function() { - return !this.actual; -}; - - -/** - * Matcher that checks to see if the actual, a Jasmine spy, was called. - */ -jasmine.Matchers.prototype.toHaveBeenCalled = function() { - if (arguments.length > 0) { - throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith'); - } - - if (!jasmine.isSpy(this.actual)) { - throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); - } - - this.message = function() { - return [ - "Expected spy " + this.actual.identity + " to have been called.", - "Expected spy " + this.actual.identity + " not to have been called." - ]; - }; - - return this.actual.wasCalled; -}; - -/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */ -jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled; - -/** - * Matcher that checks to see if the actual, a Jasmine spy, was not called. - * - * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead - */ -jasmine.Matchers.prototype.wasNotCalled = function() { - if (arguments.length > 0) { - throw new Error('wasNotCalled does not take arguments'); - } - - if (!jasmine.isSpy(this.actual)) { - throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); - } - - this.message = function() { - return [ - "Expected spy " + this.actual.identity + " to not have been called.", - "Expected spy " + this.actual.identity + " to have been called." - ]; - }; - - return !this.actual.wasCalled; -}; - -/** - * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters. - * - * @example - * - */ -jasmine.Matchers.prototype.toHaveBeenCalledWith = function() { - var expectedArgs = jasmine.util.argsToArray(arguments); - if (!jasmine.isSpy(this.actual)) { - throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); - } - this.message = function() { - if (this.actual.callCount === 0) { - // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw] - return [ - "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.", - "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was." - ]; - } else { - return [ - "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall), - "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall) - ]; - } - }; - - return this.env.contains_(this.actual.argsForCall, expectedArgs); -}; - -/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */ -jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith; - -/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */ -jasmine.Matchers.prototype.wasNotCalledWith = function() { - var expectedArgs = jasmine.util.argsToArray(arguments); - if (!jasmine.isSpy(this.actual)) { - throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); - } - - this.message = function() { - return [ - "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was", - "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was" - ]; - }; - - return !this.env.contains_(this.actual.argsForCall, expectedArgs); -}; - -/** - * Matcher that checks that the expected item is an element in the actual Array. - * - * @param {Object} expected - */ -jasmine.Matchers.prototype.toContain = function(expected) { - return this.env.contains_(this.actual, expected); -}; - -/** - * Matcher that checks that the expected item is NOT an element in the actual Array. - * - * @param {Object} expected - * @deprecated as of 1.0. Use not.toNotContain() instead. - */ -jasmine.Matchers.prototype.toNotContain = function(expected) { - return !this.env.contains_(this.actual, expected); -}; - -jasmine.Matchers.prototype.toBeLessThan = function(expected) { - return this.actual < expected; -}; - -jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { - return this.actual > expected; -}; - -/** - * Matcher that checks that the expected item is equal to the actual item - * up to a given level of decimal precision (default 2). - * - * @param {Number} expected - * @param {Number} precision - */ -jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) { - if (!(precision === 0)) { - precision = precision || 2; - } - var multiplier = Math.pow(10, precision); - var actual = Math.round(this.actual * multiplier); - expected = Math.round(expected * multiplier); - return expected == actual; -}; - -/** - * Matcher that checks that the expected exception was thrown by the actual. - * - * @param {String} expected - */ -jasmine.Matchers.prototype.toThrow = function(expected) { - var result = false; - var exception; - if (typeof this.actual != 'function') { - throw new Error('Actual is not a function'); - } - try { - this.actual(); - } catch (e) { - exception = e; - } - if (exception) { - result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected)); - } - - var not = this.isNot ? "not " : ""; - - this.message = function() { - if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { - return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' '); - } else { - return "Expected function to throw an exception."; - } - }; - - return result; -}; - -jasmine.Matchers.Any = function(expectedClass) { - this.expectedClass = expectedClass; -}; - -jasmine.Matchers.Any.prototype.matches = function(other) { - if (this.expectedClass == String) { - return typeof other == 'string' || other instanceof String; - } - - if (this.expectedClass == Number) { - return typeof other == 'number' || other instanceof Number; - } - - if (this.expectedClass == Function) { - return typeof other == 'function' || other instanceof Function; - } - - if (this.expectedClass == Object) { - return typeof other == 'object'; - } - - return other instanceof this.expectedClass; -}; - -jasmine.Matchers.Any.prototype.toString = function() { - return ''; -}; - -/** - * @constructor - */ -jasmine.MultiReporter = function() { - this.subReporters_ = []; -}; -jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); - -jasmine.MultiReporter.prototype.addReporter = function(reporter) { - this.subReporters_.push(reporter); -}; - -(function() { - var functionNames = [ - "reportRunnerStarting", - "reportRunnerResults", - "reportSuiteResults", - "reportSpecStarting", - "reportSpecResults", - "log" - ]; - for (var i = 0; i < functionNames.length; i++) { - var functionName = functionNames[i]; - jasmine.MultiReporter.prototype[functionName] = (function(functionName) { - return function() { - for (var j = 0; j < this.subReporters_.length; j++) { - var subReporter = this.subReporters_[j]; - if (subReporter[functionName]) { - subReporter[functionName].apply(subReporter, arguments); - } - } - }; - })(functionName); - } -})(); -/** - * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults - * - * @constructor - */ -jasmine.NestedResults = function() { - /** - * The total count of results - */ - this.totalCount = 0; - /** - * Number of passed results - */ - this.passedCount = 0; - /** - * Number of failed results - */ - this.failedCount = 0; - /** - * Was this suite/spec skipped? - */ - this.skipped = false; - /** - * @ignore - */ - this.items_ = []; -}; - -/** - * Roll up the result counts. - * - * @param result - */ -jasmine.NestedResults.prototype.rollupCounts = function(result) { - this.totalCount += result.totalCount; - this.passedCount += result.passedCount; - this.failedCount += result.failedCount; -}; - -/** - * Adds a log message. - * @param values Array of message parts which will be concatenated later. - */ -jasmine.NestedResults.prototype.log = function(values) { - this.items_.push(new jasmine.MessageResult(values)); -}; - -/** - * Getter for the results: message & results. - */ -jasmine.NestedResults.prototype.getItems = function() { - return this.items_; -}; - -/** - * Adds a result, tracking counts (total, passed, & failed) - * @param {jasmine.ExpectationResult|jasmine.NestedResults} result - */ -jasmine.NestedResults.prototype.addResult = function(result) { - if (result.type != 'log') { - if (result.items_) { - this.rollupCounts(result); - } else { - this.totalCount++; - if (result.passed()) { - this.passedCount++; - } else { - this.failedCount++; - } - } - } - this.items_.push(result); -}; - -/** - * @returns {Boolean} True if everything below passed - */ -jasmine.NestedResults.prototype.passed = function() { - return this.passedCount === this.totalCount; -}; -/** - * Base class for pretty printing for expectation results. - */ -jasmine.PrettyPrinter = function() { - this.ppNestLevel_ = 0; -}; - -/** - * Formats a value in a nice, human-readable string. - * - * @param value - */ -jasmine.PrettyPrinter.prototype.format = function(value) { - if (this.ppNestLevel_ > 40) { - throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); - } - - this.ppNestLevel_++; - try { - if (value === jasmine.undefined) { - this.emitScalar('undefined'); - } else if (value === null) { - this.emitScalar('null'); - } else if (value === jasmine.getGlobal()) { - this.emitScalar(''); - } else if (value instanceof jasmine.Matchers.Any) { - this.emitScalar(value.toString()); - } else if (typeof value === 'string') { - this.emitString(value); - } else if (jasmine.isSpy(value)) { - this.emitScalar("spy on " + value.identity); - } else if (value instanceof RegExp) { - this.emitScalar(value.toString()); - } else if (typeof value === 'function') { - this.emitScalar('Function'); - } else if (typeof value.nodeType === 'number') { - this.emitScalar('HTMLNode'); - } else if (value instanceof Date) { - this.emitScalar('Date(' + value + ')'); - } else if (value.__Jasmine_been_here_before__) { - this.emitScalar(''); - } else if (jasmine.isArray_(value) || typeof value == 'object') { - value.__Jasmine_been_here_before__ = true; - if (jasmine.isArray_(value)) { - this.emitArray(value); - } else { - this.emitObject(value); - } - delete value.__Jasmine_been_here_before__; - } else { - this.emitScalar(value.toString()); - } - } finally { - this.ppNestLevel_--; - } -}; - -jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { - for (var property in obj) { - if (property == '__Jasmine_been_here_before__') continue; - fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined && - obj.__lookupGetter__(property) !== null) : false); - } -}; - -jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; -jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; -jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; -jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_; - -jasmine.StringPrettyPrinter = function() { - jasmine.PrettyPrinter.call(this); - - this.string = ''; -}; -jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); - -jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { - this.append(value); -}; - -jasmine.StringPrettyPrinter.prototype.emitString = function(value) { - this.append("'" + value + "'"); -}; - -jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { - this.append('[ '); - for (var i = 0; i < array.length; i++) { - if (i > 0) { - this.append(', '); - } - this.format(array[i]); - } - this.append(' ]'); -}; - -jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { - var self = this; - this.append('{ '); - var first = true; - - this.iterateObject(obj, function(property, isGetter) { - if (first) { - first = false; - } else { - self.append(', '); - } - - self.append(property); - self.append(' : '); - if (isGetter) { - self.append(''); - } else { - self.format(obj[property]); - } - }); - - this.append(' }'); -}; - -jasmine.StringPrettyPrinter.prototype.append = function(value) { - this.string += value; -}; -jasmine.Queue = function(env) { - this.env = env; - this.blocks = []; - this.running = false; - this.index = 0; - this.offset = 0; - this.abort = false; -}; - -jasmine.Queue.prototype.addBefore = function(block) { - this.blocks.unshift(block); -}; - -jasmine.Queue.prototype.add = function(block) { - this.blocks.push(block); -}; - -jasmine.Queue.prototype.insertNext = function(block) { - this.blocks.splice((this.index + this.offset + 1), 0, block); - this.offset++; -}; - -jasmine.Queue.prototype.start = function(onComplete) { - this.running = true; - this.onComplete = onComplete; - this.next_(); -}; - -jasmine.Queue.prototype.isRunning = function() { - return this.running; -}; - -jasmine.Queue.LOOP_DONT_RECURSE = true; - -jasmine.Queue.prototype.next_ = function() { - var self = this; - var goAgain = true; - - while (goAgain) { - goAgain = false; - - if (self.index < self.blocks.length && !this.abort) { - var calledSynchronously = true; - var completedSynchronously = false; - - var onComplete = function () { - if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) { - completedSynchronously = true; - return; - } - - if (self.blocks[self.index].abort) { - self.abort = true; - } - - self.offset = 0; - self.index++; - - var now = new Date().getTime(); - if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) { - self.env.lastUpdate = now; - self.env.setTimeout(function() { - self.next_(); - }, 0); - } else { - if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) { - goAgain = true; - } else { - self.next_(); - } - } - }; - self.blocks[self.index].execute(onComplete); - - calledSynchronously = false; - if (completedSynchronously) { - onComplete(); - } - - } else { - self.running = false; - if (self.onComplete) { - self.onComplete(); - } - } - } -}; - -jasmine.Queue.prototype.results = function() { - var results = new jasmine.NestedResults(); - for (var i = 0; i < this.blocks.length; i++) { - if (this.blocks[i].results) { - results.addResult(this.blocks[i].results()); - } - } - return results; -}; - - -/** - * Runner - * - * @constructor - * @param {jasmine.Env} env - */ -jasmine.Runner = function(env) { - var self = this; - self.env = env; - self.queue = new jasmine.Queue(env); - self.before_ = []; - self.after_ = []; - self.suites_ = []; -}; - -jasmine.Runner.prototype.execute = function() { - var self = this; - if (self.env.reporter.reportRunnerStarting) { - self.env.reporter.reportRunnerStarting(this); - } - self.queue.start(function () { - self.finishCallback(); - }); -}; - -jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) { - beforeEachFunction.typeName = 'beforeEach'; - this.before_.splice(0,0,beforeEachFunction); -}; - -jasmine.Runner.prototype.afterEach = function(afterEachFunction) { - afterEachFunction.typeName = 'afterEach'; - this.after_.splice(0,0,afterEachFunction); -}; - - -jasmine.Runner.prototype.finishCallback = function() { - this.env.reporter.reportRunnerResults(this); -}; - -jasmine.Runner.prototype.addSuite = function(suite) { - this.suites_.push(suite); -}; - -jasmine.Runner.prototype.add = function(block) { - if (block instanceof jasmine.Suite) { - this.addSuite(block); - } - this.queue.add(block); -}; - -jasmine.Runner.prototype.specs = function () { - var suites = this.suites(); - var specs = []; - for (var i = 0; i < suites.length; i++) { - specs = specs.concat(suites[i].specs()); - } - return specs; -}; - -jasmine.Runner.prototype.suites = function() { - return this.suites_; -}; - -jasmine.Runner.prototype.topLevelSuites = function() { - var topLevelSuites = []; - for (var i = 0; i < this.suites_.length; i++) { - if (!this.suites_[i].parentSuite) { - topLevelSuites.push(this.suites_[i]); - } - } - return topLevelSuites; -}; - -jasmine.Runner.prototype.results = function() { - return this.queue.results(); -}; -/** - * Internal representation of a Jasmine specification, or test. - * - * @constructor - * @param {jasmine.Env} env - * @param {jasmine.Suite} suite - * @param {String} description - */ -jasmine.Spec = function(env, suite, description) { - if (!env) { - throw new Error('jasmine.Env() required'); - } - if (!suite) { - throw new Error('jasmine.Suite() required'); - } - var spec = this; - spec.id = env.nextSpecId ? env.nextSpecId() : null; - spec.env = env; - spec.suite = suite; - spec.description = description; - spec.queue = new jasmine.Queue(env); - - spec.afterCallbacks = []; - spec.spies_ = []; - - spec.results_ = new jasmine.NestedResults(); - spec.results_.description = description; - spec.matchersClass = null; -}; - -jasmine.Spec.prototype.getFullName = function() { - return this.suite.getFullName() + ' ' + this.description + '.'; -}; - - -jasmine.Spec.prototype.results = function() { - return this.results_; -}; - -/** - * All parameters are pretty-printed and concatenated together, then written to the spec's output. - * - * Be careful not to leave calls to jasmine.log in production code. - */ -jasmine.Spec.prototype.log = function() { - return this.results_.log(arguments); -}; - -jasmine.Spec.prototype.runs = function (func) { - var block = new jasmine.Block(this.env, func, this); - this.addToQueue(block); - return this; -}; - -jasmine.Spec.prototype.addToQueue = function (block) { - if (this.queue.isRunning()) { - this.queue.insertNext(block); - } else { - this.queue.add(block); - } -}; - -/** - * @param {jasmine.ExpectationResult} result - */ -jasmine.Spec.prototype.addMatcherResult = function(result) { - this.results_.addResult(result); -}; - -jasmine.Spec.prototype.expect = function(actual) { - var positive = new (this.getMatchersClass_())(this.env, actual, this); - positive.not = new (this.getMatchersClass_())(this.env, actual, this, true); - return positive; -}; - -/** - * Waits a fixed time period before moving to the next block. - * - * @deprecated Use waitsFor() instead - * @param {Number} timeout milliseconds to wait - */ -jasmine.Spec.prototype.waits = function(timeout) { - var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this); - this.addToQueue(waitsFunc); - return this; -}; - -/** - * Waits for the latchFunction to return true before proceeding to the next block. - * - * @param {Function} latchFunction - * @param {String} optional_timeoutMessage - * @param {Number} optional_timeout - */ -jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { - var latchFunction_ = null; - var optional_timeoutMessage_ = null; - var optional_timeout_ = null; - - for (var i = 0; i < arguments.length; i++) { - var arg = arguments[i]; - switch (typeof arg) { - case 'function': - latchFunction_ = arg; - break; - case 'string': - optional_timeoutMessage_ = arg; - break; - case 'number': - optional_timeout_ = arg; - break; - } - } - - var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this); - this.addToQueue(waitsForFunc); - return this; -}; - -jasmine.Spec.prototype.fail = function (e) { - var expectationResult = new jasmine.ExpectationResult({ - passed: false, - message: e ? jasmine.util.formatException(e) : 'Exception', - trace: { stack: e.stack } - }); - this.results_.addResult(expectationResult); -}; - -jasmine.Spec.prototype.getMatchersClass_ = function() { - return this.matchersClass || this.env.matchersClass; -}; - -jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { - var parent = this.getMatchersClass_(); - var newMatchersClass = function() { - parent.apply(this, arguments); - }; - jasmine.util.inherit(newMatchersClass, parent); - jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass); - this.matchersClass = newMatchersClass; -}; - -jasmine.Spec.prototype.finishCallback = function() { - this.env.reporter.reportSpecResults(this); -}; - -jasmine.Spec.prototype.finish = function(onComplete) { - this.removeAllSpies(); - this.finishCallback(); - if (onComplete) { - onComplete(); - } -}; - -jasmine.Spec.prototype.after = function(doAfter) { - if (this.queue.isRunning()) { - this.queue.add(new jasmine.Block(this.env, doAfter, this)); - } else { - this.afterCallbacks.unshift(doAfter); - } -}; - -jasmine.Spec.prototype.execute = function(onComplete) { - var spec = this; - if (!spec.env.specFilter(spec)) { - spec.results_.skipped = true; - spec.finish(onComplete); - return; - } - - this.env.reporter.reportSpecStarting(this); - - spec.env.currentSpec = spec; - - spec.addBeforesAndAftersToQueue(); - - spec.queue.start(function () { - spec.finish(onComplete); - }); -}; - -jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { - var runner = this.env.currentRunner(); - var i; - - for (var suite = this.suite; suite; suite = suite.parentSuite) { - for (i = 0; i < suite.before_.length; i++) { - this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this)); - } - } - for (i = 0; i < runner.before_.length; i++) { - this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this)); - } - for (i = 0; i < this.afterCallbacks.length; i++) { - this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this)); - } - for (suite = this.suite; suite; suite = suite.parentSuite) { - for (i = 0; i < suite.after_.length; i++) { - this.queue.add(new jasmine.Block(this.env, suite.after_[i], this)); - } - } - for (i = 0; i < runner.after_.length; i++) { - this.queue.add(new jasmine.Block(this.env, runner.after_[i], this)); - } -}; - -jasmine.Spec.prototype.explodes = function() { - throw 'explodes function should not have been called'; -}; - -jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { - if (obj == jasmine.undefined) { - throw "spyOn could not find an object to spy upon for " + methodName + "()"; - } - - if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) { - throw methodName + '() method does not exist'; - } - - if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { - throw new Error(methodName + ' has already been spied upon'); - } - - var spyObj = jasmine.createSpy(methodName); - - this.spies_.push(spyObj); - spyObj.baseObj = obj; - spyObj.methodName = methodName; - spyObj.originalValue = obj[methodName]; - - obj[methodName] = spyObj; - - return spyObj; -}; - -jasmine.Spec.prototype.removeAllSpies = function() { - for (var i = 0; i < this.spies_.length; i++) { - var spy = this.spies_[i]; - spy.baseObj[spy.methodName] = spy.originalValue; - } - this.spies_ = []; -}; - -/** - * Internal representation of a Jasmine suite. - * - * @constructor - * @param {jasmine.Env} env - * @param {String} description - * @param {Function} specDefinitions - * @param {jasmine.Suite} parentSuite - */ -jasmine.Suite = function(env, description, specDefinitions, parentSuite) { - var self = this; - self.id = env.nextSuiteId ? env.nextSuiteId() : null; - self.description = description; - self.queue = new jasmine.Queue(env); - self.parentSuite = parentSuite; - self.env = env; - self.before_ = []; - self.after_ = []; - self.children_ = []; - self.suites_ = []; - self.specs_ = []; -}; - -jasmine.Suite.prototype.getFullName = function() { - var fullName = this.description; - for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { - fullName = parentSuite.description + ' ' + fullName; - } - return fullName; -}; - -jasmine.Suite.prototype.finish = function(onComplete) { - this.env.reporter.reportSuiteResults(this); - this.finished = true; - if (typeof(onComplete) == 'function') { - onComplete(); - } -}; - -jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { - beforeEachFunction.typeName = 'beforeEach'; - this.before_.unshift(beforeEachFunction); -}; - -jasmine.Suite.prototype.afterEach = function(afterEachFunction) { - afterEachFunction.typeName = 'afterEach'; - this.after_.unshift(afterEachFunction); -}; - -jasmine.Suite.prototype.results = function() { - return this.queue.results(); -}; - -jasmine.Suite.prototype.add = function(suiteOrSpec) { - this.children_.push(suiteOrSpec); - if (suiteOrSpec instanceof jasmine.Suite) { - this.suites_.push(suiteOrSpec); - this.env.currentRunner().addSuite(suiteOrSpec); - } else { - this.specs_.push(suiteOrSpec); - } - this.queue.add(suiteOrSpec); -}; - -jasmine.Suite.prototype.specs = function() { - return this.specs_; -}; - -jasmine.Suite.prototype.suites = function() { - return this.suites_; -}; - -jasmine.Suite.prototype.children = function() { - return this.children_; -}; - -jasmine.Suite.prototype.execute = function(onComplete) { - var self = this; - this.queue.start(function () { - self.finish(onComplete); - }); -}; -jasmine.WaitsBlock = function(env, timeout, spec) { - this.timeout = timeout; - jasmine.Block.call(this, env, null, spec); -}; - -jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block); - -jasmine.WaitsBlock.prototype.execute = function (onComplete) { - if (jasmine.VERBOSE) { - this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...'); - } - this.env.setTimeout(function () { - onComplete(); - }, this.timeout); -}; -/** - * A block which waits for some condition to become true, with timeout. - * - * @constructor - * @extends jasmine.Block - * @param {jasmine.Env} env The Jasmine environment. - * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true. - * @param {Function} latchFunction A function which returns true when the desired condition has been met. - * @param {String} message The message to display if the desired condition hasn't been met within the given time period. - * @param {jasmine.Spec} spec The Jasmine spec. - */ -jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) { - this.timeout = timeout || env.defaultTimeoutInterval; - this.latchFunction = latchFunction; - this.message = message; - this.totalTimeSpentWaitingForLatch = 0; - jasmine.Block.call(this, env, null, spec); -}; -jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block); - -jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10; - -jasmine.WaitsForBlock.prototype.execute = function(onComplete) { - if (jasmine.VERBOSE) { - this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen')); - } - var latchFunctionResult; - try { - latchFunctionResult = this.latchFunction.apply(this.spec); - } catch (e) { - this.spec.fail(e); - onComplete(); - return; - } - - if (latchFunctionResult) { - onComplete(); - } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) { - var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen'); - this.spec.fail({ - name: 'timeout', - message: message - }); - - this.abort = true; - onComplete(); - } else { - this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT; - var self = this; - this.env.setTimeout(function() { - self.execute(onComplete); - }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT); - } -}; -// Mock setTimeout, clearTimeout -// Contributed by Pivotal Computer Systems, www.pivotalsf.com - -jasmine.FakeTimer = function() { - this.reset(); - - var self = this; - self.setTimeout = function(funcToCall, millis) { - self.timeoutsMade++; - self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false); - return self.timeoutsMade; - }; - - self.setInterval = function(funcToCall, millis) { - self.timeoutsMade++; - self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true); - return self.timeoutsMade; - }; - - self.clearTimeout = function(timeoutKey) { - self.scheduledFunctions[timeoutKey] = jasmine.undefined; - }; - - self.clearInterval = function(timeoutKey) { - self.scheduledFunctions[timeoutKey] = jasmine.undefined; - }; - -}; - -jasmine.FakeTimer.prototype.reset = function() { - this.timeoutsMade = 0; - this.scheduledFunctions = {}; - this.nowMillis = 0; -}; - -jasmine.FakeTimer.prototype.tick = function(millis) { - var oldMillis = this.nowMillis; - var newMillis = oldMillis + millis; - this.runFunctionsWithinRange(oldMillis, newMillis); - this.nowMillis = newMillis; -}; - -jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) { - var scheduledFunc; - var funcsToRun = []; - for (var timeoutKey in this.scheduledFunctions) { - scheduledFunc = this.scheduledFunctions[timeoutKey]; - if (scheduledFunc != jasmine.undefined && - scheduledFunc.runAtMillis >= oldMillis && - scheduledFunc.runAtMillis <= nowMillis) { - funcsToRun.push(scheduledFunc); - this.scheduledFunctions[timeoutKey] = jasmine.undefined; - } - } - - if (funcsToRun.length > 0) { - funcsToRun.sort(function(a, b) { - return a.runAtMillis - b.runAtMillis; - }); - for (var i = 0; i < funcsToRun.length; ++i) { - try { - var funcToRun = funcsToRun[i]; - this.nowMillis = funcToRun.runAtMillis; - funcToRun.funcToCall(); - if (funcToRun.recurring) { - this.scheduleFunction(funcToRun.timeoutKey, - funcToRun.funcToCall, - funcToRun.millis, - true); - } - } catch(e) { - } - } - this.runFunctionsWithinRange(oldMillis, nowMillis); - } -}; - -jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) { - this.scheduledFunctions[timeoutKey] = { - runAtMillis: this.nowMillis + millis, - funcToCall: funcToCall, - recurring: recurring, - timeoutKey: timeoutKey, - millis: millis - }; -}; - -/** - * @namespace - */ -jasmine.Clock = { - defaultFakeTimer: new jasmine.FakeTimer(), - - reset: function() { - jasmine.Clock.assertInstalled(); - jasmine.Clock.defaultFakeTimer.reset(); - }, - - tick: function(millis) { - jasmine.Clock.assertInstalled(); - jasmine.Clock.defaultFakeTimer.tick(millis); - }, - - runFunctionsWithinRange: function(oldMillis, nowMillis) { - jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis); - }, - - scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) { - jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring); - }, - - useMock: function() { - if (!jasmine.Clock.isInstalled()) { - var spec = jasmine.getEnv().currentSpec; - spec.after(jasmine.Clock.uninstallMock); - - jasmine.Clock.installMock(); - } - }, - - installMock: function() { - jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer; - }, - - uninstallMock: function() { - jasmine.Clock.assertInstalled(); - jasmine.Clock.installed = jasmine.Clock.real; - }, - - real: { - setTimeout: jasmine.getGlobal().setTimeout, - clearTimeout: jasmine.getGlobal().clearTimeout, - setInterval: jasmine.getGlobal().setInterval, - clearInterval: jasmine.getGlobal().clearInterval - }, - - assertInstalled: function() { - if (!jasmine.Clock.isInstalled()) { - throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()"); - } - }, - - isInstalled: function() { - return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer; - }, - - installed: null -}; -jasmine.Clock.installed = jasmine.Clock.real; - -//else for IE support -jasmine.getGlobal().setTimeout = function(funcToCall, millis) { - if (jasmine.Clock.installed.setTimeout.apply) { - return jasmine.Clock.installed.setTimeout.apply(this, arguments); - } else { - return jasmine.Clock.installed.setTimeout(funcToCall, millis); - } -}; - -jasmine.getGlobal().setInterval = function(funcToCall, millis) { - if (jasmine.Clock.installed.setInterval.apply) { - return jasmine.Clock.installed.setInterval.apply(this, arguments); - } else { - return jasmine.Clock.installed.setInterval(funcToCall, millis); - } -}; - -jasmine.getGlobal().clearTimeout = function(timeoutKey) { - if (jasmine.Clock.installed.clearTimeout.apply) { - return jasmine.Clock.installed.clearTimeout.apply(this, arguments); - } else { - return jasmine.Clock.installed.clearTimeout(timeoutKey); - } -}; - -jasmine.getGlobal().clearInterval = function(timeoutKey) { - if (jasmine.Clock.installed.clearTimeout.apply) { - return jasmine.Clock.installed.clearInterval.apply(this, arguments); - } else { - return jasmine.Clock.installed.clearInterval(timeoutKey); - } -}; - -jasmine.version_= { - "major": 1, - "minor": 1, - "build": 0, - "revision": 1308618948, - "release_candidate": 1 -}; diff --git a/lib/es5-shim/tests/lib/jasmine_favicon.png b/lib/es5-shim/tests/lib/jasmine_favicon.png deleted file mode 100644 index 218f3b4..0000000 Binary files a/lib/es5-shim/tests/lib/jasmine_favicon.png and /dev/null differ diff --git a/lib/es5-shim/tests/lib/json2.js b/lib/es5-shim/tests/lib/json2.js deleted file mode 100644 index ac58079..0000000 --- a/lib/es5-shim/tests/lib/json2.js +++ /dev/null @@ -1,478 +0,0 @@ -/* - http://www.JSON.org/json2.js - 2009-08-17 - - Public Domain. - - NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. - - See http://www.JSON.org/js.html - - This file creates a global JSON object containing two methods: stringify - and parse. - - JSON.stringify(value, replacer, space) - value any JavaScript value, usually an object or array. - - replacer an optional parameter that determines how object - values are stringified for objects. It can be a - function or an array of strings. - - space an optional parameter that specifies the indentation - of nested structures. If it is omitted, the text will - be packed without extra whitespace. If it is a number, - it will specify the number of spaces to indent at each - level. If it is a string (such as '\t' or ' '), - it contains the characters used to indent at each level. - - This method produces a JSON text from a JavaScript value. - - When an object value is found, if the object contains a toJSON - method, its toJSON method will be called and the result will be - stringified. A toJSON method does not serialize: it returns the - value represented by the name/value pair that should be serialized, - or undefined if nothing should be serialized. The toJSON method - will be passed the key associated with the value, and this will be - bound to the value - - For example, this would serialize Dates as ISO strings. - - Date.prototype.toJSON = function (key) { - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - return this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z'; - }; - - You can provide an optional replacer method. It will be passed the - key and value of each member, with this bound to the containing - object. The value that is returned from your method will be - serialized. If your method returns undefined, then the member will - be excluded from the serialization. - - If the replacer parameter is an array of strings, then it will be - used to select the members to be serialized. It filters the results - such that only members with keys listed in the replacer array are - stringified. - - Values that do not have JSON representations, such as undefined or - functions, will not be serialized. Such values in objects will be - dropped; in arrays they will be replaced with null. You can use - a replacer function to replace those with JSON values. - JSON.stringify(undefined) returns undefined. - - The optional space parameter produces a stringification of the - value that is filled with line breaks and indentation to make it - easier to read. - - If the space parameter is a non-empty string, then that string will - be used for indentation. If the space parameter is a number, then - the indentation will be that many spaces. - - Example: - - text = JSON.stringify(['e', {pluribus: 'unum'}]); - // text is '["e",{"pluribus":"unum"}]' - - - text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); - // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' - - text = JSON.stringify([new Date()], function (key, value) { - return this[key] instanceof Date ? - 'Date(' + this[key] + ')' : value; - }); - // text is '["Date(---current time---)"]' - - - JSON.parse(text, reviver) - This method parses a JSON text to produce an object or array. - It can throw a SyntaxError exception. - - The optional reviver parameter is a function that can filter and - transform the results. It receives each of the keys and values, - and its return value is used instead of the original value. - If it returns what it received, then the structure is not modified. - If it returns undefined then the member is deleted. - - Example: - - // Parse the text. Values that look like ISO date strings will - // be converted to Date objects. - - myData = JSON.parse(text, function (key, value) { - var a; - if (typeof value === 'string') { - a = -/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); - if (a) { - return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], - +a[5], +a[6])); - } - } - return value; - }); - - myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { - var d; - if (typeof value === 'string' && - value.slice(0, 5) === 'Date(' && - value.slice(-1) === ')') { - d = new Date(value.slice(5, -1)); - if (d) { - return d; - } - } - return value; - }); - - - This is a reference implementation. You are free to copy, modify, or - redistribute. - - This code should be minified before deployment. - See http://javascript.crockford.com/jsmin.html - - USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO - NOT CONTROL. -*/ - -/*jslint evil: true */ - -/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, - call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, - getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, - lastIndex, length, parse, prototype, push, replace, slice, stringify, - test, toJSON, toString, valueOf -*/ - -"use strict"; - -// Create a JSON object only if one does not already exist. We create the -// methods in a closure to avoid creating global variables. - -if (!this.JSON) { - this.JSON = {}; -} - -(function () { - - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - if (typeof Date.prototype.toJSON !== 'function') { - - Date.prototype.toJSON = function (key) { - - return isFinite(this.valueOf()) ? - this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z' : null; - }; - - String.prototype.toJSON = - Number.prototype.toJSON = - Boolean.prototype.toJSON = function (key) { - return this.valueOf(); - }; - } - - var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - gap, - indent, - meta = { // table of character substitutions - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - }, - rep; - - - function quote(string) { - -// If the string contains no control characters, no quote characters, and no -// backslash characters, then we can safely slap some quotes around it. -// Otherwise we must also replace the offending characters with safe escape -// sequences. - - escapable.lastIndex = 0; - return escapable.test(string) ? - '"' + string.replace(escapable, function (a) { - var c = meta[a]; - return typeof c === 'string' ? c : - '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) + '"' : - '"' + string + '"'; - } - - - function str(key, holder) { -// Produce a string from holder[key]. - - var i, // The loop counter. - k, // The member key. - v, // The member value. - length, - mind = gap, - partial, - value = holder[key]; - -// If the value has a toJSON method, call it to obtain a replacement value. - - if (value && typeof value === 'object' && - typeof value.toJSON === 'function') { - value = value.toJSON(key); - } - -// If we were called with a replacer function, then call the replacer to -// obtain a replacement value. - - if (typeof rep === 'function') { - value = rep.call(holder, key, value); - } - -// What happens next depends on the value's type. - - switch (typeof value) { - case 'string': - return quote(value); - - case 'number': - -// JSON numbers must be finite. Encode non-finite numbers as null. - - return isFinite(value) ? String(value) : 'null'; - - case 'boolean': - case 'null': - -// If the value is a boolean or null, convert it to a string. Note: -// typeof null does not produce 'null'. The case is included here in -// the remote chance that this gets fixed someday. - - return String(value); - -// If the type is 'object', we might be dealing with an object or an array or -// null. - - case 'object': - -// Due to a specification blunder in ECMAScript, typeof null is 'object', -// so watch out for that case. - - if (!value) { - return 'null'; - } - -// Make an array to hold the partial results of stringifying this object value. - - gap += indent; - partial = []; - -// Is the value an array? - - if (Object.prototype.toString.apply(value) === '[object Array]') { - -// The value is an array. Stringify every element. Use null as a placeholder -// for non-JSON values. - - length = value.length; - for (i = 0; i < length; i += 1) { - partial[i] = str(i, value) || 'null'; - } - -// Join all of the elements together, separated with commas, and wrap them in -// brackets. - - v = partial.length === 0 ? '[]' : - gap ? '[\n' + gap + - partial.join(',\n' + gap) + '\n' + - mind + ']' : - '[' + partial.join(',') + ']'; - gap = mind; - return v; - } - -// If the replacer is an array, use it to select the members to be stringified. - - if (rep && typeof rep === 'object') { - length = rep.length; - for (i = 0; i < length; i += 1) { - k = rep[i]; - if (typeof k === 'string') { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } else { - -// Otherwise, iterate through all of the keys in the object. - - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } - -// Join all of the member texts together, separated with commas, -// and wrap them in braces. - - v = partial.length === 0 ? '{}' : - gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + - mind + '}' : '{' + partial.join(',') + '}'; - gap = mind; - return v; - } - } - -// If the JSON object does not yet have a stringify method, give it one. - - if (typeof JSON.stringify !== 'function') { - JSON.stringify = function (value, replacer, space) { -// The stringify method takes a value and an optional replacer, and an optional -// space parameter, and returns a JSON text. The replacer can be a function -// that can replace values, or an array of strings that will select the keys. -// A default replacer method can be provided. Use of the space parameter can -// produce text that is more easily readable. - - var i; - gap = ''; - indent = ''; - -// If the space parameter is a number, make an indent string containing that -// many spaces. - - if (typeof space === 'number') { - for (i = 0; i < space; i += 1) { - indent += ' '; - } - -// If the space parameter is a string, it will be used as the indent string. - - } else if (typeof space === 'string') { - indent = space; - } - -// If there is a replacer, it must be a function or an array. -// Otherwise, throw an error. - - rep = replacer; - if (replacer && typeof replacer !== 'function' && - (typeof replacer !== 'object' || - typeof replacer.length !== 'number')) { - throw new Error('JSON.stringify'); - } - -// Make a fake root object containing our value under the key of ''. -// Return the result of stringifying the value. - - return str('', {'': value}); - }; - } - - -// If the JSON object does not yet have a parse method, give it one. - - if (typeof JSON.parse !== 'function') { - JSON.parse = function (text, reviver) { - -// The parse method takes a text and an optional reviver function, and returns -// a JavaScript value if the text is a valid JSON text. - - var j; - - function walk(holder, key) { - -// The walk method is used to recursively walk the resulting structure so -// that modifications can be made. - - var k, v, value = holder[key]; - if (value && typeof value === 'object') { - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - } - } - } - return reviver.call(holder, key, value); - } - - -// Parsing happens in four stages. In the first stage, we replace certain -// Unicode characters with escape sequences. JavaScript handles many characters -// incorrectly, either silently deleting them, or treating them as line endings. - - cx.lastIndex = 0; - if (cx.test(text)) { - text = text.replace(cx, function (a) { - return '\\u' + - ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }); - } - -// In the second stage, we run the text against regular expressions that look -// for non-JSON patterns. We are especially concerned with '()' and 'new' -// because they can cause invocation, and '=' because it can cause mutation. -// But just to be safe, we want to reject all unexpected forms. - -// We split the second stage into 4 regexp operations in order to work around -// crippling inefficiencies in IE's and Safari's regexp engines. First we -// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we -// replace all simple value tokens with ']' characters. Third, we delete all -// open brackets that follow a colon or comma or that begin the text. Finally, -// we look to see that the remaining characters are only whitespace or ']' or -// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. - - if (/^[\],:{}\s]*$/. -test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). -replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). -replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { - -// In the third stage we use the eval function to compile the text into a -// JavaScript structure. The '{' operator is subject to a syntactic ambiguity -// in JavaScript: it can begin a block or an object literal. We wrap the text -// in parens to eliminate the ambiguity. - - j = eval('(' + text + ')'); - -// In the optional fourth stage, we recursively walk the new structure, passing -// each name/value pair to a reviver function for possible transformation. - - return typeof reviver === 'function' ? - walk({'': j}, '') : j; - } - -// If the text is not JSON parseable, then a SyntaxError is thrown. - - throw new SyntaxError('JSON.parse'); - }; - } -}()); diff --git a/lib/es5-shim/tests/spec/s-array.js b/lib/es5-shim/tests/spec/s-array.js deleted file mode 100644 index 707b164..0000000 --- a/lib/es5-shim/tests/spec/s-array.js +++ /dev/null @@ -1,1144 +0,0 @@ -describe('Array', function() { - var testSubject; - beforeEach(function() { - testSubject = [2, 3, undefined, true, 'hej', null, false, 0]; - delete testSubject[1]; - }); - function createArrayLikeFromArray(arr) { - var o = {}; - Array.prototype.forEach.call(arr, function(e, i) { - o[i]=e; - }); - o.length = arr.length; - return o; - }; - - describe('forEach', function() { - "use strict"; - var expected, actual; - - beforeEach(function() { - expected = {0:2, 2: undefined, 3:true, 4: 'hej', 5:null, 6:false, 7:0 }; - actual = {}; - }); - it('should pass the right parameters', function() { - var callback = jasmine.createSpy('callback'), - array = ['1']; - array.forEach(callback); - expect(callback).toHaveBeenCalledWith('1', 0, array); - }); - it('should not affect elements added to the array after it has begun', function() { - var arr = [1,2,3], - i = 0; - arr.forEach(function(a) { - i++; - arr.push(a+3); - }); - expect(arr).toEqual([1,2,3,4,5,6]); - expect(i).toBe(3); - }); - - it('should set the right context when given none', function() { - var context; - [1].forEach(function() {context = this;}); - expect(context).toBe(function() {return this}.call()); - }); - it('should iterate all', function() { - testSubject.forEach(function(obj, index) { - actual[index] = obj; - }); - expect(actual).toExactlyMatch(expected); - }); - it('should iterate all using a context', function() { - var o = { a: actual }; - - testSubject.forEach(function(obj, index) { - this.a[index] = obj; - }, o); - expect(actual).toExactlyMatch(expected); - }); - - it('should iterate all in an array-like object', function() { - var ts = createArrayLikeFromArray(testSubject); - Array.prototype.forEach.call(ts, function(obj, index) { - actual[index] = obj; - }); - expect(actual).toExactlyMatch(expected); - }); - it('should iterate all in an array-like object using a context', function() { - var ts = createArrayLikeFromArray(testSubject), - o = { a: actual }; - - Array.prototype.forEach.call(ts, function(obj, index) { - this.a[index] = obj; - }, o); - expect(actual).toExactlyMatch(expected); - }); - - describe('strings', function() { - var str = 'Hello, World!', - toString = Object.prototype.toString; - it('should iterate all in a string', function() { - actual = []; - Array.prototype.forEach.call(str, function(item, index) { - actual[index] = item; - }); - expect(actual).toExactlyMatch(str.split('')); - }); - it('should iterate all in a string using a context', function() { - actual = []; - var o = { a: actual }; - Array.prototype.forEach.call(str, function(item, index) { - this.a[index] = item; - }, o); - expect(actual).toExactlyMatch(str.split('')); - }); - it('should have String object for third argument of callback', function() { - Array.prototype.forEach.call(str, function(item, index, obj) { - actual = obj; - }); - expect(typeof actual).toBe("object"); - expect(toString.call(actual)).toBe("[object String]"); - }); - }); - }); - describe('some', function() { - var actual, expected, numberOfRuns; - - beforeEach(function() { - expected = {0:2, 2: undefined, 3:true }; - actual = {}; - numberOfRuns = 0; - }); - - it('should pass the correct values along to the callback', function() { - var callback = jasmine.createSpy('callback'); - var array = ['1']; - array.some(callback); - expect(callback).toHaveBeenCalledWith('1', 0, array); - }); - it('should not affect elements added to the array after it has begun', function() { - var arr = [1,2,3], - i = 0; - arr.some(function(a) { - i++; - arr.push(a+3); - return i > 3; - }); - expect(arr).toEqual([1,2,3,4,5,6]); - expect(i).toBe(3); - }); - it('should set the right context when given none', function() { - var context; - [1].some(function() {context = this;}); - expect(context).toBe(function() {return this}.call()); - }); - - it('should return false if it runs to the end', function() { - actual = testSubject.some(function() {}); - expect(actual).toBeFalsy(); - }); - it('should return true if it is stopped somewhere', function() { - actual = testSubject.some(function() { return true; }); - expect(actual).toBeTruthy(); - }); - it('should return false if there are no elements', function() { - actual = [].some(function() { return true; }); - expect(actual).toBeFalsy(); - }); - - it('should stop after 3 elements', function() { - testSubject.some(function(obj, index) { - actual[index] = obj; - numberOfRuns += 1; - if(numberOfRuns == 3) { - return true; - } - return false; - }); - expect(actual).toExactlyMatch(expected); - }); - it('should stop after 3 elements using a context', function() { - var o = { a: actual }; - testSubject.some(function(obj, index) { - this.a[index] = obj; - numberOfRuns += 1; - if(numberOfRuns == 3) { - return true; - } - return false; - }, o); - expect(actual).toExactlyMatch(expected); - }); - - it('should stop after 3 elements in an array-like object', function() { - var ts = createArrayLikeFromArray(testSubject); - Array.prototype.some.call(ts, function(obj, index) { - actual[index] = obj; - numberOfRuns += 1; - if(numberOfRuns == 3) { - return true; - } - return false; - }); - expect(actual).toExactlyMatch(expected); - }); - it('should stop after 3 elements in an array-like object using a context', function() { - var ts = createArrayLikeFromArray(testSubject); - var o = { a: actual }; - Array.prototype.some.call(ts, function(obj, index) { - this.a[index] = obj; - numberOfRuns += 1; - if(numberOfRuns == 3) { - return true; - } - return false; - }, o); - expect(actual).toExactlyMatch(expected); - }); - }); - describe('every', function() { - var actual, expected, numberOfRuns; - - beforeEach(function() { - expected = {0:2, 2: undefined, 3:true }; - actual = {}; - numberOfRuns = 0; - }); - - it('should pass the correct values along to the callback', function() { - var callback = jasmine.createSpy('callback'); - var array = ['1']; - array.every(callback); - expect(callback).toHaveBeenCalledWith('1', 0, array); - }); - it('should not affect elements added to the array after it has begun', function() { - var arr = [1,2,3], - i = 0; - arr.every(function(a) { - i++; - arr.push(a+3); - return i <= 3; - }); - expect(arr).toEqual([1,2,3,4,5,6]); - expect(i).toBe(3); - }); - it('should set the right context when given none', function() { - var context; - [1].every(function() {context = this;}); - expect(context).toBe(function() {return this}.call()); - }); - - it('should return true if the array is empty', function() { - actual = [].every(function() { return true; }); - expect(actual).toBeTruthy(); - - actual = [].every(function() { return false; }); - expect(actual).toBeTruthy(); - }); - it('should return true if it runs to the end', function() { - actual = [1,2,3].every(function() { return true; }); - expect(actual).toBeTruthy(); - }); - it('should return false if it is stopped before the end', function() { - actual = [1,2,3].every(function() { return false; }); - expect(actual).toBeFalsy(); - }); - - it('should return after 3 elements', function() { - testSubject.every(function(obj, index) { - actual[index] = obj; - numberOfRuns += 1; - if(numberOfRuns == 3) { - return false; - } - return true; - }); - expect(actual).toExactlyMatch(expected); - }); - it('should stop after 3 elements using a context', function() { - var o = { a: actual }; - testSubject.every(function(obj, index) { - this.a[index] = obj; - numberOfRuns += 1; - if(numberOfRuns == 3) { - return false; - } - return true; - }, o); - expect(actual).toExactlyMatch(expected); - }); - - it('should stop after 3 elements in an array-like object', function() { - var ts = createArrayLikeFromArray(testSubject); - Array.prototype.every.call(ts, function(obj, index) { - actual[index] = obj; - numberOfRuns += 1; - if(numberOfRuns == 3) { - return false; - } - return true; - }); - expect(actual).toExactlyMatch(expected); - }); - it('should stop after 3 elements in an array-like object using a context', function() { - var ts = createArrayLikeFromArray(testSubject); - var o = { a: actual }; - Array.prototype.every.call(ts, function(obj, index) { - this.a[index] = obj; - numberOfRuns += 1; - if(numberOfRuns == 3) { - return false; - } - return true; - }, o); - expect(actual).toExactlyMatch(expected); - }); - }); - - describe('indexOf', function() { - "use strict"; - var actual, expected, testSubject; - - beforeEach(function() { - testSubject = [2, 3, undefined, true, 'hej', null, 2, false, 0]; - delete testSubject[1]; - - }); - - it('should find the element', function() { - expected = 4; - actual = testSubject.indexOf('hej'); - expect(actual).toEqual(expected); - }); - it('should not find the element', function() { - expected = -1; - actual = testSubject.indexOf('mus'); - expect(actual).toEqual(expected); - }); - it('should find undefined as well', function() { - expected = -1; - actual = testSubject.indexOf(undefined); - expect(actual).not.toEqual(expected); - }); - it('should skip unset indexes', function() { - expected = 2; - actual = testSubject.indexOf(undefined); - expect(actual).toEqual(expected); - }); - it('should use a strict test', function() { - actual = testSubject.indexOf(null); - expect(actual).toEqual(5); - - actual = testSubject.indexOf('2'); - expect(actual).toEqual(-1); - }); - it('should skip the first if fromIndex is set', function() { - expect(testSubject.indexOf(2, 2)).toEqual(6); - expect(testSubject.indexOf(2, 0)).toEqual(0); - expect(testSubject.indexOf(2, 6)).toEqual(6); - }); - it('should work with negative fromIndex', function() { - expect(testSubject.indexOf(2, -3)).toEqual(6); - expect(testSubject.indexOf(2, -9)).toEqual(0); - }); - it('should work with fromIndex being greater than the length', function() { - expect(testSubject.indexOf(0, 20)).toEqual(-1); - }); - it('should work with fromIndex being negative and greater than the length', function() { - expect(testSubject.indexOf('hej', -20)).toEqual(4); - }); - - describe('Array-like', function ArrayLike() { - var indexOf = Array.prototype.indexOf, - testAL; - beforeEach(function beforeEach() { - testAL = {}; - testSubject = [2, 3, undefined, true, 'hej', null, 2, false, 0]; - testSubject.forEach(function (o,i) { - testAL[i] = o; - }); - testAL.length = testSubject.length; - }); - it('should find the element (array-like)', function() { - expected = 4; - actual = indexOf.call(testAL, 'hej'); - expect(actual).toEqual(expected); - }); - it('should not find the element (array-like)', function() { - expected = -1; - actual = indexOf.call(testAL, 'mus'); - expect(actual).toEqual(expected); - }); - it('should find undefined as well (array-like)', function() { - expected = -1; - actual = indexOf.call(testAL, undefined); - expect(actual).not.toEqual(expected); - }); - it('should skip unset indexes (array-like)', function() { - expected = 2; - actual = indexOf.call(testAL, undefined); - expect(actual).toEqual(expected); - }); - it('should use a strict test (array-like)', function() { - actual = Array.prototype.indexOf.call(testAL, null); - expect(actual).toEqual(5); - - actual = Array.prototype.indexOf.call(testAL, '2'); - expect(actual).toEqual(-1); - }); - it('should skip the first if fromIndex is set (array-like)', function() { - expect(indexOf.call(testAL, 2, 2)).toEqual(6); - expect(indexOf.call(testAL, 2, 0)).toEqual(0); - expect(indexOf.call(testAL, 2, 6)).toEqual(6); - }); - it('should work with negative fromIndex (array-like)', function() { - expect(indexOf.call(testAL, 2, -3)).toEqual(6); - expect(indexOf.call(testAL, 2, -9)).toEqual(0); - }); - it('should work with fromIndex being greater than the length (array-like)', function() { - expect(indexOf.call(testAL, 0, 20)).toEqual(-1); - }); - it('should work with fromIndex being negative and greater than the length (array-like)', function() { - expect(indexOf.call(testAL, 'hej', -20)).toEqual(4); - }); - }); - }); - describe('lastIndexOf', function() { - "use strict"; - var actual, expected, testSubject, testAL; - - beforeEach(function() { - testSubject = [2, 3, undefined, true, 'hej', null, 2, 3, false, 0]; - delete testSubject[1]; - delete testSubject[7]; - }); - describe('Array', function() { - it('should find the element', function() { - expected = 4; - actual = testSubject.lastIndexOf('hej'); - expect(actual).toEqual(expected); - }); - it('should not find the element', function() { - expected = -1; - actual = testSubject.lastIndexOf('mus'); - expect(actual).toEqual(expected); - }); - it('should find undefined as well', function() { - expected = -1; - actual = testSubject.lastIndexOf(undefined); - expect(actual).not.toEqual(expected); - }); - it('should skip unset indexes', function() { - expected = 2; - actual = testSubject.lastIndexOf(undefined); - expect(actual).toEqual(expected); - }); - it('should use a strict test', function() { - actual = testSubject.lastIndexOf(null); - expect(actual).toEqual(5); - - actual = testSubject.lastIndexOf('2'); - expect(actual).toEqual(-1); - }); - it('should skip the first if fromIndex is set', function() { - expect(testSubject.lastIndexOf(2, 2)).toEqual(0); - expect(testSubject.lastIndexOf(2, 0)).toEqual(0); - expect(testSubject.lastIndexOf(2, 6)).toEqual(6); - }); - it('should work with negative fromIndex', function() { - expect(testSubject.lastIndexOf(2, -3)).toEqual(6); - expect(testSubject.lastIndexOf(2, -9)).toEqual(0); - }); - it('should work with fromIndex being greater than the length', function() { - expect(testSubject.lastIndexOf(2, 20)).toEqual(6); - }); - it('should work with fromIndex being negative and greater than the length', function() { - expect(testSubject.lastIndexOf(2, -20)).toEqual(-1); - }); - }); - - describe('Array like', function() { - var lastIndexOf = Array.prototype.lastIndexOf, - testAL; - beforeEach(function() { - testAL = {}; - testSubject.forEach(function (o,i) { - testAL[i] = o; - }); - testAL.length = testSubject.length; - }); - it('should find the element (array-like)', function() { - expected = 4; - actual = lastIndexOf.call(testAL, 'hej'); - expect(actual).toEqual(expected); - }); - it('should not find the element (array-like)', function() { - expected = -1; - actual = lastIndexOf.call(testAL, 'mus'); - expect(actual).toEqual(expected); - }); - it('should find undefined as well (array-like)', function() { - expected = -1; - actual = lastIndexOf.call(testAL, undefined); - expect(actual).not.toEqual(expected); - }); - it('should skip unset indexes (array-like)', function() { - expected = 2; - actual = lastIndexOf.call(testAL, undefined); - expect(actual).toEqual(expected); - }); - it('should use a strict test (array-like)', function() { - actual = lastIndexOf.call(testAL, null); - expect(actual).toEqual(5); - - actual = lastIndexOf.call(testAL, '2'); - expect(actual).toEqual(-1); - }); - it('should skip the first if fromIndex is set', function() { - expect(lastIndexOf.call(testAL, 2, 2)).toEqual(0); - expect(lastIndexOf.call(testAL, 2, 0)).toEqual(0); - expect(lastIndexOf.call(testAL, 2, 6)).toEqual(6); - }); - it('should work with negative fromIndex', function() { - expect(lastIndexOf.call(testAL, 2, -3)).toEqual(6); - expect(lastIndexOf.call(testAL, 2, -9)).toEqual(0); - }); - it('should work with fromIndex being greater than the length', function() { - expect(lastIndexOf.call(testAL, 2, 20)).toEqual(6); - }); - it('should work with fromIndex being negative and greater than the length', function() { - expect(lastIndexOf.call(testAL, 2, -20)).toEqual(-1); - }); - }); - }); - - describe('filter', function() { - var filteredArray, - callback = function callback(o, i, arr) { - return ( - i != 3 && i != 5 - ); - }; - - beforeEach(function() { - testSubject = [2, 3, undefined, true, 'hej', 3, null, false, 0]; - delete testSubject[1]; - filteredArray = [2, undefined, 'hej', null, false, 0]; - }); - describe('Array object', function() { - - it('should call the callback with the proper arguments', function() { - var callback = jasmine.createSpy('callback'), - arr = ['1']; - arr.filter(callback); - expect(callback).toHaveBeenCalledWith('1', 0, arr); - }); - it('should not affect elements added to the array after it has begun', function() { - var arr = [1,2,3], - i = 0; - arr.filter(function(a) { - i++; - if(i <= 4) { - arr.push(a+3); - } - return true; - }); - expect(arr).toEqual([1,2,3,4,5,6]); - expect(i).toBe(3); - }); - it('should skip non-set values', function() { - var passedValues = {}; - testSubject = [1,2,3,4]; - delete testSubject[1]; - testSubject.filter(function(o, i) { - passedValues[i] = o; - return true; - }); - expect(passedValues).toExactlyMatch(testSubject); - }); - it('should pass the right context to the filter', function() { - var passedValues = {}; - testSubject = [1,2,3,4]; - delete testSubject[1]; - testSubject.filter(function(o, i) { - this[i] = o; - return true; - }, passedValues); - expect(passedValues).toExactlyMatch(testSubject); - }); - it('should set the right context when given none', function() { - var context; - [1].filter(function() {context = this;}); - expect(context).toBe(function() {return this}.call()); - }); - it('should remove only the values for which the callback returns false', function() { - var result = testSubject.filter(callback); - expect(result).toExactlyMatch(filteredArray); - }); - it('should leave the original array untouched', function() { - var copy = testSubject.slice(); - testSubject.filter(callback); - expect(testSubject).toExactlyMatch(copy); - }); - it('should not be affected by same-index mutation', function () { - var results = [1, 2, 3] - .filter(function (value, index, array) { - array[index] = 'a'; - return true; - }); - expect(results).toEqual([1, 2, 3]); - }); - }); - describe('Array like', function() { - beforeEach(function() { - testSubject = createArrayLikeFromArray(testSubject); - }); - it('should call the callback with the proper arguments', function() { - var callback = jasmine.createSpy('callback'), - arr = createArrayLikeFromArray(['1']); - Array.prototype.filter.call(arr, callback); - expect(callback).toHaveBeenCalledWith('1', 0, arr); - }); - it('should not affect elements added to the array after it has begun', function() { - var arr = createArrayLikeFromArray([1,2,3]), - i = 0; - Array.prototype.filter.call(arr, function(a) { - i++; - if(i <= 4) { - arr[i+2] = a+3; - } - return true; - }); - delete arr.length; - expect(arr).toExactlyMatch([1,2,3,4,5,6]); - expect(i).toBe(3); - }); - it('should skip non-set values', function() { - var passedValues = {}; - testSubject = createArrayLikeFromArray([1,2,3,4]); - delete testSubject[1]; - Array.prototype.filter.call(testSubject, function(o, i) { - passedValues[i] = o; - return true; - }); - delete testSubject.length; - expect(passedValues).toExactlyMatch(testSubject); - }); - it('should set the right context when given none', function() { - var context; - Array.prototype.filter.call(createArrayLikeFromArray([1]), function() {context = this;}, undefined); - expect(context).toBe(function() {return this}.call()); - }); - it('should pass the right context to the filter', function() { - var passedValues = {}; - testSubject = createArrayLikeFromArray([1,2,3,4]); - delete testSubject[1]; - Array.prototype.filter.call(testSubject, function(o, i) { - this[i] = o; - return true; - }, passedValues); - delete testSubject.length; - expect(passedValues).toExactlyMatch(testSubject); - }); - it('should remove only the values for which the callback returns false', function() { - var result = Array.prototype.filter.call(testSubject, callback); - expect(result).toExactlyMatch(filteredArray); - }); - it('should leave the original array untouched', function() { - var copy = createArrayLikeFromArray(testSubject); - Array.prototype.filter.call(testSubject, callback); - expect(testSubject).toExactlyMatch(copy); - }); - }); - }); - describe('map', function() { - var callback; - beforeEach(function() { - var i = 0; - callback = function() { - return i++; - }; - }); - describe('Array object', function() { - it('should call callback with the right parameters', function() { - var callback = jasmine.createSpy('callback'), - array = [1]; - array.map(callback); - expect(callback).toHaveBeenCalledWith(1, 0, array); - }); - it('should set the context correctly', function() { - var context = {}; - testSubject.map(function(o,i) { - this[i] = o; - }, context); - expect(context).toExactlyMatch(testSubject); - }); - it('should set the right context when given none', function() { - var context; - [1].map(function() {context = this;}); - expect(context).toBe(function() {return this}.call()); - }); - it('should not change the array it is called on', function() { - var copy = testSubject.slice(); - testSubject.map(callback); - expect(testSubject).toExactlyMatch(copy); - }); - it('should only run for the number of objects in the array when it started', function() { - var arr = [1,2,3], - i = 0; - arr.map(function(o) { - arr.push(o+3); - i++; - return o; - }); - expect(arr).toExactlyMatch([1,2,3,4,5,6]); - expect(i).toBe(3); - }); - it('should properly translate the values as according to the callback', function() { - var result = testSubject.map(callback), - expected = [0,0,1,2,3,4,5,6]; - delete expected[1]; - expect(result).toExactlyMatch(expected); - }); - it('should skip non-existing values', function() { - var array = [1,2,3,4], - i = 0; - delete array[2]; - array.map(function() { - i++; - }); - expect(i).toBe(3); - }); - }); - describe('Array-like', function() { - beforeEach(function() { - testSubject = createArrayLikeFromArray(testSubject); - }); - it('should call callback with the right parameters', function() { - var callback = jasmine.createSpy('callback'), - array = createArrayLikeFromArray([1]); - Array.prototype.map.call(array, callback); - expect(callback).toHaveBeenCalledWith(1, 0, array); - }); - it('should set the context correctly', function() { - var context = {}; - Array.prototype.map.call(testSubject, function(o,i) { - this[i] = o; - }, context); - delete testSubject.length; - expect(context).toExactlyMatch(testSubject); - }); - it('should set the right context when given none', function() { - var context; - Array.prototype.map.call(createArrayLikeFromArray([1]), function() {context = this;}); - expect(context).toBe(function() {return this}.call()); - }); - it('should not change the array it is called on', function() { - var copy = createArrayLikeFromArray(testSubject); - Array.prototype.map.call(testSubject, callback); - expect(testSubject).toExactlyMatch(copy); - }); - it('should only run for the number of objects in the array when it started', function() { - var arr = createArrayLikeFromArray([1,2,3]), - i = 0; - Array.prototype.map.call(arr, function(o) { - Array.prototype.push.call(arr, o+3); - i++; - return o; - }); - delete arr.length; - expect(arr).toExactlyMatch([1,2,3,4,5,6]); - expect(i).toBe(3); - }); - it('should properly translate the values as according to the callback', function() { - var result = Array.prototype.map.call(testSubject, callback), - expected = [0,0,1,2,3,4,5,6]; - delete expected[1]; - expect(result).toExactlyMatch(expected); - }); - it('should skip non-existing values', function() { - var array = createArrayLikeFromArray([1,2,3,4]), - i = 0; - delete array[2]; - Array.prototype.map.call(array, function() { - i++; - }); - expect(i).toBe(3); - }); - }); - }); - - describe('reduce', function() { - beforeEach(function() { - testSubject = [1,2,3]; - }); - - describe('Array', function() { - it('should pass the correct arguments to the callback', function() { - var spy = jasmine.createSpy().andReturn(0); - testSubject.reduce(spy); - expect(spy.calls[0].args).toExactlyMatch([1, 2, 1, testSubject]); - }); - it('should start with the right initialValue', function() { - var spy = jasmine.createSpy().andReturn(0); - testSubject.reduce(spy, 0); - expect(spy.calls[0].args).toExactlyMatch([0, 1, 0, testSubject]); - }); - it('should not affect elements added to the array after it has begun', function() { - var arr = [1,2,3], - i = 0; - arr.reduce(function(a, b) { - i++; - if(i <= 4) { - arr.push(a+3); - }; - return b; - }); - expect(arr).toEqual([1,2,3,4,5]); - expect(i).toBe(2); - }); - it('should work as expected for empty arrays', function() { - var spy = jasmine.createSpy(); - expect(function() { - [].reduce(spy); - }).toThrow(); - expect(spy).not.toHaveBeenCalled(); - }); - it('should throw correctly if no callback is given', function() { - expect(function() { - testSubject.reduce(); - }).toThrow(); - }); - it('should return the expected result', function() { - expect(testSubject.reduce(function(a,b) { - return (a||'').toString()+(b||'').toString(); - })).toEqual(testSubject.join('')); - }); - it('should not directly affect the passed array', function() { - var copy = testSubject.slice(); - testSubject.reduce(function(a,b) { - return a+b; - }); - expect(testSubject).toEqual(copy); - }); - it('should skip non-set values', function() { - delete testSubject[1]; - var visited = {}; - testSubject.reduce(function(a,b) { - if(a) - visited[a] = true; - if(b) - visited[b] = true; - return 0; - }); - - expect(visited).toEqual({ '1': true, '3': true }); - }); - it('should have the right length', function() { - expect(testSubject.reduce.length).toBe(1); - }); - }); - describe('Array-like objects', function() { - beforeEach(function() { - testSubject = createArrayLikeFromArray(testSubject); - testSubject.reduce = Array.prototype.reduce; - }); - it('should pass the correct arguments to the callback', function() { - var spy = jasmine.createSpy().andReturn(0); - testSubject.reduce(spy); - expect(spy.calls[0].args).toExactlyMatch([1, 2, 1, testSubject]); - }); - it('should start with the right initialValue', function() { - var spy = jasmine.createSpy().andReturn(0); - testSubject.reduce(spy, 0); - expect(spy.calls[0].args).toExactlyMatch([0, 1, 0, testSubject]); - }); - it('should not affect elements added to the array after it has begun', function() { - var arr = createArrayLikeFromArray([1,2,3]), - i = 0; - Array.prototype.reduce.call(arr, function(a, b) { - i++; - if(i <= 4) { - arr[i+2] = a+3; - }; - return b; - }); - expect(arr).toEqual({ - 0: 1, - 1: 2, - 2: 3, - 3: 4, - 4: 5, - length: 3 - }); - expect(i).toBe(2); - }); - it('should work as expected for empty arrays', function() { - var spy = jasmine.createSpy(); - expect(function() { - Array.prototype.reduce.call({length: 0}, spy); - }).toThrow(); - expect(spy).not.toHaveBeenCalled(); - }); - it('should throw correctly if no callback is given', function() { - expect(function() { - testSubject.reduce(); - }).toThrow(); - }); - it('should return the expected result', function() { - expect(testSubject.reduce(function(a,b) { - return (a||'').toString()+(b||'').toString(); - })).toEqual('123'); - }); - it('should not directly affect the passed array', function() { - var copy = createArrayLikeFromArray(testSubject); - testSubject.reduce(function(a,b) { - return a+b; - }); - delete(testSubject.reduce); - expect(testSubject).toEqual(copy); - }); - it('should skip non-set values', function() { - delete testSubject[1]; - var visited = {}; - testSubject.reduce(function(a,b) { - if(a) - visited[a] = true; - if(b) - visited[b] = true; - return 0; - }); - - expect(visited).toEqual({ '1': true, '3': true }); - }); - it('should have the right length', function() { - expect(testSubject.reduce.length).toBe(1); - }); - }); - }); - describe('reduceRight', function() { - beforeEach(function() { - testSubject = [1,2,3]; - }); - - describe('Array', function() { - it('should pass the correct arguments to the callback', function() { - var spy = jasmine.createSpy().andReturn(0); - testSubject.reduceRight(spy); - expect(spy.calls[0].args).toExactlyMatch([3, 2, 1, testSubject]); - }); - it('should start with the right initialValue', function() { - var spy = jasmine.createSpy().andReturn(0); - testSubject.reduceRight(spy, 0); - expect(spy.calls[0].args).toExactlyMatch([0, 3, 2, testSubject]); - }); - it('should not affect elements added to the array after it has begun', function() { - var arr = [1,2,3], - i = 0; - arr.reduceRight(function(a, b) { - i++; - if(i <= 4) { - arr.push(a+3); - }; - return b; - }); - expect(arr).toEqual([1,2,3,6,5]); - expect(i).toBe(2); - }); - it('should work as expected for empty arrays', function() { - var spy = jasmine.createSpy(); - expect(function() { - [].reduceRight(spy); - }).toThrow(); - expect(spy).not.toHaveBeenCalled(); - }); - it('should throw correctly if no callback is given', function() { - expect(function() { - testSubject.reduceRight(); - }).toThrow(); - }); - it('should return the expected result', function() { - expect(testSubject.reduceRight(function(a,b) { - return (a||'').toString()+(b||'').toString(); - })).toEqual('321'); - }); - it('should not directly affect the passed array', function() { - var copy = testSubject.slice(); - testSubject.reduceRight(function(a,b) { - return a+b; - }); - expect(testSubject).toEqual(copy); - }); - it('should skip non-set values', function() { - delete testSubject[1]; - var visited = {}; - testSubject.reduceRight(function(a,b) { - if(a) - visited[a] = true; - if(b) - visited[b] = true; - return 0; - }); - - expect(visited).toEqual({ '1': true, '3': true }); - }); - it('should have the right length', function() { - expect(testSubject.reduceRight.length).toBe(1); - }); - }); - describe('Array-like objects', function() { - beforeEach(function() { - testSubject = createArrayLikeFromArray(testSubject); - testSubject.reduceRight = Array.prototype.reduceRight; - }); - it('should pass the correct arguments to the callback', function() { - var spy = jasmine.createSpy().andReturn(0); - testSubject.reduceRight(spy); - expect(spy.calls[0].args).toExactlyMatch([3, 2, 1, testSubject]); - }); - it('should start with the right initialValue', function() { - var spy = jasmine.createSpy().andReturn(0); - testSubject.reduceRight(spy, 0); - expect(spy.calls[0].args).toExactlyMatch([0, 3, 2, testSubject]); - }); - it('should not affect elements added to the array after it has begun', function() { - var arr = createArrayLikeFromArray([1,2,3]), - i = 0; - Array.prototype.reduceRight.call(arr, function(a, b) { - i++; - if(i <= 4) { - arr[i+2] = a+3; - }; - return b; - }); - expect(arr).toEqual({ - 0: 1, - 1: 2, - 2: 3, - 3: 6, - 4: 5, - length: 3 // does not get updated on property assignment - }); - expect(i).toBe(2); - }); - it('should work as expected for empty arrays', function() { - var spy = jasmine.createSpy(); - expect(function() { - Array.prototype.reduceRight.call({length:0}, spy); - }).toThrow(); - expect(spy).not.toHaveBeenCalled(); - }); - it('should throw correctly if no callback is given', function() { - expect(function() { - testSubject.reduceRight(); - }).toThrow(); - }); - it('should return the expected result', function() { - expect(testSubject.reduceRight(function(a,b) { - return (a||'').toString()+(b||'').toString(); - })).toEqual('321'); - }); - it('should not directly affect the passed array', function() { - var copy = createArrayLikeFromArray(testSubject); - testSubject.reduceRight(function(a,b) { - return a+b; - }); - delete(testSubject.reduceRight); - expect(testSubject).toEqual(copy); - }); - it('should skip non-set values', function() { - delete testSubject[1]; - var visited = {}; - testSubject.reduceRight(function(a,b) { - if(a) - visited[a] = true; - if(b) - visited[b] = true; - return 0; - }); - - expect(visited).toEqual({ '1': true, '3': true }); - }); - it('should have the right length', function() { - expect(testSubject.reduceRight.length).toBe(1); - }); - }); - }); - - describe('isArray', function () { - it('should work for Array', function () { - var ret = Array.isArray([]); - - expect(ret).toBe(true); - }); - - it('should fail for other objects', function () { - var objects = [ - "someString", - true, - false, - 42, - 0, - {}, - Object.create(null), - /foo/, - arguments, - document.getElementsByTagName("div") - ]; - - objects.forEach(function (v) { - expect(Array.isArray(v)).toBe(false); - }); - }); - }); - - describe('unshift', function () { - it('should return length', function () { - expect([].unshift(0)).toEqual(1); - }); - }); - - describe('splice', function () { - var b = ["b"], - a = [1, "a", b], - test; - beforeEach(function() { - test = a.slice(0); - }); - - it('basic implementation test 1', function () { - expect(test.splice(0)).toEqual(a); - }); - it('basic implementation test 2', function () { - test.splice(0, 2); - expect(test).toEqual([b]); - }); - - - it('should do nothing if method called with no arguments', function () { - expect(test.splice()).toEqual([]); - expect(test).toEqual(a); - }); - //TODO:: Is this realy TRUE behavior? - it('should set first argument to 0 if first argument is set but undefined', function () { - var test2 = test.slice(0); - expect(test.splice(void 0, 2)).toEqual(test2.splice(0, 2)); - expect(test).toEqual(test2); - }); - - it('should deleted and return all items after "start" when second argument is undefined', function () { - expect(test.splice(0)).toEqual(a); - expect(test).toEqual([]); - }); - it('should deleted and return all items after "start" when second argument is undefined', function () { - expect(test.splice(2)).toEqual([b]); - expect(test).toEqual([1, "a"]); - }); - it('runshould have the right length', function () { - expect(test.splice.length).toBe(2); - }); - }); - - -}); diff --git a/lib/es5-shim/tests/spec/s-date.js b/lib/es5-shim/tests/spec/s-date.js deleted file mode 100644 index 1759d79..0000000 --- a/lib/es5-shim/tests/spec/s-date.js +++ /dev/null @@ -1,149 +0,0 @@ -describe('Date', function () { - - describe('now', function () { - it('should be the current time', function () { - expect(Date.now() === new Date().getTime()).toBe(true); - }); - }); - - describe("parse", function () { - // TODO: Write the rest of the test. - - it('should support extended years', function () { - - expect(Date.parse('0001-01-01T00:00:00Z')).toBe(-62135596800000); - expect(Date.parse('+275760-09-13T00:00:00.000Z')).toBe(8.64e15); - expect(Date.parse('+033658-09-27T01:46:40.000Z')).toBe(1e15); - expect(Date.parse('-000001-01-01T00:00:00Z')).toBe(-62198755200000); - expect(Date.parse('+002009-12-15T00:00:00Z')).toBe(1260835200000); - - }); - - it('should work', function () { - //Chrome 19 Opera 12 Firefox 11 IE 9 Safari 5.1.1 - expect(Date.parse("2012-11-31T23:59:59.000Z")).toBeFalsy(); //1354406399000 NaN NaN 1354406399000 NaN - expect(Date.parse("2012-12-31T23:59:59.000Z")).toBe(1356998399000); //1356998399000 1356998399000 1356998399000 1356998399000 1356998399000 - expect(Date.parse("2012-12-31T23:59:60.000Z")).toBeFalsy(); //NaN NaN NaN NaN 1356998400000 - expect(Date.parse("2012-04-04T05:02:02.170Z")).toBe(1333515722170); //1333515722170 1333515722170 1333515722170 1333515722170 1333515722170 - expect(Date.parse("2012-04-04T24:00:00.000Z")).toBe(1333584000000); //NaN 1333584000000 1333584000000 1333584000000 1333584000000 - expect(Date.parse("2012-04-04T24:00:00.500Z")).toBeFalsy(); //NaN NaN 1333584000500 1333584000500 NaN - expect(Date.parse("2012-12-31T10:08:60.000Z")).toBeFalsy(); //NaN NaN NaN NaN 1356948540000 - expect(Date.parse("2012-13-01T12:00:00.000Z")).toBeFalsy(); //NaN NaN NaN NaN NaN - expect(Date.parse("2012-12-32T12:00:00.000Z")).toBeFalsy(); //NaN NaN NaN NaN NaN - expect(Date.parse("2012-12-31T25:00:00.000Z")).toBeFalsy(); //NaN NaN NaN NaN NaN - expect(Date.parse("2012-12-31T24:01:00.000Z")).toBeFalsy(); //NaN NaN NaN 1356998460000 NaN - expect(Date.parse("2012-12-31T12:60:00.000Z")).toBeFalsy(); //NaN NaN NaN NaN NaN - expect(Date.parse("2012-12-31T12:00:60.000Z")).toBeFalsy(); //NaN NaN NaN NaN 1356955260000 - expect(Date.parse("2012-00-31T23:59:59.000Z")).toBeFalsy(); //NaN NaN NaN NaN NaN - expect(Date.parse("2012-12-00T23:59:59.000Z")).toBeFalsy(); //NaN NaN NaN NaN NaN - expect(Date.parse("2012-02-29T12:00:00.000Z")).toBe(1330516800000); //1330516800000 1330516800000 1330516800000 1330516800000 1330516800000 - expect(Date.parse("2011-02-29T12:00:00.000Z")).toBeFalsy(); //1298980800000 NaN NaN 1298980800000 NaN - expect(Date.parse("2011-03-01T12:00:00.000Z")).toBe(1298980800000); //1298980800000 1298980800000 1298980800000 1298980800000 1298980800000 - - // extended years: - expect(Date.parse("0000-01-01T00:00:00.000Z")).toBe(-621672192e5); //-621672192e5 -621672192e5 -621672192e5 -621672192e5 -621672192e5 - expect(Date.parse("+275760-09-13T00:00:00.000Z")).toBe(8.64e15); //8.64e15 NaN 8.64e15 8.64e15 8.64e15 - expect(Date.parse("-271821-04-20T00:00:00.000Z")).toBe(-8.64e15); //-8.64e15 NaN -8.64e15 -8.64e15 -8.6400000864e15 - expect(Date.parse("+275760-09-13T00:00:00.001Z")).toBeFalsy(); //NaN NaN NaN 8.64e15 + 1 8.64e15 + 1 - expect(Date.parse("-271821-04-19T23:59:59.999Z")).toBeFalsy(); //NaN NaN NaN -8.64e15 - 1 -8.6400000864e15 - 1 - - // https://github.com/kriskowal/es5-shim/issues/80 Safari bug with leap day - expect(Date.parse("2034-03-01T00:00:00.000Z") - - Date.parse("2034-02-27T23:59:59.999Z")).toBe(86400001); //86400001 86400001 86400001 86400001 1 - - // Time Zone Offset - expect(Date.parse("2012-01-29T12:00:00.000+01:00")).toBe(132783480e4);//132783480e4 132783480e4 132783480e4 132783480e4 132783480e4 - expect(Date.parse("2012-01-29T12:00:00.000-00:00")).toBe(132783840e4);//132783840e4 132783840e4 132783840e4 132783840e4 132783840e4 - expect(Date.parse("2012-01-29T12:00:00.000+00:00")).toBe(132783840e4);//132783840e4 132783840e4 132783840e4 132783840e4 132783840e4 - expect(Date.parse("2012-01-29T12:00:00.000+23:59")).toBe(132775206e4);//132775206e4 132775206e4 132775206e4 132775206e4 132775206e4 - expect(Date.parse("2012-01-29T12:00:00.000-23:59")).toBe(132792474e4);//132792474e4 132792474e4 132792474e4 132792474e4 132792474e4 - expect(Date.parse("2012-01-29T12:00:00.000+24:00")).toBeFalsy(); //NaN 1327752e6 NaN 1327752000000 1327752000000 - expect(Date.parse("2012-01-29T12:00:00.000+24:01")).toBeFalsy(); //NaN NaN NaN 1327751940000 1327751940000 - expect(Date.parse("2012-01-29T12:00:00.000+24:59")).toBeFalsy(); //NaN NaN NaN 1327748460000 1327748460000 - expect(Date.parse("2012-01-29T12:00:00.000+25:00")).toBeFalsy(); //NaN NaN NaN NaN NaN - expect(Date.parse("2012-01-29T12:00:00.000+00:60")).toBeFalsy(); //NaN NaN NaN NaN NaN - expect(Date.parse("-271821-04-20T00:00:00.000+00:01")).toBeFalsy(); //NaN NaN NaN -864000000006e4 -864000008646e4 - expect(Date.parse("-271821-04-20T00:01:00.000+00:01")).toBe(-8.64e15);//-8.64e15 NaN -8.64e15 -8.64e15 -864000008640e4 - - // When time zone is missed, local offset should be used (ES 5.1 bug) - // see https://bugs.ecmascript.org/show_bug.cgi?id=112 - var tzOffset = Number(new Date(1970, 0)); - // same as (new Date().getTimezoneOffset() * 60000) - expect(Date.parse('1970-01-01T00:00:00')).toBe(tzOffset); //tzOffset 0 0 0 NaN - }); - - it("should be able to coerce to a number", function(){ - var actual = Number(new Date(1970, 0)); - var expected = parseInt(actual, 10); - expect(actual).toBeDefined(); - expect(actual).toEqual(expected); - expect(isNaN(actual)).toBeFalsy(); - }); - - }); - - describe("toString", function(){ - var actual = (new Date(1970, 0)).toString(); - beforeEach(function(){ - actual = (new Date(1970, 0)).toString(); - }); - it("should show correct date info for "+actual, function(){ - expect(actual).toMatch(/1970/); - expect(actual).toMatch(/jan/i); - expect(actual).toMatch(/thu/i); - expect(actual).toMatch(/00:00:00/); - }); - }); - - describe("valueOf", function(){ - var actual = (new Date(1970, 0)); - beforeEach(function(){ - actual = (new Date(1970, 0)).valueOf(); - }); - it("should give an int value", function(){ - expect(parseInt(actual, 10)).toBeTruthy(); - }); - }); - - describe("toISOString", function () { - // TODO: write the rest of the test. - - it('should support extended years', function () { - expect(new Date(-62198755200000).toISOString().indexOf('-000001-01-01')).toBe(0); - expect(new Date(8.64e15).toISOString().indexOf('+275760-09-13')).toBe(0); - }); - - it('should return correct dates', function () { - expect(new Date(-1).toISOString()).toBe('1969-12-31T23:59:59.999Z');// Safari 5.1.5 "1969-12-31T23:59:59.-01Z" - expect(new Date(-3509827334573292).toISOString()).toBe('-109252-01-01T10:37:06.708Z'); // Opera 11.61/Opera 12 bug with Date#getUTCMonth - }); - - }); - - describe("toJSON", function () { - - // Opera 11.6x/12 bug - it('should call toISOString', function () { - var date = new Date(0); - date.toISOString = function () { - return 1; - }; - expect(date.toJSON()).toBe(1); - }); - - it('should return null for not finite dates', function () { - var date = new Date(NaN), - json; - try { - json = date.toJSON(); - } catch (e) {} - expect(json).toBe(null); - }); - - it('should return the isoString when stringified', function () { - var date = new Date(); - expect(JSON.stringify(date.toISOString())).toBe(JSON.stringify(date)); - }) - }); - -}); \ No newline at end of file diff --git a/lib/es5-shim/tests/spec/s-function.js b/lib/es5-shim/tests/spec/s-function.js deleted file mode 100644 index aa4361e..0000000 --- a/lib/es5-shim/tests/spec/s-function.js +++ /dev/null @@ -1,147 +0,0 @@ - -describe('Function', function() { - "use strict"; - describe('bind', function() { - var actual, expected, - testSubject; - - testSubject = { - push: function(o) { - this.a.push(o); - } - }; - - function func() { - Array.prototype.forEach.call(arguments, function(a) { - this.push(a); - }, this); - return this; - }; - - beforeEach(function() { - actual = []; - testSubject.a = []; - }); - - it('binds properly without a context', function() { - var context; - testSubject.func = function() { - context = this; - }.bind(); - testSubject.func(); - expect(context).toBe(function() {return this}.call()); - }); - it('binds properly without a context, and still supplies bound arguments', function() { - var a, context; - testSubject.func = function() { - a = Array.prototype.slice.call(arguments); - context = this; - }.bind(undefined, 1,2,3); - testSubject.func(1,2,3); - expect(a).toEqual([1,2,3,1,2,3]); - expect(context).toBe(function() {return this}.call()); - }); - it('binds a context properly', function() { - testSubject.func = func.bind(actual); - testSubject.func(1,2,3); - expect(actual).toEqual([1,2,3]); - expect(testSubject.a).toEqual([]); - }); - it('binds a context and supplies bound arguments', function() { - testSubject.func = func.bind(actual, 1,2,3); - testSubject.func(4,5,6); - expect(actual).toEqual([1,2,3,4,5,6]); - expect(testSubject.a).toEqual([]); - }); - - it('returns properly without binding a context', function() { - testSubject.func = function() { - return this; - }.bind(); - var context = testSubject.func(); - expect(context).toBe(function() {return this}.call()); - }); - it('returns properly without binding a context, and still supplies bound arguments', function() { - var context; - testSubject.func = function() { - context = this; - return Array.prototype.slice.call(arguments); - }.bind(undefined, 1,2,3); - actual = testSubject.func(1,2,3); - expect(context).toBe(function() {return this}.call()); - expect(actual).toEqual([1,2,3,1,2,3]); - }); - it('returns properly while binding a context properly', function() { - var ret; - testSubject.func = func.bind(actual); - ret = testSubject.func(1,2,3); - expect(ret).toBe(actual); - expect(ret).not.toBe(testSubject); - }); - it('returns properly while binding a context and supplies bound arguments', function() { - var ret; - testSubject.func = func.bind(actual, 1,2,3); - ret = testSubject.func(4,5,6); - expect(ret).toBe(actual); - expect(ret).not.toBe(testSubject); - }); - it('passes the correct arguments as a constructor', function() { - var ret, expected = { name: "Correct" }; - testSubject.func = function(arg) { - return arg; - }.bind({ name: "Incorrect" }); - ret = new testSubject.func(expected); - expect(ret).toBe(expected); - }); - it('returns the return value of the bound function when called as a constructor', function () { - var oracle = [1, 2, 3]; - var subject = function () { - return oracle; - }.bind(null); - var result = new subject; - expect(result).toBe(oracle); - }); - it('returns the correct value if constructor returns primitive', function() { - var oracle = [1, 2, 3]; - var subject = function () { - return oracle; - }.bind(null); - var result = new subject; - expect(result).toBe(oracle); - - oracle = {}; - result = new subject; - expect(result).toBe(oracle); - - oracle = function(){}; - result = new subject; - expect(result).toBe(oracle); - - oracle = "asdf"; - result = new subject; - expect(result).not.toBe(oracle); - - oracle = null; - result = new subject; - expect(result).not.toBe(oracle); - - oracle = true; - result = new subject; - expect(result).not.toBe(oracle); - - oracle = 1; - result = new subject; - expect(result).not.toBe(oracle); - }); - it('returns the value that instance of original "class" when called as a constructor', function() { - var classA = function(x) { - this.name = x || "A"; - } - var classB = classA.bind(null, "B"); - - var result = new classB; - expect(result instanceof classA).toBe(true); - expect(result instanceof classB).toBe(true); - }); - }); -}); diff --git a/lib/es5-shim/tests/spec/s-object.js b/lib/es5-shim/tests/spec/s-object.js deleted file mode 100644 index 26fd418..0000000 --- a/lib/es5-shim/tests/spec/s-object.js +++ /dev/null @@ -1,84 +0,0 @@ -describe('Object', function () { - "use strict"; - - describe("Object.keys", function () { - var obj = { - "str": "boz", - "obj": { }, - "arr": [], - "bool": true, - "num": 42, - "null": null, - "undefined": undefined - }; - - var loopedValues = []; - for (var k in obj) { - loopedValues.push(k); - } - - var keys = Object.keys(obj); - it('should have correct length', function () { - expect(keys.length).toBe(7); - }); - - it('should return an Array', function () { - expect(Array.isArray(keys)).toBe(true); - }); - - it('should return names which are own properties', function () { - keys.forEach(function (name) { - expect(obj.hasOwnProperty(name)).toBe(true); - }); - }); - - it('should return names which are enumerable', function () { - keys.forEach(function (name) { - expect(loopedValues.indexOf(name)).toNotBe(-1); - }) - }); - - it('should throw error for non object', function () { - var e = {}; - expect(function () { - try { - Object.keys(42) - } catch (err) { - throw e; - } - }).toThrow(e); - }); - }); - - describe("Object.isExtensible", function () { - var obj = { }; - - it('should return true if object is extensible', function () { - expect(Object.isExtensible(obj)).toBe(true); - }); - - it('should return false if object is not extensible', function () { - expect(Object.isExtensible(Object.preventExtensions(obj))).toBe(false); - }); - - it('should return false if object is seal', function () { - expect(Object.isExtensible(Object.seal(obj))).toBe(false); - }); - - it('should return false if object is freeze', function () { - expect(Object.isExtensible(Object.freeze(obj))).toBe(false); - }); - - it('should throw error for non object', function () { - var e1 = {}; - expect(function () { - try { - Object.isExtensible(42) - } catch (err) { - throw e1; - } - }).toThrow(e1); - }); - }); - -}); \ No newline at end of file diff --git a/lib/es5-shim/tests/spec/s-string.js b/lib/es5-shim/tests/spec/s-string.js deleted file mode 100644 index 34ed593..0000000 --- a/lib/es5-shim/tests/spec/s-string.js +++ /dev/null @@ -1,24 +0,0 @@ -describe('String', function() { - "use strict"; - describe("trim", function() { - var test = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFFHello, World!\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF"; - - it('trims all ES5 whitespace', function() { - expect(test.trim()).toEqual("Hello, World!"); - expect(test.trim().length).toEqual(13); - }); - }); - - describe("split", function() { - var test = "ab"; - - it('If "separator" is undefined must return Array with one String - "this" string', function() { - expect(test.split()).toEqual([test]); - expect(test.split(void 0)).toEqual([test]); - }); - - it('If "separator" is undefined and "limit" set to 0 must return Array[]', function() { - expect(test.split(void 0, 0)).toEqual([]); - }); - }); -}); diff --git a/lib/jsdoc-toolkit/templates/codeview-jsdoc2-template/publish.js b/lib/jsdoc-toolkit/templates/codeview-jsdoc2-template/publish.js index 7a11178..73cc254 100755 --- a/lib/jsdoc-toolkit/templates/codeview-jsdoc2-template/publish.js +++ b/lib/jsdoc-toolkit/templates/codeview-jsdoc2-template/publish.js @@ -200,6 +200,7 @@ function makeSrcFile(path, srcDir, name) { /** Build output for displaying function parameters. */ function makeSignature(params, hideOpt) { + var nextOpts = false; if (!params) return "()"; var signature = "(" + @@ -220,7 +221,8 @@ function makeSignature(params, hideOpt) { }); if(!hideOpt){ - var match = $.type.match(/(=((["']).*\3|[\w_$]*))\}?$/); + nextOpts = nextOpts || $.type.match(/^\{?\.\.\./); + var match = nextOpts || $.type.match(/(=((["']).*\3|[\w_$]*))\}?$/); if(match){ argName += ''+ (match[2] && match[1] || 'opt') +''; } diff --git a/package.json b/package.json index e39af35..c093963 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,8 @@ { "name": "clonejs", - "version": "v0.7.4-beta", + "version": "v1.0.0-alpha", "description": "The true prototype-based JavaScript micro-framework.", + "homepage": "http://clonejs.org", "maintainers": [ { "name": "Alex Shvets", @@ -9,7 +10,7 @@ } ], "scripts": { - "test": "./node_modules/.bin/nodeunit ./test/*.test.js" + "test": "tools/test.quick.sh" }, "repository": { "type": "git", diff --git a/src/clone.js b/src/clone.js index 6aa3519..845b3b2 100644 --- a/src/clone.js +++ b/src/clone.js @@ -1,1292 +1,191 @@ -/**#nocode+*/ -(function(global){'use strict'; -/**#nocode-*/ /** - * @title clone.js - the true prototype-based JavaScript micro-framework. - * @version v0.7.4-beta - * @author Alex Shvets - * * @class - * This is the framework that implements the true [prototype-based OOP⠙][1] paradigm in JS. - * It's based on the ECMA Script 5 features like [Object.create⠙][2] and [property descriptors⠙][3]. - * [1]: http://en.wikipedia.org/wiki/Prototype-based_programming - * [2]: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create - * [3]: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty - * - *

[View on GitHub](http://github.com/quadroid/clonejs#readme) - * - * ### Naming conventions - * - * Var names, **prefixed by "$"**, contain object, used as prototype for other objects. - * For example: - * - * var $array = Array.prototype, $myType = {}, - * myTypeInstance = Object.create($myType);// $object.apply($myType, 'create'); - * - * - * Properties, **prefixed by "_"**, are private. - * - * [![githalytics.com alpha](https://cruel-carlota.pagodabox.com/3110be9614da5cb337ebd483c187010f "githalytics.com")](http://githalytics.com/quadroid/clonejs) - * - * @description - * The main difference with other class-producing tools like `Ext.define`, `dojo.declare`, `Backbone.Model.extend` - * is that `$object.clone` will return an object (prototype with defined constructor-function) instead of function - * (with defined prototype-object). So, you don't need for instantiation, you can just start using the cloned object right now. - * But, if you need more than one instance, you can create it by `$yourProto.create`. - * - * @example - * - * var myObj = {a:1, b:2, c:3}; - * var cloneOfMyObj = $object.apply(myObj, 'clone'); - * cloneOfMyObj.a = 11; // myObj.a still == 1 - * myObj.b = 22; // cloneOfMyObj.b will be also changed to 22 - * - * var $myType = $object.clone({ - * '(final) property1': "not configurable and not writable", - * '(writable final) property2': "not configurable only", - * '(hidden) property3': "not enumerable", - * '(const) constant': "not writable", - * property4 : "simple property", - * '(get) property3alias': 'property3',// automatically create getter - * _item : "private property (not enumerable)", - * '(get) item': function() { return this._item }, - * '(set) item': function(v){ this._item = v }, - * constructor : function MyType(){ - * this.applySuper(arguments); - * // do something... - * } - * }); - * assert( $myType.property3alias === $myType.property3 ); * - * var myTypeInstance = $myType.create({property4: "initialize simple property"}); - * assert( $myType.isPrototypeOf(myTypeInstance) ); - * - * var $myArray1 = $object.clone.call(Array.prototype, {customMethod: function(){}}); - * var $myArray2 = $object.copy(Array).setProperties({customMethod: function(){}}); - * + * clone.js - the true prototype-based javascript nano-framework. + * @version v1.0.0-alpha + * @author Alex Shvets + * @see www.clonejs.org + * + * @description + * Function `clone` works like `Object.create`, but the second argument is simple object, not property descriptor. + * @param {!Object} obj - Object to clone + * @param {!object} state - The properties of new, cloned object, should be object literal only ({key:"value"}) + * @param {Object=} behavior$ - The behavior (methods) of new, cloned object) */ -var $object = /** @lands $object# */{ - - /** - * Create a clone of object. - * @see $object.describe - * @see Object.create⠙ - * @example - * var $myProto = {a:1, b:2, c:3}; - * var clone = $object.clone.apply($myProto); - * clone.a = 11; // $myProto.a still == 1 - * $myProto.b = 22; // clone.b will be also changed to 22 - * @this {Object} Prototype or instance. - * @returns {$object} - * @memberOf $object# - */ - clone: function(/** Object= */properties, /** PropertyDescriptor= */defaultDescriptor){ - if(arguments.length){ - var descriptors = $object.describe.apply(this, arguments); - } - return Object.create(this, descriptors); - }, - - /** - * Use this method to create an instances of prototype objects. - * Behaves like a [clone](#clone) method. But also apply [constructor][1]. - * All arguments, passed to `create()`, will be forwarded to [constructor][1]. - * [1]: #constructor - * [2]: http://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/seal - * [3]: https://developers.google.com/v8/design#prop_access - * @see $object#clone - * @see $object#constructor - * @see $object.describe - * @this {$object} Prototype. - * @returns {$object} - * - * @example - * var $myType = $object.clone({ - * constructor: 'MyType', - * }); - * var myTypeInstance = $myType.create(); - * assert( myTypeInstance.constructor === $myType.constructor ); - * assert( $myType.isPrototypeOf(myTypeInstance) ); - * - * @memberOf $object# - */ - create: function(/** Object|...?= */properties, /** PropertyDescriptor= */defaultDescriptor){ - var obj = this.clone(); - return obj.constructor.apply(obj, arguments) || obj; - }, - - /** - * Default object constructor. Override it if you want to create custom type. - * Defines given properties. - * @see $object.describe - * @see $object#create - * @this {Object} Instance only. - * @memberOf $object# - */ - constructor: function Object$(/** Object= */properties, /** PropertyDescriptor= */defaultDescriptor){ - if(typeof properties == 'object'){ - this.defineProperties(properties, defaultDescriptor); - }else if(arguments.length){ - return Object(properties); - } - }, - - /** - * Translate object to property descriptors. - * For example, `{a: {b:1}, c:2}` will be translated to `{a: {value: {b:1}}, b: {value: 2}}`. - * - * Functions (except getters) and properties prefixed by "_" will be automatically marked as non-enumerable. - * - * Uppercase properties will be not writable. - * - * You can prefix your property names by `(get|set|const|final|hidden|writable)`: - *

- *
(get)
define getter, if string passed, the getter will be auto generated. - *
(set)
define setter, if string passed, the setter will be auto generated. - *
(const)
make property unwritable. - *
(final)
make property unwritable, and prevent it deleting and descriptor modifications. - *
(hidden)
make property non-enumerable. - *
(writable)
make property writable (use with final). - *
- * @param properties - * @param defaultDescriptor The default property descriptor. - * @returns {{PropertyDescriptor}} Property descriptors. - * @this {Object} Prototype only. - * @static - * @memberOf $object - */ - describe: function(/** Object */properties, /** PropertyDescriptor= */defaultDescriptor){ - - var descriptors = {}; - - /// Default properties descriptor: - - var $defaultDescriptor = defaultDescriptor ? defaultDescriptor : { - configurable: true, - enumerable: true, - writable: true - }; - - /// Iterate properties: - - var hidingAllowed = !(defaultDescriptor && defaultDescriptor.enumerable); - - for(var name in properties){ - - var value = properties[name]; - var descriptor = Object.create($defaultDescriptor); - - /// apply property modifiers: - - if( name[0]=='(' ){ - //TODO: fix regexp to not mach the '(getset) property' - var matches = name.match(/^\((((get|set|const|hidden|final|writable) *)+)\) +(.+)$/); - if( matches ){ - var prefixes = matches[1].split(' ').sort(); - name = matches[4]; - - if(descriptors[name]) descriptor = descriptors[name]; - - for(var i in prefixes) switch(prefixes[i]){ - case 'const': descriptor.writable = false; break; - case 'final': descriptor.configurable = false; descriptor.writable = false; break; - case 'get': descriptor.get = value; break; - case 'hidden': descriptor.enumerable = false; break; - case 'set': descriptor.set = value; break; - case 'writable': descriptor.writable = true; break; - } - } - } - - /// define getters/setters: - - if(descriptor.get || descriptor.set){ - if(typeof value == 'string'){ - var hiddenPropertyName = value; - if(typeof descriptor.get == 'string'){ - descriptor.get = function getter(){ - return this[hiddenPropertyName]; - } - }else{ - descriptor.set = function setter(newValue){ - this[hiddenPropertyName] = newValue; - } - } +var clone = (function(){ + function clone(/** !Object */obj, /** !object */state, /** Object= */behavior$){ + var newObj = clone2(obj, behavior$ || state); + if(behavior$){ + newObj = clone2(newObj, state); + if( behavior$.__inits__ ){ + var accessors = behavior$.__inits__; + for(var key in accessors){ + clone.defineInitProperty(behavior$, key, accessors[key], + {configurable:true}, + {configurable:true, writable:true, enumerable:true} + ); } - descriptor.value = undefined; - if(descriptor.get) value = undefined;// do not allow to hide getter as method - }else{ - descriptor.value = value; + delete behavior$.__inits__; } - - /// hide methods and private properties: - - if(hidingAllowed && typeof(value)=='function' || name[0]=='_'){ - descriptor.enumerable = false; - } - - /// constants: - - if(name.toUpperCase() == name){ - descriptor.writable = false; - } - - /// - - descriptors[name] = descriptor; - } - - /// constructor: - - if( descriptors.hasOwnProperty('constructor') ){ - var $prototype = this; - var constructor = descriptors.constructor.value; - if(typeof constructor == 'string'){ - var typeName = constructor; - // isn't slow, see http://jsperf.com/eval-vs-new-function-vs-function - constructor = Function( - 'return function '+typeName+'(){return this.applySuper(arguments)}' - )(); - constructor.typeName = typeName; - descriptors.constructor.value = constructor; - - }else if(!constructor.typeName){ - constructor.typeName = constructor.name || 'CloneOf'+$prototype.constructor.typeName;//+n - } - - constructor.prototype = $prototype; - descriptors.constructor.enumerable = false; } - - /// - - return descriptors; - }, + return newObj; + } - /** - * Apply method of super object (prototype) to this object. - * @returns {*} - * @see $object#__super__ - * @see $object#callSuper - * @this {Object} Instance only. - * @protected - * @memberOf $object# - */ - applySuper: function(/** Array|string='constructor' */ methodName, /** Array= */args){ - if(typeof(methodName) != 'string'){ - args = arguments[0]; - methodName = 'constructor'; - }// - - '__super__' in this || this.getSuper(true); - - // save super - var savedSuper = this.__super__; - // set super to next by prototype chain, in case if method also call applySuper - this.__super__ = Object.getPrototypeOf(savedSuper); - // apply method - var returned = savedSuper[methodName].apply(this, args); - // restore super - this.__super__ = savedSuper; - - return returned; - }, - - /** @see $object#applySuper - * @see $object#__super__ - * @this {Object} Instance only. - * @protected - * @memberOf $object# */ - callSuper: function(/** string */methodName, /** ?= */ arg1, /** ...?= */argN){ - var args = Array.prototype.slice.call(arguments, 1); - return this.applySuper(methodName, args); - }, - - /** - * Returns parent prototype for this instance. - * @this {Object} Instance only. - * @returns {Object} - * @memberOf $object# - */ - getSuper: function(/** boolean=false */define){ - var __super__ = Object.getPrototypeOf(Object.getPrototypeOf(this)); - if(define){ - this.defineProperty( - '__super__', {value: __super__, writable:true, configurable:true} - /** - * Link to the instance prototype. - * Dynamically changed to next by prototype chain, while `{@link #applySuper}` method executing. - * System property. **Use it only for debug purposes**. - * @name __super__ - * @type {?Object} - * @see $object#applySuper - * @private - * @memberOf $object# - */ - ); - } - return __super__; - }, + // // // // // // // // // // // // // // // // // // // // // // // // // // + // setup functions (depends on JavaScript version): - /** - * Use this method to wrap callback, that can call `{@link #applySuper}` method. - * @see $object#applySuper - * @this {Object} Instance only. - * @returns {Function} - * @memberOf $object# - */ - createSuperSafeCallback: function(/** Function|string */functionOrMethodName, /** Object= */boundThis){ - if(typeof functionOrMethodName == 'string'){ - var fn = this[functionOrMethodName]; - if(typeof boundThis == 'undefined') boundThis = this; - }else{ - fn = functionOrMethodName; - } - // - - var self = this; - var callbackSuper = this.__super__; - - return function superSafeCallback(){ - - if(self.__super__ === callbackSuper){ - return fn.apply(boundThis||this, arguments); - - }else{ - var savedSuper = self.__super__; - self.__super__ = callbackSuper; - var returned = fn.apply(boundThis||this, arguments); - self.__super__ = savedSuper; - - return returned; - } - } - }, - - /** - * Returns all changed properties, since cloning of object. - * Separate object from its prototype and return it. - * @this {Object} Instance or prototype. - * @param listPrivate Add non-enumerable properties. - * @returns {$object} - * @memberOf $object# - */ - getState: function(/** boolean=false */listPrivate){ - var currentState = $object.create(); - var ownProperties = listPrivate ? Object.getOwnPropertyNames(this) : Object.keys(this); - - for(var i= 0, length=ownProperties.length; i $collection -> $object -> Object.prototype -> null - * - * // see prototype chains produced by copy: - * - * $users.copy(): - * ~$users -> $object - * - * $users.copy(rootPrototype:Array): - * ~$users -> Array.prototype - * - * $users.copy(rootPrototype:$parent, parentsLevel:Infinity): - * ~$users -> ~$collection -> ~$object -> $parent - * - * $users.copy(rootPrototype:$parent, parentsLevel:Infinity, mixParents:true): - * ~($users + $collection + $object) -> $parent - * - * // where ~$users: - * New plain object, that have a copy of every own $user property. - * - * @this {Object} Instance or prototype. - * - * @param deepMethod - * How to process inner objects. Can be: - * "deepCopy" - see `{@link #deepCopy}` - * "deepClone" - see `{@link #deepClone}` - * "" - do nothing (default). - * - * @param rootPrototype - * The root prototype for created object prototype chain. If it is Constructor, Constructor.prototype will be used instead. - * By default - $object; - * - * @param parentsLevel - * How many parents should be included. By default - zero. - * Set this to Infinity if you want to copy all object parents properties up to $object. - * - * @param mixParents - * Should be false if objects have methods, that call `{@link #applySuper}`. - * If true, all own properties of all objects will be directly attached to the one returned object. - * False by default. - * - * @returns {Object} - * @memberOf $object# - */ - copy: function( - /** ('deepClone'|'deepCopy')="" */deepMethod, - /** (Object|Constructor)=$object */rootPrototype, - /** number=0 */parentsLevel, - /** boolean=false */mixParents - //** Array=all */propertiesList - ){ - for(var i=0, value=arguments[i], length=arguments.length; i - - var sourceObj = this; - if( typeof(sourceObj)=='function' && Object.getOwnPropertyNames(sourceObj.prototype) ){ - sourceObj = sourceObj.prototype; - } - var newObj = Object.create(rootPrototype); - var updateObj = newObj; - - var sourceObjects = []; - do{ - sourceObjects.push(sourceObj); - sourceObj = Object.getPrototypeOf(sourceObj); - }while(parentsLevel-- && sourceObj != Object.prototype); - - sourceObjects = sourceObjects.reverse(); - - for(var i=0, length=sourceObjects.length; i + descriptor = clone2(descriptor, { + get: function clone_initGetter(){ + return this[propertyName] = /* <- call setter */getter.call(this, propertyName, initedDescriptor); }, - - as: function(obj2){ - return this.valueOf() - && not ^ obj1[method] === obj2[method]; - } - } - }, - - /** - * @see $object#can - * @this {Object} Instance or prototype. - * @memberof $object# */ - cant: function(/** string */method){ - return this.can(method, 1); - }, - - /** - * Returns array of object prototype chain. - * @this {Object} Instance or prototype. - * @returns {Array} - * @memberof $object# - */ - getPrototypes: function(/** Object=$object */$last, /** boolean=false */notRevert){ - var prototypes = []; - var proto = this; - var pushMethod = notRevert ? 'push' : 'unshift'; - if(typeof $last == 'undefined') $last = $object; - - while((proto = Object.getPrototypeOf(proto)) != $last){ - prototypes[pushMethod](proto); - } - - return prototypes; - }, - - - /** - * Executes a provided function once per every enumerable property. - * Is identical to `for in`. - * @this {Object} Instance or prototype. - * @memberof $object# */ - forEach: function( - /** function(*=value,string=key,Object=this) */ - callback, - /** Object=this */scope, - /** boolean=true */enumerableOnly, - /** boolean=false */ownOnly - ){ - if(typeof scope !== 'object' && typeof scope !== 'function'){ - ownOnly = enumerableOnly; - enumerableOnly = scope; - scope = this; - - }else if(scope === undefined){ - scope = this; - } - if( enumerableOnly === undefined){ - enumerableOnly = true; - } - // - - if(!enumerableOnly){ - var keys = $object.getKeys.call(this, enumerableOnly, ownOnly); - for(var i= 0, length= keys.length; i - - if(!enumerableOnly){ - - var keys = $object.getKeys.call(this, enumerableOnly, ownOnly); - for(var i= 0, length= keys.length; i + }); + define(obj, propertyName, descriptor); + }; + + clone.defineConstructor = function clone_defineConstructor(obj, /** string='constructor' */propertyName){ + function InitClone(state){ + for(var key in state) this[key] = state[key]; + } + InitClone.prototype = obj; + define(obj, propertyName||'constructor', {value: InitClone, writable:true, configurable:true}); + return InitClone; + }; + + clone.create = function clone_create(/** !object */state, /** object= */behavior$){ + return clone(clone.prototype, state, behavior$); + };// clone.bind(null, clone.prototype); - if(!enumerableOnly){ + // // // // // // // // // // // // // // // // // // // // // // // // // // + // behavior of all created by clone.create objects: + + var prototype = [ + /** @memberOf clone# */ + function $clone(/** object=object */state, /** object= */behavior$){ + return clone(this, state||{}, behavior$); + }, + /** @memberOf clone# */ + function $extend(/** !object */state, /** object= */behavior$){ + var newBehavior$ = clone(this, state, behavior$); - var keys = $object.getKeys.call(this, enumerableOnly, ownOnly); - for(var i= 0, length= keys.length; iObject.defineProperties⠙ - * @see $object.describe - * @this {Object} Instance or prototype. - * @memberOf $object# */ - defineProperties: function(/** Object= */properties, /** PropertyDescriptor= */defaultDescriptor){ - return Object.defineProperties(this, $object.describe.apply(this, arguments)); - }, - - /** Wrapper for [Object.defineProperty⠙](http://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty) - * @this {Object} Instance or prototype. - * @memberOf $object# */ - defineProperty: function(/** string */name, /** PropertyDescriptor */propertyDescriptor){ - return Object.defineProperty(this, name, propertyDescriptor); + return new OwnConstructor(state); } - -}; - -// make methods not enumerable: -//$object./*re*/defineProperties($object); - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * @class - * The namespace object. - * @description - * If you run the following code: - * - * ns.extend('collection', {name: 'collection'}); - * ns.collection.extend('arrayCollection', {name: 'arrayCollection'}); - * - * The structure of the namespace will be: - * - * ns == { - * $collection: {name: 'collection'}, - * collection: { - * $arrayCollection: {name: 'arrayCollection'}, - * arrayCollection: { - * prototype: {name: 'arrayCollection'}, - * extend: ns.extend, - * put: ns.put - * }, - * prototype: {name: 'collection'}, - * extend: ns.extend, - * put: ns.put - * }, - * prototype: $object, - * extend: ns.extend, - * put: ns.put - * } - * - */ -var $namespace = /** @lands $namespace# */{ - /** - * The prototype of every object in this namespace (default - `{@link $object}`). - * @name prototype - * @type Object - * @memberOf $namespace# */ - prototype: $object, - - constructor: function(/** Object=$object */prototype){ - if(prototype) this.prototype = prototype; - }, - /** - * Extend namespace by prototype. - * @see $object#clone - * @see $object.describe - * @param nsItemName - * The name of the new sub-namespace - * (begins with lower case letter). - * @param prototype - * If this arg is not a clone (or sub-clone) of `ns.prototype`, - * the new object will be created (cloned from `ns.prototype`). - * @param defaultDescriptor - * The default {@link PropertyDescriptor} for created prototype. - * @returns {$namespace} The created sub-namespace. - * @memberOf $namespace# */ - extend: function extend(/** string */nsItemName, /** Object */prototype, /** PropertyDescriptor= */defaultDescriptor){ - - var $parent = this.prototype, parentNS = this; - - if( $parent.isPrototypeOf(prototype) ){ - var $newProto = prototype; - + function defineProperty_shim(/** !Object */obj, /** string */propertyName, /** !Object */descriptor){ + var proto = obj.__proto__ || obj; + if(descriptor.get || descriptor.set){ + var PropertyName = propertyName[0].toUpperCase() + propertyName.substring(1); + obj[propertyName] = function initAccessor_shim(value){ + if(value){ + obj["set" + PropertyName](value); + }else{ + return obj["get" + PropertyName](value); + } + }; + if (descriptor.get){ + proto["get" + PropertyName] = descriptor.get; + }if(descriptor.set){ + proto["set" + PropertyName] = descriptor.set; + } }else{ - - var properties = prototype; - var typeName = nsItemName[0].toUpperCase() + nsItemName.substr(1); - if( properties.hasOwnProperty('constructor') ){ - properties.constructor.typeName = typeName; + if( descriptor.enumerable ){ + obj[propertyName] = descriptor.value; }else{ - properties.constructor = typeName; + proto[propertyName] = descriptor.value; } - $newProto = $parent.clone(properties, defaultDescriptor); - } - - var newNS = /*parentNS*/$namespace.create($newProto); - this['$'+nsItemName] = $newProto; - this[nsItemName] = newNS; - - return newNS; - }, - - /** - * Put object into this namespace. - * If `nsPathName` not specified, all prototype parents will be also pushed to this namespace. - * @param nsPathName - * If not specified, the value of `prototype.constructor.typeName` or `prototype.constructor.name` will be used. - * @param prototype - * @returns {$namespace} The created sub-namespace. - * @memberOf $namespace# */ - put: function(/** string= */nsPathName, /** Object */prototype){ - - if(typeof nsPathName != 'string'){ - prototype = nsPathName; - nsPathName = undefined; - }// - - if( nsPathName /*&& nsPathName.indexOf('.') > 0*/ ){ - - var currentNS = this; - var nameParts = nsPathName.split('.'); - var nsItemName = nameParts.pop(); - var proto = prototype; - nameParts.forEach(function(namePart){ - if(!(namePart in currentNS)){ - - proto = Object.getPrototypeOf(proto); - var typeName = proto.constructor.typeName || proto.constructor.name; - if(namePart !== typeName[0].toLowerCase() + typeName.substr(1) ){ - - proto = {}; - } - - currentNS.extend(namePart, proto); - } - currentNS = currentNS[namePart]; - }); - - return applyExtend(currentNS, prototype, nsItemName); - - }else{ - - var prototypes = prototype.getPrototypes(); - prototypes.push(prototype); - - var eachNS = this; - prototypes.forEach(function(proto){ - var typeName = proto.constructor.typeName || proto.constructor.name; - nsItemName = typeName[0].toLowerCase() + typeName.substr(1); - - applyExtend(eachNS, proto, nsItemName); - - eachNS = eachNS[nsItemName]; - }); - - return eachNS; - } - - function applyExtend(eachNS, proto, nsItemName){ - if(!(nsItemName in eachNS) || eachNS[nsItemName] !== proto){ - return eachNS.extend(nsItemName, proto); - } - } - } -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -var exports = { - - get $object(){ - $object.defineProperties($object); - Object.defineProperty(this, '$object', {value: $object}); - return $object; - }, - - get $namespace(){ - $object = this.$object; - $namespace = $object.clone($namespace); - Object.defineProperty(this, '$namespace', {value: $namespace}); - return $namespace; - }, - - inject: injectIntoObjectPrototype, - - /** - * Deprecated, use $bject instead. - * @deprecated */ - get prototype(){return this.$object}, - /** @deprecated */ - extend: $namespace.extend, - /** @deprecated */ - put: $namespace.put -}; - -if(typeof module != 'undefined' && module.exports){ - /// CommonJS module: - - module.exports = exports; - -}else if(global.requirejs && typeof define == 'function'){ - /// RequireJS module: - - define(function(){return exports}); - -}else{ - /// No modules detected: - - if('clonejs' in global){ - var options = global.clonejs; - - if(options.inject){ - injectIntoObjectPrototype(); } } +})(); - if(!options || options.$object !== false){ - global.$object = exports.$object; - } - - global.clonejs = exports; -} - -return; - - function injectIntoObjectPrototype(){ - Object.defineProperties(Object.prototype, $object.describe($object)); - $object = Object.prototype; - Object.defineProperty(exports, '$object', {value: $object}); - } - - /** - * @name _global_ - * @namespace - * Description of some native types. - * Listed objects does not present in global (window) object, it's only descriptions. - */ - /** - * Object, that has at least one of the following property: - * `value`, `get`, `set`, `writable`, `configurable`, `enumerable`. - * @see Object.defineProperty⠙ - * @name PropertyDescriptor - * @typedef {({value:*}|{get:{function():*}}|{set:{function(*):void}}|{writable:boolean}|{configurable:boolean}|{enumerable:boolean})} */ - PropertyDescriptor; - - /** - * JavaScript class. Function, that can be called by "new" operator and/or have modified prototype property. - * For example: `Object`, `Array`, `RegExp`. - * @name Constructor - * @typedef {Function} */ - -/**#nocode+*/ -})(this); -/**#nocode-*/ +if(module) module.exports = clone; diff --git a/test/0-1-npm-package.test.sh b/test/0-1-npm-package.test.sh new file mode 100755 index 0000000..a493163 --- /dev/null +++ b/test/0-1-npm-package.test.sh @@ -0,0 +1,5 @@ +#!/bin/sh +echo ":: npm package test ::::::::::::::::::::::::::::::" +#set -x + +`dirname $0`/exec-on-tmp-repo.sh "npm test" \ No newline at end of file diff --git a/test/1-main.test.js b/test/1-main.test.js new file mode 100644 index 0000000..4b0bc72 --- /dev/null +++ b/test/1-main.test.js @@ -0,0 +1,3 @@ +global.clone = require('../src/clone.js'); + +module.exports = require('./clone.spec.js'); \ No newline at end of file diff --git a/test/2-minified.test.js b/test/2-minified.test.js new file mode 100644 index 0000000..c512bb7 --- /dev/null +++ b/test/2-minified.test.js @@ -0,0 +1,3 @@ +global.clone = require('../build/clone.min.js'); + +module.exports = require('./clone.spec.js'); \ No newline at end of file diff --git a/test/clone.spec.js b/test/clone.spec.js new file mode 100644 index 0000000..add2e56 --- /dev/null +++ b/test/clone.spec.js @@ -0,0 +1,44 @@ +// nodeunit + +this.tests = { + + clone: { + "2 args": function(test){ + //TODO: 2 args test + test.done(); + }, + "3 args": function(test){ + //TODO: 3 args test + test.done(); + }, + create: function(test){ + var c = clone.create({a:1}); + test.ok( c.hasOwnProperty('a') ); + test.equal( Object.getPrototypeOf(c), clone.prototype); + test.strictEqual( Object.getOwnPropertyNames(c).length, 1); + + test.done(); + }, + + __inits__: function(test){ + var obj = clone.create({ + getterCalls: 0 + },{ + __inits__: { + getterOnce: function(){ + this.getterCalls++; + return 'G'; + } + } + }); + + test.equal(obj.getterOnce, 'G'); + test.equal(obj.getterOnce, 'G'); + test.equal(obj.getterOnce, 'G'); + test.equal(obj.getterCalls, 1); + + test.done(); + } + + } +}; diff --git a/test/clone.test.js b/test/clone.test.js deleted file mode 100644 index da42aec..0000000 --- a/test/clone.test.js +++ /dev/null @@ -1,480 +0,0 @@ -// nodeunit - -if(typeof clonejs === 'undefined'){ - var clonejs = require('../src/clone.js'), - $object = clonejs.$object; -} - -this.tests = { - - clone: { - '': function(test){ - var clone = $object.clone({a:1}); - test.ok( clone.hasOwnProperty('a') ); - test.equal( Object.getPrototypeOf(clone), $object); - test.strictEqual( Object.getOwnPropertyNames(clone).length, 1); - - clone = $object.clone({a:1}, {}); - test.ok( clone.hasOwnProperty('a') ); - test.equal( Object.getPrototypeOf(clone), $object); - test.strictEqual( Object.getOwnPropertyNames(clone).length, 1); - - clone = $object.clone(); - test.strictEqual( Object.getOwnPropertyNames(clone).length, 0); - test.equal( Object.getPrototypeOf(clone), $object); - - test.done(); - }, - - call: function(test){ - var $proto = {a: 1}; - - var clone = $object.clone.call($proto); - test.equal( Object.getPrototypeOf(clone), $proto, - 'check prototype'); - - clone = $object.clone.call($proto, {b:2}); - test.ok( clone.hasOwnProperty('b') ); - - clone = $object.clone.call($proto, {b:2}, {}); - test.ok( clone.hasOwnProperty('b') ); - - test.done(); - }, - - constructor: function(test){ - var constructor = $object.clone({constructor: ''}).constructor; - var c = $object.clone({constructor: ''}); - test.ok(constructor !== c.constructor); - test.ok(constructor !== $object.clone().constructor); - test.equal(typeof constructor, 'function'); - - - test.done(); - } - }, - - create: { - - '': function(test){ - var customConstructorCalled = false; - var $myType = $object.clone({ - constructor: function(){ - customConstructorCalled = true; - } - }); - var instance = $myType.create({ignored: true}); - test.ok(customConstructorCalled); - test.ok(typeof instance.ignored == 'undefined'); - - // instance = $object.create(); - // test.ok( Object.isSealed(instance), 'the created object should be sealed by default'); - - test.done(); - }, - - 'super property should can be modified': function(test){ - - var obj = $object.clone({a: 1}).create(); - obj.a = 2; - - test.equal(obj.a, 2); - - test.done(); - } - }, - - describe: function(test){ - - function Constructor(){} - - test.deepEqual( - $object.describe({ - _p: undefined, - '(const) _unwritable': 231, - property1: 11, - '(hidden) property2': 22, - '(writable) property3': 33, - '(final) property4': 44, -'(final writable) property5': 55, - method: Function, - constructor: Constructor - }),{ - _p: {value: undefined, enumerable:false}, - _unwritable: {value: 231, enumerable:false, writable: false}, - property1: {value: 11}, - property2: {value: 22, enumerable:false}, - property3: {value: 33, writable:true}, - property4: {value: 44, writable:false, configurable: false}, - property5: {value: 55, writable:true, configurable: false}, - method: {value: Function, enumerable:false}, - constructor: {value: Constructor, enumerable:false} - } - ); - - /// Constructor: - - var proto = {}; - var descriptors = $object.describe.call(proto, {constructor: 'MyCustomName'}); - - var constructor = descriptors.constructor.value; - test.equal(typeof constructor, 'function'); - test.equal(constructor.name, 'MyCustomName'); - test.equal(constructor.typeName, 'MyCustomName'); - test.strictEqual(constructor.prototype, proto); - - var $obj = $object.clone().clone(); - constructor.call($obj, {key: 11}); - - test.equal($obj.key, 11); - - /// TODO: test defaultDescriptor - - test.done(); - }, - - 'can, cant': function(test){ - - var $myObj = $object.clone({ - fly: function(){}, - swim: function(a,b,c){} - }); - var myObj = $myObj.create(); - test.ok(!! myObj.can('swim').as($myObj) ); - test.ok(!! $object.can.call(myObj, 'fly').like($myObj) ); - - test.ok(! myObj.cant('swim').as($myObj) ); - test.ok(! $object.cant.call(myObj, 'fly').like($myObj) ); - - test.done(); - }, - - copy: function(test){ - var myArray = $object.copy(Array); - myArray[0] = 11; - myArray[1] = 22; - test.deepEqual(myArray, [11 ,22]); - - myArray.defineProperties({test: 'T'}); - test.strictEqual(myArray.test, 'T'); - - - var $collection = $object.clone({items: []}); - var $users = $collection.clone({name: ''}); - - // $users full prototype chain: - //$users -> $collection -> $object -> Object.prototype -> null - - // see prototype chains produced by copy: - - var userCopy = $users.copy(); - //~$users -> $object - test.equal(Object.getPrototypeOf(userCopy), $object); - test.ok(userCopy.hasOwnProperty('name')); - test.ok(userCopy.items === undefined); - - userCopy = $users.copy(Array); - //~$users -> Array.prototype - test.equal(Object.getPrototypeOf(userCopy), Array.prototype); - test.ok(userCopy.hasOwnProperty('name')); - test.ok(userCopy.items === undefined); - test.ok(userCopy.clone === undefined); - - userCopy = $users.copy(Array, Infinity); - //~$users -> ~$collection -> ~$object -> Array.prototype - test.ok(userCopy.hasOwnProperty('name')); - test.ok(userCopy.getPrototype().hasOwnProperty('items')); - test.ok(userCopy.getPrototype().getPrototype().hasOwnProperty('clone')); - test.ok(userCopy.getPrototype().getPrototype().getPrototype() === Array.prototype); - - userCopy = $users.copy(Array, Infinity, true); - //~($users + $collection + $object) -> Array.prototype - test.equal(Object.getPrototypeOf(userCopy), Array.prototype); - test.ok(userCopy.hasOwnProperty('name')); - test.ok(userCopy.hasOwnProperty('items')); - test.ok(userCopy.hasOwnProperty('clone')); - - //TODO: add tests for deepCopy/deepClone - - test.done(); - }, - - deepCopy: function(test){ - var obj = $object.clone({l1: {l2: {l3: null}}}); - var deepCopy = obj.deepCopy(); - test.strictEqual(deepCopy.l1.l2.l3, null); - - obj.l1.l2.l3 = 11; - test.strictEqual(deepCopy.l1.l2.l3, null); - - deepCopy.l1.l2.l3 = 22; - test.strictEqual(obj.l1.l2.l3, 11); - - test.done(); - }, - - deepClone: function(test){ - var obj = $object.clone({l1: {l2: {l3: null}}}); - var deepClone = obj.deepClone(); - test.strictEqual(deepClone.l1.l2.l3, null); - - obj.l1.l2.l3 = 11; - test.strictEqual(deepClone.l1.l2.l3, 11); - - deepClone.l1.l2.l3 = 22; - test.strictEqual(obj.l1.l2.l3, 11); - - test.done(); - }, - - '__super__': { - 'callSuper, applySuper': function(test){ - var calls = []; - var $parent = $object.clone({ - constructor: function(arg){ - calls.push('collection'); - this.callSuper('constructor', arg); - } - }); - var $child = $parent.clone({ - constructor: function(arg){ - calls.push('users'); - this.applySuper(arguments); - } - }); - var child = $child.create({setBy$objectConstructor: 11}); - - test.deepEqual(calls, ['users','collection']); - test.equal(child.setBy$objectConstructor, 11); - - test.done(); - }, - - 'createSuperSafeCallback, __super__': function(test){ - - test.expect(3); - - var $parent = $object.clone({ - testSuper: function(){ - test.strictEqual(this.__super__, $object); - } - }); - var $child = $parent.clone({ - constructor: function(){ - this.applySuper(); - test.strictEqual(this.__super__, $parent); - }, - - asyncCheck: function(){ - var callback = this.createSuperSafeCallback(function(){ - test.strictEqual(this.__super__, $parent); - this.applySuper('testSuper'); - },this); - - setTimeout(callback, 0); - } - }); - - var child = $child.create(); - child.asyncCheck(); - - setTimeout(function(){ - test.done(); - },0); - }, - - "first call applySuper() on sealed object \ - should doesn't throw an error": function(test){ - - var $parent = $object.clone({ - method: function(){} - }); - var $child = $parent.clone({ - method: function(arg){ - this.applySuper('method'); - } - }); - var child = $child.clone(); - child.seal(); - - test.doesNotThrow(function(){ - child.method(); - }); - - test.done(); - } - }, - - apply: function(test){ - //methodName, args, withObj, asObj - var asObj = {defineProperties: function(){ - this.called = true; - return this; - }}; - var obj = $object.apply(Array(22,33), 'defineProperties',[{a:11}], asObj); - test.equal(obj.a, undefined); - test.ok(obj.called); - test.equal(obj[0], 22); - test.equal(Object.getPrototypeOf(obj), Array.prototype); - - //methodName, args, withObj - obj = $object.apply(Array(22,33), 'defineProperties',[{a:11}]); - test.equal(obj.a, 11); - test.equal(obj[0], 22); - test.equal(Object.getPrototypeOf(obj), Array.prototype); - - //methodName, withObj - obj = $object.apply(Array(22,33), 'defineProperties'); - test.equal(obj[0], 22); - test.equal(Object.getPrototypeOf(obj), Array.prototype); - - test.done(); - }, - - concat: function(test){ - var $parent = $object.clone({a: 1}); - var $child = $parent.clone({b: 2}); - var toMerge = $child .clone({c: 3, _c: 33}); - - var obj = $object.clone().concat(toMerge); - test.strictEqual(obj._c, 33); - test.strictEqual(obj.c, 3); - test.strictEqual(obj.b, undefined); - test.strictEqual(obj.a, undefined); - - obj = $object.clone().concat(toMerge, ['a','_c']); - test.strictEqual(obj._c, 33); - test.strictEqual(obj.c, undefined); - test.strictEqual(obj.b, undefined); - test.strictEqual(obj.a, 1); - - obj = $object.clone().concat(toMerge, true); - test.strictEqual(obj._c, 33); - test.strictEqual(obj.c, 3); - test.strictEqual(obj.b, 2); - test.strictEqual(obj.a, 1); - - test.done(); - }, - - getPrototypes: function(test){ - var ns = clonejs.$namespace.clone(); - ns.extend('level1',{n:1}) - .extend('level1_1',{n:2}) - .extend('level1_1_1',{n:3}); - - var $obj = ns.level1.level1_1.$level1_1_1.create(); - - test.deepEqual($obj.getPrototypes(), [{n:1}, {n:2}, {n:3}]); - test.deepEqual($obj.getPrototypes(undefined, true), [{n:3}, {n:2}, {n:1}]); - test.deepEqual($obj.getPrototypes(Object.prototype), [Object.prototype, {n:1}, {n:2}, {n:3}]); - //test.deepEqual($obj.getPrototypes(null), [Object.prototype, Object.prototype, {n:1}, {n:2}, {n:3}]); - - test.done(); - }, - - getValues: function(test){ - var obj = $object.clone({en:'1 0', _p:'0 0'}).clone({ownEn:'1 1', _own:'0 1'}); - // enumerable, own - test.deepEqual(obj.getValues(true, true).sort(), [ '1 1' ]); - test.deepEqual(obj.getValues(false, false).sort(), [ '0 0', '0 1', '1 0', '1 1' ]); - test.deepEqual(obj.getValues(false, true).sort(), [ '0 1', '1 1' ]); - test.deepEqual(obj.getValues(true, false).sort(), [ '1 0', '1 1' ]); - - test.done(); - }, - - setValues: function(test){ - var obj = $object.clone({en:'1 0', _p:'0 0'}).clone({ownEn:'1 1', _own:'0 1'}), values; - - values = obj.getValues(); - test.deepEqual(obj, obj.copy(Infinity).setValues(values) ); - - values = obj.getValues(true); - test.deepEqual(obj, obj.copy(Infinity).setValues(values, true) ); - - values = obj.getValues(false); - test.deepEqual(obj, obj.copy(Infinity).setValues(values, false) ); - -// values = obj.getValues(true, false); -// test.deepEqual(obj, obj.copy(Infinity).setValues(values, true, false) ); - - values = obj.getValues(false, true); - test.deepEqual(obj, obj.copy(Infinity).setValues(values, false, true) ); - -// values = obj.getValues(false, false); -// test.deepEqual(obj, obj.copy(Infinity).setValues(values, false, false) ); - - - test.done(); - }, - - $namespace: { - /* - - namespace contents: - ns = { - prototype: $ns, - items: { - prototype: $item, - subitems: {}, - $subitem: $subitem, - - extend: $ns.extend - }, - $item: $item, - - extend: $ns.extend, - put: $ns.put - } - - 1) $subitem should be a direct child of $item - 2) items, subitems should be plural - - clone.clone() - clone.prototype - */ - - extend: function(test){ - var ns1 = clonejs.$namespace.create(); - ns1.extend('collection', {name: 'collection'}) - .extend('arrayCollection', {name: 'arrayCollection'}); - - _ns_check(ns1, test); - - test.done(); - }, - - put: function(test){ - var $collection = $object.clone({constructor: 'Collection'}), - $arrayCollection = $collection.clone({constructor: 'ArrayCollection'}); - var ns2 = clonejs.$namespace.create(); - ns2.put($arrayCollection); - - _ns_check(ns2, test); - - var ns3 = clonejs.$namespace.create(); - ns3.put('collection.arrayCollection', $arrayCollection); - - _ns_check(ns3, test); - - test.done(); - } - } -}; - -function _ns_check(newNS, test){ - test.strictEqual(newNS.prototype, $object); - test.strictEqual(newNS.extend, clonejs.$namespace.extend); - test.strictEqual(newNS.put, clonejs.$namespace.put); - - test.ok( $object.isPrototypeOf(newNS.$collection) ); - test.equal( newNS.$collection.constructor.typeName, 'Collection'); - test.strictEqual(newNS.collection.prototype, newNS.$collection); - test.strictEqual(newNS.collection.extend, clonejs.$namespace.extend); - - test.ok( newNS.$collection.isPrototypeOf(newNS.collection.$arrayCollection) ); - test.equal( newNS.collection.$arrayCollection.constructor.typeName, 'ArrayCollection'); - test.strictEqual(newNS.collection.arrayCollection.prototype, newNS.collection.$arrayCollection); - test.strictEqual(newNS.collection.arrayCollection.extend, clonejs.$namespace.extend); -} diff --git a/test/conf/jstd-nodeunit-runner.js b/test/conf/jstd-nodeunit-runner.js deleted file mode 100644 index cfcdc20..0000000 --- a/test/conf/jstd-nodeunit-runner.js +++ /dev/null @@ -1,53 +0,0 @@ -function require(fileName){} -console = jstestdriver.console; - - - -function runNodeUnit(tests, groupName){ - - console.log(111, groupName); - - var $newTestCase = {}; - - for(var name in tests){ - var test = tests[name]; - if(typeof test == 'function'){ - $newTestCase['test ' + name] = test.bind(tests, runNodeUnit.testArg); - - }else if(typeof test == 'object'){ - runNodeUnit(test, groupName ? groupName+'.'+name : name); - } - } - - if($newTestCase.length){ - var NewTestCase = TestCase(groupName); - NewTestCase.prototype = $newTestCase; - } -} - -runNodeUnit.testArg = { - ok: function(actual, msg){ - assertTrue(msg, actual); - }, - equal: function(actual, expected, msg){ - assertEquals(msg, expected, actual); - }, - strictEqual: function(actual, expected, msg){ - assertSame(msg, expected, actual); - }, - deepEqual: function(actual, expected, msg){ - assertEquals(msg, expected.length, actual.length); - //TODO: - }, - expect: function(){}, - done: function(){} -} - - - -//runNodeUnit({ -// 'test $object': this['test $object'], -// 'test ns': this['test ns'] -//},'t'); - -runNodeUnit(this['test $object'], 'test'); \ No newline at end of file diff --git a/test/conf/jstd-nodeunit.conf b/test/conf/jstd-nodeunit.conf deleted file mode 100644 index 6fcbe70..0000000 --- a/test/conf/jstd-nodeunit.conf +++ /dev/null @@ -1,6 +0,0 @@ -load: - - ../../src/clone.js - - ../clone.test.js - -test: - - jstd-nodeunit-runner.js diff --git a/test/conf/nodeunit-browser.html b/test/conf/nodeunit-browser.html index 4d4de55..b7caa3a 100644 --- a/test/conf/nodeunit-browser.html +++ b/test/conf/nodeunit-browser.html @@ -8,10 +8,9 @@ - - +