Move Add-on SDK source to toolkit/jetpack

This commit is contained in:
NTD 2018-02-09 06:46:43 -05:00 committed by Roy Tam
commit 23b67db438
993 changed files with 484 additions and 100663 deletions

View file

@ -0,0 +1,5 @@
language: node_js
node_js:
- 0.4
- 0.5
- 0.6

View file

@ -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

View file

@ -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.

View file

@ -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"
```

View file

@ -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

View file

@ -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"
}
]
}

View file

@ -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)

View file

@ -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)