summaryrefslogtreecommitdiffstats
path: root/addon-sdk/source/lib/method
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /addon-sdk/source/lib/method
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'addon-sdk/source/lib/method')
-rw-r--r--addon-sdk/source/lib/method/.travis.yml5
-rw-r--r--addon-sdk/source/lib/method/History.md55
-rw-r--r--addon-sdk/source/lib/method/License.md18
-rw-r--r--addon-sdk/source/lib/method/Readme.md117
-rw-r--r--addon-sdk/source/lib/method/core.js225
-rw-r--r--addon-sdk/source/lib/method/package.json41
-rw-r--r--addon-sdk/source/lib/method/test/browser.js20
-rw-r--r--addon-sdk/source/lib/method/test/common.js272
8 files changed, 753 insertions, 0 deletions
diff --git a/addon-sdk/source/lib/method/.travis.yml b/addon-sdk/source/lib/method/.travis.yml
new file mode 100644
index 000000000..780731a47
--- /dev/null
+++ b/addon-sdk/source/lib/method/.travis.yml
@@ -0,0 +1,5 @@
+language: node_js
+node_js:
+ - 0.4
+ - 0.5
+ - 0.6
diff --git a/addon-sdk/source/lib/method/History.md b/addon-sdk/source/lib/method/History.md
new file mode 100644
index 000000000..95258c45f
--- /dev/null
+++ b/addon-sdk/source/lib/method/History.md
@@ -0,0 +1,55 @@
+# Changes
+
+## 1.0.2 / 2012-12-26
+
+ - Delegate to polymorphic methods from `.define` and `.implement` so, they
+ can be overidden.
+
+## 1.0.1 / 2012-11-11
+
+ - Fix issues with different `Error` types as they all inherit from
+ `Error`.
+
+## 1.0.0 / 2012-11-09
+
+ - Add browser test integration.
+ - Fix cross-browser incompatibilities & test failures.
+ - Add support for host objects.
+ - Add optional `hint` argument for method to ease debugging.
+ - Remove default implementation at definition time.
+
+## 0.1.1 / 2012-10-15
+
+ - Fix regression causing custom type implementation to be stored on objects.
+
+## 0.1.0 / 2012-10-15
+
+ - Remove dependency on name module.
+ - Implement fallback for engines that do not support ES5.
+ - Add support for built-in type extensions without extending their prototypes.
+ - Make API for default definitions more intuitive.
+ Skipping type argument now defines default:
+
+ isFoo.define(function(value) {
+ return false
+ })
+
+ - Make exposed `define` and `implement` polymorphic.
+ - Removed dev dependency on swank-js.
+ - Primitive types `string, number, boolean` no longer inherit method
+ implementations from `Object`.
+
+## 0.0.3 / 2012-07-17
+
+ - Remove module boilerplate
+
+## 0.0.2 / 2012-06-26
+
+ - Name changes to make it less conflicting with other library conventions.
+ - Expose function version of `define` & `implement` methods.
+ - Expose `Null` and `Undefined` object holding implementations for an
+ associated types.
+
+## 0.0.1 / 2012-06-25
+
+ - Initial release
diff --git a/addon-sdk/source/lib/method/License.md b/addon-sdk/source/lib/method/License.md
new file mode 100644
index 000000000..ed76489a3
--- /dev/null
+++ b/addon-sdk/source/lib/method/License.md
@@ -0,0 +1,18 @@
+Copyright 2012 Irakli Gozalishvili. All rights reserved.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
diff --git a/addon-sdk/source/lib/method/Readme.md b/addon-sdk/source/lib/method/Readme.md
new file mode 100644
index 000000000..9584c9160
--- /dev/null
+++ b/addon-sdk/source/lib/method/Readme.md
@@ -0,0 +1,117 @@
+# method
+
+[![Build Status](https://secure.travis-ci.org/Gozala/method.png)](http://travis-ci.org/Gozala/method)
+
+Library provides an API for defining polymorphic methods that dispatch on the
+first argument type. This provides a powerful way for decouple abstraction
+interface definition from an actual implementation per type, without risks
+of interference with other libraries.
+
+### Motivation
+
+ - Provide a high-performance, dynamic polymorphism construct as an
+ alternative to existing object methods that does not provides any
+ mechanics for guarding against name conflicts.
+ - Allow independent extension of types, and implementations of methods
+ on types, by different parties.
+
+## Install
+
+ npm install method
+
+## Use
+
+```js
+var method = require("method")
+
+// Define `isWatchable` method that can be implemented for any type.
+var isWatchable = method("isWatchable")
+
+// If you call it on any object it will
+// throw as nothing implements that method yet.
+//isWatchable({}) // => Exception: method is not implemented
+
+// If you define private method on `Object.prototype`
+// all objects will inherit it.
+Object.prototype[isWatchable] = function() {
+ return false;
+}
+
+isWatchable({}) // => false
+
+
+// Although `isWatchable` property above will be enumerable and there for
+// may damage some assumbtions made by other libraries. There for it"s
+// recomended to use built-in helpers methods that will define extension
+// without breaking assumbtions made by other libraries:
+
+isWatchable.define(Object, function() { return false })
+
+
+// There are primitive types in JS that won"t inherit methods from Object:
+isWatchable(null) // => Exception: method is not implemented
+
+// One could either implement methods for such types:
+isWatchable.define(null, function() { return false })
+isWatchable.define(undefined, function() { return false })
+
+// Or simply define default implementation:
+isWatchable.define(function() { return false })
+
+// Alternatively default implementation may be provided at creation:
+isWatchable = method(function() { return false })
+
+// Method dispatches on an first argument type. That allows us to create
+// new types with an alternative implementations:
+function Watchable() {}
+isWatchable.define(Watchable, function() { return true })
+
+// This will make all `Watchable` instances watchable!
+isWatchable(new Watchable()) // => true
+
+// Arbitrary objects can also be extended to implement given method. For example
+// any object can simply made watchable:
+function watchable(object) {
+ return isWatchable.implement(objct, function() { return true })
+}
+
+isWatchable(watchable({})) // => true
+
+// Full protocols can be defined with such methods:
+var observers = "observers@" + module.filename
+var watchers = method("watchers")
+var watch = method("watch")
+var unwatch = method("unwatch")
+
+watchers.define(Watchable, function(target) {
+ return target[observers] || (target[observers] = [])
+})
+
+watch.define(Watchable, function(target, watcher) {
+ var observers = watchers(target)
+ if (observers.indexOf(watcher) < 0) observers.push(watcher)
+ return target
+})
+unwatch.define(Watchable, function(target, watcher) {
+ var observers = watchers(target)
+ var index = observers.indexOf(watcher)
+ if (observers.indexOf(watcher) >= 0) observers.unshift(watcher)
+ return target
+})
+
+// Define type Port that inherits form Watchable
+
+function Port() {}
+Port.prototype = Object.create(Watchable.prototype)
+
+var emit = method("emit")
+emit.define(Port, function(port, message) {
+ watchers(port).slice().forEach(function(watcher) {
+ watcher(message)
+ })
+})
+
+var p = new Port()
+watch(p, console.log)
+emit(p, "hello world") // => info: "hello world"
+```
diff --git a/addon-sdk/source/lib/method/core.js b/addon-sdk/source/lib/method/core.js
new file mode 100644
index 000000000..a6a5261e6
--- /dev/null
+++ b/addon-sdk/source/lib/method/core.js
@@ -0,0 +1,225 @@
+"use strict";
+
+var defineProperty = Object.defineProperty || function(object, name, property) {
+ object[name] = property.value
+ return object
+}
+
+// Shortcut for `Object.prototype.toString` for faster access.
+var typefy = Object.prototype.toString
+
+// Map to for jumping from typeof(value) to associated type prefix used
+// as a hash in the map of builtin implementations.
+var types = { "function": "Object", "object": "Object" }
+
+// Array is used to save method implementations for the host objects in order
+// to avoid extending them with non-primitive values that could cause leaks.
+var host = []
+// Hash map is used to save method implementations for builtin types in order
+// to avoid extending their prototypes. This also allows to share method
+// implementations for types across diff contexts / frames / compartments.
+var builtin = {}
+
+function Primitive() {}
+function ObjectType() {}
+ObjectType.prototype = new Primitive()
+function ErrorType() {}
+ErrorType.prototype = new ObjectType()
+
+var Default = builtin.Default = Primitive.prototype
+var Null = builtin.Null = new Primitive()
+var Void = builtin.Void = new Primitive()
+builtin.String = new Primitive()
+builtin.Number = new Primitive()
+builtin.Boolean = new Primitive()
+
+builtin.Object = ObjectType.prototype
+builtin.Error = ErrorType.prototype
+
+builtin.EvalError = new ErrorType()
+builtin.InternalError = new ErrorType()
+builtin.RangeError = new ErrorType()
+builtin.ReferenceError = new ErrorType()
+builtin.StopIteration = new ErrorType()
+builtin.SyntaxError = new ErrorType()
+builtin.TypeError = new ErrorType()
+builtin.URIError = new ErrorType()
+
+
+function Method(hint) {
+ /**
+ Private Method is a callable private name that dispatches on the first
+ arguments same named Method:
+
+ method(object, ...rest) => object[method](...rest)
+
+ Optionally hint string may be provided that will be used in generated names
+ to ease debugging.
+
+ ## Example
+
+ var foo = Method()
+
+ // Implementation for any types
+ foo.define(function(value, arg1, arg2) {
+ // ...
+ })
+
+ // Implementation for a specific type
+ foo.define(BarType, function(bar, arg1, arg2) {
+ // ...
+ })
+ **/
+
+ // Create an internal unique name if `hint` is provided it is used to
+ // prefix name to ease debugging.
+ var name = (hint || "") + "#" + Math.random().toString(32).substr(2)
+
+ function dispatch(value) {
+ // Method dispatches on type of the first argument.
+ // If first argument is `null` or `void` associated implementation is
+ // looked up in the `builtin` hash where implementations for built-ins
+ // are stored.
+ var type = null
+ var method = value === null ? Null[name] :
+ value === void(0) ? Void[name] :
+ // Otherwise attempt to use method with a generated private
+ // `name` that is supposedly in the prototype chain of the
+ // `target`.
+ value[name] ||
+ // Otherwise assume it's one of the built-in type instances,
+ // in which case implementation is stored in a `builtin` hash.
+ // Attempt to find a implementation for the given built-in
+ // via constructor name and method name.
+ ((type = builtin[(value.constructor || "").name]) &&
+ type[name]) ||
+ // Otherwise assume it's a host object. For host objects
+ // actual method implementations are stored in the `host`
+ // array and only index for the implementation is stored
+ // in the host object's prototype chain. This avoids memory
+ // leaks that otherwise could happen when saving JS objects
+ // on host object.
+ host[value["!" + name] || void(0)] ||
+ // Otherwise attempt to lookup implementation for builtins by
+ // a type of the value. This basically makes sure that all
+ // non primitive values will delegate to an `Object`.
+ ((type = builtin[types[typeof(value)]]) && type[name])
+
+
+ // If method implementation for the type is still not found then
+ // just fallback for default implementation.
+ method = method || Default[name]
+
+
+ // If implementation is still not found (which also means there is no
+ // default) just throw an error with a descriptive message.
+ if (!method) throw TypeError("Type does not implements method: " + name)
+
+ // If implementation was found then just delegate.
+ return method.apply(method, arguments)
+ }
+
+ // Make `toString` of the dispatch return a private name, this enables
+ // method definition without sugar:
+ //
+ // var method = Method()
+ // object[method] = function() { /***/ }
+ dispatch.toString = function toString() { return name }
+
+ // Copy utility methods for convenient API.
+ dispatch.implement = implementMethod
+ dispatch.define = defineMethod
+
+ return dispatch
+}
+
+// Create method shortcuts form functions.
+var defineMethod = function defineMethod(Type, lambda) {
+ return define(this, Type, lambda)
+}
+var implementMethod = function implementMethod(object, lambda) {
+ return implement(this, object, lambda)
+}
+
+// Define `implement` and `define` polymorphic methods to allow definitions
+// and implementations through them.
+var implement = Method("implement")
+var define = Method("define")
+
+
+function _implement(method, object, lambda) {
+ /**
+ Implements `Method` for the given `object` with a provided `implementation`.
+ Calling `Method` with `object` as a first argument will dispatch on provided
+ implementation.
+ **/
+ return defineProperty(object, method.toString(), {
+ enumerable: false,
+ configurable: false,
+ writable: false,
+ value: lambda
+ })
+}
+
+function _define(method, Type, lambda) {
+ /**
+ Defines `Method` for the given `Type` with a provided `implementation`.
+ Calling `Method` with a first argument of this `Type` will dispatch on
+ provided `implementation`. If `Type` is a `Method` default implementation
+ is defined. If `Type` is a `null` or `undefined` `Method` is implemented
+ for that value type.
+ **/
+
+ // Attempt to guess a type via `Object.prototype.toString.call` hack.
+ var type = Type && typefy.call(Type.prototype)
+
+ // If only two arguments are passed then `Type` is actually an implementation
+ // for a default type.
+ if (!lambda) Default[method] = Type
+ // If `Type` is `null` or `void` store implementation accordingly.
+ else if (Type === null) Null[method] = lambda
+ else if (Type === void(0)) Void[method] = lambda
+ // If `type` hack indicates built-in type and type has a name us it to
+ // store a implementation into associated hash. If hash for this type does
+ // not exists yet create one.
+ else if (type !== "[object Object]" && Type.name) {
+ var Bulitin = builtin[Type.name] || (builtin[Type.name] = new ObjectType())
+ Bulitin[method] = lambda
+ }
+ // If `type` hack indicates an object, that may be either object or any
+ // JS defined "Class". If name of the constructor is `Object`, assume it's
+ // built-in `Object` and store implementation accordingly.
+ else if (Type.name === "Object")
+ builtin.Object[method] = lambda
+ // Host objects are pain!!! Every browser does some crazy stuff for them
+ // So far all browser seem to not implement `call` method for host object
+ // constructors. If that is a case here, assume it's a host object and
+ // store implementation in a `host` array and store `index` in the array
+ // in a `Type.prototype` itself. This avoids memory leaks that could be
+ // caused by storing JS objects on a host objects.
+ else if (Type.call === void(0)) {
+ var index = host.indexOf(lambda)
+ if (index < 0) index = host.push(lambda) - 1
+ // Prefix private name with `!` so it can be dispatched from the method
+ // without type checks.
+ implement("!" + method, Type.prototype, index)
+ }
+ // If Got that far `Type` is user defined JS `Class`. Define private name
+ // as hidden property on it's prototype.
+ else
+ implement(method, Type.prototype, lambda)
+}
+
+// And provided implementations for a polymorphic equivalents.
+_define(define, _define)
+_define(implement, _implement)
+
+// Define exports on `Method` as it's only thing being exported.
+Method.implement = implement
+Method.define = define
+Method.Method = Method
+Method.method = Method
+Method.builtin = builtin
+Method.host = host
+
+module.exports = Method
diff --git a/addon-sdk/source/lib/method/package.json b/addon-sdk/source/lib/method/package.json
new file mode 100644
index 000000000..7bb004e28
--- /dev/null
+++ b/addon-sdk/source/lib/method/package.json
@@ -0,0 +1,41 @@
+{
+ "name": "method",
+ "id": "method",
+ "version": "1.0.2",
+ "description": "Functional polymorphic method dispatch",
+ "keywords": [
+ "method",
+ "dispatch",
+ "protocol",
+ "polymorphism",
+ "type dispatch"
+ ],
+ "author": "Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)",
+ "homepage": "https://github.com/Gozala/method",
+ "main": "./core.js",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/Gozala/method.git",
+ "web": "https://github.com/Gozala/method"
+ },
+ "bugs": {
+ "url": "http://github.com/Gozala/method/issues/"
+ },
+ "devDependencies": {
+ "test": "~0.x.0",
+ "repl-utils": "~2.0.1",
+ "phantomify": "~0.1.0"
+ },
+ "scripts": {
+ "test": "npm run test-node && npm run test-browser",
+ "test-browser": "node ./node_modules/phantomify/bin/cmd.js ./test/browser.js",
+ "test-node": "node ./test/common.js",
+ "repl": "node node_modules/repl-utils"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://github.com/Gozala/method/License.md"
+ }
+ ]
+}
diff --git a/addon-sdk/source/lib/method/test/browser.js b/addon-sdk/source/lib/method/test/browser.js
new file mode 100644
index 000000000..7c8e6cd52
--- /dev/null
+++ b/addon-sdk/source/lib/method/test/browser.js
@@ -0,0 +1,20 @@
+"use strict";
+
+exports["test common"] = require("./common")
+
+var Method = require("../core")
+
+exports["test host objects"] = function(assert) {
+ var isElement = Method("is-element")
+ isElement.define(function() { return false })
+
+ isElement.define(Element, function() { return true })
+
+ assert.notDeepEqual(typeof(Element.prototype[isElement]), "number",
+ "Host object's prototype is extended with a number value")
+
+ assert.ok(!isElement({}), "object is not an Element")
+ assert.ok(document.createElement("div"), "Element is an element")
+}
+
+require("test").run(exports)
diff --git a/addon-sdk/source/lib/method/test/common.js b/addon-sdk/source/lib/method/test/common.js
new file mode 100644
index 000000000..0418c3a23
--- /dev/null
+++ b/addon-sdk/source/lib/method/test/common.js
@@ -0,0 +1,272 @@
+"use strict";
+
+var Method = require("../core")
+
+function type(value) {
+ return Object.prototype.toString.call(value).
+ split(" ").
+ pop().
+ split("]").
+ shift().
+ toLowerCase()
+}
+
+var values = [
+ null, // 0
+ undefined, // 1
+ Infinity, // 2
+ NaN, // 3
+ 5, // 4
+ {}, // 5
+ Object.create({}), // 6
+ Object.create(null), // 7
+ [], // 8
+ /foo/, // 9
+ new Date(), // 10
+ Function, // 11
+ function() {}, // 12
+ true, // 13
+ false, // 14
+ "string" // 15
+]
+
+function True() { return true }
+function False() { return false }
+
+var trues = values.map(True)
+var falses = values.map(False)
+
+exports["test throws if not implemented"] = function(assert) {
+ var method = Method("nope")
+
+ assert.throws(function() {
+ method({})
+ }, /not implement/i, "method throws if not implemented")
+
+ assert.throws(function() {
+ method(null)
+ }, /not implement/i, "method throws on null")
+}
+
+exports["test all types inherit from default"] = function(assert) {
+ var isImplemented = Method("isImplemented")
+ isImplemented.define(function() { return true })
+
+ values.forEach(function(value) {
+ assert.ok(isImplemented(value),
+ type(value) + " inherits deafult implementation")
+ })
+}
+
+exports["test default can be implemented later"] = function(assert) {
+ var isImplemented = Method("isImplemented")
+ isImplemented.define(function() {
+ return true
+ })
+
+ values.forEach(function(value) {
+ assert.ok(isImplemented(value),
+ type(value) + " inherits deafult implementation")
+ })
+}
+
+exports["test dispatch not-implemented"] = function(assert) {
+ var isDefault = Method("isDefault")
+ values.forEach(function(value) {
+ assert.throws(function() {
+ isDefault(value)
+ }, /not implement/, type(value) + " throws if not implemented")
+ })
+}
+
+exports["test dispatch default"] = function(assert) {
+ var isDefault = Method("isDefault")
+
+ // Implement default
+ isDefault.define(True)
+ assert.deepEqual(values.map(isDefault), trues,
+ "all implementation inherit from default")
+
+}
+
+exports["test dispatch null"] = function(assert) {
+ var isNull = Method("isNull")
+
+ // Implement default
+ isNull.define(False)
+ isNull.define(null, True)
+ assert.deepEqual(values.map(isNull),
+ [ true ].
+ concat(falses.slice(1)),
+ "only null gets methods defined for null")
+}
+
+exports["test dispatch undefined"] = function(assert) {
+ var isUndefined = Method("isUndefined")
+
+ // Implement default
+ isUndefined.define(False)
+ isUndefined.define(undefined, True)
+ assert.deepEqual(values.map(isUndefined),
+ [ false, true ].
+ concat(falses.slice(2)),
+ "only undefined gets methods defined for undefined")
+}
+
+exports["test dispatch object"] = function(assert) {
+ var isObject = Method("isObject")
+
+ // Implement default
+ isObject.define(False)
+ isObject.define(Object, True)
+ assert.deepEqual(values.map(isObject),
+ [ false, false, false, false, false ].
+ concat(trues.slice(5, 13)).
+ concat([false, false, false]),
+ "all values except primitives inherit Object methods")
+
+}
+
+exports["test dispatch number"] = function(assert) {
+ var isNumber = Method("isNumber")
+ isNumber.define(False)
+ isNumber.define(Number, True)
+
+ assert.deepEqual(values.map(isNumber),
+ falses.slice(0, 2).
+ concat(true, true, true).
+ concat(falses.slice(5)),
+ "all numbers inherit from Number method")
+}
+
+exports["test dispatch string"] = function(assert) {
+ var isString = Method("isString")
+ isString.define(False)
+ isString.define(String, True)
+
+ assert.deepEqual(values.map(isString),
+ falses.slice(0, 15).
+ concat(true),
+ "all strings inherit from String method")
+}
+
+exports["test dispatch function"] = function(assert) {
+ var isFunction = Method("isFunction")
+ isFunction.define(False)
+ isFunction.define(Function, True)
+
+ assert.deepEqual(values.map(isFunction),
+ falses.slice(0, 11).
+ concat(true, true).
+ concat(falses.slice(13)),
+ "all functions inherit from Function method")
+}
+
+exports["test dispatch date"] = function(assert) {
+ var isDate = Method("isDate")
+ isDate.define(False)
+ isDate.define(Date, True)
+
+ assert.deepEqual(values.map(isDate),
+ falses.slice(0, 10).
+ concat(true).
+ concat(falses.slice(11)),
+ "all dates inherit from Date method")
+}
+
+exports["test dispatch RegExp"] = function(assert) {
+ var isRegExp = Method("isRegExp")
+ isRegExp.define(False)
+ isRegExp.define(RegExp, True)
+
+ assert.deepEqual(values.map(isRegExp),
+ falses.slice(0, 9).
+ concat(true).
+ concat(falses.slice(10)),
+ "all regexps inherit from RegExp method")
+}
+
+exports["test redefine for descendant"] = function(assert) {
+ var isFoo = Method("isFoo")
+ var ancestor = {}
+ isFoo.implement(ancestor, function() { return true })
+ var descendant = Object.create(ancestor)
+ isFoo.implement(descendant, function() { return false })
+
+ assert.ok(isFoo(ancestor), "defined on ancestor")
+ assert.ok(!isFoo(descendant), "overrided for descendant")
+}
+
+exports["test on custom types"] = function(assert) {
+ function Bar() {}
+ var isBar = Method("isBar")
+
+ isBar.define(function() { return false })
+ isBar.define(Bar, function() { return true })
+
+ assert.ok(!isBar({}), "object is get's default implementation")
+ assert.ok(isBar(new Bar()), "Foo type objects get own implementation")
+
+ var isObject = Method("isObject")
+ isObject.define(function() { return false })
+ isObject.define(Object, function() { return true })
+
+ assert.ok(isObject(new Bar()), "foo inherits implementation from object")
+
+
+ isObject.define(Bar, function() { return false })
+
+ assert.ok(!isObject(new Bar()),
+ "implementation inherited form object can be overrided")
+}
+
+
+exports["test error types"] = function(assert) {
+ var isError = Method("isError")
+ isError.define(function() { return false })
+ isError.define(Error, function() { return true })
+
+ assert.ok(isError(Error("boom")), "error is error")
+ assert.ok(isError(TypeError("boom")), "type error is an error")
+ assert.ok(isError(EvalError("boom")), "eval error is an error")
+ assert.ok(isError(RangeError("boom")), "range error is an error")
+ assert.ok(isError(ReferenceError("boom")), "reference error is an error")
+ assert.ok(isError(SyntaxError("boom")), "syntax error is an error")
+ assert.ok(isError(URIError("boom")), "URI error is an error")
+}
+
+exports["test override define polymorphic method"] = function(assert) {
+ var define = Method.define
+ var implement = Method.implement
+
+ var fn = Method("fn")
+ var methods = {}
+ implement(define, fn, function(method, label, implementation) {
+ methods[label] = implementation
+ })
+
+ function foo() {}
+
+ define(fn, "foo-case", foo)
+
+ assert.equal(methods["foo-case"], foo, "define set property")
+}
+
+exports["test override define via method API"] = function(assert) {
+ var define = Method.define
+ var implement = Method.implement
+
+ var fn = Method("fn")
+ var methods = {}
+ define.implement(fn, function(method, label, implementation) {
+ methods[label] = implementation
+ })
+
+ function foo() {}
+
+ define(fn, "foo-case", foo)
+
+ assert.equal(methods["foo-case"], foo, "define set property")
+}
+
+require("test").run(exports)