1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-20 19:07:58 +01:00

Document some crap.

This commit is contained in:
Kris Maglione
2009-11-12 01:36:32 -05:00
parent b607764012
commit 79d1d68797
2 changed files with 215 additions and 32 deletions

View File

@@ -134,18 +134,41 @@ function isobject(obj) {
return typeof obj === "object" && obj != null; return typeof obj === "object" && obj != null;
} }
function isarray(obj) { /**
return Object.prototype.toString.call(obj) == "[object Array]"; * Returns true if and only if its sole argument is an
* instance of the builtin Array type. The array may come from
* any window, frame, namespace, or execution context, which
* is not the case when using (obj instanceof Array).
*/
function isarray(val) {
return Object.prototype.toString.call(val) == "[object Array]";
} }
/**
* Returns true if and only if its sole argument is an
* instance of the builtin Generator type. This includes
* functions containing the 'yield' statement and generator
* statements such as (x for (x in obj)).
*/
function isgenerator(val) { function isgenerator(val) {
return Object.prototype.toString.call(val) == "[object Generator]"; return Object.prototype.toString.call(val) == "[object Generator]";
} }
/**
* Returns true if and only if its sole argument is a String,
* as defined by the builtin type. May be constructed via
* String(foo) or new String(foo) from any window, frame,
* namespace, or execution context, which is not the case when
* using (obj instanceof String) or (typeof obj == "string").
*/
function isstring(val) { function isstring(val) {
return typeof val === "string" || val instanceof String; return Object.prototype.toString.call(val) == "[object String]";
} }
/**
* Returns true if and only if its sole argument may be called
* as a function. This includes classes and function objects.
*/
function callable(val) { function callable(val) {
return typeof val === "function"; return typeof val === "function";
} }
@@ -155,7 +178,28 @@ function call(fn) {
return fn; return fn;
} }
function curry(fn, length, acc) { /**
* Curries a function to the given number of arguments. Each
* call of the resulting function returns a new function. When
* a call does not contain enough arguments to satisfy the
* required number, the resulting function is another curried
* function with previous arguments accumulated.
*
* function foo(a, b, c) [a, b, c].join(" ");
* curry(foo)(1, 2, 3) -> "1 2 3";
* curry(foo)(4)(5, 6) -> "4 5 6";
* curry(foo)(4)(8)(9) -> "7 8 9";
*
* @param {function} fn The function to curry.
* @param {integer} length The number of arguments expected.
* @default fn.length
* @optional
* @param {object} self The 'this' value for the returned
* function. When omitted, the value of 'this' from the
* first call to the function is preserved.
* @optional
*/
function curry(fn, length, self, acc) {
if (length == null) if (length == null)
length = fn.length; length = fn.length;
if (length == 0) if (length == 0)
@@ -164,7 +208,6 @@ function curry(fn, length, acc) {
/* Close over function with 'this' */ /* Close over function with 'this' */
function close(self, fn) function () fn.apply(self, Array.slice(arguments)); function close(self, fn) function () fn.apply(self, Array.slice(arguments));
let first = (arguments.length < 3);
if (acc == null) if (acc == null)
acc = []; acc = [];
@@ -173,18 +216,35 @@ function curry(fn, length, acc) {
/* The curried result should preserve 'this' */ /* The curried result should preserve 'this' */
if (arguments.length == 0) if (arguments.length == 0)
return close(this, arguments.callee); return close(self || this, arguments.callee);
if (args.length >= length) if (args.length >= length)
return fn.apply(this, args); return fn.apply(self || this, args);
if (first) return curry(fn, length, self || this, args);
fn = close(this, fn);
return curry(fn, length, args);
} }
} }
function update(targ) { /**
* Updates an object with the properties of another object. Getters
* and setters are copied as expected. Moreover, any function
* properties receive new 'supercall' and 'superapply' properties,
* which will call the identically named function in target's
* prototype.
*
* let a = { foo: function (arg) "bar " + arg }
* let b = { __proto__: a }
* update(b, { foo: function () arguments.callee.supercall(this, "baz") });
*
* a.foo("foo") -> "bar foo"
* b.foo() -> "bar baz"
*
* @param {Object} target The object to update.
* @param {Object} src The source object from which to update target.
* May be provided multiple times.
* @returns {Object} Returns its updated first argument.
*/
function update(target) {
for (let i=1; i < arguments.length; i++) { for (let i=1; i < arguments.length; i++) {
let src = arguments[i]; let src = arguments[i];
foreach(keys(src || {}), function(k) { foreach(keys(src || {}), function(k) {
@@ -192,10 +252,10 @@ function update(targ) {
set = src.__lookupSetter__(k); set = src.__lookupSetter__(k);
if (!get && !set) { if (!get && !set) {
var v = src[k]; var v = src[k];
targ[k] = v; target[k] = v;
if (targ.__proto__ && callable(v)) { if (target.__proto__ && callable(v)) {
v.superapply = function(self, args) { v.superapply = function(self, args) {
return targ.__proto__[k].apply(self, args); return target.__proto__[k].apply(self, args);
} }
v.supercall = function(self) { v.supercall = function(self) {
return v.superapply(self, Array.slice(arguments, 1)); return v.superapply(self, Array.slice(arguments, 1));
@@ -203,28 +263,64 @@ function update(targ) {
} }
} }
if (get) if (get)
targ.__defineGetter__(k, get); target.__defineGetter__(k, get);
if (set) if (set)
targ.__defineSetter__(k, set); target.__defineSetter__(k, set);
}); });
} }
return targ; return target;
} }
function extend(subc, superc, overrides) { /**
subc.prototype = {}; * Extends a subclass with a superclass. The subclass's
update(subc.prototype, overrides); * prototype is replaced with a new object, which inherits
// This is unduly expensive. * from the super class's prototype, {@see update}d with the
subc.prototype.__proto__ = superc.prototype; * members of 'overrides'.
*
* @param {function} subclass
* @param {function} superclass
* @param {Object} overrides @optional
*/
function extend(subclass, superclass, overrides) {
subclass.prototype = {};
update(subclass.prototype, overrides);
// This is unduly expensive. Unfortunately necessary since
// we apparently can't rely on the presence of the
// debugger to enumerate properties when we have
// __iterators__ attached to prototypes.
subclass.prototype.__proto__ = superclass.prototype;
subc.superclass = superc.prototype; subclass.superclass = superclass.prototype;
subc.prototype.constructor = subc; subclass.prototype.constructor = subclass;
subc.prototype.__class__ = subc; subclass.prototype.__class__ = subclass;
if (superc.prototype.constructor === Object.prototype.constructor) if (superclass.prototype.constructor === Object.prototype.constructor)
superc.prototype.constructor = superc; superclass.prototype.constructor = superclass;
} }
/**
* @constructor Class
*
* Constructs a new Class. Arguments marked as optional must be
* either entirely elided, or they must have the exact type
* specified.
*
* @param {string} name The class's as it will appear when toString
* is called, as well as in stack traces.
* @optional
* @param {function} base The base class for this module. May be any
* callable object.
* @optional
* @default Class
* @param {Object} prototype The prototype for instances of this
* object. The object itself is copied and not used as a
* prototype directly.
* @param {Object} classProperties The class properties for the new
* module constructor. More than one may be provided.
* @optional
*
* @returns {function} The constructor for the resulting class.
*/
function Class() { function Class() {
function constructor() { function constructor() {
let self = { let self = {
@@ -274,10 +370,24 @@ function Class() {
} }
Class.toString = function () "[class " + this.constructor.name + "]", Class.toString = function () "[class " + this.constructor.name + "]",
Class.prototype = { Class.prototype = {
/**
* Initializes new instances of this class. Called automatically
* when new instances are created.
*/
init: function() {}, init: function() {},
toString: function () "[instance " + this.constructor.name + "]", toString: function () "[instance " + this.constructor.name + "]",
/**
* Exactly like {@see nsIDOMWindow#setTimeout}, except that it
* preserves the value of 'this' on invocation of 'callback'.
*
* @param {function} callback The function to call after 'timeout'
* @param {number} timeout The timeout, in seconds, to wait
* before calling 'callback'.
* @returns {integer} The ID of this timeout, to be passed to
* {@see nsIDOMWindow#clearTimeout}.
*/
setTimeout: function (callback, timeout) { setTimeout: function (callback, timeout) {
const self = this; const self = this;
function target() callback.call(self); function target() callback.call(self);
@@ -285,9 +395,24 @@ Class.prototype = {
} }
}; };
/**
* @class Struct
*
* Creates a new Struct constructor, used for creating objects with
* a fixed set of named members. Each argument should be the name of
* a member in the resulting objects. These names will correspond to
* the arguments passed to the resultant constructor. Instances of
* the new struct may be treated vary much like arrays, and provide
* many of the same methods.
*
* const Point = Struct("x", "y", "z");
* let p1 = Point(x, y, z);
*
* @returns {function} The constructor for the new Struct.
*/
const Struct = Class("Struct", { const Struct = Class("Struct", {
init: function () { init: function () {
let args = Array.slice(arguments); let args = this._args = Array.slice(arguments);
this.__defineGetter__("length", function () args.length); this.__defineGetter__("length", function () args.length);
this.__defineGetter__("members", function () args.slice()); this.__defineGetter__("members", function () args.slice());
for (let arg in Iterator(args)) { for (let arg in Iterator(args)) {
@@ -305,6 +430,16 @@ const Struct = Class("Struct", {
return self; return self;
} }
Struct.prototype = this; Struct.prototype = this;
/**
* Sets a lazily constructed default value for a member of
* the struct. The value is constructed once, the first time
* it is accesed and memoized thereafter.
*
* @param {string} key The name of the member for which to
* provide the default value.
* @param {function} val The function which is to generate
* the default value.
*/
Struct.defaultValue = function (key, val) { Struct.defaultValue = function (key, val) {
let i = args.indexOf(key); let i = args.indexOf(key);
Struct.prototype.__defineGetter__(i, function () (this[i] = val.call(this), this[i])); // Kludge for FF 3.0 Struct.prototype.__defineGetter__(i, function () (this[i] = val.call(this), this[i])); // Kludge for FF 3.0

View File

@@ -3,12 +3,60 @@
// This work is licensed for reuse under an MIT license. Details are // This work is licensed for reuse under an MIT license. Details are
// given in the LICENSE.txt file included with this file. // given in the LICENSE.txt file included with this file.
const ModuleBase = Class("ModuleBase", { requires: [] }); /**
function Module(name, inst, clas, moduleInit) { * @class ModuleBase
* The base class for all modules.
*/
const ModuleBase = Class("ModuleBase", {
/**
* @property {[string]} A list of module prerequisites which
* must be initialized before this module is loaded.
*/
requires: [],
toString: function () "[module " + this.constructor.name + "]",
});
/**
* @constructor Module
*
* Constructs a new ModuleBase class and makes arrangements for its
* initialization. Arguments marked as optional must be either
* entirely elided, or they must have the exact type specified.
* Loading semantics are as follows:
*
* - A module is garunteed not to be initialized before any of its
* prerequisites as listed in its {@see ModuleBase#requires} member.
* - A module is considered initialized once its been instantiated,
* it's {@see Class#init} method has been called, and its
* instance has been installed into the top-level {@see modules}
* object.
* - Once the module has been initialized, its module-dependent
* initialization functions will be called as described hereafter.
* @param {string} name The module's name as it will appear in the
* top-level {@see modules} object.
* @param {ModuleBase} base The base class for this module.
* @optional
* @param {Object} prototype The prototype for instances of this
* object. The object itself is copied and not used as a
* prototype directly.
* @param {Object} classProperties The class properties for the new
* module constructor.
* @optional
* @param {Object} moduleInit The module initialization functions
* for the new module. Each function is called as soon as the
* named module has been initialized, but after the module
* itself. The constructors are garunteed to be called in the
* same order that the dependent modules were initialized.
* @optional
*
* @returns {function} The constructor for the resulting module.
*/
function Module(name, prototype, classProperties, moduleInit) {
var base = ModuleBase; var base = ModuleBase;
if (callable(inst)) if (callable(prototype))
base = Array.splice(arguments, 1, 1)[0] base = Array.splice(arguments, 1, 1)[0]
const module = Class(name, base, inst, clas); const module = Class(name, base, prototype, classProperties);
module.INIT = moduleInit || {}; module.INIT = moduleInit || {};
module.requires = inst.requires || []; module.requires = inst.requires || [];
Module.list.push(module); Module.list.push(module);