diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 00000000000..69fad358018 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory": "bower_components" +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..9099689136d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.gitignore b/.gitignore index 52570c2fba3..37c9f7bd638 100644 --- a/.gitignore +++ b/.gitignore @@ -13,11 +13,9 @@ _yardoc assets assets/bpm_libs.js assets/bpm_styles.css -bin/ coverage dist -docs/build -docs/node_modules +docs lib/*/tests/all.js lib/*/tests/qunit* lib/bundler/man @@ -35,6 +33,9 @@ tmp.bpm tmp.spade tests/source node_modules -.vagrant bundle/ *~ +publish_to_bower/ +bower_components/ +npm-debug.log +.ember-cli diff --git a/.jscsrc b/.jscsrc new file mode 100644 index 00000000000..f0258a52b20 --- /dev/null +++ b/.jscsrc @@ -0,0 +1,62 @@ +{ + "esnext": true, + "excludeFiles": ["ember-runtime/ext/rsvp.js"], + "additionalRules": [ "lib/jscs-rules/*.js" ], + "disallowSpacesInsideArrayBrackets": "all", + "disallowMultipleVarDeclWithAssignment": true, + "requireSpaceBeforeObjectValues": true, + "requireCommaBeforeLineBreak": true, + "requireBlocksOnNewline": 1, + "disallowKeywordsOnNewLine": ["else"], + "disallowSpacesBeforeSemicolons": true, + "disallowNewlineBeforeBlockStatements": true, + "requireSpacesInConditionalExpression": { + "afterTest": true, + "beforeConsequent": true, + "afterConsequent": true, + "beforeAlternate": true + }, + "disallowSpacesInCallExpression": true, + "disallowSpacesInsideRoundBracesInCallExpression": true, + "disallowEmptyBlocks": true, + "requireSpacesInsideObjectBrackets": "all", + "requireCurlyBraces": [ + "if", + "else", + "for", + "while", + "do", + "try", + "catch" + ], + "requireLineFeedAtFileEnd": true, + "disallowTrailingWhitespace": true, + "disallowTrailingComma": true, + "requireSpaceBeforeBlockStatements": true, + "validateIndentation": 2, + "validateParameterSeparator": ", ", + "validateQuoteMarks": "'", + "requireSpaceBeforeKeywords": [ + "else", + "while", + "catch" + ], + "requireSpaceAfterKeywords": [ + "do", + "for", + "if", + "else", + "switch", + "case", + "try", + "while", + "with", + "return" + ], + "requireSpaceBetweenArguments": true, + "requireSpacesAfterClosingParenthesisInFunctionDeclaration": { + "beforeOpeningRoundBrace": false, + "beforeOpeningCurlyBrace": true + }, + "requireCommentsToIncludeAccess": true +} diff --git a/.jshintrc b/.jshintrc index 257a9f85f25..3264fa60dba 100644 --- a/.jshintrc +++ b/.jshintrc @@ -3,37 +3,32 @@ "QUnit", "define", "console", - "Ember", "DS", "Handlebars", - "Metamorph", "RSVP", "require", "requireModule", "equal", "notEqual", "notStrictEqual", - "test", "asyncTest", - "testBoth", - "testWithDefault", - "raises", "throws", "deepEqual", - "start", - "stop", "ok", "strictEqual", - "module", "expect", "minispade", "expectAssertion", + "expectDeprecation", + "expectNoDeprecation", + "ignoreAssertion", + "ignoreDeprecation", // A safe subset of "browser:true": - "window", "location", "document", "XMLSerializer", + "window", "document", "setTimeout", "clearTimeout", "setInterval", "clearInterval" ], - + "esnext": true, "node" : false, "browser" : false, @@ -58,5 +53,7 @@ "sub": true, "strict": false, "white": false, - "eqnull": true + "eqnull": true, + "trailing": true, + "unused": "vars" } diff --git a/.travis.yml b/.travis.yml index 32527838d35..912babde2a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,33 +1,53 @@ --- -rvm: -- 1.9.3 +language: node_js node_js: -- "0.10" + - "0.10" + +sudo: false + +cache: + directories: + - node_modules + - bower_components + +before_install: + - "npm config set spin false" + - "npm install -g npm@^2" + - "npm --version" + install: -- "npm install -g defeatureify" -- "bundle install --deployment" -after_success: bundle exec rake publish_build -script: rake test\[standard] -notifications: - campfire: - rooms: - - secure: ! 'ia5CUz3FeqK+s238B9ApRz1vt/qpM/WtI5HlYS7GH5WPBbC5vsSUIwV9IqM8 - - HKvTwLQKHUP5e+6I7E40/ofbQycsNSeglJ0mRRzdLe2SeN68uPsjuy5AKnpn - - KpIzGa9OC5tZfN/RqJskLuP8QRvqNCLPyesY1E5GM7lTKYa92PM=' - on_success: change - on_failure: always + - "npm install" + +after_success: + - "./bin/publish_builds" + +script: + - npm test + env: global: - - S3_BUCKET_NAME=builds.emberjs.com - - secure: ! 'KXJmcGLpnxnPmmei/qPNVcdQxLX1xyYIaVocinQ0YAjtBvCtAwg63EWMFnGp + - SAUCE_USERNAME=ember-ci + - SAUCE_ACCESS_KEY=b5cff982-069f-4a0d-ac34-b77e57c2e295 + - DISABLE_SOURCE_MAPS=true + - BROCCOLI_ENV=production + - S3_BUILD_CACHE_BUCKET=emberjs-build-cache + - S3_BUCKET_NAME=builds.emberjs.com + - secure: "SHnuJ4A3QbSc3LV2fYynDPbbSbhVl0ZWnCiKPuRgwnddDnoSaMQUY2RqyHdtsQGdUZCOeNaMvYUhYx6hzxBVHn0yuN3KA20aSwvYdwaMgZXfJi+lyxgsEI8iYdksWXvVbCAyKM8zjTWXUtNcMBGtsGYOfdD41wfZgI8GsI0YYJc=" + - secure: ! 'KXJmcGLpnxnPmmei/qPNVcdQxLX1xyYIaVocinQ0YAjtBvCtAwg63EWMFnGp VIzUNikE+Cej3g+nwEdDJiL1c9NFPL+zCnriR2iMVjPak+IQaG3YcMm0T+hY /WLEPAquZBKw1gU6lBEUuDumTlkXQQdHz3cJYoidAXz3uV1EXIU=' - - secure: ! 'qCW0BVNFuQjAI53pvvE6oeGxtEdZ+RlvcCpYjU4vxEjedidEEcHKtIVh7d7J + - secure: ! 'qCW0BVNFuQjAI53pvvE6oeGxtEdZ+RlvcCpYjU4vxEjedidEEcHKtIVh7d7J PZ8DNTxX0zsp2jjY8NwTR5MC8NBH+J5VjuTSGv82t5sm0i0jzaBmOOSLbKqH I/BFT0MbnR6JVCZiPV7TCWPgY1gvgZ6TEEIKGqauDMUBdL8ZK6I=' + - secure: e0yxVfwVW61d3Mi/QBOsY6Rfd1mZd3VXUd9xNRoz/fkvQJRuVwDe7oG3NOuJ4LZzvMw7BJ+zpDV9D8nKhAyPEEOgpkkMHUB7Ds83pHG4qSMzm4EAwBCadDLXCQirldz8dzN5FAqgGucXoj5fj/p2SKOkO6qWIZveGr8pdBJEG1E= + matrix: + - TEST_SUITE=each-package-tests + - TEST_SUITE=built-tests EMBER_ENV=production DISABLE_JSCS=true DISABLE_JSHINT=true + - TEST_SUITE=old-jquery + - TEST_SUITE=extend-prototypes + - TEST_SUITE=node DISABLE_JSCS=true DISABLE_JSHINT=true + - TEST_SUITE=sauce diff --git a/.watchmanconfig b/.watchmanconfig new file mode 100644 index 00000000000..5e9462c2005 --- /dev/null +++ b/.watchmanconfig @@ -0,0 +1,3 @@ +{ + "ignore_dirs": ["tmp"] +} diff --git a/Assetfile b/Assetfile deleted file mode 100644 index 0db59c59438..00000000000 --- a/Assetfile +++ /dev/null @@ -1,86 +0,0 @@ -require 'ember-dev' - -distros = { - "runtime" => %w(ember-metal rsvp container ember-runtime), - "template-compiler" => %w(ember-handlebars-compiler), - "data-deps" => %w(ember-metal rsvp container ember-runtime), - "full" => %w(ember-metal rsvp container ember-runtime ember-views metamorph handlebars ember-handlebars-compiler ember-handlebars ember-routing ember-application ember-extension-support) -} - -class AddMicroLoader < Rake::Pipeline::Filter - LOADER = File.expand_path("packages/loader/lib/main.js") - - def initialize(options={}, &block) - super(&block) - @global = options[:global] - end - - def generate_output(inputs, output) - output.write "(function() {\n" unless @global - - output.write File.read(LOADER) - - inputs.each do |input| - output.write input.read - end - - output.write "\n})();\n" unless @global - end - - def additional_dependencies(input) - [ LOADER ] - end -end - -#MEGAHAX -ember_spade_postprocess = "filter AddMicroLoader, :global => true" - -instance_eval File.read(EmberDev.support_path.join('Assetfile')) - -distros.each do |name, modules| - name = name == "full" ? "ember" : "ember-#{name}" - - input "dist/modules" do - - # Add ember-testing to ember distro - if name == "ember" - match "{ember-testing.js}" do - concat ["ember-testing.js"], "#{name}.js" - end - end - - module_paths = modules.map{|m| "#{m}.js" } - match "{#{module_paths.join(',')}}" do - concat(module_paths){ ["#{name}.js", "#{name}.prod.js"] } - end - - match "{#{name}.js,#{name}.prod.js}" do - filter HandlebarsPrecompiler - if File.exists?("features.json") - filter EmberDefeatureify - end - filter AddMicroLoader unless name == "ember-template-compiler" - end - - # Add debug to the main distro - match "{#{name}.js,ember-debug.js}" do - filter VersionInfo - concat ["ember-debug.js"], "#{name}.js" unless name == "ember-template-compiler" - filter EmberStub if name == "ember-template-compiler" - end - - # Strip dev code - match "#{name}.prod.js" do - filter(EmberStripDebugMessagesFilter) { ["#{name}.prod.js", "min/#{name}.js"] } - end - - # Minify - match "min/#{name}.js" do - uglify{ "#{name}.min.js" } - filter VersionInfo - filter EmberLicenseFilter - end - end -end - -# vim: filetype=ruby diff --git a/Brocfile.js b/Brocfile.js new file mode 100644 index 00000000000..af614b6f15b --- /dev/null +++ b/Brocfile.js @@ -0,0 +1,63 @@ +/* jshint node: true */ + +// To create fast production builds (without ES3 support, minification, derequire, or JSHint) +// run the following: +// +// DISABLE_ES3=true DISABLE_JSCS=true DISABLE_JSHINT=true DISABLE_MIN=true DISABLE_DEREQUIRE=true ember serve --environment=production + +var fs = require('fs'); + +var EmberBuild = require('emberjs-build'); +var packages = require('./lib/packages'); + +var applyFeatureFlags = require('babel-plugin-feature-flags'); + +var vendoredPackage = require('emberjs-build/lib/vendored-package'); +var htmlbarsPackage = require('emberjs-build/lib/htmlbars-package'); +var vendoredES6Package = require('emberjs-build/lib/es6-vendored-package'); + +var featuresJson = fs.readFileSync('./features.json', { encoding: 'utf8' }); + +function babelConfigFor(environment) { + var isDevelopment = (environment === 'development'); + + var features = JSON.parse(featuresJson).features; + features["mandatory-setter"] = isDevelopment; + + return { + plugins: [ + applyFeatureFlags({ + import: { module: 'ember-metal/features' }, + features: features + }) + ] + }; +} + +var emberBuild = new EmberBuild({ + babel: { + development: babelConfigFor('development'), + production: babelConfigFor('production') + }, + htmlbars: require('htmlbars'), + packages: packages, + vendoredPackages: { + 'loader': vendoredPackage('loader'), + 'rsvp': vendoredES6Package('rsvp'), + 'backburner': vendoredES6Package('backburner'), + 'router': vendoredES6Package('router.js'), + 'dag-map': vendoredES6Package('dag-map'), + 'route-recognizer': htmlbarsPackage('route-recognizer', { libPath: 'node_modules/route-recognizer/dist/es6/' }), + 'dom-helper': htmlbarsPackage('dom-helper'), + 'morph-range': htmlbarsPackage('morph-range'), + 'morph-attr': htmlbarsPackage('morph-attr'), + 'htmlbars-runtime': htmlbarsPackage('htmlbars-runtime'), + 'htmlbars-compiler': htmlbarsPackage('htmlbars-compiler'), + 'htmlbars-syntax': htmlbarsPackage('htmlbars-syntax'), + 'simple-html-tokenizer': htmlbarsPackage('simple-html-tokenizer'), + 'htmlbars-test-helpers': htmlbarsPackage('htmlbars-test-helpers', { singleFile: true }), + 'htmlbars-util': htmlbarsPackage('htmlbars-util') + } +}); + +module.exports = emberBuild.getDistTrees(); diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index 0cf18a7d3e3..00000000000 --- a/CHANGELOG +++ /dev/null @@ -1,1085 +0,0 @@ -*Ember 1.0.0 (August 31, 2013)* - -* Fix nested `{{yield}}` -* `ReduceComputed` groups changed properties. -* Multiple fixes and improvements to the new Array Computed Properties -* Adds the ability to specify view class for render -* Restructure controller init, to minimize property lookups -* Provide hook for persistence libraries to inject custom find behavior. -* Sync router.js -* Controller#controllers property should be readOnly -* Invalid Controller#controllers accesses throw runtime exceptions -* Inform about the Ember Inspector if not installed -* Don't force a layout on registered components -* Make TextField and TextArea components -* Adds Function.prototype.observesImmediately -* Move ember-states into a plugin: https://github.com/emberjs/ember-states -* Update Backburner -* Disabled model factory injections by default. -* Fix bug where link-to wouldn't be active even if resource is active -* Add Ember.PromiseProxyMixin -* Some fixes to grouped each -* Update to rsvp-2.0.2; fixes unit tests for RSVP#rethrow in IE 6,7,8 -* Rename computed array macros to match #3158 -* Consider `controllerName` in Ember.Route#render() -* Allow a template explicitly set on a view to be used when rendering a route. - - -*Ember 1.0.0-rc.8 (August 28, 2013)* - -* View, controller & route action handlers are now expected to be defined on an `actions` object. -* registerBoundHelper won't treat quoted strings / numbers as paths -* Array Computed Properties -* Rename bindAttr to bind-attr. -* Rename linkTo to link-to. -* Improved default route.serialize behavior. It will now attempt to populate named properties with the corresponding property on the model. -* Added Ember.getProperties -* Smarter linkTo observers -* Fix `Ember.EnumerableUtils#replace` to allow large size of array -* rsvp.js refresh with RSVP#rethrow and promise#fail -* Make sets during init behave the same as create(props) -* Continue to make view creation container aware -* Sync router.js - Closes #3153, #3180 -* Application#resolver -> Application#Resolver -* The resolver now provides the normalization -* Add currentRouteName to ApplicationController -* Lookup itemViewClass and emptyView of collectionView if given as string -* Change behavior around uncached computed properties. -* Aliased xProperty methods in enumerable to xBy and aliased some and someProperty to any and anyBy respectively -* Factory Injections -* Support replaceURL on HashLocation -* Assorted performance improvements -* Add Ember.on, Function.prototype.on, init event -* Fix some `{{yield}}` bugs -* Improved `Route#controllerFor` to support `controllerName` and non-route lookups - - -*Ember 1.0.0-rc.7 (August 14, 2013)* - -* correctly preserve a views container -* Reference to RSVP repo for documentation -* Remove obsolete paragraph from ObjectController comments -* Add rel attribute binding to linkTo helper -* Add Ember.DataAdapter in ember-extension-support -* Asserts that a target element is in the DOM on `appendTo` and `replaceIn`. -* add Ember.create unit test, preventing parent object's pollute -* Sync with router.js -* fix #3094 -* View event handlers inside eventManager should be wrapped in run loop -* fix #3093 -* Handlebars template properties should not be methods -* Add assert that `this` is correct in deferReadiness and advanceReadiness. @stefanpenner / @lukemelia -* Remove `previousObject` argument from `Ember.Enumerable#nextObject` -* Remove `context` argument from `Ember.Enumerable#nextObject` -* Fixed some docs for Ember.Route -* Added the ability to send a context with actions in components -* Fixed a typo in documentation for {{log}} -* Added `mergedProperties` to ember-metal, Ember.Route's `events` -* render helper: falsy contexts no longer treated as absent -* Fix yield helper to only be craycray for components -* Components should not be singleton (just like views) -* Make methods on the router overridable. Denote private methods with _ -* router.js sync - don't overwrite URL's on noop transitions -* adding docs for observers -* Clearer messaging for changes and removal of bad assert -* Removed old-router -* Clarified Ember.warn message for linkTo loading state -* linkTo param of 0 should be treated as a url param -* Aborts/redirects in willTransition don't enter LoadingRoute -* Assertion if incrementProperty given non-numeric value -* Add sendAction() to Ember.Component -* {{yield}} view should be virtual -* Remove warning about route rendering that was inaccurate and confusing -* Fix {{template}} deprecation warnings in tests -* Ember.controllerFor and Route#controllerFor no longer generate controllers -* improve readability of some exceptions caught b -* update release rakefile to work with the updated website -* Clean up Handlebars helpers registered in tests -* Better route assertions - Fixes #2003 -* Mixins don't technically extend Ember.Mixin -* Docs and whitespace cleanup -* Re-add Ember.Object.create docs and document createWithMixins -* Revert "document the create method in for subclasses of Ember.Object" -* router.js sync - simplified transition promise chain -* Added a License to the gemspec - Fixes #3050 -* Only use valueNormalizer if one is present insideGroup. Fixes #2809 -* Remove unnecessary assertion for `Ember.inspect` -* Fixed problem with dependentKeys on registerBoundHelper. -* Should allow numbers in tagNames i.e. h1-6 -* [CVE-2013-4170] Fix for Potential XSS Exploit When Binding to User-Supplied Data -* Update component_registration_test.js to use component vs. control -* Fix test to normalize URL for IE7 -* Fix date assertion that returned by `Ember.inspect` -* fix tests, isolate keywords in component, yield back controller and keywords in addition to context -* Add some more tests to stress-test yield -* Make yielded content look at the original context -* Don't set context in Ember.controllerFor -* Tweak htmlSafe docs -* Improve error message for missing itemView -* Improve assertion for non-Array passed to #each -* Add Example for Ember.computed.alias -* Remove unreferenced property `Ember.Comparable#isComparable` -* Remove unused argument for `Ember.Array#objectAt` -* Fix indeterminate checkbox that is set on insert -* Add jQuery 1.9 to testing rake task -* Support object with `Ember.String.fmt` -* Add 'date', 'regexp' and 'error' supprot to `Ember.inspect` -* Improve `Ember.inspect` for array -* Fix replacement for `Ember.String.fmt` to be parsed as decimal digit -* Upgrade to latest router.js -* {{input}} helper doesn't override default type -* Deprecate `template` in favor of `partial` -* Document htmlSafe -* upgrade RSVP -* Expose `options` arg in `debugger` HB helper -* Use the original arg length of wrapped CP funcs, still call the wrapper -* Documentation for sendEvent and doc change in removeListeners -* Fixed incorrect example of multi-arg registerBoundHelper -* Support indeterminate property in checkboxes -* Fix: didInsertElement was fired twice -* upload prod builds to s3 -* Application#setupForTesting should set `Ember.testing = true` -* remove un-needed context preservation -* Don't push childViews if undefined/invalid (issue #2967) -* keyEvent integration test helper to simulate keydown, keypress etc. -* Add documentation to cover the `{{each}}` helper's `emptyViewClass` option. -* Removes an unused Ember.get include -* Improve Ember.Logger setup - Fixes #2962 -* Better documentation for Ember.run.throttle and debounce -* Update Backburner.js -* View helper learns about the container -* Fix the jQuery patch code for ember-testing click in Firefox. -* update ember-dev to give proper assertion test failures -* [fixes #2947] container#unregister -* Validate fullNames on resolve -* Route#model by default now uses lookupFactory -* add resolveModel to the default resolver -* fix deprecation warning -* ember-application test refactoring -* Specify controller of a route via controllerName -* Remove non ASCII character in handlebars assertion error message -* .jshintrc: set browser:false -* Throw exception on invalid arguments for pushObjects method (issue #2848) -* {{linkTo}} bound contexts, loading class -* Use released handlebars -* Fixed bug in Ember.Application#reset that calls `startRouting` twice. -* assert that item view exists in container and camelize lookup name -* Remove property for compatibility -* Created helpful error message when using @each on an array that does not return objects -* Update Router.js: slashless handleURL, numeric/string params -* Allows itemView option into the each/collection helper. If itemView exists and there is a controller container, then it will attempt to resolve the view via the container. -* Add Ember.Route#disconnectOutlet, to allow for clearing a previously rendered outlet. Fixes #2002 -* remove duplication of testing for Ember.run.debounce -* Update supported ruby version -* Updated JSBin And JSFiddle links to point to working fiddle/bin -* Document the container -* Use Ember.isNone instead of Ember.none -* Quoteless route param in linkTo performs lookup -* Allow value of TextField to be 0 -* Fire mousedown & mouseup on clicks, plus focus for text fields. -* Add a check for jQuery versions with a specific checkbox click bug. -* warns when trying to get a falsy property -* Updating new Ember.Component documentation to remove confusion -* Stringify linkTo examples -* Update router.js. Fixes #2897. -* Added functionality to Router.map to allow it to be called multiple times without the map being overwritten. Allows routes to be added at runtime. One test with multiple cases also added. -* Revert "Use Ember setter to set Ember.Route controller." -* Calling router.map now appends the routes instead of replacing them -* simplify history.state support check -* Polyfill history.state for non-supporting browsers -* Switch from unbind to off for router location events -* Support grouping option for Ember.Select using optgroup -* Update Handlebars version to 1.0.0 -* Show `beforeModel` and `afterModel` in API Route docs -* update lock file -* Add tests for #1866 - loc helper -* add loc helper -* document ember-testing helpers - -*Ember 1.0.0-rc.6 (June 23, 2013)* - -* Refactored `Ember.Route`s teardown mechanism for rendered views. This fixes #2857, previously multiple outlets were not tore down. -* Rename Control to Component. This avoids conflicts with the existing (behind-a-flag) control and is clearer about intent. -* Remove Ember.register to avoid introducing yet-another registration mechanism and move the logic into Ember.Handlebars.helper. -* Add test for parentViewDidChange event. -* Trigger parentViewDidChange event.[Fixes #2423] -* Make `control` helper more resilient. -* Ember.Select 0 can now be the selected value [Fixes #2763] -* Fix Ember.Select example. -* Ember.Control add inline docs. -* Add Ember.Control -* Make template loader an initializer -* Add lookupFactory -* Fix to support jQuery 1.7 -* In mid-transition, `modelFor` accepts both camelCase and underscore naming -* In StateManager, use instanceof check instead of the legacy isState attribute. This is potentially breaking, but very unlikely to affect real-world code. -* StateManager and states now pass their `container` to child states. -* Ember.Test tests refactor -* Ember.Test fix wait helper resolution value -* Router facelift – Async transitions -* Ember.Test find helper no longer throws an error if the selector is not found. -* Additional API docs for LinkView -* [Fixes #2840] - textfield binding issue with null -* Update Backburner.js -* Make sure we are inside a run loop before syncing -* Inline helper function, remove uneeded function call. -* Remove unnecessary function call from `Ember.normalizeTuple` -* Ember.SortableMixin: new option sortFunction -* Update docs so that `Ember.View.$` is a method, not a property. -* Add documentation to cover LinkView's `eventName` property -* Improve docs for event names -* Remove expectAssertion in favor of ember-dev -* Added ability to change event type on which Ember.LinkView is triggered -* ContainerView#initializeViews learns about the container -* Improve Ember.View#createChildView container support -* Ensure assertion failures are test failures. -* Fix failing tests for non-blocking assertions -* Make the test suite work with non-blocking assertions -* Utilize the browser console.assert when possible -* Added custom test helper for testing assertions: expectAssertion -* Ember assertions work more like console.assert e.g. they are now uncatchable -* Update ember-dev -* Visit helper update router url before handling it -* Moved set of events to listen on by default to a property of EventDispatcher so it can be overridden -* Fix typo in array mixin docs -* Clarify subclasses of Ember.CoreView #2556 -* Fix naming of _displayPropertyDidChange in comment -* Assert keyName not null and not undefined in get() and set() -* Add `debounce` to Ember.run. Uses `backburner.debounce` -* Cleaned up a bad check inside of `Ember.View._hasEquivalentView` that was causing routes with the same template and controller, but different view classes, not to render. -* Add documentation and test for Ember.Handlebars.helper -* Fix ember-dev s3 push. -* Fix App#reset to correctly reset even when Router.map was never called. -* Added test case that the render helper throws when a controller name doesn't resolve -* Release tooling improvements -* Adds assertion for misnamed controller name provided to render helper. [Fixes #2385] - -*Ember 1.0.0-rc.5 (June 01, 2013)* - -* Added assertion for incorrect container lookup names -* adding docs for Ember.beforeObserver -* Remove ember-testing from production build -* Fixed bug with promises on startup. Fixes #2756. -* sync router.js fixes App#reset in ember-testing issue -* Notes that replaceWith only works with 'history' - Fixes #2744 -* Fix failing tests in IE7 by normalizing URL -* Update backburner to fix IE8 failing test -* Update Backburner.js fixing the performance regression introduce in rc4 -* maintain ruby'esq version string for gems -* remove starter_kit upload task (we just use the github tarbals) - -*Ember 1.0.0-rc.4 (May 27, 2013)* - -* Loader: improve missing module error message -* Fix click test helper selector context -* fixes #2737: 'In the Router, if ApplicationController is an ObjectController, currentPath is proxied to the content.' -* Update backburner with autorun release -* use Ember.run.join internally for App#reset -* Add Ember.run.join -* Include 1.10 in jQuery version check -* Fix to ignore internal property in `Ember.keys` -* ensure willDestroy happens in action queue so live objects have a chance to respond to it before destroy -* Fix view leak (issue #2712) -* Added logging of view lookups -* App learns to LOG_ACTIVE_GENERATION -* Added support for calling multiple async test helpers concurrently -* fix misleading docs [fixes https://github.com/emberjs/website/issues/485] -* Added the ability to chain test helpers -* BREAKING: Move setting controller's `model` into setupController -* Updated ember-latest jsbin starting point URL -* Documentation for ComputedProperty cachable -* Mask deprecation warning in metaPath testing -* mask deprecation warnings (when knowingly triggering them) -* Deprecate Ember.metaPath -* Treat {{#each}} as {{#each this}} -* Set actions as the default run loop queue -* Replace Ember.RunLoop with Backburner.js -* Deactivate route handlers before destroying container in App.reset() - Upgrade router.js micro-framework -* Create Test Adapter to keep ember-testing framework agnostic -* Simplify not-null-or-undefined checks -* [fixes #2697] -* update doc example to current router -* Ember.computed learns oneWay computed -* Find helper now throws when element not found and added selector context -* Fix downloads link for starter-kit -* Move /** @scope */ comments inline to their extend calls -* fixing JSON syntax error and upgrading ember-handlebars-compiler dependency to 1.0.0-rc.3 -* Documentation: fix code block of Ember.String.capitalize -* Ember.Deferred now handles optional then handlers. -* upgrade ember-dev -* App#reset now only brings it's own run-loop if needed. -* gitignore bundler/* this allows for a local bundle --standalone -* Small corrections to Route.events documentation. -* Add assertion about setting the same current view to multiple container views -* Remove SC compatibility in Ember.Array -* Document and add assertion reflecting that helpers created with registerBoundHelper don't support invocation with Handlebars blocks. -* Trigger change in fillIn helper in ember testing -* Fix undefined error when promise rejected on startup -* Ember testing capture exceptions thrown in promises -* Rewrite `EMBER_VERSION` with `Ember::VERSION` -* Fix docs to use extend instead of create when setting observers -* Makes partial helper only lookup the deprecated template name if the first try is unsuccessful. -* Removed duplicate test for normalizeTuple -* Ember testing update url in visit helper -* bump RSVP (it now has RSVP.reject) -* Make parentController available from an itemController -* Stop unnecessary `jQuery.fn` extension -* Include `Ember::VERSION` in 'ember-source' gem -* Create Ember.Test with registerHelper method -* Improve {{render}} docs. -* Don't add disabled class if disabledWhen not provided -* More accurate, helpful error message for handlebars version errors. -* Adds disabledWhen option to {{linkTo}} helper -* Clean up pendingDisconnections propertly -* Make router's render idempotent -* Switch from bind to on for routing handlers. -* Switch from delegate/undelegate to on/off for EventDispatcher. -* Remove IE specified test -* Adding regression test -* Remove unused helper function -* This function is already defined as `set` -* Deferred self rejection does not need special handling -* Fix rejecting a deferred with itself -* Fix CollectionView.arrayDidChange documentation -* ember-testing: Make wait a promise and a helper -* tests on chained helpers added ember-testing for running in qunit -* Added `routeTo` for event-based transitions -* Prevent unnecessary re-rendering when only route context has changed -* Add test for visit helper in ember testing -* Reduce the polling interval to make tests run much faster -* Update route-recognizer - Fixes #2559 -* Revert "Use isNone to check tag name" -* Support for redirection from ApplicationRoute -* Improving Ember.Select's null-content regresion test -* Prevent another exception on empty Ember.Select.content -* prevent exception on empty Em.Select content -* deprecate the defaultContainer (see: http://git.io/EKPpnA) -* RSVP is now promise/a+ 1.1 compliant -* Fix test for setTimeout with negative wait for older IE -* Use `Function.prototype.apply` to call `setTimeout` on older IE -* Use Ember.isNone -* Fixed view subclasses being instrumented as render.render.* -* Fixes #2526 - Updates JsFiddle and JsBin links for rc.3 -* Add tests to deferred mixin -* Allow missing whitespace for assertion fot html text -* Fix incrementProperty/decrementProperty to be able to use with 0 -* RSVP2 -* Adds the ability to specify the view class used by the outlet Handlebars helper -* Make view helpers work with bindings -* get of property in false values should return undefined -* Really normalize hash params this time -* Normalize Ember.Handlebars.helper hashes -* Fix bug with Ember.Handlebars.helper -* Ember.EventDispatcher is now container managed. -* typeInjection's public api is via injection -* App#reset now triggers a eventDispatcher teardown -* Added docs of ArrayContentDidChange for array -* Move linkTo docs to helper instead of LinkView -* Use tag name supported by html 4 -* Fix to use `Ember.ArrayPolyfills.forEach` -* Switch assertion for simulated Ember.create -* document {{input}} and {{textarea}} helpers -* convert bools to flags so it is easier to add new ones -* Fix to use `Ember.ArrayPolyfills.forEach` for IE8 -* Skip Object.getOwnPropertyDescriptor only IE8 -* Use stub `Object.create` for IE8 -* Force downcase tag name for IE8 -* rake release:gem + some cleanup -* Reduce late time to less than resolution capability of `setTimeout` -* Kepp timers order -* Adjust wait time to tick next run loop for more browsers -* additional Controller#needs documentation -* make use of Ember.isNone explicit in Ember.isEmpty -* Added API docs for 'needs' property of controller -* Use isNone to check tag name -* Added length property to Ember.Map - -*Ember 1.0.0-rc.3 (April 19, 2013)* - -* fn.call is wasteful when the thisArg is not needed. -* dont needlessly close-over and rebuild insertViewCollection -* Don't apply href to LinkView that isn't using 'a' tag -* Documents {{linkTo}} -* Include ember-testing in full build -* Use `jQuery.is(':disabled')` instead of `jQuery(':disbled').length` for Opera -* Remove assigned but unused variable -* Document run.scheduleOnce, truncate run.once docs. Fixes #2132. -* fix failing tests for outerHTML fallback -* don't rely on EXTEND_PROTOTYPES == true -* Fixes Ember.EnumerableUtils without extend prototypes -* Do not flag .generateController for documentation. -* Do not build the docs for `.cachable`. Fixes #2329. -* cleanup MutableEnumerable documentation -* Add Ember.Application#removeTestHelpers -* Fix a couple issues -* First pass of work for the ember-testing package -* Fixes error in documentation referring to non-existent 'Customizing Your Bindings' section -* Fix method comments -* Fix redirecting to child routes -* Fixes to MetamorphView's DOMManager replace -* Fixes #870 Lazy destruction + App#reset issues -* Eliminate unused variables -* Point to updated preconfigured starting points for JSFiddle/JSBin with latest Ember build that is now being auto-posted to builds.emberjs.com -* Fixes #2388: Added if statement to _resetSubControllers -* scope cached state transition hashes to the state manager class, so extending and mixins work with StateMangers as expected -* Fixes for upload of published builds. -* Update to latest ember-dev so that publish task can work properly -* Configure Travis for automatic deploy to AWS -* Add missing item type -* Do no emit Ember.alias deprecation warnings during alias tests -* add invokeRecursively to ViewCollection -* Failing test showing StateManagers using mixins to get some of their states have unexpected behavior -* Fix HistoryLocation rootURL handling and webkit workaround -* Remove unused argument from helper functions -* Use `toArray` to remove duplication -* Allow option view for Ember.Select overwritable -* Actually make Ember.alias() print deprecation warnings. -* use ``Ember.String.fmt`` instead of String extension -* automatically upload all passing builds to s3 -* [Fixes #2424] App#reset -* s/nexts/these (nexts is not a word) -* More verbose error message on failed linkTo routing attempts -* viewName is a property -* remove uneeded closures -* JSDoc should use {*} for mixed types instead of {anything} and {any} -* add an "includeSelf" parameter to "invokeRecursively" -* Fix ArrayController#length when content is not explicitly set -* Close #2043 - fix issue with removing last element in collection -* Stop application template from duplicating on re-render -* assertion to catch mixins being passed to Object.create -* Enhance Ember.TargetActionSupport and introduce Ember.ViewTargetActionSupport -* fix {{textarea}} assert message -* Test for unwatch methods on object length property -* Tests for watch methods on length properties -* Test for isWatching on length property of an object -* Move Ember.typeOf to metal -* Fix array watching issue. Was affecting more than just plain arrays due to differences between typeOf and isArray. -* Remove mention of passing mixins to create. -* Revert "Fix Application#reset destroy issue" -* Fix view helper documentation and example to reflect context -* Ignore webkitStorageInfo during namespace lookup to avoid warning -* Fix Application#reset destroy issue -* Make Chrome initial popstate workaround account for rootURL -* Use a string instead of an array in RenderBuffer -* Convert a for in loop to a plain for loop -* Improve view container lookup performance -* remove uneeded asynchrony from Ember.Deferred tests -* remove unneeded asynchrony from routing tests -* Add {{text area}} -* Default text input action to 'enter' -* Add {{input action="foo" on="keyPress"}} -* More metal cleanup -* Better organize ember-metal and cache function lookups. -* remove sync from render to buffer -* make tests not depend on synchronous change events -* fix test not to expect synchronous observers -* Define Mixin properties in prototype -* Update ember-dev gem to latest version -* Share empty arrays in Ember.View prototype. Lazily slice it upon manipulation. -* Add views to Ember.View.views upon insertion in DOM rather than on init. Fixes #1553 -* Make object destruction async so we can reduce churn when destroying interconnected object graphs. -* Define Ember.CoreObject#willDestroy. Fixes #1438. -* cleanup unneeded volatile() -* Match the transitionTo APIs. -* Avoid recursively calling transitionTo. -* Improve the performance of view notifications and transitions. -* Extract a private ViewCollection class to aid in manipulating several views at once. -* Add support for {{input type="checkbox"}} -* Add Ember.Handlebars.helper -* Add {{input type="text"}} -* Insert adjacent child views in batches rather than individually. - -*Ember 1.0.0-rc.2 (March 29, 2013)* - -* Improved the App initialization process and deprecated Ember.Application#initialize. If you were using this, use deferReadiness and advanceReadiness instead. -* Added support for Ember.Application#then which fires similarly to the isReady hook -* Added more Ember.computed macros -* Added readOnly flag for computed properties -* Enumerable#compact now removes undefined values -* Fixed issue with unregistering actions on virtual views -* Make Ember.LinkView public -* Add support for jQuery 2.0 -* Support browsers (FF 10 or less) that don't support domElement.outerHTML -* Made it easier to augment the Application's container's resolver -* Support tag as an alias for tagName in the {{view}} helper -* Add 'name' to attributeBinding for Ember.TextField and Ember.Select -* Return merged object from Ember.merge -* Deprecate setting tagNames on Metamorphs - Refs #2248 -* Avoid parent's implicit index route clobbering child's explicit index. -* App#reset behaves more closely to App#create -* Make Evented#on, #off, and #one chainable -* Add basic implementation of allowedKeys for the {{action}} helper -* Improved Ember.Array#slice implementation -* Fix ArrayProxy arrangedObject handling - Fixes #2120, #2138 -* Added ability to customize default generated controllers and routes -* Better HistoryLocation popstate handling - Fixes #2234 -* Fix an issue with IE7 -* Normalized Ember.run.later and Ember.run.next behavior. -* Fix issue where classNameBindings can try to update removed DOM element. -* Ember.Array methods always return Ember.Arrays -* RSVP is now exposed as Ember.RSVP -* ObjectProxy does not attempt to proxy unknown properties on create -* Can now set ENV.LOG_VERSION to false to disable version logging -* Ember.ArrayController#lastObject no longer raises when empty -* Fixes to {{render}} helper when used with model -* Improvements to {{linkTo}} controller handling -* Fix {{bindAttr}} when targeting prop in {{#each prop in array}} - #1523 -* String#camelize lowercases the first letter -* Other miscellaneous bug fixes and documentation improvements - -*Ember 1.0.0-rc.1 (February 15, 2013)* - -* Upgrade to Handlebars 1.0.0-rc.3 -* Update RSVP.js -* Update router.js -* Support 0 values for input tags -* Support for jQuery 1.9 -* ArrayController now defaults to empty array -* Added Vagrant support for setting up a development environment -* Adds {{each itemController="..."}} -* Fix issues where route transitions would not register properly -* Initial support for Application#reset -* Fix handling of keywords in bind helpers -* Better handling of DOM properties -* Better handling of complex {{#if}} targets -* {{linkTo}} shouldn't change view context -* Router#send accepts multiple params -* Provide a view's template name for debugging -* Create activate and deactivate hooks for router -* {{action}} targets are now looked up lazily -* The model for Route#render is now bound -* Improvements to ContainerView -* Added 'pattern' attribute to text field for iOS. -* CollectionView context is now its content -* Various enhancements to bound helpers: adds multiple property support to bound helpers, adds bind-able options hash properties, adds {{unbound}} helper support to render unbound form of helpers. -* Add App.inject -* Add Ember.EnumberableUtils.intersection -* Deprecate Controller#controllerFor in favour of Controller#needs -* Adds `bubbles` property to Ember.TextField -* Allow overriding of Ember.Router#handleURL -* Allow libraries loaded before Ember to tie into Ember load hooks -* Fixed behavior with Route#render and named outlets -* Fix bug where history location does not account for root URL -* Allow redirecting from mid-route -* Support string literals as param for {{linkTo}} and {{action}} -* Empty object proxies are no longer truthy in {{#if}} - -*Ember 1.0.0-pre.4 (January 17, 2013)* - -* Add {{partial}} -* Fix regressions in router.js -* Support jQuery 1.9.0 -* Use the controller with the same name as the template passed to render, if it exists - -*Ember 1.0.0-pre.3 (January 17, 2013)* - -* BREAKING CHANGE: New Router API -* BREAKING CHANGE: `Ember.Object.create` behaves like `setProperties`. Use `createWithMixins` for the old behavior. -* BREAKING CHANGE: No longer default a view's context to itself -* BREAKING CHANGE: Remove the nearest view computed properties -* Significant performance improvements -* Bound handlebars helpers with `registerBoundHelper` -* Ember.String improvements -* TextSupport handles input, cut, and paste events -* Add `action` support to Ember.TextField -* Warn about using production builds in localhost -* Update Metamorph -* Deprecate Ember.alias in favour of Ember.aliasMethod -* Add Ember.computed.alias -* Allow chaining on DeferredMixin#then -* ArrayController learned itemControllerClass. -* Added VagrantFile and chef cookbooks to ease ember build for developers. -* Provide an Ember.Handlebars precompilation package -* Removed Tab controls -* Fix Chrome (pre v25) MutationObserver Memory Leak -* Update to Promises/A+ compatible RSVP -* Improved instrumentation -* Rename empty to isEmpty and none to isNone -* Added support for toStringExtension to augment toString -* Implement a default computed property setter. -* Add support for unhandledEvent to StateManager. -* Load external dependencies via an AMD shim -* Pass in the old value into the CP as a third argument -* Deep copy support for NativeArray -* Added an afterRender queue for scheduling code to run after the render queue has been drained -* Implement _super() for computed properties -* Miscellaneous bug fixes -* General cleanup - -*Ember 1.0.0-pre.2 (October 25, 2012)* - -* Ember.SortableMixin: don't remove and reinsert items when their sort order doesn't change. Fixes #1486. -* Fix edge cases with adding/removing observers -* Added 'disabled' attribute binding to Select -* Deprecate usage of {{collection}} without a class in favor of {{each}} -* Changing `Ember.Handlebars.getPath` to `Ember.Handlebars.get` for consistency. This addresses #1469. -* Since `$.uuid` was removed from jQuery master, we're switching to using `Ember.uuid` instead. -* Add Ember.View#nearestOfType, deprecate nearestInstanceOf -* Adds support for globbed routes -* Remove CP_DEFAULT_CACHEABLE flag -* Remove VIEW_PRESERVES_CONTEXT flag -* Replace willRerender with willClearRender -* Bumped jQuery requirement to 1.7.2+, explicitly forbidding 1.7 and 1.7.1 (see: #1448) -* Add Ember.String.classify() to string extensions -* HistoryLocation now utilizes history.replaceState -* Add a basic instrumentation API -* Allow extension of chosen prototypes instead of the current all or none. -* Remove dependency on `window` throughout Ember -* Don't attempt to concat a concatenatedProperty onto an object that doesn't have a concat method -* Remove ember-views dependency from ember-states -* Multiselect updates array content in place. -* Support applications without a router -* Add Ember.Deferred mixin which implements promises using RSVP.js -* Fix for popstate firing on page load. -* Fixed bug in CP setter where observers could be suspended and never restored. -* Fixed a bug with setting computed properties that modify the passed in value. -* Initial work to allow operation with handlebars runtime only -* A listener registered with one can be removed with off -* Calling removeListener without method should remove all listeners -* Add autoinit flag to Application to call initialize on DOM ready. -* Create view for application template if no ApplicationView. -* Remove support for inline anonymous templates. -* Rename createRouter to setupRouter to make clear. -* Extract createRouter from Application#initialize -* Extract runInjections from Application#initialize -* Simplify syntax so we can extract more easily -* Extract createEventDispatcher from Application#init -* Update for Handlebars 1.0.rc.1 -* Fix State.transitionTo to handle multiple contexts -* Cleanup classNameBindings on remove -* Support defining injections to occur after other injections -* Computed prop setter improvements -* fix :: syntax in classNameBindings to work with falsy values -* Fix Ember.Error properties -* Improved error handling with Ember.onerror -* Adds currentPath to Ember.StateManager -* Provide default args to tryInvoke - fixes #1327 -* Fix a bug in multi-selects with primitive options -* Fix formatURL to use rootURL and remove formatPath -* Fixing Ember.Router.route when rootURL is used -* ContainerViews should invalidate `element` on children when rendering. -* Add test for selecting in multi selects with prompts -* Fix: Passing a regex to split in IE8 returns a single item array, causing class names beginning with a colon to fail to render in IE8. -* Adding itemViewClass attribute to the each helper. -* Reorganize load hooks to be more sane -* Improve application readiness framework -* Small restructuring of ArrayProxy -* Add #setObjects to mutable array. A helper for replacing whole content of the array with a new one. -* Fixed selecting items in ember multi-selects -* Add disconnectOutlet method to controller -* The content property of an ArrayProxy instance should be defined before modifying it -* Adds a has() method to Ember.OrderedSet -* Adds hooks for suspending observers -* Check that a controller inherits from Ember.Object before instantiating it to the router. -* Support jQuery 1.8 - fixes #1267 -* Ember.empty returns true if empty Ember.ArrayProxy -* add scheduleOnce and remove flag -* add various lifecycle tests to check updated ContainerView path. Expose problem with flag for scheduling one time. -* Moving location tests to routing package -* Make outlet a Metamorph view -* Tests showing problem with adding and replacing -* refactor ContainerView children rendering to not make assumptions at scheduling time, just at render time. -* Remove remaining references to viewstates -* Select element should initialize with the correct selectedIndex when using valueBinding -* Remove deprecated Ember.ViewState. -* Handle undefined element in bindAttr and classNameBindings -* Render now uses context instead of _context -* Better version replacement regexp -* Outlets reference context instead of controller. -* Rakefile :clean remove 'tmp' folder -* Performance improvements - -*Ember 1.0.pre (August 03, 2012)* - -* Return undefined instead of empty jQuery object for Ember.View#$ when not in DOM -* Adds didDefineProperty hook -* Implement immediateObserver placeholder in preparation for making observers asynchronous -* Change {{action}} API for more explicit contexts -* Add connectControllers convenience -* Assert that transitionTo at least matched a state -* Delay routing while contexts are loading -* Also rename trySetPath to trySet -* Replaced getPath/setPath with get/set -* Remove LEGACY_HANDLEBARS_TAG flag -* Add two new core methods to allow invoking possibly unknown methods on objects -* Change ternary syntax to double colon sytax -* Add tests for ternary operator in class bindings -* Test for defined Router lacking App(View|Controller) -* Allow alternate clicks for href handling - Fixes #1096 -* Respect initialState when transitioning to parent of current state - Fixes #1144 -* add reverseObjects -* Fixing rootURL when path is empty -* HistoryLocation appends paths to router rootURL -* Make Ember.Logger support the 'info' and 'debug' methods on fallback (for IE8). -* Support currentView on init if ContainerView is created with one -* {{bindAttr class="this"}} now works; fixes #810 -* Allow connectOutlet(outletName, name, context) syntax -* turn on mandatory setter for ember-debug if not set -* Change the default setUnknownProperty to define it before setting. -* {{view}} now evaluates the context of class bindings using the same rules applied to other bindings -* dataTransfer property for drag and drop events -* require jQuery 1.7, no longer accept 1.6 -* add mandatory setter assertion -* Add date comparison to Ember.compare -* We use jquery event handling for hashchange/popstate -* Deprecate Ember.Tabs - Fixes #409 -* Remove data-tag-name "feature" from -``` - -Here's the best part: templates are bindings-aware. That means that if -you ever change the value of the property that you told us to display, -we'll update it for you automatically. And because you've specified -dependencies, changes to *those* properties are reflected as well. - -Hopefully you can see how all three of these powerful tools work -together: start with some primitive properties, then start building up -more sophisticated properties and their dependencies using computed -properties. Once you've described the data, you only have to say -how it gets displayed once, and Ember.js takes care of the rest. It -doesn't matter how the underlying data changes, whether from an XHR -request or the user performing an action; your user interface always -stays up-to-date. This eliminates entire categories of edge cases that -developers struggle with every day. - -# Getting Started - -For new users, we recommend downloading the [Ember.js Starter -Kit](https://github.com/emberjs/starter-kit/tags), which includes -everything you need to get started. +- [Website](http://emberjs.com) +- [Guides](http://emberjs.com/guides) +- [API](http://emberjs.com/api) +- [Community](http://emberjs.com/community) +- [Blog](http://emberjs.com/blog) +- [Builds](http://emberjs.com/builds) # Building Ember.js -NOTE: Due to the rename, these instructions may be in flux - -1. Run `bundle install` to fetch the necessary ruby gems. -2. Run `rake dist` to build Ember.js. Two builds will be placed in the `dist/` directory. - * `ember.js` and `ember.min.js` - unminified and minified builds of Ember.js - -If you are building under Linux, you will need a JavaScript runtime for -minification, for which we recommend installing nodejs. Alternatively -you may have luck with another of the runtimes supported by -[execjs](https://github.com/sstephenson/execjs). +1. Ensure that [Node.js](http://nodejs.org/) is installed. +2. Run `npm install` to ensure the required dependencies are installed. +3. Run `npm run build` to build Ember.js. The builds will be placed in the `dist/` directory. # Contribution -[See](https://github.com/emberjs/ember.js/blob/master/CONTRIBUTING.md) +See [CONTRIBUTING.md](https://github.com/emberjs/ember.js/blob/master/CONTRIBUTING.md) # How to Run Unit Tests -## Setup - -1. Install Ruby 1.9.3+. There are many resources on the web can help; -one of the best is [rvm](https://rvm.io/). - -2. Install Bundler: `gem install bundler` +1. Follow the setup steps listed above under [Building Ember.js](#building-emberjs). -3. Run `bundle` inside the project root to install the gem dependencies. +2. To start the development server, run `npm start`. -## In Your Browser +3. To run all tests, visit . -1. To start the development server, run `rackup`. - -2. Then visit: `http://localhost:9292/?package=PACKAGE_NAME`. Replace -`PACKAGE_NAME` with the name of the package you want to run. For +4. To test a specific package, visit `http://localhost:4200/tests/index.html?package=PACKAGE_NAME`. Replace +`PACKAGE_NAME` with the name of the package you want to test. For example: - * [Ember.js Runtime](http://localhost:9292/?package=ember-runtime) - * [Ember.js Views](http://localhost:9292/?package=ember-views) - * [Ember.js Handlebars](http://localhost:9292/?package=ember-handlebars) - -To run multiple packages, you can separate them with commas. You can run -all the tests using the `all` package: + * [Ember.js Runtime](http://localhost:4200/tests/index.html?package=ember-runtime) + * [Ember.js Views](http://localhost:4200/tests/index.html?package=ember-views) + * [Ember.js Handlebars](http://localhost:4200/tests/index.html?package=ember-handlebars) - +To test multiple packages, you can separate them with commas. You can also pass `jquery=VERSION` in the test URL to test different -versions of jQuery. Default is 1.9.0. +versions of jQuery. ## From the CLI -1. Install phantomjs from http://phantomjs.org +1. Install phantomjs from http://phantomjs.org. -2. Run `rake test` to run a basic test suite or run `rake test[all]` to +2. Run `npm test` to run a basic test suite or run `TEST_SUITE=all npm test` to run a more comprehensive suite. -3. (Mac OS X Only) Run `rake autotest` to automatically re-run tests - when any files are changed. - -# Building API Docs - -The Ember.js API Docs provide a detailed collection of methods, classes, -and viewable source code. - -NOTE: Requires node.js to generate. - -See for annotated introductory documentation. - -## Preview API documentation - -* Clone https://github.com/emberjs/website.git at the same level as the - main Ember repo. - -* From the website repo, run `rake preview` - -* The docs will be available at - - -## Build API documentation - -* From the website repo, run `rake build` - -* The website, along with documentation will be built into the `build` - directory - diff --git a/Rakefile b/Rakefile index 7facda9c37c..30870514bf2 100644 --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,9 @@ require 'bundler/setup' -require 'ember-dev/tasks' require './lib/ember/version' require 'zlib' +require 'fileutils' +require 'pathname' +require 'json' ### RELEASE TASKS ### @@ -12,7 +14,7 @@ namespace :release do end task :gem do - sh "rakep" + sh 'npm run-script build' sh 'gem build ember-source.gemspec' sh "gem push ember-source-#{Ember::VERSION.gsub('-','.')}.gem" end @@ -51,7 +53,7 @@ namespace :release do mkdir_p "tmp" cd("tmp") do - sh "git clone https://github.com/emberjs/starter-kit.git" + sh "git clone git@github.com:emberjs/starter-kit.git" end end @@ -155,19 +157,3 @@ namespace :release do desc "Deploy a new Ember release" task :deploy => ['ember:release:deploy', 'starter_kit:deploy', 'website:deploy'] end - -task :publish_build => :dist do - root = File.dirname(__FILE__) + '/dist/' - EmberDev::Publish.to_s3({ - :access_key_id => ENV['S3_ACCESS_KEY_ID'], - :secret_access_key => ENV['S3_SECRET_ACCESS_KEY'], - :bucket_name => ENV['S3_BUCKET_NAME'], - :files => ['ember.js', 'ember-runtime.js'].map { |f| root + f }, - :exclude_minified => [ 'ember.prod.js' ].map { |f| root + f } - }) -end - -task :clean => "ember:clean" -task :dist => "ember:dist" -task :test, [:suite] => "ember:test" -task :default => "ember:test" diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md new file mode 100644 index 00000000000..da73ad68de3 --- /dev/null +++ b/STYLEGUIDE.md @@ -0,0 +1,383 @@ +# Ember.js JavaScript Style Guide + +## Table Of Contents + ++ [Objects](#objects) ++ [Array](#arrays) ++ [Variables](#variables) ++ [Whitespace](#whitespace) ++ [Commas](#commas) ++ [Semicolons](#semicolons) ++ [Block Statements](#block-statements) ++ [Conditional Statements](#conditional-statements) ++ [Properties](#properties) ++ [Functions](#functions) ++ [Arrow Functions](#arrow-functions) ++ [Function Arguments](#function-arguments) ++ [Rest Parameters](#rest-parameters) ++ [Destructuring](#destructuring) ++ [Comments](#comments) + +## Objects + ++ Use literal form for object creation. + +```javascript +var foo = {}; +``` + ++ Pad single-line objects with white-space. + +```javascript +var bar = { color: 'orange' }; +``` + +## Arrays + ++ Use literal form for array creation (unless you know the exact length). + +```javascript +var foo = []; +``` + ++ If you know the exact length and know that array is not going to grow, use `Array`. + +```javascript +var foo = new Array(16); +``` + ++ Use `push` to add an item to an array. + +```javascript +var foo = []; +foo.push('bar'); +``` + +## Variables + ++ Put all non-assigning declarations on one line. + +```javascript +var a, b; +``` + ++ Use a single `var` declaration for each assignment. + +```javascript +var a = 1; +var b = 2; +``` + ++ Declare variables at the top of their scope. + +```javascript +function foo() { + var bar; + + console.log('foo bar!'); + + bar = getBar(); +} +``` + +## Whitespace + ++ Use soft tabs set to 2 spaces. + +```javascript +function() { +∙∙var name; +} +``` + ++ Place 1 space before the leading brace. + +```javascript +obj.set('foo', { + foo: 'bar' +}); + +test('foo-bar', function() { +}); +``` + ++ No spaces before semicolons. + +```javascript +var foo = {}; +``` + ++ Keep parenthesis adjacent to the function name when declared or called. + +```javascript +function foo() { +} + +foo(); +``` + +## Commas + ++ Skip trailing commas. + +```javascript +var foo = [1, 2, 3]; +var bar = { a: 'a' }; +``` + ++ Skip leading commas. + +```javascript +var foo = [ + 1, + 2, + 3 +]; +``` + +## Semicolons + ++ Use semicolons. + +## Block Statements + ++ Use spaces. + +```javascript +// conditional +if (notFound) { + return 0; +} else { + return 1; +} + +switch (condition) { + case 'yes': + // code + break; +} + +// loops +for (var key in keys) { + // code +} + +for (var i = 0, l = keys.length; i < l; i++) { + // code +} + +while (true) { + // code +} + +try { + // code that throws an error +} catch(e) { + // code that handles an error +} +``` + ++ Opening curly brace should be on the same line as the beginning of a statement or declaration. + +```javascript +function foo() { + var obj = { + val: 'test' + }; + + return { + data: obj + }; +} + +if (foo === 1) { + foo(); +} + +for (var key in keys) { + bar(e); +} + +while (true) { + foo(); +} +``` + ++ Keep `else` and its accompanying braces on the same line. + +```javascript +if (foo === 1) { + bar = 2; +} else { + bar = '2'; +} + +if (foo === 1) { + bar = 2; +} else if (foo === 2) { + bar = 1; +} else { + bar = 3; +} +``` + +## Conditional Statements + ++ Use `===` and `!==`. ++ Use curly braces. + +```javascript +if (notFound) { + return; +} +``` + ++ Use explicit conditions. + +```javascript +if (arr.length > 0) { + // code +} + +if (foo !== '') { + // code +} +``` + +## Properties + ++ Use dot-notation when accessing properties. + +```javascript +var foo = { + bar: 'bar' +}; + +foo.bar; +``` + ++ Use `[]` when accessing properties with a variable. + +```javascript +var propertyName = 'bar'; +var foo = { + bar: 'bar' +}; + +foo[propertyName]; +``` + +## Functions + ++ Make sure to name functions when you define them. + +```javascript +function fooBar() { +} +``` +## Arrow Functions + ++ Make sure arrow functions are done on multiple lines. + +```javascript +var foo = [1,2,3,4].map((item) => { + return item * 2; +}); +``` + +## Function Arguments + +`arguments` object must not be passed or leaked anywhere. +See the [reference](https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#3-managing-arguments). + ++ Use a `for` loop with `arguments` (instead of `slice`). + +```javascript +function fooBar() { + var args = new Array(arguments.length); + + for (var i = 0; i < args.length; ++i) { + args[i] = arguments[i]; + } + + return args; +} +``` + ++ Don't re-assign the arguments. + +```javascript +function fooBar() { + arguments = 3; +} + +function fooBar(opt) { + opt = 3; +} +``` + ++ Use a new variable if you need to re-assign an argument. + +```javascript +function fooBar(opt) { + var options = opt; + + options = 3; +} +``` + +## Rest Parameters + +Since [Babel implements](https://babeljs.io/repl/#?experimental=true&playground=true&evaluate=true&loose=false&spec=false&code=function%20foo\(...args\)%20%7B%0A%20%20%0A%7D) Rest parameters in a non-leaking matter you should use them whenever applicable. + +```javascript +function foo(...args) { + args.forEach((item) => { + console.log(item); + }); +} +``` + +## Destructuring + +When decomposing simple arrays or objects, prefer [destructuring](http://babeljs.io/docs/learn-es6/#destructuring). + +```javascript +// array destructuring +var fullName = 'component:foo-bar'; +var [ + first, + last +] = fullName.split(':'); +``` + +```javascript +// object destructuring +var person = { + firstName: 'Stefan', + lastName: 'Penner' +} + +var { + firstName, + lastName +} = person; +``` + + +## Comments + ++ Use [YUIDoc](http://yui.github.io/yuidoc/syntax/index.html) comments for + documenting functions. ++ Use `//` for single line comments. + +```javascript +function foo() { + var bar = 5; + + // multiplies `bar` by 2. + fooBar(bar); + + console.log(bar); +} +``` diff --git a/VERSION b/VERSION index 3eefcb9dd5b..227cea21564 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +2.0.0 diff --git a/Vagrantfile b/Vagrantfile deleted file mode 100644 index 87cc3808767..00000000000 --- a/Vagrantfile +++ /dev/null @@ -1,16 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -Vagrant::Config.run do |config| - config.vm.box = "precise64-ruby-1.9.3-p194" - config.vm.box_url = "https://dl.dropbox.com/u/14292474/vagrantboxes/precise64-ruby-1.9.3-p194.box" - - # We need a javascript runtime to build ember.js with rake - # and phantomjs to execute test suite. - # - config.vm.provision :chef_solo do |chef| - chef.cookbooks_path = "cookbooks" - chef.add_recipe "nodejs::install_from_source" - chef.add_recipe "phantomjs" - end -end diff --git a/benchmarks/README.md b/benchmarks/README.md deleted file mode 100644 index fbd0bf97734..00000000000 --- a/benchmarks/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Extremely simple Ember benchmarks - -To run the benchmarks, serve the repository root on a web server (`gem install -asdf; asdf`), run `rake` to build Ember, and open e.g. -`http://localhost:9292/benchmarks/index.html?suitePath=plain_object.js` to run -`benchmarks/suites/plain_object.js`. Run `cp -r dist distold` to benchmark -different versions against each other. diff --git a/benchmarks/benchmark.js b/benchmarks/benchmark.js deleted file mode 100644 index fcb422c9e9e..00000000000 --- a/benchmarks/benchmark.js +++ /dev/null @@ -1,3833 +0,0 @@ -/*! - * Benchmark.js v1.0.0-pre - * Copyright 2010-2012 Mathias Bynens - * Based on JSLitmus.js, copyright Robert Kieffer - * Modified by John-David Dalton - * Available under MIT license - */ -;(function(window, undefined) { - 'use strict'; - - /** Used to assign each benchmark an incrimented id */ - var counter = 0; - - /** Detect DOM document object */ - var doc = isHostType(window, 'document') && document; - - /** Detect free variable `define` */ - var freeDefine = typeof define == 'function' && - typeof define.amd == 'object' && define.amd && define; - - /** Detect free variable `exports` */ - var freeExports = typeof exports == 'object' && exports && - (typeof global == 'object' && global && global == global.global && (window = global), exports); - - /** Detect free variable `require` */ - var freeRequire = typeof require == 'function' && require; - - /** Used to crawl all properties regardless of enumerability */ - var getAllKeys = Object.getOwnPropertyNames; - - /** Used to get property descriptors */ - var getDescriptor = Object.getOwnPropertyDescriptor; - - /** Used in case an object doesn't have its own method */ - var hasOwnProperty = {}.hasOwnProperty; - - /** Used to check if an object is extensible */ - var isExtensible = Object.isExtensible || function() { return true; }; - - /** Used to access the browser's high resolution timer */ - var perfObject = isHostType(window, 'performance') && performance; - - /** Used to call the browser's high resolution timer */ - var perfName = perfObject && ( - perfObject.now && 'now' || - perfObject.mozNow && 'mozNow' || - perfObject.msNow && 'msNow' || - perfObject.oNow && 'oNow' || - perfObject.webkitNow && 'webkitNow' - ); - - /** Used to check if an own property is enumerable */ - var propertyIsEnumerable = {}.propertyIsEnumerable; - - /** Used to set property descriptors */ - var setDescriptor = Object.defineProperty; - - /** Used to resolve a value's internal [[Class]] */ - var toString = {}.toString; - - /** Used to prevent a `removeChild` memory leak in IE < 9 */ - var trash = doc && doc.createElement('div'); - - /** Used to integrity check compiled tests */ - var uid = 'uid' + (+new Date); - - /** Used to avoid infinite recursion when methods call each other */ - var calledBy = {}; - - /** Used to avoid hz of Infinity */ - var divisors = { - '1': 4096, - '2': 512, - '3': 64, - '4': 8, - '5': 0 - }; - - /** - * T-Distribution two-tailed critical values for 95% confidence - * http://www.itl.nist.gov/div898/handbook/eda/section3/eda3672.htm - */ - var tTable = { - '1': 12.706,'2': 4.303, '3': 3.182, '4': 2.776, '5': 2.571, '6': 2.447, - '7': 2.365, '8': 2.306, '9': 2.262, '10': 2.228, '11': 2.201, '12': 2.179, - '13': 2.16, '14': 2.145, '15': 2.131, '16': 2.12, '17': 2.11, '18': 2.101, - '19': 2.093, '20': 2.086, '21': 2.08, '22': 2.074, '23': 2.069, '24': 2.064, - '25': 2.06, '26': 2.056, '27': 2.052, '28': 2.048, '29': 2.045, '30': 2.042, - 'infinity': 1.96 - }; - - /** - * Critical Mann-Whitney U-values for 95% confidence - * http://www.saburchill.com/IBbiology/stats/003.html - */ - var uTable = { - '5': [0, 1, 2], - '6': [1, 2, 3, 5], - '7': [1, 3, 5, 6, 8], - '8': [2, 4, 6, 8, 10, 13], - '9': [2, 4, 7, 10, 12, 15, 17], - '10': [3, 5, 8, 11, 14, 17, 20, 23], - '11': [3, 6, 9, 13, 16, 19, 23, 26, 30], - '12': [4, 7, 11, 14, 18, 22, 26, 29, 33, 37], - '13': [4, 8, 12, 16, 20, 24, 28, 33, 37, 41, 45], - '14': [5, 9, 13, 17, 22, 26, 31, 36, 40, 45, 50, 55], - '15': [5, 10, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64], - '16': [6, 11, 15, 21, 26, 31, 37, 42, 47, 53, 59, 64, 70, 75], - '17': [6, 11, 17, 22, 28, 34, 39, 45, 51, 57, 63, 67, 75, 81, 87], - '18': [7, 12, 18, 24, 30, 36, 42, 48, 55, 61, 67, 74, 80, 86, 93, 99], - '19': [7, 13, 19, 25, 32, 38, 45, 52, 58, 65, 72, 78, 85, 92, 99, 106, 113], - '20': [8, 14, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 98, 105, 112, 119, 127], - '21': [8, 15, 22, 29, 36, 43, 50, 58, 65, 73, 80, 88, 96, 103, 111, 119, 126, 134, 142], - '22': [9, 16, 23, 30, 38, 45, 53, 61, 69, 77, 85, 93, 101, 109, 117, 125, 133, 141, 150, 158], - '23': [9, 17, 24, 32, 40, 48, 56, 64, 73, 81, 89, 98, 106, 115, 123, 132, 140, 149, 157, 166, 175], - '24': [10, 17, 25, 33, 42, 50, 59, 67, 76, 85, 94, 102, 111, 120, 129, 138, 147, 156, 165, 174, 183, 192], - '25': [10, 18, 27, 35, 44, 53, 62, 71, 80, 89, 98, 107, 117, 126, 135, 145, 154, 163, 173, 182, 192, 201, 211], - '26': [11, 19, 28, 37, 46, 55, 64, 74, 83, 93, 102, 112, 122, 132, 141, 151, 161, 171, 181, 191, 200, 210, 220, 230], - '27': [11, 20, 29, 38, 48, 57, 67, 77, 87, 97, 107, 118, 125, 138, 147, 158, 168, 178, 188, 199, 209, 219, 230, 240, 250], - '28': [12, 21, 30, 40, 50, 60, 70, 80, 90, 101, 111, 122, 132, 143, 154, 164, 175, 186, 196, 207, 218, 228, 239, 250, 261, 272], - '29': [13, 22, 32, 42, 52, 62, 73, 83, 94, 105, 116, 127, 138, 149, 160, 171, 182, 193, 204, 215, 226, 238, 249, 260, 271, 282, 294], - '30': [13, 23, 33, 43, 54, 65, 76, 87, 98, 109, 120, 131, 143, 154, 166, 177, 189, 200, 212, 223, 235, 247, 258, 270, 282, 293, 305, 317] - }; - - /** - * An object used to flag environments/features. - * - * @static - * @memberOf Benchmark - * @type Object - */ - var support = {}; - - (function() { - - /** - * Detect Adobe AIR. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.air = isClassOf(window.runtime, 'ScriptBridgingProxyObject'); - - /** - * Detect if `arguments` objects have the correct internal [[Class]] value. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.argumentsClass = isClassOf(arguments, 'Arguments'); - - /** - * Detect if in a browser environment. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.browser = doc && isHostType(window, 'navigator'); - - /** - * Detect if strings support accessing characters by index. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.charByIndex = - // IE 8 supports indexes on string literals but not string objects - ('x'[0] + Object('x')[0]) == 'xx'; - - /** - * Detect if strings have indexes as own properties. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.charByOwnIndex = - // Narwhal, Rhino, RingoJS, IE 8, and Opera < 10.52 support indexes on - // strings but don't detect them as own properties - support.charByIndex && hasKey('x', '0'); - - /** - * Detect if Java is enabled/exposed. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.java = isClassOf(window.java, 'JavaPackage'); - - /** - * Detect if the Timers API exists. - * - * @memberOf Benchmark.support - * @type Boolean - */ - support.timeout = isHostType(window, 'setTimeout') && isHostType(window, 'clearTimeout'); - - /** - * Detect if functions support decompilation. - * - * @name decompilation - * @memberOf Benchmark.support - * @type Boolean - */ - try { - // Safari 2.x removes commas in object literals - // from Function#toString results - // http://webk.it/11609 - // Firefox 3.6 and Opera 9.25 strip grouping - // parentheses from Function#toString results - // http://bugzil.la/559438 - support.decompilation = Function( - 'return (' + (function(x) { return { 'x': '' + (1 + x) + '', 'y': 0 }; }) + ')' - )()(0).x === '1'; - } catch(e) { - support.decompilation = false; - } - - /** - * Detect ES5+ property descriptor API. - * - * @name descriptors - * @memberOf Benchmark.support - * @type Boolean - */ - try { - var o = {}; - support.descriptors = (setDescriptor(o, o, o), 'value' in getDescriptor(o, o)); - } catch(e) { - support.descriptors = false; - } - - /** - * Detect ES5+ Object.getOwnPropertyNames(). - * - * @name getAllKeys - * @memberOf Benchmark.support - * @type Boolean - */ - try { - support.getAllKeys = /\bvalueOf\b/.test(getAllKeys(Object.prototype)); - } catch(e) { - support.getAllKeys = false; - } - }()); - - /** - * Timer object used by `clock()` and `Deferred#resolve`. - * - * @private - * @type Object - */ - var timer = { - - /** - * The timer namespace object or constructor. - * - * @private - * @memberOf timer - * @type Function|Object - */ - 'ns': Date, - - /** - * Starts the deferred timer. - * - * @private - * @memberOf timer - * @param {Object} deferred The deferred instance. - */ - 'start': null, // lazy defined in `clock()` - - /** - * Stops the deferred timer. - * - * @private - * @memberOf timer - * @param {Object} deferred The deferred instance. - */ - 'stop': null // lazy defined in `clock()` - }; - - /** Shortcut for inverse results */ - var noArgumentsClass = !support.argumentsClass, - noCharByIndex = !support.charByIndex, - noCharByOwnIndex = !support.charByOwnIndex; - - /** Math shortcuts */ - var abs = Math.abs, - floor = Math.floor, - max = Math.max, - min = Math.min, - pow = Math.pow, - sqrt = Math.sqrt; - - /*--------------------------------------------------------------------------*/ - - /** - * The Benchmark constructor. - * - * @constructor - * @param {String} name A name to identify the benchmark. - * @param {Function|String} fn The test to benchmark. - * @param {Object} [options={}] Options object. - * @example - * - * // basic usage (the `new` operator is optional) - * var bench = new Benchmark(fn); - * - * // or using a name first - * var bench = new Benchmark('foo', fn); - * - * // or with options - * var bench = new Benchmark('foo', fn, { - * - * // displayed by Benchmark#toString if `name` is not available - * 'id': 'xyz', - * - * // called when the benchmark starts running - * 'onStart': onStart, - * - * // called after each run cycle - * 'onCycle': onCycle, - * - * // called when aborted - * 'onAbort': onAbort, - * - * // called when a test errors - * 'onError': onError, - * - * // called when reset - * 'onReset': onReset, - * - * // called when the benchmark completes running - * 'onComplete': onComplete, - * - * // compiled/called before the test loop - * 'setup': setup, - * - * // compiled/called after the test loop - * 'teardown': teardown - * }); - * - * // or name and options - * var bench = new Benchmark('foo', { - * - * // a flag to indicate the benchmark is deferred - * 'defer': true, - * - * // benchmark test function - * 'fn': function(deferred) { - * // call resolve() when the deferred test is finished - * deferred.resolve(); - * } - * }); - * - * // or options only - * var bench = new Benchmark({ - * - * // benchmark name - * 'name': 'foo', - * - * // benchmark test as a string - * 'fn': '[1,2,3,4].sort()' - * }); - * - * // a test's `this` binding is set to the benchmark instance - * var bench = new Benchmark('foo', function() { - * 'My name is '.concat(this.name); // My name is foo - * }); - */ - function Benchmark(name, fn, options) { - var me = this; - - // allow instance creation without the `new` operator - if (me == null || me.constructor != Benchmark) { - return new Benchmark(name, fn, options); - } - // juggle arguments - if (isClassOf(name, 'Object')) { - // 1 argument (options) - options = name; - } - else if (isClassOf(name, 'Function')) { - // 2 arguments (fn, options) - options = fn; - fn = name; - } - else if (isClassOf(fn, 'Object')) { - // 2 arguments (name, options) - options = fn; - fn = null; - me.name = name; - } - else { - // 3 arguments (name, fn [, options]) - me.name = name; - } - setOptions(me, options); - me.id || (me.id = ++counter); - me.fn == null && (me.fn = fn); - me.stats = deepClone(me.stats); - me.times = deepClone(me.times); - } - - /** - * The Deferred constructor. - * - * @constructor - * @memberOf Benchmark - * @param {Object} clone The cloned benchmark instance. - */ - function Deferred(clone) { - var me = this; - if (me == null || me.constructor != Deferred) { - return new Deferred(clone); - } - me.benchmark = clone; - clock(me); - } - - /** - * The Event constructor. - * - * @constructor - * @memberOf Benchmark - * @param {String|Object} type The event type. - */ - function Event(type) { - var me = this; - return (me == null || me.constructor != Event) - ? new Event(type) - : (type instanceof Event) - ? type - : extend(me, { 'timeStamp': +new Date }, typeof type == 'string' ? { 'type': type } : type); - } - - /** - * The Suite constructor. - * - * @constructor - * @memberOf Benchmark - * @param {String} name A name to identify the suite. - * @param {Object} [options={}] Options object. - * @example - * - * // basic usage (the `new` operator is optional) - * var suite = new Benchmark.Suite; - * - * // or using a name first - * var suite = new Benchmark.Suite('foo'); - * - * // or with options - * var suite = new Benchmark.Suite('foo', { - * - * // called when the suite starts running - * 'onStart': onStart, - * - * // called between running benchmarks - * 'onCycle': onCycle, - * - * // called when aborted - * 'onAbort': onAbort, - * - * // called when a test errors - * 'onError': onError, - * - * // called when reset - * 'onReset': onReset, - * - * // called when the suite completes running - * 'onComplete': onComplete - * }); - */ - function Suite(name, options) { - var me = this; - - // allow instance creation without the `new` operator - if (me == null || me.constructor != Suite) { - return new Suite(name, options); - } - // juggle arguments - if (isClassOf(name, 'Object')) { - // 1 argument (options) - options = name; - } else { - // 2 arguments (name [, options]) - me.name = name; - } - setOptions(me, options); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Note: Some array methods have been implemented in plain JavaScript to avoid - * bugs in IE, Opera, Rhino, and Mobile Safari. - * - * IE compatibility mode and IE < 9 have buggy Array `shift()` and `splice()` - * functions that fail to remove the last element, `object[0]`, of - * array-like-objects even though the `length` property is set to `0`. - * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()` - * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9. - * - * In Opera < 9.50 and some older/beta Mobile Safari versions using `unshift()` - * generically to augment the `arguments` object will pave the value at index 0 - * without incrimenting the other values's indexes. - * https://github.com/documentcloud/underscore/issues/9 - * - * Rhino and environments it powers, like Narwhal and RingoJS, may have - * buggy Array `concat()`, `reverse()`, `shift()`, `slice()`, `splice()` and - * `unshift()` functions that make sparse arrays non-sparse by assigning the - * undefined indexes a value of undefined. - * https://github.com/mozilla/rhino/commit/702abfed3f8ca043b2636efd31c14ba7552603dd - */ - - /** - * Creates an array containing the elements of the host array followed by the - * elements of each argument in order. - * - * @memberOf Benchmark.Suite - * @returns {Array} The new array. - */ - function concat() { - var value, - j = -1, - length = arguments.length, - result = slice.call(this), - index = result.length; - - while (++j < length) { - value = arguments[j]; - if (isClassOf(value, 'Array')) { - for (var k = 0, l = value.length; k < l; k++, index++) { - if (k in value) { - result[index] = value[k]; - } - } - } else { - result[index++] = value; - } - } - return result; - } - - /** - * Utility function used by `shift()`, `splice()`, and `unshift()`. - * - * @private - * @param {Number} start The index to start inserting elements. - * @param {Number} deleteCount The number of elements to delete from the insert point. - * @param {Array} elements The elements to insert. - * @returns {Array} An array of deleted elements. - */ - function insert(start, deleteCount, elements) { - // `result` should have its length set to the `deleteCount` - // see https://bugs.ecmascript.org/show_bug.cgi?id=332 - var deleteEnd = start + deleteCount, - elementCount = elements ? elements.length : 0, - index = start - 1, - length = start + elementCount, - object = this, - result = Array(deleteCount), - tail = slice.call(object, deleteEnd); - - // delete elements from the array - while (++index < deleteEnd) { - if (index in object) { - result[index - start] = object[index]; - delete object[index]; - } - } - // insert elements - index = start - 1; - while (++index < length) { - object[index] = elements[index - start]; - } - // append tail elements - start = index--; - length = max(0, (object.length >>> 0) - deleteCount + elementCount); - while (++index < length) { - if ((index - start) in tail) { - object[index] = tail[index - start]; - } else { - delete object[index]; - } - } - // delete excess elements - deleteCount = deleteCount > elementCount ? deleteCount - elementCount : 0; - while (deleteCount--) { - delete object[length + deleteCount]; - } - object.length = length; - return result; - } - - /** - * Rearrange the host array's elements in reverse order. - * - * @memberOf Benchmark.Suite - * @returns {Array} The reversed array. - */ - function reverse() { - var upperIndex, - value, - index = -1, - object = Object(this), - length = object.length >>> 0, - middle = floor(length / 2); - - if (length > 1) { - while (++index < middle) { - upperIndex = length - index - 1; - value = upperIndex in object ? object[upperIndex] : uid; - if (index in object) { - object[upperIndex] = object[index]; - } else { - delete object[upperIndex]; - } - if (value != uid) { - object[index] = value; - } else { - delete object[index]; - } - } - } - return object; - } - - /** - * Removes the first element of the host array and returns it. - * - * @memberOf Benchmark.Suite - * @returns {Mixed} The first element of the array. - */ - function shift() { - return insert.call(this, 0, 1)[0]; - } - - /** - * Creates an array of the host array's elements from the start index up to, - * but not including, the end index. - * - * @memberOf Benchmark.Suite - * @param {Number} start The starting index. - * @param {Number} end The end index. - * @returns {Array} The new array. - */ - function slice(start, end) { - var index = -1, - object = Object(this), - length = object.length >>> 0, - result = []; - - start = toInteger(start); - start = start < 0 ? max(length + start, 0) : min(start, length); - start--; - end = end == null ? length : toInteger(end); - end = end < 0 ? max(length + end, 0) : min(end, length); - - while ((++index, ++start) < end) { - if (start in object) { - result[index] = object[start]; - } - } - return result; - } - - /** - * Allows removing a range of elements and/or inserting elements into the - * host array. - * - * @memberOf Benchmark.Suite - * @param {Number} start The start index. - * @param {Number} deleteCount The number of elements to delete. - * @param {Mixed} [val1, val2, ...] values to insert at the `start` index. - * @returns {Array} An array of removed elements. - */ - function splice(start, deleteCount) { - var object = Object(this), - length = object.length >>> 0; - - start = toInteger(start); - start = start < 0 ? max(length + start, 0) : min(start, length); - deleteCount = min(max(toInteger(deleteCount), 0), length - start); - return insert.call(object, start, deleteCount, slice.call(arguments, 2)); - } - - /** - * Converts the specified `value` to an integer. - * - * @private - * @param {Mixed} value The value to convert. - * @returns {Number} The resulting integer. - */ - function toInteger(value) { - value = +value; - return value === 0 || !isFinite(value) ? value || 0 : value - (value % 1); - } - - /** - * Appends arguments to the host array. - * - * @memberOf Benchmark.Suite - * @returns {Number} The new length. - */ - function unshift() { - var object = Object(this); - insert.call(object, 0, 0, arguments); - return object.length; - } - - /*--------------------------------------------------------------------------*/ - - /** - * A generic `Function#bind` like method. - * - * @private - * @param {Function} fn The function to be bound to `thisArg`. - * @param {Mixed} thisArg The `this` binding for the given function. - * @returns {Function} The bound function. - */ - function bind(fn, thisArg) { - return function() { fn.apply(thisArg, arguments); }; - } - - /** - * Creates a function from the given arguments string and body. - * - * @private - * @param {String} args The comma separated function arguments. - * @param {String} body The function body. - * @returns {Function} The new function. - */ - function createFunction() { - // lazy define - createFunction = function(args, body) { - var result, - anchor = freeDefine ? define.amd : Benchmark, - prop = uid + 'createFunction'; - - runScript((freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '=function(' + args + '){' + body + '}'); - result = anchor[prop]; - delete anchor[prop]; - return result; - }; - // fix JaegerMonkey bug - // http://bugzil.la/639720 - createFunction = support.browser && (createFunction('', 'return"' + uid + '"') || noop)() == uid ? createFunction : Function; - return createFunction.apply(null, arguments); - } - - /** - * Delay the execution of a function based on the benchmark's `delay` property. - * - * @private - * @param {Object} bench The benchmark instance. - * @param {Object} fn The function to execute. - */ - function delay(bench, fn) { - bench._timerId = setTimeout(fn, bench.delay * 1e3); - } - - /** - * Destroys the given element. - * - * @private - * @param {Element} element The element to destroy. - */ - function destroyElement(element) { - trash.appendChild(element); - trash.innerHTML = ''; - } - - /** - * Iterates over an object's properties, executing the `callback` for each. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} callback The function executed per own property. - * @param {Object} options The options object. - * @returns {Object} Returns the object iterated over. - */ - function forProps() { - var forShadowed, - skipSeen, - forArgs = true, - shadowed = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']; - - (function(enumFlag, key) { - // must use a non-native constructor to catch the Safari 2 issue - function Klass() { this.valueOf = 0; }; - Klass.prototype.valueOf = 0; - // check various for-in bugs - for (key in new Klass) { - enumFlag += key == 'valueOf' ? 1 : 0; - } - // check if `arguments` objects have non-enumerable indexes - for (key in arguments) { - key == '0' && (forArgs = false); - } - // Safari 2 iterates over shadowed properties twice - // http://replay.waybackmachine.org/20090428222941/http://tobielangel.com/2007/1/29/for-in-loop-broken-in-safari/ - skipSeen = enumFlag == 2; - // IE < 9 incorrectly makes an object's properties non-enumerable if they have - // the same name as other non-enumerable properties in its prototype chain. - forShadowed = !enumFlag; - }(0)); - - // lazy define - forProps = function(object, callback, options) { - options || (options = {}); - - var result = object; - object = Object(object); - - var ctor, - key, - keys, - skipCtor, - done = !result, - which = options.which, - allFlag = which == 'all', - index = -1, - iteratee = object, - length = object.length, - ownFlag = allFlag || which == 'own', - seen = {}, - skipProto = isClassOf(object, 'Function'), - thisArg = options.bind; - - if (thisArg !== undefined) { - callback = bind(callback, thisArg); - } - // iterate all properties - if (allFlag && support.getAllKeys) { - for (index = 0, keys = getAllKeys(object), length = keys.length; index < length; index++) { - key = keys[index]; - if (callback(object[key], key, object) === false) { - break; - } - } - } - // else iterate only enumerable properties - else { - for (key in object) { - // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 - // (if the prototype or a property on the prototype has been set) - // incorrectly set a function's `prototype` property [[Enumerable]] value - // to `true`. Because of this we standardize on skipping the `prototype` - // property of functions regardless of their [[Enumerable]] value. - if ((done = - !(skipProto && key == 'prototype') && - !(skipSeen && (hasKey(seen, key) || !(seen[key] = true))) && - (!ownFlag || ownFlag && hasKey(object, key)) && - callback(object[key], key, object) === false)) { - break; - } - } - // in IE < 9 strings don't support accessing characters by index - if (!done && (forArgs && isArguments(object) || - ((noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String') && - (iteratee = noCharByIndex ? object.split('') : object)))) { - while (++index < length) { - if ((done = - callback(iteratee[index], String(index), object) === false)) { - break; - } - } - } - if (!done && forShadowed) { - // Because IE < 9 can't set the `[[Enumerable]]` attribute of an existing - // property and the `constructor` property of a prototype defaults to - // non-enumerable, we manually skip the `constructor` property when we - // think we are iterating over a `prototype` object. - ctor = object.constructor; - skipCtor = ctor && ctor.prototype && ctor.prototype.constructor === ctor; - for (index = 0; index < 7; index++) { - key = shadowed[index]; - if (!(skipCtor && key == 'constructor') && - hasKey(object, key) && - callback(object[key], key, object) === false) { - break; - } - } - } - } - return result; - }; - return forProps.apply(null, arguments); - } - - /** - * Gets the name of the first argument from a function's source. - * - * @private - * @param {Function} fn The function. - * @returns {String} The argument name. - */ - function getFirstArgument(fn) { - return (!hasKey(fn, 'toString') && - (/^[\s(]*function[^(]*\(([^\s,)]+)/.exec(fn) || 0)[1]) || ''; - } - - /** - * Computes the arithmetic mean of a sample. - * - * @private - * @param {Array} sample The sample. - * @returns {Number} The mean. - */ - function getMean(sample) { - return reduce(sample, function(sum, x) { - return sum + x; - }) / sample.length || 0; - } - - /** - * Gets the source code of a function. - * - * @private - * @param {Function} fn The function. - * @param {String} altSource A string used when a function's source code is unretrievable. - * @returns {String} The function's source code. - */ - function getSource(fn, altSource) { - var result = altSource; - if (isStringable(fn)) { - result = String(fn); - } else if (support.decompilation) { - // escape the `{` for Firefox 1 - result = (/^[^{]+\{([\s\S]*)}\s*$/.exec(fn) || 0)[1]; - } - return (result || '').replace(/^\s+|\s+$/g, ''); - } - - /** - * Checks if a value is an `arguments` object. - * - * @private - * @param {Mixed} value The value to check. - * @returns {Boolean} Returns `true` if the value is an `arguments` object, else `false`. - */ - function isArguments() { - // lazy define - isArguments = function(value) { - return toString.call(value) == '[object Arguments]'; - }; - if (noArgumentsClass) { - isArguments = function(value) { - return hasKey(value, 'callee') && - !(propertyIsEnumerable && propertyIsEnumerable.call(value, 'callee')); - }; - } - return isArguments(arguments[0]); - } - - /** - * Checks if an object is of the specified class. - * - * @private - * @param {Mixed} value The value to check. - * @param {String} name The name of the class. - * @returns {Boolean} Returns `true` if the value is of the specified class, else `false`. - */ - function isClassOf(value, name) { - return value != null && toString.call(value) == '[object ' + name + ']'; - } - - /** - * Host objects can return type values that are different from their actual - * data type. The objects we are concerned with usually return non-primitive - * types of object, function, or unknown. - * - * @private - * @param {Mixed} object The owner of the property. - * @param {String} property The property to check. - * @returns {Boolean} Returns `true` if the property value is a non-primitive, else `false`. - */ - function isHostType(object, property) { - var type = object != null ? typeof object[property] : 'number'; - return !/^(?:boolean|number|string|undefined)$/.test(type) && - (type == 'object' ? !!object[property] : true); - } - - /** - * Checks if the specified `value` is an object created by the `Object` - * constructor assuming objects created by the `Object` constructor have no - * inherited enumerable properties and assuming there are no `Object.prototype` - * extensions. - * - * @private - * @param {Mixed} value The value to check. - * @returns {Boolean} Returns `true` if `value` is an object, else `false`. - */ - function isObject(value) { - var ctor, - result = !!value && toString.call(value) == '[object Object]'; - - if (result && noArgumentsClass) { - // avoid false positives for `arguments` objects in IE < 9 - result = !isArguments(value); - } - if (result) { - // IE < 9 presents nodes like `Object` objects: - // IE < 8 are missing the node's constructor property - // IE 8 node constructors are typeof "object" - ctor = value.constructor; - // check if the constructor is `Object` as `Object instanceof Object` is `true` - if ((result = isClassOf(ctor, 'Function') && ctor instanceof ctor)) { - // An object's own properties are iterated before inherited properties. - // If the last iterated key belongs to an object's own property then - // there are no inherited enumerable properties. - forProps(value, function(subValue, subKey) { result = subKey; }); - result = result === true || hasKey(value, result); - } - } - return result; - } - - /** - * Checks if a value can be safely coerced to a string. - * - * @private - * @param {Mixed} value The value to check. - * @returns {Boolean} Returns `true` if the value can be coerced, else `false`. - */ - function isStringable(value) { - return hasKey(value, 'toString') || isClassOf(value, 'String'); - } - - /** - * Wraps a function and passes `this` to the original function as the - * first argument. - * - * @private - * @param {Function} fn The function to be wrapped. - * @returns {Function} The new function. - */ - function methodize(fn) { - return function() { - var args = [this]; - args.push.apply(args, arguments); - return fn.apply(null, args); - }; - } - - /** - * A no-operation function. - * - * @private - */ - function noop() { - // no operation performed - } - - /** - * A wrapper around require() to suppress `module missing` errors. - * - * @private - * @param {String} id The module id. - * @returns {Mixed} The exported module or `null`. - */ - function req(id) { - try { - var result = freeExports && freeRequire(id); - } catch(e) { } - return result || null; - } - - /** - * Runs a snippet of JavaScript via script injection. - * - * @private - * @param {String} code The code to run. - */ - function runScript(code) { - var anchor = freeDefine ? define.amd : Benchmark, - script = doc.createElement('script'), - sibling = doc.getElementsByTagName('script')[0], - parent = sibling.parentNode, - prop = uid + 'runScript', - prefix = '(' + (freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '||function(){})();'; - - // Firefox 2.0.0.2 cannot use script injection as intended because it executes - // asynchronously, but that's OK because script injection is only used to avoid - // the previously commented JaegerMonkey bug. - try { - // remove the inserted script *before* running the code to avoid differences - // in the expected script element count/order of the document. - script.appendChild(doc.createTextNode(prefix + code)); - anchor[prop] = function() { destroyElement(script); }; - } catch(e) { - parent = parent.cloneNode(false); - sibling = null; - script.text = code; - } - parent.insertBefore(script, sibling); - delete anchor[prop]; - } - - /** - * A helper function for setting options/event handlers. - * - * @private - * @param {Object} bench The benchmark instance. - * @param {Object} [options={}] Options object. - */ - function setOptions(bench, options) { - options = extend({}, bench.constructor.options, options); - bench.options = forOwn(options, function(value, key) { - if (value != null) { - // add event listeners - if (/^on[A-Z]/.test(key)) { - forEach(key.split(' '), function(key) { - bench.on(key.slice(2).toLowerCase(), value); - }); - } else if (!hasKey(bench, key)) { - bench[key] = deepClone(value); - } - } - }); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Handles cycling/completing the deferred benchmark. - * - * @memberOf Benchmark.Deferred - */ - function resolve() { - var me = this, - clone = me.benchmark, - bench = clone._original; - - if (bench.aborted) { - // cycle() -> clone cycle/complete event -> compute()'s invoked bench.run() cycle/complete - me.teardown(); - clone.running = false; - cycle(me); - } - else if (++me.cycles < clone.count) { - // continue the test loop - if (support.timeout) { - // use setTimeout to avoid a call stack overflow if called recursively - setTimeout(function() { clone.compiled.call(me, timer); }, 0); - } else { - clone.compiled.call(me, timer); - } - } - else { - timer.stop(me); - me.teardown(); - delay(clone, function() { cycle(me); }); - } - } - - /*--------------------------------------------------------------------------*/ - - /** - * A deep clone utility. - * - * @static - * @memberOf Benchmark - * @param {Mixed} value The value to clone. - * @returns {Mixed} The cloned value. - */ - function deepClone(value) { - var accessor, - circular, - clone, - ctor, - descriptor, - extensible, - key, - length, - markerKey, - parent, - result, - source, - subIndex, - data = { 'value': value }, - index = 0, - marked = [], - queue = { 'length': 0 }, - unmarked = []; - - /** - * An easily detectable decorator for cloned values. - */ - function Marker(object) { - this.raw = object; - } - - /** - * The callback used by `forProps()`. - */ - function forPropsCallback(subValue, subKey) { - // exit early to avoid cloning the marker - if (subValue && subValue.constructor == Marker) { - return; - } - // add objects to the queue - if (subValue === Object(subValue)) { - queue[queue.length++] = { 'key': subKey, 'parent': clone, 'source': value }; - } - // assign non-objects - else { - try { - // will throw an error in strict mode if the property is read-only - clone[subKey] = subValue; - } catch(e) { } - } - } - - /** - * Gets an available marker key for the given object. - */ - function getMarkerKey(object) { - // avoid collisions with existing keys - var result = uid; - while (object[result] && object[result].constructor != Marker) { - result += 1; - } - return result; - } - - do { - key = data.key; - parent = data.parent; - source = data.source; - clone = value = source ? source[key] : data.value; - accessor = circular = descriptor = false; - - // create a basic clone to filter out functions, DOM elements, and - // other non `Object` objects - if (value === Object(value)) { - // use custom deep clone function if available - if (isClassOf(value.deepClone, 'Function')) { - clone = value.deepClone(); - } else { - ctor = value.constructor; - switch (toString.call(value)) { - case '[object Array]': - clone = new ctor(value.length); - break; - - case '[object Boolean]': - clone = new ctor(value == true); - break; - - case '[object Date]': - clone = new ctor(+value); - break; - - case '[object Object]': - isObject(value) && (clone = new ctor); - break; - - case '[object Number]': - case '[object String]': - clone = new ctor(value); - break; - - case '[object RegExp]': - clone = ctor(value.source, - (value.global ? 'g' : '') + - (value.ignoreCase ? 'i' : '') + - (value.multiline ? 'm' : '')); - } - } - // continue clone if `value` doesn't have an accessor descriptor - // http://es5.github.com/#x8.10.1 - if (clone && clone != value && - !(descriptor = source && support.descriptors && getDescriptor(source, key), - accessor = descriptor && (descriptor.get || descriptor.set))) { - // use an existing clone (circular reference) - if ((extensible = isExtensible(value))) { - markerKey = getMarkerKey(value); - if (value[markerKey]) { - circular = clone = value[markerKey].raw; - } - } else { - // for frozen/sealed objects - for (subIndex = 0, length = unmarked.length; subIndex < length; subIndex++) { - data = unmarked[subIndex]; - if (data.object === value) { - circular = clone = data.clone; - break; - } - } - } - if (!circular) { - // mark object to allow quickly detecting circular references and tie it to its clone - if (extensible) { - value[markerKey] = new Marker(clone); - marked.push({ 'key': markerKey, 'object': value }); - } else { - // for frozen/sealed objects - unmarked.push({ 'clone': clone, 'object': value }); - } - // iterate over object properties - forProps(value, forPropsCallback, { 'which': 'all' }); - } - } - } - if (parent) { - // for custom property descriptors - if (accessor || (descriptor && !(descriptor.configurable && descriptor.enumerable && descriptor.writable))) { - if ('value' in descriptor) { - descriptor.value = clone; - } - setDescriptor(parent, key, descriptor); - } - // for default property descriptors - else { - parent[key] = clone; - } - } else { - result = clone; - } - } while ((data = queue[index++])); - - // remove markers - for (index = 0, length = marked.length; index < length; index++) { - data = marked[index]; - delete data.object[data.key]; - } - return result; - } - - /** - * An iteration utility for arrays and objects. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @static - * @memberOf Benchmark - * @param {Array|Object} object The object to iterate over. - * @param {Function} callback The function called per iteration. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Array|Object} Returns the object iterated over. - */ - function each(object, callback, thisArg) { - var result = object; - object = Object(object); - - var fn = callback, - index = -1, - length = object.length, - isSnapshot = !!(object.snapshotItem && (length = object.snapshotLength)), - isSplittable = (noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String'), - isConvertable = isSnapshot || isSplittable || 'item' in object, - origObject = object; - - // in Opera < 10.5 `hasKey(object, 'length')` returns `false` for NodeLists - if (length === length >>> 0) { - if (isConvertable) { - // the third argument of the callback is the original non-array object - callback = function(value, index) { - return fn.call(this, value, index, origObject); - }; - // in IE < 9 strings don't support accessing characters by index - if (isSplittable) { - object = object.split(''); - } else { - object = []; - while (++index < length) { - // in Safari 2 `index in object` is always `false` for NodeLists - object[index] = isSnapshot ? result.snapshotItem(index) : result[index]; - } - } - } - forEach(object, callback, thisArg); - } else { - forOwn(object, callback, thisArg); - } - return result; - } - - /** - * Copies enumerable properties from the source(s) object to the destination object. - * - * @static - * @memberOf Benchmark - * @param {Object} destination The destination object. - * @param {Object} [source={}] The source object. - * @returns {Object} The destination object. - */ - function extend(destination, source) { - // Chrome < 14 incorrectly sets `destination` to `undefined` when we `delete arguments[0]` - // http://code.google.com/p/v8/issues/detail?id=839 - var result = destination; - delete arguments[0]; - - forEach(arguments, function(source) { - forProps(source, function(value, key) { - result[key] = value; - }); - }); - return result; - } - - /** - * A generic `Array#filter` like method. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Function|String} callback The function/alias called per iteration. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Array} A new array of values that passed callback filter. - * @example - * - * // get odd numbers - * Benchmark.filter([1, 2, 3, 4, 5], function(n) { - * return n % 2; - * }); // -> [1, 3, 5]; - * - * // get fastest benchmarks - * Benchmark.filter(benches, 'fastest'); - * - * // get slowest benchmarks - * Benchmark.filter(benches, 'slowest'); - * - * // get benchmarks that completed without erroring - * Benchmark.filter(benches, 'successful'); - */ - function filter(array, callback, thisArg) { - var result; - - if (callback == 'successful') { - // callback to exclude those that are errored, unrun, or have hz of Infinity - callback = function(bench) { return bench.cycles && isFinite(bench.hz); }; - } - else if (callback == 'fastest' || callback == 'slowest') { - // get successful, sort by period + margin of error, and filter fastest/slowest - result = filter(array, 'successful').sort(function(a, b) { - a = a.stats; b = b.stats; - return (a.mean + a.moe > b.mean + b.moe ? 1 : -1) * (callback == 'fastest' ? 1 : -1); - }); - result = filter(result, function(bench) { - return result[0].compare(bench) == 0; - }); - } - return result || reduce(array, function(result, value, index) { - return callback.call(thisArg, value, index, array) ? (result.push(value), result) : result; - }, []); - } - - /** - * A generic `Array#forEach` like method. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Function} callback The function called per iteration. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Array} Returns the array iterated over. - */ - function forEach(array, callback, thisArg) { - var index = -1, - length = (array = Object(array)).length >>> 0; - - if (thisArg !== undefined) { - callback = bind(callback, thisArg); - } - while (++index < length) { - if (index in array && - callback(array[index], index, array) === false) { - break; - } - } - return array; - } - - /** - * Iterates over an object's own properties, executing the `callback` for each. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @static - * @memberOf Benchmark - * @param {Object} object The object to iterate over. - * @param {Function} callback The function executed per own property. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Object} Returns the object iterated over. - */ - function forOwn(object, callback, thisArg) { - return forProps(object, callback, { 'bind': thisArg, 'which': 'own' }); - } - - /** - * Converts a number to a more readable comma-separated string representation. - * - * @static - * @memberOf Benchmark - * @param {Number} number The number to convert. - * @returns {String} The more readable string representation. - */ - function formatNumber(number) { - number = String(number).split('.'); - return number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') + - (number[1] ? '.' + number[1] : ''); - } - - /** - * Checks if an object has the specified key as a direct property. - * - * @static - * @memberOf Benchmark - * @param {Object} object The object to check. - * @param {String} key The key to check for. - * @returns {Boolean} Returns `true` if key is a direct property, else `false`. - */ - function hasKey() { - // lazy define for worst case fallback (not as accurate) - hasKey = function(object, key) { - var parent = object != null && (object.constructor || Object).prototype; - return !!parent && key in Object(object) && !(key in parent && object[key] === parent[key]); - }; - // for modern browsers - if (isClassOf(hasOwnProperty, 'Function')) { - hasKey = function(object, key) { - return object != null && hasOwnProperty.call(object, key); - }; - } - // for Safari 2 - else if ({}.__proto__ == Object.prototype) { - hasKey = function(object, key) { - var result = false; - if (object != null) { - object = Object(object); - object.__proto__ = [object.__proto__, object.__proto__ = null, result = key in object][0]; - } - return result; - }; - } - return hasKey.apply(this, arguments); - } - - /** - * A generic `Array#indexOf` like method. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Mixed} value The value to search for. - * @param {Number} [fromIndex=0] The index to start searching from. - * @returns {Number} The index of the matched value or `-1`. - */ - function indexOf(array, value, fromIndex) { - var index = toInteger(fromIndex), - length = (array = Object(array)).length >>> 0; - - index = (index < 0 ? max(0, length + index) : index) - 1; - while (++index < length) { - if (index in array && value === array[index]) { - return index; - } - } - return -1; - } - - /** - * Modify a string by replacing named tokens with matching object property values. - * - * @static - * @memberOf Benchmark - * @param {String} string The string to modify. - * @param {Object} object The template object. - * @returns {String} The modified string. - */ - function interpolate(string, object) { - forOwn(object, function(value, key) { - // escape regexp special characters in `key` - string = string.replace(RegExp('#\\{' + key.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1') + '\\}', 'g'), value); - }); - return string; - } - - /** - * Invokes a method on all items in an array. - * - * @static - * @memberOf Benchmark - * @param {Array} benches Array of benchmarks to iterate over. - * @param {String|Object} name The name of the method to invoke OR options object. - * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. - * @returns {Array} A new array of values returned from each method invoked. - * @example - * - * // invoke `reset` on all benchmarks - * Benchmark.invoke(benches, 'reset'); - * - * // invoke `emit` with arguments - * Benchmark.invoke(benches, 'emit', 'complete', listener); - * - * // invoke `run(true)`, treat benchmarks as a queue, and register invoke callbacks - * Benchmark.invoke(benches, { - * - * // invoke the `run` method - * 'name': 'run', - * - * // pass a single argument - * 'args': true, - * - * // treat as queue, removing benchmarks from front of `benches` until empty - * 'queued': true, - * - * // called before any benchmarks have been invoked. - * 'onStart': onStart, - * - * // called between invoking benchmarks - * 'onCycle': onCycle, - * - * // called after all benchmarks have been invoked. - * 'onComplete': onComplete - * }); - */ - function invoke(benches, name) { - var args, - bench, - queued, - index = -1, - eventProps = { 'currentTarget': benches }, - options = { 'onStart': noop, 'onCycle': noop, 'onComplete': noop }, - result = map(benches, function(bench) { return bench; }); - - /** - * Invokes the method of the current object and if synchronous, fetches the next. - */ - function execute() { - var listeners, - async = isAsync(bench); - - if (async) { - // use `getNext` as the first listener - bench.on('complete', getNext); - listeners = bench.events.complete; - listeners.splice(0, 0, listeners.pop()); - } - // execute method - result[index] = isClassOf(bench && bench[name], 'Function') ? bench[name].apply(bench, args) : undefined; - // if synchronous return true until finished - return !async && getNext(); - } - - /** - * Fetches the next bench or executes `onComplete` callback. - */ - function getNext(event) { - var cycleEvent, - last = bench, - async = isAsync(last); - - if (async) { - last.off('complete', getNext); - last.emit('complete'); - } - // emit "cycle" event - eventProps.type = 'cycle'; - eventProps.target = last; - cycleEvent = Event(eventProps); - options.onCycle.call(benches, cycleEvent); - - // choose next benchmark if not exiting early - if (!cycleEvent.aborted && raiseIndex() !== false) { - bench = queued ? benches[0] : result[index]; - if (isAsync(bench)) { - delay(bench, execute); - } - else if (async) { - // resume execution if previously asynchronous but now synchronous - while (execute()) { } - } - else { - // continue synchronous execution - return true; - } - } else { - // emit "complete" event - eventProps.type = 'complete'; - options.onComplete.call(benches, Event(eventProps)); - } - // When used as a listener `event.aborted = true` will cancel the rest of - // the "complete" listeners because they were already called above and when - // used as part of `getNext` the `return false` will exit the execution while-loop. - if (event) { - event.aborted = true; - } else { - return false; - } - } - - /** - * Checks if invoking `Benchmark#run` with asynchronous cycles. - */ - function isAsync(object) { - // avoid using `instanceof` here because of IE memory leak issues with host objects - var async = args[0] && args[0].async; - return Object(object).constructor == Benchmark && name == 'run' && - ((async == null ? object.options.async : async) && support.timeout || object.defer); - } - - /** - * Raises `index` to the next defined index or returns `false`. - */ - function raiseIndex() { - var length = result.length; - if (queued) { - // if queued remove the previous bench and subsequent skipped non-entries - do { - ++index > 0 && shift.call(benches); - } while ((length = benches.length) && !('0' in benches)); - } - else { - while (++index < length && !(index in result)) { } - } - // if we reached the last index then return `false` - return (queued ? length : index < length) ? index : (index = false); - } - - // juggle arguments - if (isClassOf(name, 'String')) { - // 2 arguments (array, name) - args = slice.call(arguments, 2); - } else { - // 2 arguments (array, options) - options = extend(options, name); - name = options.name; - args = isClassOf(args = 'args' in options ? options.args : [], 'Array') ? args : [args]; - queued = options.queued; - } - - // start iterating over the array - if (raiseIndex() !== false) { - // emit "start" event - bench = result[index]; - eventProps.type = 'start'; - eventProps.target = bench; - options.onStart.call(benches, Event(eventProps)); - - // end early if the suite was aborted in an "onStart" listener - if (benches.aborted && benches.constructor == Suite && name == 'run') { - // emit "cycle" event - eventProps.type = 'cycle'; - options.onCycle.call(benches, Event(eventProps)); - // emit "complete" event - eventProps.type = 'complete'; - options.onComplete.call(benches, Event(eventProps)); - } - // else start - else { - if (isAsync(bench)) { - delay(bench, execute); - } else { - while (execute()) { } - } - } - } - return result; - } - - /** - * Creates a string of joined array values or object key-value pairs. - * - * @static - * @memberOf Benchmark - * @param {Array|Object} object The object to operate on. - * @param {String} [separator1=','] The separator used between key-value pairs. - * @param {String} [separator2=': '] The separator used between keys and values. - * @returns {String} The joined result. - */ - function join(object, separator1, separator2) { - var result = [], - length = (object = Object(object)).length, - arrayLike = length === length >>> 0; - - separator2 || (separator2 = ': '); - each(object, function(value, key) { - result.push(arrayLike ? value : key + separator2 + value); - }); - return result.join(separator1 || ','); - } - - /** - * A generic `Array#map` like method. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Function} callback The function called per iteration. - * @param {Mixed} thisArg The `this` binding for the callback. - * @returns {Array} A new array of values returned by the callback. - */ - function map(array, callback, thisArg) { - return reduce(array, function(result, value, index) { - result[index] = callback.call(thisArg, value, index, array); - return result; - }, Array(Object(array).length >>> 0)); - } - - /** - * Retrieves the value of a specified property from all items in an array. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {String} property The property to pluck. - * @returns {Array} A new array of property values. - */ - function pluck(array, property) { - return map(array, function(object) { - return object == null ? undefined : object[property]; - }); - } - - /** - * A generic `Array#reduce` like method. - * - * @static - * @memberOf Benchmark - * @param {Array} array The array to iterate over. - * @param {Function} callback The function called per iteration. - * @param {Mixed} accumulator Initial value of the accumulator. - * @returns {Mixed} The accumulator. - */ - function reduce(array, callback, accumulator) { - var noaccum = arguments.length < 3; - forEach(array, function(value, index) { - accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, array); - }); - return accumulator; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Aborts all benchmarks in the suite. - * - * @name abort - * @memberOf Benchmark.Suite - * @returns {Object} The suite instance. - */ - function abortSuite() { - var event, - me = this, - resetting = calledBy.resetSuite; - - if (me.running) { - event = Event('abort'); - me.emit(event); - if (!event.cancelled || resetting) { - // avoid infinite recursion - calledBy.abortSuite = true; - me.reset(); - delete calledBy.abortSuite; - - if (!resetting) { - me.aborted = true; - invoke(me, 'abort'); - } - } - } - return me; - } - - /** - * Adds a test to the benchmark suite. - * - * @memberOf Benchmark.Suite - * @param {String} name A name to identify the benchmark. - * @param {Function|String} fn The test to benchmark. - * @param {Object} [options={}] Options object. - * @returns {Object} The benchmark instance. - * @example - * - * // basic usage - * suite.add(fn); - * - * // or using a name first - * suite.add('foo', fn); - * - * // or with options - * suite.add('foo', fn, { - * 'onCycle': onCycle, - * 'onComplete': onComplete - * }); - */ - function add(name, fn, options) { - var me = this, - bench = Benchmark(name, fn, options), - event = Event({ 'type': 'add', 'target': bench }); - - if (me.emit(event), !event.cancelled) { - me.push(bench); - } - return me; - } - - /** - * Creates a new suite with cloned benchmarks. - * - * @name clone - * @memberOf Benchmark.Suite - * @param {Object} options Options object to overwrite cloned options. - * @returns {Object} The new suite instance. - */ - function cloneSuite(options) { - var me = this, - result = new me.constructor(extend({}, me.options, options)); - - // copy own properties - forOwn(me, function(value, key) { - if (!hasKey(result, key)) { - result[key] = value && isClassOf(value.clone, 'Function') - ? value.clone() - : deepClone(value); - } - }); - return result; - } - - /** - * An `Array#filter` like method. - * - * @name filter - * @memberOf Benchmark.Suite - * @param {Function|String} callback The function/alias called per iteration. - * @returns {Object} A new suite of benchmarks that passed callback filter. - */ - function filterSuite(callback) { - var me = this, - result = new me.constructor; - - result.push.apply(result, filter(me, callback)); - return result; - } - - /** - * Resets all benchmarks in the suite. - * - * @name reset - * @memberOf Benchmark.Suite - * @returns {Object} The suite instance. - */ - function resetSuite() { - var event, - me = this, - aborting = calledBy.abortSuite; - - if (me.running && !aborting) { - // no worries, `resetSuite()` is called within `abortSuite()` - calledBy.resetSuite = true; - me.abort(); - delete calledBy.resetSuite; - } - // reset if the state has changed - else if ((me.aborted || me.running) && - (me.emit(event = Event('reset')), !event.cancelled)) { - me.running = false; - if (!aborting) { - invoke(me, 'reset'); - } - } - return me; - } - - /** - * Runs the suite. - * - * @name run - * @memberOf Benchmark.Suite - * @param {Object} [options={}] Options object. - * @returns {Object} The suite instance. - * @example - * - * // basic usage - * suite.run(); - * - * // or with options - * suite.run({ 'async': true, 'queued': true }); - */ - function runSuite(options) { - var me = this; - - me.reset(); - me.running = true; - options || (options = {}); - - invoke(me, { - 'name': 'run', - 'args': options, - 'queued': options.queued, - 'onStart': function(event) { - me.emit(event); - }, - 'onCycle': function(event) { - var bench = event.target; - if (bench.error) { - me.emit({ 'type': 'error', 'target': bench }); - } - me.emit(event); - event.aborted = me.aborted; - }, - 'onComplete': function(event) { - me.running = false; - me.emit(event); - } - }); - return me; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Executes all registered listeners of the specified event type. - * - * @memberOf Benchmark, Benchmark.Suite - * @param {String|Object} type The event type or object. - * @returns {Mixed} Returns the return value of the last listener executed. - */ - function emit(type) { - var listeners, - me = this, - event = Event(type), - events = me.events, - args = (arguments[0] = event, arguments); - - event.currentTarget || (event.currentTarget = me); - event.target || (event.target = me); - delete event.result; - - if (events && (listeners = hasKey(events, event.type) && events[event.type])) { - forEach(listeners.slice(), function(listener) { - if ((event.result = listener.apply(me, args)) === false) { - event.cancelled = true; - } - return !event.aborted; - }); - } - return event.result; - } - - /** - * Returns an array of event listeners for a given type that can be manipulated - * to add or remove listeners. - * - * @memberOf Benchmark, Benchmark.Suite - * @param {String} type The event type. - * @returns {Array} The listeners array. - */ - function listeners(type) { - var me = this, - events = me.events || (me.events = {}); - - return hasKey(events, type) ? events[type] : (events[type] = []); - } - - /** - * Unregisters a listener for the specified event type(s), - * or unregisters all listeners for the specified event type(s), - * or unregisters all listeners for all event types. - * - * @memberOf Benchmark, Benchmark.Suite - * @param {String} [type] The event type. - * @param {Function} [listener] The function to unregister. - * @returns {Object} The benchmark instance. - * @example - * - * // unregister a listener for an event type - * bench.off('cycle', listener); - * - * // unregister a listener for multiple event types - * bench.off('start cycle', listener); - * - * // unregister all listeners for an event type - * bench.off('cycle'); - * - * // unregister all listeners for multiple event types - * bench.off('start cycle complete'); - * - * // unregister all listeners for all event types - * bench.off(); - */ - function off(type, listener) { - var me = this, - events = me.events; - - events && each(type ? type.split(' ') : events, function(listeners, type) { - var index; - if (typeof listeners == 'string') { - type = listeners; - listeners = hasKey(events, type) && events[type]; - } - if (listeners) { - if (listener) { - index = indexOf(listeners, listener); - if (index > -1) { - listeners.splice(index, 1); - } - } else { - listeners.length = 0; - } - } - }); - return me; - } - - /** - * Registers a listener for the specified event type(s). - * - * @memberOf Benchmark, Benchmark.Suite - * @param {String} type The event type. - * @param {Function} listener The function to register. - * @returns {Object} The benchmark instance. - * @example - * - * // register a listener for an event type - * bench.on('cycle', listener); - * - * // register a listener for multiple event types - * bench.on('start cycle', listener); - */ - function on(type, listener) { - var me = this, - events = me.events || (me.events = {}); - - forEach(type.split(' '), function(type) { - (hasKey(events, type) - ? events[type] - : (events[type] = []) - ).push(listener); - }); - return me; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Aborts the benchmark without recording times. - * - * @memberOf Benchmark - * @returns {Object} The benchmark instance. - */ - function abort() { - var event, - me = this, - resetting = calledBy.reset; - - if (me.running) { - event = Event('abort'); - me.emit(event); - if (!event.cancelled || resetting) { - // avoid infinite recursion - calledBy.abort = true; - me.reset(); - delete calledBy.abort; - - if (support.timeout) { - clearTimeout(me._timerId); - delete me._timerId; - } - if (!resetting) { - me.aborted = true; - me.running = false; - } - } - } - return me; - } - - /** - * Creates a new benchmark using the same test and options. - * - * @memberOf Benchmark - * @param {Object} options Options object to overwrite cloned options. - * @returns {Object} The new benchmark instance. - * @example - * - * var bizarro = bench.clone({ - * 'name': 'doppelganger' - * }); - */ - function clone(options) { - var me = this, - result = new me.constructor(extend({}, me, options)); - - // correct the `options` object - result.options = extend({}, me.options, options); - - // copy own custom properties - forOwn(me, function(value, key) { - if (!hasKey(result, key)) { - result[key] = deepClone(value); - } - }); - return result; - } - - /** - * Determines if a benchmark is faster than another. - * - * @memberOf Benchmark - * @param {Object} other The benchmark to compare. - * @returns {Number} Returns `-1` if slower, `1` if faster, and `0` if indeterminate. - */ - function compare(other) { - var critical, - zStat, - me = this, - sample1 = me.stats.sample, - sample2 = other.stats.sample, - size1 = sample1.length, - size2 = sample2.length, - maxSize = max(size1, size2), - minSize = min(size1, size2), - u1 = getU(sample1, sample2), - u2 = getU(sample2, sample1), - u = min(u1, u2); - - function getScore(xA, sampleB) { - return reduce(sampleB, function(total, xB) { - return total + (xB > xA ? 0 : xB < xA ? 1 : 0.5); - }, 0); - } - - function getU(sampleA, sampleB) { - return reduce(sampleA, function(total, xA) { - return total + getScore(xA, sampleB); - }, 0); - } - - function getZ(u) { - return (u - ((size1 * size2) / 2)) / sqrt((size1 * size2 * (size1 + size2 + 1)) / 12); - } - - // exit early if comparing the same benchmark - if (me == other) { - return 0; - } - // reject the null hyphothesis the two samples come from the - // same population (i.e. have the same median) if... - if (size1 + size2 > 30) { - // ...the z-stat is greater than 1.96 or less than -1.96 - // http://www.statisticslectures.com/topics/mannwhitneyu/ - zStat = getZ(u); - return abs(zStat) > 1.96 ? (zStat > 0 ? -1 : 1) : 0; - } - // ...the U value is less than or equal the critical U value - // http://www.geoib.com/mann-whitney-u-test.html - critical = maxSize < 5 || minSize < 3 ? 0 : uTable[maxSize][minSize - 3]; - return u <= critical ? (u == u1 ? 1 : -1) : 0; - } - - /** - * Reset properties and abort if running. - * - * @memberOf Benchmark - * @returns {Object} The benchmark instance. - */ - function reset() { - var data, - event, - me = this, - index = 0, - changes = { 'length': 0 }, - queue = { 'length': 0 }; - - if (me.running && !calledBy.abort) { - // no worries, `reset()` is called within `abort()` - calledBy.reset = true; - me.abort(); - delete calledBy.reset; - } - else { - // a non-recursive solution to check if properties have changed - // http://www.jslab.dk/articles/non.recursive.preorder.traversal.part4 - data = { 'destination': me, 'source': extend({}, me.constructor.prototype, me.options) }; - do { - forOwn(data.source, function(value, key) { - var changed, - destination = data.destination, - currValue = destination[key]; - - if (value && typeof value == 'object') { - if (isClassOf(value, 'Array')) { - // check if an array value has changed to a non-array value - if (!isClassOf(currValue, 'Array')) { - changed = currValue = []; - } - // or has changed its length - if (currValue.length != value.length) { - changed = currValue = currValue.slice(0, value.length); - currValue.length = value.length; - } - } - // check if an object has changed to a non-object value - else if (!currValue || typeof currValue != 'object') { - changed = currValue = {}; - } - // register a changed object - if (changed) { - changes[changes.length++] = { 'destination': destination, 'key': key, 'value': currValue }; - } - queue[queue.length++] = { 'destination': currValue, 'source': value }; - } - // register a changed primitive - else if (value !== currValue && !(value == null || isClassOf(value, 'Function'))) { - changes[changes.length++] = { 'destination': destination, 'key': key, 'value': value }; - } - }); - } - while ((data = queue[index++])); - - // if changed emit the `reset` event and if it isn't cancelled reset the benchmark - if (changes.length && (me.emit(event = Event('reset')), !event.cancelled)) { - forEach(changes, function(data) { - data.destination[data.key] = data.value; - }); - } - } - return me; - } - - /** - * Displays relevant benchmark information when coerced to a string. - * - * @name toString - * @memberOf Benchmark - * @returns {String} A string representation of the benchmark instance. - */ - function toStringBench() { - var me = this, - error = me.error, - hz = me.hz, - id = me.id, - stats = me.stats, - size = stats.sample.length, - pm = support.java ? '+/-' : '\xb1', - result = me.name || (isNaN(id) ? id : ''); - - if (error) { - result += ': ' + join(error); - } else { - result += ' x ' + formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + ' ops/sec ' + pm + - stats.rme.toFixed(2) + '% (' + size + ' run' + (size == 1 ? '' : 's') + ' sampled)'; - } - return result; - } - - /*--------------------------------------------------------------------------*/ - - /** - * Clocks the time taken to execute a test per cycle (secs). - * - * @private - * @param {Object} bench The benchmark instance. - * @returns {Number} The time taken. - */ - function clock() { - var applet, - options = Benchmark.options, - template = { 'begin': 's$=new n$', 'end': 'r$=(new n$-s$)/1e3', 'uid': uid }, - timers = [{ 'ns': timer.ns, 'res': max(0.0015, getRes('ms')), 'unit': 'ms' }]; - - // lazy define for hi-res timers - clock = function(clone) { - var deferred; - if (clone instanceof Deferred) { - deferred = clone; - clone = deferred.benchmark; - } - - var bench = clone._original, - fn = bench.fn, - fnArg = deferred ? getFirstArgument(fn) || 'deferred' : '', - stringable = isStringable(fn); - - var source = { - 'setup': getSource(bench.setup, preprocess('m$.setup()')), - 'fn': getSource(fn, preprocess('f$(' + fnArg + ')')), - 'fnArg': fnArg, - 'teardown': getSource(bench.teardown, preprocess('m$.teardown()')) - }; - - var compiled = bench.compiled, - count = bench.count = clone.count, - decompilable = support.decompilation || stringable, - id = bench.id, - isEmpty = !(source.fn || stringable), - name = bench.name || (typeof id == 'number' ? '' : id), - ns = timer.ns, - result = 0; - - // init `minTime` if needed - clone.minTime = bench.minTime || (bench.minTime = bench.options.minTime = options.minTime); - - // repair nanosecond timer - // (some Chrome builds erase the `ns` variable after millions of executions) - if (applet) { - try { - ns.nanoTime(); - } catch(e) { - // use non-element to avoid issues with libs that augment them - ns = timer.ns = new applet.Packages.nano; - } - } - - if (!compiled) { - // compile in setup/teardown functions and the test loop - compiled = bench.compiled = createFunction(preprocess('t$'), interpolate( - preprocess(deferred - ? 'var d$=this,#{fnArg}=d$,m$=d$.benchmark._original,f$=m$.fn,su$=m$.setup,td$=m$.teardown;' + - // when `deferred.cycles` is `0` then... - 'if(!d$.cycles){' + - // set `deferred.fn` - 'd$.fn=function(){var #{fnArg}=d$;if(typeof f$=="function"){try{#{fn}\n}catch(e$){f$(d$)}}else{#{fn}\n}};' + - // set `deferred.teardown` - 'd$.teardown=function(){d$.cycles=0;if(typeof td$=="function"){try{#{teardown}\n}catch(e$){td$()}}else{#{teardown}\n}};' + - // execute the benchmark's `setup` - 'if(typeof su$=="function"){try{#{setup}\n}catch(e$){su$()}}else{#{setup}\n};' + - // start timer - 't$.start(d$);' + - // execute `deferred.fn` and return a dummy object - '}d$.fn();return{}' - - : 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count,n$=t$.ns;#{setup}\n#{begin};' + - 'while(i$--){#{fn}\n}#{end};#{teardown}\nreturn{elapsed:r$,uid:"#{uid}"}'), - source - )); - - try { - if (isEmpty) { - // Firefox may remove dead code from Function#toString results - // http://bugzil.la/536085 - throw new Error('The test "' + name + '" is empty. This may be the result of dead code removal.'); - } - else if (!deferred) { - // pretest to determine if compiled code is exits early, usually by a - // rogue `return` statement, by checking for a return object with the uid - bench.count = 1; - compiled = (compiled.call(bench, timer) || {}).uid == uid && compiled; - bench.count = count; - } - } catch(e) { - compiled = null; - clone.error = e || new Error(String(e)); - bench.count = count; - } - // fallback when a test exits early or errors during pretest - if (decompilable && !compiled && !deferred && !isEmpty) { - compiled = createFunction(preprocess('t$'), interpolate( - preprocess( - (clone.error && !stringable - ? 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count' - : 'function f$(){#{fn}\n}var r$,s$,m$=this,i$=m$.count' - ) + - ',n$=t$.ns;#{setup}\n#{begin};m$.f$=f$;while(i$--){m$.f$()}#{end};' + - 'delete m$.f$;#{teardown}\nreturn{elapsed:r$}' - ), - source - )); - - try { - // pretest one more time to check for errors - bench.count = 1; - compiled.call(bench, timer); - bench.compiled = compiled; - bench.count = count; - delete clone.error; - } - catch(e) { - bench.count = count; - if (clone.error) { - compiled = null; - } else { - bench.compiled = compiled; - clone.error = e || new Error(String(e)); - } - } - } - } - // assign `compiled` to `clone` before calling in case a deferred benchmark - // immediately calls `deferred.resolve()` - clone.compiled = compiled; - // if no errors run the full test loop - if (!clone.error) { - result = compiled.call(deferred || bench, timer).elapsed; - } - return result; - }; - - /*------------------------------------------------------------------------*/ - - /** - * Gets the current timer's minimum resolution (secs). - */ - function getRes(unit) { - var measured, - begin, - count = 30, - divisor = 1e3, - ns = timer.ns, - sample = []; - - // get average smallest measurable time - while (count--) { - if (unit == 'us') { - divisor = 1e6; - if (ns.stop) { - ns.start(); - while (!(measured = ns.microseconds())) { } - } else if (perfName) { - divisor = 1e3; - measured = Function('n', 'var r,s=n.' + perfName + '();while(!(r=n.' + perfName + '()-s)){};return r')(ns); - } else { - begin = ns(); - while (!(measured = ns() - begin)) { } - } - } - else if (unit == 'ns') { - divisor = 1e9; - begin = ns.nanoTime(); - while (!(measured = ns.nanoTime() - begin)) { } - } - else { - begin = new ns; - while (!(measured = new ns - begin)) { } - } - // check for broken timers (nanoTime may have issues) - // http://alivebutsleepy.srnet.cz/unreliable-system-nanotime/ - if (measured > 0) { - sample.push(measured); - } else { - sample.push(Infinity); - break; - } - } - // convert to seconds - return getMean(sample) / divisor; - } - - /** - * Replaces all occurrences of `$` with a unique number and - * template tokens with content. - */ - function preprocess(code) { - return interpolate(code, template).replace(/\$/g, /\d+/.exec(uid)); - } - - /*------------------------------------------------------------------------*/ - - // detect nanosecond support from a Java applet - each(doc && doc.applets || [], function(element) { - return !(timer.ns = applet = 'nanoTime' in element && element); - }); - - // check type in case Safari returns an object instead of a number - try { - if (typeof timer.ns.nanoTime() == 'number') { - timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' }); - } - } catch(e) { } - - // detect Chrome's microsecond timer: - // enable benchmarking via the --enable-benchmarking command - // line switch in at least Chrome 7 to use chrome.Interval - try { - if ((timer.ns = new (window.chrome || window.chromium).Interval)) { - timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); - } - } catch(e) { } - - // detect `performance.now` microsecond resolution timer - if ((timer.ns = perfName && perfObject)) { - timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); - } - - // detect Node's microtime module: - // npm install microtime - if ((timer.ns = (req('microtime') || { 'now': 0 }).now)) { - timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); - } - - // pick timer with highest resolution - timer = reduce(timers, function(timer, other) { - return other.res < timer.res ? other : timer; - }); - - // remove unused applet - if (timer.unit != 'ns' && applet) { - applet = destroyElement(applet); - } - // error if there are no working timers - if (timer.res == Infinity) { - throw new Error('Benchmark.js was unable to find a working timer.'); - } - // use API of chosen timer - if (timer.unit == 'ns') { - extend(template, { - 'begin': 's$=n$.nanoTime()', - 'end': 'r$=(n$.nanoTime()-s$)/1e9' - }); - } - else if (timer.unit == 'us') { - if (timer.ns.stop) { - extend(template, { - 'begin': 's$=n$.start()', - 'end': 'r$=n$.microseconds()/1e6' - }); - } else if (perfName) { - extend(template, { - 'begin': 's$=n$.' + perfName + '()', - 'end': 'r$=(n$.' + perfName + '()-s$)/1e3' - }); - } else { - extend(template, { - 'begin': 's$=n$()', - 'end': 'r$=(n$()-s$)/1e6' - }); - } - } - - // define `timer` methods - timer.start = createFunction(preprocess('o$'), - preprocess('var n$=this.ns,#{begin};o$.elapsed=0;o$.timeStamp=s$')); - - timer.stop = createFunction(preprocess('o$'), - preprocess('var n$=this.ns,s$=o$.timeStamp,#{end};o$.elapsed=r$')); - - // resolve time span required to achieve a percent uncertainty of at most 1% - // http://spiff.rit.edu/classes/phys273/uncert/uncert.html - options.minTime || (options.minTime = max(timer.res / 2 / 0.01, 0.05)); - return clock.apply(null, arguments); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Computes stats on benchmark results. - * - * @private - * @param {Object} bench The benchmark instance. - * @param {Object} options The options object. - */ - function compute(bench, options) { - options || (options = {}); - - var async = options.async, - elapsed = 0, - initCount = bench.initCount, - minSamples = bench.minSamples, - queue = [], - sample = bench.stats.sample; - - /** - * Adds a number of clones to the queue. - */ - function enqueue(count) { - while (count--) { - queue.push(bench.clone({ - '_original': bench, - 'events': { - 'abort': [update], - 'cycle': [update], - 'error': [update], - 'start': [update] - } - })); - } - } - - /** - * Updates the clone/original benchmarks to keep their data in sync. - */ - function update(event) { - var clone = this, - type = event.type; - - if (bench.running) { - if (type == 'start') { - // Note: `clone.minTime` prop is inited in `clock()` - clone.count = bench.initCount; - } - else { - if (type == 'error') { - bench.error = clone.error; - } - if (type == 'abort') { - bench.abort(); - bench.emit('cycle'); - } else { - event.currentTarget = event.target = bench; - bench.emit(event); - } - } - } else if (bench.aborted) { - // clear abort listeners to avoid triggering bench's abort/cycle again - clone.events.abort.length = 0; - clone.abort(); - } - } - - /** - * Determines if more clones should be queued or if cycling should stop. - */ - function evaluate(event) { - var critical, - df, - mean, - moe, - rme, - sd, - sem, - variance, - clone = event.target, - done = bench.aborted, - now = +new Date, - size = sample.push(clone.times.period), - maxedOut = size >= minSamples && (elapsed += now - clone.times.timeStamp) / 1e3 > bench.maxTime, - times = bench.times, - varOf = function(sum, x) { return sum + pow(x - mean, 2); }; - - // exit early for aborted or unclockable tests - if (done || clone.hz == Infinity) { - maxedOut = !(size = sample.length = queue.length = 0); - } - - if (!done) { - // sample mean (estimate of the population mean) - mean = getMean(sample); - // sample variance (estimate of the population variance) - variance = reduce(sample, varOf, 0) / (size - 1) || 0; - // sample standard deviation (estimate of the population standard deviation) - sd = sqrt(variance); - // standard error of the mean (a.k.a. the standard deviation of the sampling distribution of the sample mean) - sem = sd / sqrt(size); - // degrees of freedom - df = size - 1; - // critical value - critical = tTable[Math.round(df) || 1] || tTable.infinity; - // margin of error - moe = sem * critical; - // relative margin of error - rme = (moe / mean) * 100 || 0; - - extend(bench.stats, { - 'deviation': sd, - 'mean': mean, - 'moe': moe, - 'rme': rme, - 'sem': sem, - 'variance': variance - }); - - // Abort the cycle loop when the minimum sample size has been collected - // and the elapsed time exceeds the maximum time allowed per benchmark. - // We don't count cycle delays toward the max time because delays may be - // increased by browsers that clamp timeouts for inactive tabs. - // https://developer.mozilla.org/en/window.setTimeout#Inactive_tabs - if (maxedOut) { - // reset the `initCount` in case the benchmark is rerun - bench.initCount = initCount; - bench.running = false; - done = true; - times.elapsed = (now - times.timeStamp) / 1e3; - } - if (bench.hz != Infinity) { - bench.hz = 1 / mean; - times.cycle = mean * bench.count; - times.period = mean; - } - } - // if time permits, increase sample size to reduce the margin of error - if (queue.length < 2 && !maxedOut) { - enqueue(1); - } - // abort the invoke cycle when done - event.aborted = done; - } - - // init queue and begin - enqueue(minSamples); - invoke(queue, { - 'name': 'run', - 'args': { 'async': async }, - 'queued': true, - 'onCycle': evaluate, - 'onComplete': function() { bench.emit('complete'); } - }); - } - - /*--------------------------------------------------------------------------*/ - - /** - * Cycles a benchmark until a run `count` can be established. - * - * @private - * @param {Object} clone The cloned benchmark instance. - * @param {Object} options The options object. - */ - function cycle(clone, options) { - options || (options = {}); - - var deferred; - if (clone instanceof Deferred) { - deferred = clone; - clone = clone.benchmark; - } - - var clocked, - cycles, - divisor, - event, - minTime, - period, - async = options.async, - bench = clone._original, - count = clone.count, - times = clone.times; - - // continue, if not aborted between cycles - if (clone.running) { - // `minTime` is set to `Benchmark.options.minTime` in `clock()` - cycles = ++clone.cycles; - clocked = deferred ? deferred.elapsed : clock(clone); - minTime = clone.minTime; - - if (cycles > bench.cycles) { - bench.cycles = cycles; - } - if (clone.error) { - event = Event('error'); - event.message = clone.error; - clone.emit(event); - if (!event.cancelled) { - clone.abort(); - } - } - } - - // continue, if not errored - if (clone.running) { - // time taken to complete last test cycle - bench.times.cycle = times.cycle = clocked; - // seconds per operation - period = bench.times.period = times.period = clocked / count; - // ops per second - bench.hz = clone.hz = 1 / period; - // avoid working our way up to this next time - bench.initCount = clone.initCount = count; - // do we need to do another cycle? - clone.running = clocked < minTime; - - if (clone.running) { - // tests may clock at `0` when `initCount` is a small number, - // to avoid that we set its count to something a bit higher - if (!clocked && (divisor = divisors[clone.cycles]) != null) { - count = floor(4e6 / divisor); - } - // calculate how many more iterations it will take to achive the `minTime` - if (count <= clone.count) { - count += Math.ceil((minTime - clocked) / period); - } - clone.running = count != Infinity; - } - } - // should we exit early? - event = Event('cycle'); - clone.emit(event); - if (event.aborted) { - clone.abort(); - } - // figure out what to do next - if (clone.running) { - // start a new cycle - clone.count = count; - if (deferred) { - clone.compiled.call(deferred, timer); - } else if (async) { - delay(clone, function() { cycle(clone, options); }); - } else { - cycle(clone); - } - } - else { - // fix TraceMonkey bug associated with clock fallbacks - // http://bugzil.la/509069 - if (support.browser) { - runScript(uid + '=1;delete ' + uid); - } - // done - clone.emit('complete'); - } - } - - /*--------------------------------------------------------------------------*/ - - /** - * Runs the benchmark. - * - * @memberOf Benchmark - * @param {Object} [options={}] Options object. - * @returns {Object} The benchmark instance. - * @example - * - * // basic usage - * bench.run(); - * - * // or with options - * bench.run({ 'async': true }); - */ - function run(options) { - var me = this, - event = Event('start'); - - // set `running` to `false` so `reset()` won't call `abort()` - me.running = false; - me.reset(); - me.running = true; - - me.count = me.initCount; - me.times.timeStamp = +new Date; - me.emit(event); - - if (!event.cancelled) { - options = { 'async': ((options = options && options.async) == null ? me.async : options) && support.timeout }; - - // for clones created within `compute()` - if (me._original) { - if (me.defer) { - Deferred(me); - } else { - cycle(me, options); - } - } - // for original benchmarks - else { - compute(me, options); - } - } - return me; - } - - /*--------------------------------------------------------------------------*/ - - // Firefox 1 erroneously defines variable and argument names of functions on - // the function itself as non-configurable properties with `undefined` values. - // The bugginess continues as the `Benchmark` constructor has an argument - // named `options` and Firefox 1 will not assign a value to `Benchmark.options`, - // making it non-writable in the process, unless it is the first property - // assigned by for-in loop of `extend()`. - extend(Benchmark, { - - /** - * The default options copied by benchmark instances. - * - * @static - * @memberOf Benchmark - * @type Object - */ - 'options': { - - /** - * A flag to indicate that benchmark cycles will execute asynchronously - * by default. - * - * @memberOf Benchmark.options - * @type Boolean - */ - 'async': false, - - /** - * A flag to indicate that the benchmark clock is deferred. - * - * @memberOf Benchmark.options - * @type Boolean - */ - 'defer': false, - - /** - * The delay between test cycles (secs). - * @memberOf Benchmark.options - * @type Number - */ - 'delay': 0.005, - - /** - * Displayed by Benchmark#toString when a `name` is not available - * (auto-generated if absent). - * - * @memberOf Benchmark.options - * @type String - */ - 'id': undefined, - - /** - * The default number of times to execute a test on a benchmark's first cycle. - * - * @memberOf Benchmark.options - * @type Number - */ - 'initCount': 1, - - /** - * The maximum time a benchmark is allowed to run before finishing (secs). - * Note: Cycle delays aren't counted toward the maximum time. - * - * @memberOf Benchmark.options - * @type Number - */ - 'maxTime': 5, - - /** - * The minimum sample size required to perform statistical analysis. - * - * @memberOf Benchmark.options - * @type Number - */ - 'minSamples': 5, - - /** - * The time needed to reduce the percent uncertainty of measurement to 1% (secs). - * - * @memberOf Benchmark.options - * @type Number - */ - 'minTime': 0, - - /** - * The name of the benchmark. - * - * @memberOf Benchmark.options - * @type String - */ - 'name': undefined, - - /** - * An event listener called when the benchmark is aborted. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onAbort': undefined, - - /** - * An event listener called when the benchmark completes running. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onComplete': undefined, - - /** - * An event listener called after each run cycle. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onCycle': undefined, - - /** - * An event listener called when a test errors. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onError': undefined, - - /** - * An event listener called when the benchmark is reset. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onReset': undefined, - - /** - * An event listener called when the benchmark starts running. - * - * @memberOf Benchmark.options - * @type Function - */ - 'onStart': undefined - }, - - /** - * Platform object with properties describing things like browser name, - * version, and operating system. - * - * @static - * @memberOf Benchmark - * @type Object - */ - 'platform': req('platform') || window.platform || { - - /** - * The platform description. - * - * @memberOf Benchmark.platform - * @type String - */ - 'description': window.navigator && navigator.userAgent || null, - - /** - * The name of the browser layout engine. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'layout': null, - - /** - * The name of the product hosting the browser. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'product': null, - - /** - * The name of the browser/environment. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'name': null, - - /** - * The name of the product's manufacturer. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'manufacturer': null, - - /** - * The name of the operating system. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'os': null, - - /** - * The alpha/beta release indicator. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'prerelease': null, - - /** - * The browser/environment version. - * - * @memberOf Benchmark.platform - * @type String|Null - */ - 'version': null, - - /** - * Return platform description when the platform object is coerced to a string. - * - * @memberOf Benchmark.platform - * @type Function - * @returns {String} The platform description. - */ - 'toString': function() { - return this.description || ''; - } - }, - - /** - * The semantic version number. - * - * @static - * @memberOf Benchmark - * @type String - */ - 'version': '1.0.0-pre', - - // an object of environment/feature detection flags - 'support': support, - - // clone objects - 'deepClone': deepClone, - - // iteration utility - 'each': each, - - // augment objects - 'extend': extend, - - // generic Array#filter - 'filter': filter, - - // generic Array#forEach - 'forEach': forEach, - - // generic own property iteration utility - 'forOwn': forOwn, - - // converts a number to a comma-separated string - 'formatNumber': formatNumber, - - // generic Object#hasOwnProperty - // (trigger hasKey's lazy define before assigning it to Benchmark) - 'hasKey': (hasKey(Benchmark, ''), hasKey), - - // generic Array#indexOf - 'indexOf': indexOf, - - // template utility - 'interpolate': interpolate, - - // invokes a method on each item in an array - 'invoke': invoke, - - // generic Array#join for arrays and objects - 'join': join, - - // generic Array#map - 'map': map, - - // retrieves a property value from each item in an array - 'pluck': pluck, - - // generic Array#reduce - 'reduce': reduce - }); - - /*--------------------------------------------------------------------------*/ - - extend(Benchmark.prototype, { - - /** - * The number of times a test was executed. - * - * @memberOf Benchmark - * @type Number - */ - 'count': 0, - - /** - * The number of cycles performed while benchmarking. - * - * @memberOf Benchmark - * @type Number - */ - 'cycles': 0, - - /** - * The number of executions per second. - * - * @memberOf Benchmark - * @type Number - */ - 'hz': 0, - - /** - * The compiled test function. - * - * @memberOf Benchmark - * @type Function|String - */ - 'compiled': undefined, - - /** - * The error object if the test failed. - * - * @memberOf Benchmark - * @type Object - */ - 'error': undefined, - - /** - * The test to benchmark. - * - * @memberOf Benchmark - * @type Function|String - */ - 'fn': undefined, - - /** - * A flag to indicate if the benchmark is aborted. - * - * @memberOf Benchmark - * @type Boolean - */ - 'aborted': false, - - /** - * A flag to indicate if the benchmark is running. - * - * @memberOf Benchmark - * @type Boolean - */ - 'running': false, - - /** - * Compiled into the test and executed immediately **before** the test loop. - * - * @memberOf Benchmark - * @type Function|String - * @example - * - * // basic usage - * var bench = Benchmark({ - * 'setup': function() { - * var c = this.count, - * element = document.getElementById('container'); - * while (c--) { - * element.appendChild(document.createElement('div')); - * } - * }, - * 'fn': function() { - * element.removeChild(element.lastChild); - * } - * }); - * - * // compiles to something like: - * var c = this.count, - * element = document.getElementById('container'); - * while (c--) { - * element.appendChild(document.createElement('div')); - * } - * var start = new Date; - * while (count--) { - * element.removeChild(element.lastChild); - * } - * var end = new Date - start; - * - * // or using strings - * var bench = Benchmark({ - * 'setup': '\ - * var a = 0;\n\ - * (function() {\n\ - * (function() {\n\ - * (function() {', - * 'fn': 'a += 1;', - * 'teardown': '\ - * }())\n\ - * }())\n\ - * }())' - * }); - * - * // compiles to something like: - * var a = 0; - * (function() { - * (function() { - * (function() { - * var start = new Date; - * while (count--) { - * a += 1; - * } - * var end = new Date - start; - * }()) - * }()) - * }()) - */ - 'setup': noop, - - /** - * Compiled into the test and executed immediately **after** the test loop. - * - * @memberOf Benchmark - * @type Function|String - */ - 'teardown': noop, - - /** - * An object of stats including mean, margin or error, and standard deviation. - * - * @memberOf Benchmark - * @type Object - */ - 'stats': { - - /** - * The margin of error. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'moe': 0, - - /** - * The relative margin of error (expressed as a percentage of the mean). - * - * @memberOf Benchmark#stats - * @type Number - */ - 'rme': 0, - - /** - * The standard error of the mean. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'sem': 0, - - /** - * The sample standard deviation. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'deviation': 0, - - /** - * The sample arithmetic mean. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'mean': 0, - - /** - * The array of sampled periods. - * - * @memberOf Benchmark#stats - * @type Array - */ - 'sample': [], - - /** - * The sample variance. - * - * @memberOf Benchmark#stats - * @type Number - */ - 'variance': 0 - }, - - /** - * An object of timing data including cycle, elapsed, period, start, and stop. - * - * @memberOf Benchmark - * @type Object - */ - 'times': { - - /** - * The time taken to complete the last cycle (secs). - * - * @memberOf Benchmark#times - * @type Number - */ - 'cycle': 0, - - /** - * The time taken to complete the benchmark (secs). - * - * @memberOf Benchmark#times - * @type Number - */ - 'elapsed': 0, - - /** - * The time taken to execute the test once (secs). - * - * @memberOf Benchmark#times - * @type Number - */ - 'period': 0, - - /** - * A timestamp of when the benchmark started (ms). - * - * @memberOf Benchmark#times - * @type Number - */ - 'timeStamp': 0 - }, - - // aborts benchmark (does not record times) - 'abort': abort, - - // creates a new benchmark using the same test and options - 'clone': clone, - - // compares benchmark's hertz with another - 'compare': compare, - - // executes listeners - 'emit': emit, - - // get listeners - 'listeners': listeners, - - // unregister listeners - 'off': off, - - // register listeners - 'on': on, - - // reset benchmark properties - 'reset': reset, - - // runs the benchmark - 'run': run, - - // pretty print benchmark info - 'toString': toStringBench - }); - - /*--------------------------------------------------------------------------*/ - - extend(Deferred.prototype, { - - /** - * The deferred benchmark instance. - * - * @memberOf Benchmark.Deferred - * @type Object - */ - 'benchmark': null, - - /** - * The number of deferred cycles performed while benchmarking. - * - * @memberOf Benchmark.Deferred - * @type Number - */ - 'cycles': 0, - - /** - * The time taken to complete the deferred benchmark (secs). - * - * @memberOf Benchmark.Deferred - * @type Number - */ - 'elapsed': 0, - - /** - * A timestamp of when the deferred benchmark started (ms). - * - * @memberOf Benchmark.Deferred - * @type Number - */ - 'timeStamp': 0, - - // cycles/completes the deferred benchmark - 'resolve': resolve - }); - - /*--------------------------------------------------------------------------*/ - - extend(Event.prototype, { - - /** - * A flag to indicate if the emitters listener iteration is aborted. - * - * @memberOf Benchmark.Event - * @type Boolean - */ - 'aborted': false, - - /** - * A flag to indicate if the default action is cancelled. - * - * @memberOf Benchmark.Event - * @type Boolean - */ - 'cancelled': false, - - /** - * The object whose listeners are currently being processed. - * - * @memberOf Benchmark.Event - * @type Object - */ - 'currentTarget': undefined, - - /** - * The return value of the last executed listener. - * - * @memberOf Benchmark.Event - * @type Mixed - */ - 'result': undefined, - - /** - * The object to which the event was originally emitted. - * - * @memberOf Benchmark.Event - * @type Object - */ - 'target': undefined, - - /** - * A timestamp of when the event was created (ms). - * - * @memberOf Benchmark.Event - * @type Number - */ - 'timeStamp': 0, - - /** - * The event type. - * - * @memberOf Benchmark.Event - * @type String - */ - 'type': '' - }); - - /*--------------------------------------------------------------------------*/ - - /** - * The default options copied by suite instances. - * - * @static - * @memberOf Benchmark.Suite - * @type Object - */ - Suite.options = { - - /** - * The name of the suite. - * - * @memberOf Benchmark.Suite.options - * @type String - */ - 'name': undefined - }; - - /*--------------------------------------------------------------------------*/ - - extend(Suite.prototype, { - - /** - * The number of benchmarks in the suite. - * - * @memberOf Benchmark.Suite - * @type Number - */ - 'length': 0, - - /** - * A flag to indicate if the suite is aborted. - * - * @memberOf Benchmark.Suite - * @type Boolean - */ - 'aborted': false, - - /** - * A flag to indicate if the suite is running. - * - * @memberOf Benchmark.Suite - * @type Boolean - */ - 'running': false, - - /** - * An `Array#forEach` like method. - * Callbacks may terminate the loop by explicitly returning `false`. - * - * @memberOf Benchmark.Suite - * @param {Function} callback The function called per iteration. - * @returns {Object} The suite iterated over. - */ - 'forEach': methodize(forEach), - - /** - * An `Array#indexOf` like method. - * - * @memberOf Benchmark.Suite - * @param {Mixed} value The value to search for. - * @returns {Number} The index of the matched value or `-1`. - */ - 'indexOf': methodize(indexOf), - - /** - * Invokes a method on all benchmarks in the suite. - * - * @memberOf Benchmark.Suite - * @param {String|Object} name The name of the method to invoke OR options object. - * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. - * @returns {Array} A new array of values returned from each method invoked. - */ - 'invoke': methodize(invoke), - - /** - * Converts the suite of benchmarks to a string. - * - * @memberOf Benchmark.Suite - * @param {String} [separator=','] A string to separate each element of the array. - * @returns {String} The string. - */ - 'join': [].join, - - /** - * An `Array#map` like method. - * - * @memberOf Benchmark.Suite - * @param {Function} callback The function called per iteration. - * @returns {Array} A new array of values returned by the callback. - */ - 'map': methodize(map), - - /** - * Retrieves the value of a specified property from all benchmarks in the suite. - * - * @memberOf Benchmark.Suite - * @param {String} property The property to pluck. - * @returns {Array} A new array of property values. - */ - 'pluck': methodize(pluck), - - /** - * Removes the last benchmark from the suite and returns it. - * - * @memberOf Benchmark.Suite - * @returns {Mixed} The removed benchmark. - */ - 'pop': [].pop, - - /** - * Appends benchmarks to the suite. - * - * @memberOf Benchmark.Suite - * @returns {Number} The suite's new length. - */ - 'push': [].push, - - /** - * Sorts the benchmarks of the suite. - * - * @memberOf Benchmark.Suite - * @param {Function} [compareFn=null] A function that defines the sort order. - * @returns {Object} The sorted suite. - */ - 'sort': [].sort, - - /** - * An `Array#reduce` like method. - * - * @memberOf Benchmark.Suite - * @param {Function} callback The function called per iteration. - * @param {Mixed} accumulator Initial value of the accumulator. - * @returns {Mixed} The accumulator. - */ - 'reduce': methodize(reduce), - - // aborts all benchmarks in the suite - 'abort': abortSuite, - - // adds a benchmark to the suite - 'add': add, - - // creates a new suite with cloned benchmarks - 'clone': cloneSuite, - - // executes listeners of a specified type - 'emit': emit, - - // creates a new suite of filtered benchmarks - 'filter': filterSuite, - - // get listeners - 'listeners': listeners, - - // unregister listeners - 'off': off, - - // register listeners - 'on': on, - - // resets all benchmarks in the suite - 'reset': resetSuite, - - // runs all benchmarks in the suite - 'run': runSuite, - - // array methods - 'concat': concat, - - 'reverse': reverse, - - 'shift': shift, - - 'slice': slice, - - 'splice': splice, - - 'unshift': unshift - }); - - /*--------------------------------------------------------------------------*/ - - // expose Deferred, Event and Suite - extend(Benchmark, { - 'Deferred': Deferred, - 'Event': Event, - 'Suite': Suite - }); - - // expose Benchmark - // some AMD build optimizers, like r.js, check for specific condition patterns like the following: - if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { - // define as an anonymous module so, through path mapping, it can be aliased - define(function() { - return Benchmark; - }); - } - // check for `exports` after `define` in case a build optimizer adds an `exports` object - else if (freeExports) { - // in Node.js or RingoJS v0.8.0+ - if (typeof module == 'object' && module && module.exports == freeExports) { - (module.exports = Benchmark).Benchmark = Benchmark; - } - // in Narwhal or RingoJS v0.7.0- - else { - freeExports.Benchmark = Benchmark; - } - } - // in a browser or Rhino - else { - // use square bracket notation so Closure Compiler won't munge `Benchmark` - // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export - window['Benchmark'] = Benchmark; - } - - // trigger clock's lazy define early to avoid a security error - if (support.air) { - clock({ '_original': { 'fn': noop, 'count': 1, 'options': {} } }); - } -}(this)); diff --git a/benchmarks/external/backbone.html b/benchmarks/external/backbone.html deleted file mode 100644 index 7aabdd8ffac..00000000000 --- a/benchmarks/external/backbone.html +++ /dev/null @@ -1,277 +0,0 @@ - - - - - - - - - - - - - -

- Folks often ask about how the difference between Backbone and Ember's approaches to model/view binding play out in web apps. This script uses the latest Backbone.js and Ember.js to animate 100 circles (or more -- change "N" in the JavaScript), so that you can see the responsiveness after you click the button, and visualize the speed difference. The Ember team is aware that in very performance-sensitive situations, like this example, its binding implementation may be too much overhead. They have reviewed this example, and hope to be able to remove this difference in the future. Note that this is just a simple benchmark: you wouldn't be doing this in an actual app. -

- - - - -
- - - - - - diff --git a/benchmarks/iframe_runner.js b/benchmarks/iframe_runner.js deleted file mode 100644 index 4c5bdbe6971..00000000000 --- a/benchmarks/iframe_runner.js +++ /dev/null @@ -1,90 +0,0 @@ -/*globals BenchWarmer:true jQuery Benchmark*/ - -BenchWarmer = function(emberPath, logger, profile) { - this.emberPath = emberPath; - this.profile = profile; - this.logger = logger; -}; - -BenchWarmer.evalString = function(string, emberPath, logger, profile) { - var benchWarmer = new BenchWarmer(emberPath, logger, profile); - - var bench = function(name, fn) { - benchWarmer.bench(name, fn); - }; - - var before = function(fn) { - benchWarmer.before(fn); - }; - - var after = function(fn) { - benchWarmer.after(fn); - }; - - eval(string); - - return benchWarmer; -}; - -BenchWarmer.prototype = { - log: function(string) { - this.logger(string); - }, - - before: function(fn) { - this.setup = fn; - }, - - after: function(fn) { - this.teardown = fn; - }, - - bench: function(name, fn) { - var self = this; - this.name = name; - this.fn = fn; - - this.benchmark = new Benchmark(name, fn, { - async: true, - - setup: this.setup, - teardown: this.teardown, - - onCycle: function(event, bench) { - self.log("" + name + " x" + event.target.stats.sample.length + " Hz: " + Math.floor(event.target.hz)); - }, - - onComplete: function() { - var moe = Math.round(this.stats.moe / this.stats.mean * 10000) / 100; - var sampleMoe = (moe / 100) * this.hz; - self.log("" + name + " x" + this.stats.sample.length + " Hz: " + Math.floor(this.hz) + " ±" + moe + "% (" + sampleMoe + ")"); - - if (self.next) { self.next.run(); } - } - }); - - return this; - }, - - run: function() { - if (this.profile) { - var self = this; - - var count = parseInt(this.profile, 10); - - setTimeout(function() { - if (self.setup) { self.setup(); } - console.profile(self.emberPath + ": " + self.name); - for (var i=0; i - - - - - - - - -
-
-
- - diff --git a/benchmarks/nano.jar b/benchmarks/nano.jar deleted file mode 100644 index b5778403b61..00000000000 Binary files a/benchmarks/nano.jar and /dev/null differ diff --git a/benchmarks/runner.js b/benchmarks/runner.js deleted file mode 100644 index 5558d538617..00000000000 --- a/benchmarks/runner.js +++ /dev/null @@ -1,81 +0,0 @@ -/*global jQuery Benchmark BenchWarmer:true*/ - -var embers = { - before: "../distold/ember.prod.js", - after: "../dist/ember.prod.js" -}; - -function makeiframe(emberPath, suitePath, suiteCode, profile, callback) { - var iframe = jQuery("