From: dsc Date: Mon, 29 Nov 2010 04:12:48 +0000 (-0800) Subject: Refactors ezl to use CommonJS. X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=6805cad1d23a65292eb4848f7d1d8efa5e487a11;p=tanks.git Refactors ezl to use CommonJS. --- diff --git a/bin/cjs.py b/bin/cjs.py index 250e42d..dbdbc72 100755 --- a/bin/cjs.py +++ b/bin/cjs.py @@ -7,7 +7,7 @@ __version__ = (0, 0, 1) __all__ = ('ResolutionError', 'Module', 'JSResolver',) -import sys, re +import sys, re, json from itertools import chain, repeat from collections import defaultdict from subprocess import Popen, check_output, STDOUT, PIPE @@ -18,21 +18,30 @@ from path import path import pystache +AT_REQUIRE_PAT = re.compile(r'//@require\(\s*([\'"])(.*?)\1\s*\)') LINE_COMMENT_PAT = re.compile(r'(.*?)(//.*?)(?:\n|$)') PAIR_COMMENT_PAT = re.compile(r'(.*?)(/\*.*?\*/)') REQUIRE_PAT = re.compile(r'\brequire\(\s*([\'"])(.*?)\1\s*\)') + ROOT = path(__file__).abspath().dirname().dirname() LIB = ROOT/'lib/cjs' CWD = path('.') BLANK = path('') + MODULE_TEMPLATE = '' +DUMMY_TEMPLATE = '' +DEPS_TEMPLATE = '' try: - with (LIB/'module.js').open('rU') as f : + with (LIB/'module.js').open('rU') as f: MODULE_TEMPLATE = f.read() + with (LIB/'dummy.js').open('rU') as f: + DUMMY_TEMPLATE = f.read() + with (LIB/'deps.js').open('rU') as f: + DEPS_TEMPLATE = f.read() except Exception as ex: print - print 'Error reading module template file!' + print 'Error reading template file!' print ' ROOT={ROOT}, LIB={LIB}, module.js={}'.format(LIB/'module.js', **locals()) raise @@ -86,55 +95,41 @@ def canonicalise(query, base=None): return str(id) -class Repo(object): - def __init__(self, filepath, url): - self.path = filepath - self.url = url - - def __repr__(self): - return 'Repo({}, url={})'.format(self.path, self.url) - - def __str__(self): - return repr(self) - - class Module(Bunch): DEFAULTS = { - 'id' : '', # Canonical Module ID - 'file' : None, # path - 'name' : '', # Module Name - 'uri' : '', # Module URI (TODO) - 'text' : None, # Unmodified module text - 'contents' : None, # Compiled module text - '_requires' : None, - 'outpath' : None, + 'id' : '', # Canonical Module ID + 'file' : None, # path + 'name' : '', # Module Name + 'uri' : '', # Module URI (TODO) + 'text' : None, # Unmodified module text + 'contents' : None, # Compiled module text + 'outpath' : None, # Build directory + '_requires' : None, + '_at_requires' : None, } - def __init__(self, id, file, uri='', out=None, compile=True): + def __init__(self, id, file, uri=BLANK, out=None, compile=True): self.update(Module.DEFAULTS) self.id = id self.file = path(file) - self.name = self.id.split('/').pop().capitalize() + self.name = re.subn(r'\W', '', self.id.split('/').pop().capitalize())[0] if out: - out = (path(out) / self.id) + '.js' + out = path(out) + outpath = (out / self.id) + '.js' else: - out = self.file.replace('.cjs', '.js') - self.outpath = path(out) - self.uri = uri + out = BLANK + outpath = self.file.replace('.cjs', '.js') + self.outpath = path(outpath) + self.uri = str(out/uri/self.id)+'.js' - if compile: self.compile() + self.compile() # print "new!", repr(self) def compile(self): - # if uri: self.uri = uri.format(**self) # TODO: calc uri - - if not self.file.endswith('.cjs'): - return self - outdir = self.outpath.dirname() if not outdir.exists(): outdir.makedirs() @@ -149,7 +144,8 @@ class Module(Bunch): with self.file.open('rU') as f: txt = f.read() self['text'] = txt - self['contents'] = pystache.render(MODULE_TEMPLATE, self) + template = MODULE_TEMPLATE if self.file.endswith('.cjs') else DUMMY_TEMPLATE + self['contents'] = pystache.render(template, self) return self[attr] @property @@ -160,6 +156,10 @@ class Module(Bunch): def contents(self): return self.read('contents') + def findDirectives(self, text): + for areq in AT_REQUIRE_PAT.finditer(text): + yield canonicalise(areq.group(2), self) + def findRequires(self, text): text = LINE_COMMENT_PAT.subn(r'\1 ', text)[0] text = PAIR_COMMENT_PAT.subn(r'\1 ', text)[0] @@ -167,11 +167,23 @@ class Module(Bunch): for mreq in REQUIRE_PAT.finditer(text): yield canonicalise(mreq.group(2), self) + def calcRequires(self, attr): + if self._requires is None or self._at_requires is None: + self._at_requires = list(self.findDirectives(self.text)) + self._requires = list(self.findRequires(self.text)) + return getattr(self, attr) + + @property + def atRequires(self): + return self.calcRequires('_at_requires') + + @property + def nonAtRequires(self): + return self.calcRequires('_requires') + @property def requires(self): - if self._requires is None: - self._requires = list(self.findRequires(self.text)) - return self._requires + return self.calcRequires('_at_requires') + self._requires def __hash__(self): return hash(self.id) @@ -209,22 +221,30 @@ class CommonJS(object): req = cjs.lookup(query, mod) if req not in seen: queue.append(req) + if cjs.deps_name: + cjs.genDepLoader() return cjs repos = [] modules = {} # id -> Module - _graph = None # id -> set(dependants) - - - def __init__(self, repos, out='build', clean=True): - self.modules = {} - self.repos = set( path(path(p).abspath()+'/') for p in repos) - self.out = None if out is '' else out + _graph = None # id -> set(dependants) + _at_graph = None # id -> set(dependants) + + def __init__(self, repos, out='build', deps_name=None, clean=True, **options): + self.modules = {} + self.options = options + self.deps_name = deps_name + self.repos = set( path(path(p).abspath()+'/') for p in repos) + self.out = None if out is '' else out if self.out is not None and clean: out = path(self.out) - if out.exists(): out.rmtree() + for f in out.glob('*'): + if f.isdir(): + f.rmtree() + elif f.isfile(): + f.remove() def register(self, id, file): mod = self.modules[id] = Module(id=id, file=file, out=self.out) @@ -254,32 +274,67 @@ class CommonJS(object): for k, mod in self.modules.iteritems(): yield k, mod - @property - def graph(self): + def calcGraph(self, attr): if self._graph is None: - graph = self._graph = defaultdict(set) + graph = self._graph = defaultdict(set) + atgraph = self._at_graph = defaultdict(set) for mod in self.modules.values(): - for req in mod.requires: + for req in mod.nonAtRequires: graph[req].add(mod) - return self._graph + for req in mod.atRequires: + atgraph[req].add(mod) + return getattr(self, attr) @property - def deplist(self): - return '\n'.join( '%s %s' % (id, dep.id) for (id, deps) in self.graph.iteritems() for dep in deps ) + def graph(self): + return self.calcGraph('_graph') @property - def dependencies(self): + def atGraph(self): + return self.calcGraph('_at_graph') + + def tsort(self, graph): p = Popen(['tsort'], stderr=STDOUT, stdin=PIPE, stdout=PIPE) - p.stdin.write( self.deplist ) + deps = '\n'.join( '%s %s' % (id, dep.id) for (id, deps) in graph.iteritems() for dep in deps ) + p.stdin.write(deps) p.stdin.close() if p.wait() != 0: raise ResolutionError('Cannot resolve dependencies! Requirements must be acyclic!') - return p.stdout.read().strip().split('\n') + return p.stdout.read() + + @property + def dependencies(self): + deps = (self.tsort(self.atGraph)+self.tsort(self.graph)).strip().split('\n') + for i, dep in reversed(list(enumerate(deps[:]))): + try: + idx = deps.index(dep, 0, i-1) + if i != idx: + del deps[idx] + except ValueError: pass + return deps + + def dumpDependencies(self): + column = Popen(['column', '-s', '\t', '-t'], stderr=sys.stderr, stdin=PIPE, stdout=PIPE) + mods = self.modules.values() + for mod in sorted(mods, key=lambda m: len(m.requires), reverse=True): + column.stdin.write('%s\t->\t%r\n' % (mod, sorted(mod.requires))) + # print '%s\t->\t%r' % (mod, sorted(mod.requires)) + column.stdin.close() + if column.wait() != 0: + print >> sys.stderr, 'Some sort of error has occurred!' + return column.stdout.read() - def cat(self): - for dep in self.dependencies: - print self.modules[dep].contents + def genDepLoader(self): + with (path(self.out)/self.deps_name).open('w') as deps: + deps.write( pystache.render(DEPS_TEMPLATE, uris=json.dumps(self.uris)) ) + @property + def uris(self): + return [ self.modules[d].uri for d in self.dependencies ] + + @property + def scriptTags(self): + return '\n'.join( ''.format(uri) for uri in self.uris ) @@ -292,15 +347,19 @@ def main(): usage = 'usage: %prog [options] file[...] [-- [repo_path[...]]]', description = 'Compiles CommonJS modules.', version = '%prog'+" %i.%i.%i" % __version__) - parser.add_option("-p", "--repo-paths", dest='repos', default='', + parser.add_option("-p", "--repo-paths", default='', help="Comma-seperated paths to search for unqualified modules. " "If a path contains :, the portion afterward will be taken as the repo URL. [default: .]") parser.add_option("-o", "--out", default='build', help="Root directory to write compiled JS files. Specify '' to write to module's dir. [default: build]") parser.add_option("-C", "--no-clean", dest='clean', default=True, action="store_false", help="Do not clean the out-dir of compiled files. [default: False if -o, True otherwise]") - parser.add_option("-d", "--print-deps", default=False, action="store_true", + parser.add_option("--print-deps", default=False, action="store_true", help="Prints module dependencies after compiling. [default: %default]") + parser.add_option("-g", "--gen-deps-script", dest='deps_name', default=None, + help="Generates a JS script with the given name which doc-writes tags for this set of modules.") + parser.add_option("-s", "--script-tags", default=False, action="store_true", + help="Emits script-tags for this set of modules in dependency order. [default: %default]") (options, args) = parser.parse_args() @@ -310,21 +369,24 @@ def main(): (files, sep, repos) = partition(sys.argv, '--') files = filter(lambda f: f in args, files) repos = filter(lambda f: f in args, repos) - repos.extend( filter(None, options.repos.split(',')) ) + repos.extend( filter(None, options.repo_paths.split(',')) ) # print 'files:', files, 'repos:', (repos or ['.']) - js = CommonJS.discover(files=files, repos=repos or ['.'], **options.__dict__) + try: + js = CommonJS.discover(files=files, repos=repos or ['.'], **options.__dict__) + except ResolutionError as ex: + print >> sys.stderr, str(ex) + return 1 + + if options.script_tags: + print js.scriptTags if options.print_deps: - column = Popen(['column', '-s', '\t', '-t'], stderr=sys.stderr, stdin=PIPE, stdout=PIPE) - mods = js.modules.values() - for mod in sorted(mods, key=lambda m: len(m.requires), reverse=True): - column.stdin.write('%s\t->\t%r\n' % (mod, sorted(mod.requires))) - # print '%s\t->\t%r' % (mod, sorted(mod.requires)) - - column.stdin.close() - if column.wait() != 0: print 'Some sort of error has occurred!' - print column.stdout.read() + print >> sys.stderr, 'All Dependencies:' + print >> sys.stderr, js.dumpDependencies() + print >> sys.stderr, '' + print >> sys.stderr, 'Resolution:' + print >> sys.stderr, '\n'.join(js.dependencies) return 0 diff --git a/doc/notes.md b/doc/notes.md index 3285ae5..38cd78e 100644 --- a/doc/notes.md +++ b/doc/notes.md @@ -2,9 +2,8 @@ - Tanks seem to get stuck on some corners # TODOs -- How-to overlay -- Restart level button -- AI: Line-of-sight for dodging, firing +- change @require to @ensure + - AI: Don't shoot if it'll kill you or your friends - AI: Lead shots on moving targets - Config-driven unit-types (name, stats, properties; pointers to behavior scripts, assets) diff --git a/index.php b/index.php index afcb361..3ac3f78 100644 --- a/index.php +++ b/index.php @@ -62,7 +62,10 @@
- +
diff --git a/lib/cjs/deps.js b/lib/cjs/deps.js new file mode 100644 index 0000000..3735e59 --- /dev/null +++ b/lib/cjs/deps.js @@ -0,0 +1,3 @@ +{{{uris}}}.forEach(function(uri){ + document.write(''); +}); diff --git a/lib/cjs/dummy.js b/lib/cjs/dummy.js new file mode 100644 index 0000000..71c5a6b --- /dev/null +++ b/lib/cjs/dummy.js @@ -0,0 +1,14 @@ +require.install( +// Module ID +'{{{id}}}', + +// Module metadata +{ + 'name' : '{{{name}}}', + 'id' : '{{{id}}}', + 'uri' : '{{{uri}}}' +}, +// Dummy module: setup does nothing +function setup{{{name}}}(require, exports, module){}); + +{{{text}}} diff --git a/lib/cjs/module.js b/lib/cjs/module.js index 7f225e1..167f51a 100644 --- a/lib/cjs/module.js +++ b/lib/cjs/module.js @@ -1,17 +1,17 @@ require.install( // Module ID -'{{id}}', +'{{{id}}}', // Module metadata { - 'name' : '{{name}}', - 'id' : '{{id}}', - 'uri' : '{{uri}}' + 'name' : '{{{name}}}', + 'id' : '{{{id}}}', + 'uri' : '{{{uri}}}' }, // Module Setup function -function setup{{name}}(require, exports, module){ +function setup{{{name}}}(require, exports, module){ -{{text}} +{{{text}}} }); \ No newline at end of file diff --git a/lib/jquery.js b/lib/jquery.js new file mode 120000 index 0000000..0185856 --- /dev/null +++ b/lib/jquery.js @@ -0,0 +1 @@ +jquery-1.4.3.min.js \ No newline at end of file diff --git a/src/Y/class.cjs b/src/Y/class.cjs index 9ca59ab..dc1a4b5 100644 --- a/src/Y/class.cjs +++ b/src/Y/class.cjs @@ -1,7 +1,10 @@ // Inspired by John Resig's "Simple Class Inheritence" -- http://ejohn.org/blog/simple-javascript-inheritance/ -var Y = require('Y').Y -, type = require('Y/type') +var type = require('Y/type') +, YFunction = require('Y/types/function').YFunction +, core = require('Y/core') +, slice = core.slice + , KNOWN_CLASSES = type.type.KNOWN_CLASSES , classToString = function toString(){ return this.className+"()"; } ; @@ -113,7 +116,7 @@ function Class(className, Parent, members) { prototype[k] = members[k]; } - if (prototype.init) NewClass.init = Y(prototype.init); + if (prototype.init) NewClass.init = YFunction(prototype.init); KNOWN_CLASSES[className] = NewClass; @@ -171,59 +174,9 @@ var YBase = new Class("YBase", { - -/// Other Class Utilities /// - -function bindName(v, k){ - if ( isFunction(v) ) - this[k] = Y(v).bind(this); -} -// bindName = Y(bindName).curry(); - -function bindAll(o, names){ - var names = new Y(arguments, 1); - Y(names.size() ? names.generate(Y.op.get(o)) : o).forEach( bindName, o ); - return o; -} - -// Y.chainDelegates = chainDelegates; -function chainDelegates(type, name){ - var names = Y(arguments, 1), - proto = type.prototype; - names.forEach(function(name){ - proto[name] = function(){ - var o = this._o || this; - o[name].apply(o, Y(arguments)); - return this; - }; - }); - return type; -} - -// Y.mixinNames = mixinNames; -function mixinNames(o, Donor, names, override, yWrap){ - var target = ( isFunction(o) ? o.prototype : o) - , proto = ( isFunction(Donor) ? Donor.prototype : Donor); - - // Need a closure to capture the name - names.forEach(function(name){ - if ( isFunction(proto[name]) && (override || !target[name]) ) - target[name] = function(){ - var r = proto[name].apply(this._o || target, arguments); - return (yWrap ? Y(r) : r); - }; - }); - - return o; -} - exports['Class'] = exports['subclass'] = Class; exports['instantiate'] = Class.instantiate.bind(Class); exports['fabricate'] = Class.fabricate.bind(Class); - -exports['YBase'] = YBase; -exports['bindAll'] = bindAll; -exports['chainDelegates'] = chainDelegates; -exports['mixinNames'] = mixinNames; +exports['YBase'] = YBase; diff --git a/src/Y/core.cjs b/src/Y/core.cjs index 83f1594..0725a30 100644 --- a/src/Y/core.cjs +++ b/src/Y/core.cjs @@ -1,4 +1,15 @@ // Generic Collection Functions +var undefined +, globals = (function(){ return this; })() +, _Function = globals.Function +, _Array = globals.Array +, PT = "prototype" +, slice = _Array[PT].slice +; + +// function slice(a){ +// return _asl.apply(a, _asl.call(arguments, 1)); +// } function notWrapped(fn){ var self = arguments.callee.caller; @@ -9,7 +20,7 @@ function reduce(o, fn, acc){ if ( !o ) return acc; - fn = Function.toFunction(fn); + fn = _Function.toFunction(fn); var cxt = arguments[3] || o; if ( notWrapped(o.reduce) ) return o.reduce.apply(o, [fn, acc, cxt]); @@ -24,7 +35,7 @@ function map(o, fn){ if ( !o ) return o; - fn = Function.toFunction(fn); + fn = _Function.toFunction(fn); var acc = {}, cxt = arguments[2] || o; if ( notWrapped(o.map) ) return o.map.apply(o, [fn, cxt]); @@ -44,7 +55,7 @@ function filter(o, fn){ if ( !o ) return o; - fn = Function.toFunction(fn); + fn = _Function.toFunction(fn); var acc = {}, cxt = arguments[2] || o; if ( notWrapped(o.filter) ) return o.filter.apply(o, [fn, cxt]); @@ -116,3 +127,4 @@ exports['extend'] = extend; exports['dset'] = dset; exports['dattr'] = dattr; exports['dextend'] = dextend; +exports['slice'] = slice; \ No newline at end of file diff --git a/src/Y/index.cjs b/src/Y/index.cjs index bc8097e..cdfd44e 100644 --- a/src/Y/index.cjs +++ b/src/Y/index.cjs @@ -1,7 +1,8 @@ +// -*- mode: JavaScript; tab-width: 4; indent-tabs-mode: nil; -*- /// Import our external deps first /// -// require('lessly/future'); -// require('functional/to-function'); +//@require('lessly/future'); +//@require('functional/to-function'); /// Set up core and utilities /// var core = require('Y/core') @@ -17,6 +18,7 @@ core.extend(type.type, type); // Attach core & type to Y core.extend(Y, core, type); +delete Y.slice; // grr // Make top-level setters refer to the delegating versions Y['core'] = core; @@ -41,7 +43,7 @@ addNames('curry methodize genericize compose chain memoize', yfn); // Curry all operators var op = require('Y/op'); core.forEach(op, YFunction); -Y['op'] = op.extend({}, core.map(yfn.curry, op)); +Y['op'] = op['curried'] = op.extend({}, core.map(yfn.curry, op)); // Y['op'] = core.reduce(op, function(Yop, fn, k){ // Yop[k] = yfn.curry(fn); // return Yop; diff --git a/src/Y/modules/event.js b/src/Y/modules/old-y.event.js similarity index 100% rename from src/Y/modules/event.js rename to src/Y/modules/old-y.event.js diff --git a/src/Y/modules/y.cookies.js b/src/Y/modules/y.cookies.cjs similarity index 86% rename from src/Y/modules/y.cookies.js rename to src/Y/modules/y.cookies.cjs index 2342220..b3aedac 100644 --- a/src/Y/modules/y.cookies.js +++ b/src/Y/modules/y.cookies.cjs @@ -1,12 +1,12 @@ -(function(Y, undefined){ if (!Y) return; - var _document = document +, Y = require('Y').Y , enc = encodeURIComponent , dec = decodeURIComponent -, ns = Y.cookies = {} ; -ns.get = +Y['cookies'] = exports; + +exports['get'] = function getCookie(k){ var cookies = Y(_document.cookie+'').fromKV('; '); if (k !== undefined) @@ -15,7 +15,7 @@ ns.get = return cookies; }; -ns.set = +exports['set'] = function setCookie(k, v, expires, path){ expires = 'expires='+(expires || "Sun, 24-Mar-2024 11:11:11 GMT"); path = 'path='+(path || "/"); @@ -24,5 +24,3 @@ ns.set = }; // TODO: YCollection methods on ns over kv pairs. - -})(this.Y); diff --git a/src/Y/modules/y.event.js b/src/Y/modules/y.event.cjs similarity index 94% rename from src/Y/modules/y.event.js rename to src/Y/modules/y.event.cjs index d3d0be5..577aa02 100644 --- a/src/Y/modules/y.event.js +++ b/src/Y/modules/y.event.cjs @@ -1,7 +1,4 @@ -(function(Y, undefined){ - -var -ns = Y.event = {} +Y['event'] = exports; /** * A simple event. @@ -9,7 +6,7 @@ ns = Y.event = {} * TODO: If DOM event, wrap with consistent API. * TODO: use jQuery if present to wrap events. */ -, YEvent = ns.YEvent = +var YEvent = exports['YEvent'] = Y.YObject.subclass('YEvent', { init : function init( type, target, trigger, data ){ data = data || {}; @@ -69,9 +66,9 @@ Y.YObject.subclass('YEvent', { delegate[k] = methods[k].bind(this); return delegate; } -} +}, -, Emitter = ns.Emitter = +Emitter = exports['Emitter'] = Y.YObject.subclass('Emitter', Y.extend({ 'init' : function(target, parent){ @@ -90,7 +87,4 @@ Emitter.methods = methods; // Global Event Hub Emitter.global = new Emitter() -Emitter.global.decorate(Y.event); - - -})(this.Y); +Emitter.global.decorate(exports); diff --git a/src/Y/modules/y.json.js b/src/Y/modules/y.json.cjs similarity index 62% rename from src/Y/modules/y.json.js rename to src/Y/modules/y.json.cjs index ec4cde6..5d7f673 100644 --- a/src/Y/modules/y.json.js +++ b/src/Y/modules/y.json.cjs @@ -1,4 +1,4 @@ -(function(Y){ +var Y = require('Y').Y; function toJSON(o, k){ var prefix = typeof(k) === 'string' ? '"'+k+'":' : '', @@ -7,9 +7,8 @@ function toJSON(o, k){ } function install(json_fn){ - var args = new Y(arguments), - tojson = args.shift(); - args.each(function(YThing){ + var args = Y(arguments,1); + args.forEach(function(YThing){ YThing.prototype.toJSON = json_fn; }); } @@ -29,7 +28,7 @@ function quoteJSON(){ // Collections function reducer(acc, v, k, o){ - var json = toJSON(v, Y.is.array(o) ? 0 : k); + var json = toJSON(v, Y.isArray(o) ? 0 : k); return json ? (acc ? acc+','+json : json) : acc; } @@ -40,13 +39,12 @@ var collectJSON = Y(function(a, z){ // Public API -Y.toJSON = toJSON; +Y['toJSON'] = exports['toJSON'] = toJSON; -install( yNoJSON, Y.YGeneric, Y.YFunction, Y.YRegExp ); -install( yToJSON, Y, Y.YBoolean, Y.YNumber ); +// install( yNoJSON, Y.YBase, Y.YFunction, Y.YRegExp ); +// install( yToJSON, Y, Y.YBoolean, Y.YNumber ); +install( yNoJSON, Y.YBase, Y.YFunction ); +install( yToJSON, Y, Y.YNumber ); install( quoteJSON, Y.YString ); -install( collectJSON.partial('{', '}'), Y.YCollection ); +install( collectJSON.partial('{', '}'), Y.YCollection, Y.YObject ); install( collectJSON.partial('[', ']'), Y.YArray ); - - -})(this.Y); diff --git a/src/Y/modules/y.kv.js b/src/Y/modules/y.kv.cjs similarity index 88% rename from src/Y/modules/y.kv.js rename to src/Y/modules/y.kv.cjs index f6c2c82..a05be23 100644 --- a/src/Y/modules/y.kv.js +++ b/src/Y/modules/y.kv.cjs @@ -1,6 +1,5 @@ -(function(Y, undefined){ if (!Y) return; - -var enc = encodeURIComponent +var Y = require('Y').Y +, enc = encodeURIComponent , dec = decodeURIComponent ; @@ -25,4 +24,3 @@ Y.YString.prototype.fromKV = }, {}); }; -})(this.Y); diff --git a/src/Y/op.cjs b/src/Y/op.cjs index 97ef023..e621efa 100644 --- a/src/Y/op.cjs +++ b/src/Y/op.cjs @@ -1,7 +1,7 @@ /* A subset of the functional operators, used in Y's core */ -var Y = require('Y').Y -, core = require('Y/core') +var core = require('Y/core') +, slice = core.slice , op = { // XXX: Make these function statements? // comparison @@ -41,6 +41,7 @@ var Y = require('Y').Y nop: function(x){}, I: function(x){ return x; }, K: function(k){ return function(){ return k; }; }, + nth: function(n){ return function(){ return arguments[n]; }; }, val: function(def,o){ return o !== undefined ? o : def; }, ok: function(o){ return o !== undefined && o !== null; }, @@ -57,10 +58,10 @@ var Y = require('Y').Y set: core.set, // set( o, key, value, def ) attr: core.attr, // attr( o, key, value, def ) method: function(name){ - var args = Y(arguments,1); + var args = slice.call(arguments,1); return function(obj){ if (obj && obj[name]) - return obj[name].apply( obj, args.concat(Y(arguments)) ); + return obj[name].apply( obj, args.concat(slice.call(arguments)) ); else return obj; }; diff --git a/src/Y/types/array.cjs b/src/Y/types/array.cjs index 18b50e3..c1f568b 100644 --- a/src/Y/types/array.cjs +++ b/src/Y/types/array.cjs @@ -1,35 +1,35 @@ -var Y = require('Y').Y; +var YCollection = require('Y/types/collection').YCollection +, mixin = require('Y/utils').mixin +, slice = require('Y/core').slice +; exports['YArray'] = -Y.YCollection.subclass('YArray', function(YArray){ - var yclass = require('Y/class'); +YCollection.subclass('YArray', function(YArray){ - yclass.chainDelegates(YArray, 'push', 'unshift', 'sort', 'splice', 'reverse'); - yclass.mixinNames(YArray, Array, ['reduce', 'map', 'forEach', 'filter', 'slice', 'some', 'every'], true, true); - yclass.mixinNames(YArray, Array, ['indexOf', 'lastIndexOf', 'shift', 'pop', 'join'], true, false); + mixin(YArray, { donor:Array, chain:true, + names:'push unshift sort splice reverse'.split(' ') }); + mixin(YArray, { donor:Array, wrap:YArray, + names:'map forEach filter slice'.split(' ') }); + mixin(YArray, { donor:Array, + names:'reduce some every indexOf lastIndexOf shift pop join'.split(' ') }); - - - this.init = function(o){ - // YCollection.init.call(this, o || []); + this.init = function initYArray(o){ this._o = o || []; }; this.merge = this.concat = function concat( donor ){ - var A = this._o; - new Y(arguments).forEach(function( donor ){ - A = A.concat(donor instanceof YArray ? donor.end() : donor); - }); - return Y(A); + return new YArray( slice.call(arguments).reduce(function(A, donor ){ + return A.concat(donor instanceof YArray ? donor.end() : donor); + }, this._o) ); }; this.remove = function remove(v){ if (arguments.length > 1) - Y(arguments).forEach(this.remove, this); + slice.call(arguments).forEach(this.remove, this); else { var idx = this.indexOf(v); if ( idx != -1 ) @@ -62,12 +62,20 @@ Y.YCollection.subclass('YArray', function(YArray){ // }); }; + // this.zip = + // function zip(){ + // var sequences = new YArray(slice.call(arguments)).map( Y.limit(1) ).unshift(this); + // return this.map(function(_, k){ + // return sequences.invoke('attr', k); + // }).invoke('end'); + // }; + // Like map, but produces a dict // Y(["Foo?", "R&D"]).generate(encodeURIComponent) // -> Y({"Foo?":"Foo%3F", "R&D":"R%26D"}) this.generate = function generate(fn, acc){ - var args = Y(arguments), + var args = slice.call(arguments), fn = args.shift(), acc = args.shift(); return this.reduce(function(acc, v, i){ @@ -84,7 +92,7 @@ Y.YCollection.subclass('YArray', function(YArray){ this.clone = function clone(){ - return Y(this._o.slice(0)); + return new YArray(this._o.slice(0)); }; this.size = diff --git a/src/Y/types/collection.cjs b/src/Y/types/collection.cjs index 669f942..56eb0b9 100644 --- a/src/Y/types/collection.cjs +++ b/src/Y/types/collection.cjs @@ -1,25 +1,29 @@ /** YCollection is the core of Y. */ -var Y = require('Y').Y +var YBase = require('Y/class').YBase , isFunction = require('Y/type').isFunction -, extend = require('Y/core').extend -, bool = require('Y/op').bool +, core = require('Y/core') +, op = require('Y/op') +, slice = core.slice +, extend = core.extend +, attr = core.attr +, bool = op.bool ; function extendY(){ - extend.apply(this, [this._o].concat(Y(arguments))); + extend.apply(this, [this._o].concat(slice.call(arguments))); return this; } exports['YCollection'] = -Y.YBase.subclass('YCollection', { +YBase.subclass('YCollection', { 'init' : function(o){ this._o = o || {}; }, 'attr' : function attr(k, v, def){ - var r = Y.attr(this._o, k, v, def); + var r = attr(this._o, k, v, def); if (r === this._o) return this; else @@ -73,19 +77,35 @@ Y.YBase.subclass('YCollection', { }, 'clone' : function clone(){ - return Y({}).extend(this); + return new this.constructor().extend(this); }, + // 'remove' : function remove(v){ + // var o = this._o + // , toRemove = new Y(arguments); + // + // for (var k in o) { + // var v = o[k]; + // if ( toRemove.has(v) ) { + // delete o[k]; + // toRemove.remove(v); + // } + // } + // return this; + // }, + 'remove' : function remove(v){ var o = this._o - , toRemove = new Y(arguments); + , toRemove = slice.call(arguments); for (var k in o) { - var v = o[k]; - if ( toRemove.has(v) ) { + var v = o[k], idx = toRemove.indexOf(v); + if ( idx !== -1 ) { delete o[k]; - toRemove.remove(v); + toRemove.splice(idx,1); } + if (!toRemove.length) + break; } return this; }, @@ -105,10 +125,11 @@ Y.YBase.subclass('YCollection', { }, 'zip' : function zip(){ - var sequences = new Y(arguments).map( Y.limit(1) ).unshift(this); + var sequences = slice.call(arguments); + sequences.unshift(this); return this.map(function(_, k){ - return sequences.invoke('attr', k); - }).invoke('end'); + return sequences.map(op.curried.kget(k)); + }); }, 'pluck' : function pluck(key){ @@ -118,9 +139,8 @@ Y.YBase.subclass('YCollection', { }, 'invoke' : function invoke(name){ - var args = Y(arguments), - name = args.shift(); - return this.map(function(o){ + var args = slice.call(arguments,1); + return core.map(this, function(o){ return o && o[name].apply(o, args); }); }, diff --git a/src/Y/types/function.cjs b/src/Y/types/function.cjs index f354cb3..88e81ba 100644 --- a/src/Y/types/function.cjs +++ b/src/Y/types/function.cjs @@ -2,14 +2,11 @@ var undefined , WRAPS = "__wraps__" , globals = (function(){ return this; })() -, Y = require('Y').Y -, core = require('Y/core') -, type = require('Y/type') +, core = require('Y/core') +, type = require('Y/type') -, isNumber = type.isNumber , isFunction = type.isFunction -, isArray = type.isArray -, isPlainObject = type.isPlainObject +, slice = core.slice , _ = exports._ = YFunction._ = {} , YFP = YFunction.prototype @@ -48,17 +45,17 @@ function unwrap(fn){ function curry(fn){ if (fn.__curried__) - return fn.apply(this, Y(arguments,1)); + return fn.apply(this, slice.call(arguments,1)); fn = Function.toFunction(fn); - var args = Y(arguments, 1) + var args = slice.call(arguments, 1) , L = unwrap(fn).length; if ( args.length >= L ) return fn.apply(this, args); function curried(){ - var _args = args.concat( Y(arguments) ); + var _args = args.concat( slice.call(arguments) ); if ( _args.length >= L ) return fn.apply(this, _args); else @@ -80,7 +77,7 @@ function methodize(fn) { m = fn.__methodized__ = function methodized(){ - return fn.apply(this, [this].concat( Y(arguments) )); + return fn.apply(this, [this].concat( slice.call(arguments) )); }; m[WRAPS] = fn; return m; @@ -95,7 +92,7 @@ function genericize( fn ) { g = fn.__genericized__ = function genericized(){ - var args = Y(arguments); + var args = slice.call(arguments); return fn.apply(args.shift(), args); }; g[WRAPS] = fn; @@ -106,20 +103,20 @@ function genericize( fn ) { function _composer(x,fn){ return fn.call(this, x); } function compose(f,g){ - var fns = Y(arguments).map(Function.toFunction); + var fns = slice.call(arguments).map(Function.toFunction); return function(){ - return fns.reduce(_composer, Y(arguments), this); + return fns.reduce(_composer, slice.call(arguments), this); }; } function chain(f,g){ - var fns = Y(arguments).map(Function.toFunction); + var fns = slice.call(arguments).map(Function.toFunction); if ( g.__sequence__ ) fns = g.__sequence__.concat( fns.slice(1) ); function chained(){ - var args = Y(arguments) + var args = slice.call(arguments) , i = fns.length; while (i-- > 0) args = fns[i].call(this, x); return args; @@ -131,10 +128,10 @@ function chain(f,g){ // YFunction.prototype.lazy = methodize(lazy); // function lazy(fn){ -// var args = Y(arguments, 1) +// var args = slice.call(arguments, 1) // , L = unwrap(fn).length // , lazied = function(){ -// var _args = Y(arguments) +// var _args = slice.call(arguments) // , f = _args[0]; // // if ( isFunction(f) ) { @@ -158,7 +155,7 @@ function chain(f,g){ var _bind = _Function.prototype.bind; function bind(fn, context, args){ - var bound = _bind.apply(fn, Y(arguments,1)); + var bound = _bind.apply(fn, slice.call(arguments,1)); bound[WRAPS] = fn; return YFunction(bound); } @@ -166,10 +163,10 @@ function bind(fn, context, args){ // Remembers arguments but obeys current context function partial(fn){ - var args = Y(arguments,1) + var args = slice.call(arguments,1) , partially = function partially(){ - return fn.apply( this, args.concat(Y(arguments)) ); + return fn.apply( this, args.concat(slice.call(arguments)) ); }; partially[WRAPS] = fn; return YFunction(partially); @@ -192,7 +189,7 @@ function memoize(fn){ fn.__memoized__ = function memorizer(){ // toJSON would be a better alternative, but that won't work cross-browser - var key = Y(arguments).join('\0\0\0') + var key = slice.call(arguments).join('\0\0\0') , cache = arguments.callee.cache; if ( !(key in cache) ) cache[key] = fn.apply(this, arguments); @@ -215,9 +212,12 @@ var _ofArityWrapper = YFunction._ofArityWrapper = memoize(function(n, limit){ + var i = n, args = []; + while (i-- > 0) args.unshift('$'+i); + // range(n).map( op.add('$') ).join(',') return eval('(function '+(limit ? 'limited' : 'artized')+'(fn){ '+ - 'return function('+Y.range(n).map( Y.op.add('$') ).join(',')+'){ '+ - 'return fn.apply(this,' + (limit ? 'Y(arguments).slice(0,'+n+')' : 'arguments')+ + 'return function('+args.join(',')+'){ '+ + 'return fn.apply(this,' + (limit ? 'slice.call(arguments, 0,'+n+')' : 'arguments')+ '); }; })'); }); @@ -265,9 +265,9 @@ function getName( fn ){ return fn.className || fn.name || (fn+'').match( /function\s*([^\(]*)\(/ )[1] || ''; } -function splat(fn, x){ - return fn[ isArray(x) ? "apply" : "call"](this, x); -} +// function splat(fn, x){ +// return fn[ isArray(x) ? "apply" : "call"](this, x); +// } @@ -284,7 +284,6 @@ exports['memoize'] = memoize; exports['aritize'] = aritize; exports['limit'] = limit; exports['getName'] = getName; -// exports['splat'] = splat; // Methodize and then attach to YFunction's prototype YFP.extend(core.map(exports, methodize)); diff --git a/src/Y/types/number.cjs b/src/Y/types/number.cjs index 875a641..6fb9bb5 100644 --- a/src/Y/types/number.cjs +++ b/src/Y/types/number.cjs @@ -1,4 +1,4 @@ -var Y = require('Y').Y +var YCollection = require('Y/types/collection').YCollection , op = require('Y/op') ; @@ -38,7 +38,7 @@ function range(start, end, step){ exports['YNumber'] = -Y.YCollection.subclass('YNumber', { +YCollection.subclass('YNumber', { init: function(o){ this._o = o || 0; }, diff --git a/src/Y/types/object.cjs b/src/Y/types/object.cjs index 3aeec15..07db9d7 100644 --- a/src/Y/types/object.cjs +++ b/src/Y/types/object.cjs @@ -1,10 +1,11 @@ -var Y = require('Y').Y -, isArray = Y.isArray +var YCollection = require('Y/types/collection').YCollection +, type = require('Y/type') +, isArray = type.isArray ; exports['YObject'] = -Y.YCollection.subclass('YObject', { +YCollection.subclass('YObject', { 'init': function initYObject(o){ this._o = o || {}; diff --git a/src/Y/types/string.cjs b/src/Y/types/string.cjs index cff211f..f8f608f 100644 --- a/src/Y/types/string.cjs +++ b/src/Y/types/string.cjs @@ -1,18 +1,17 @@ -var Y = require('Y').Y -, mixinNames = require('Y/class').mixinNames -, op = require('Y/op') +var YCollection = require('Y/types/collection').YCollection +, mixin = require('Y/utils').mixin +, op = require('Y/op') +, core = require('Y/core') +, slice = core.slice ; exports['YString'] = -Y.YCollection.subclass('YString', function(YString){ +YCollection.subclass('YString', function(YString){ - mixinNames(YString, String, [ - 'slice', 'split', - 'substr', 'substring', - 'concat', 'replace', - 'toLowerCase', 'toUpperCase' - ], true, true); - mixinNames(YString, String, [ 'indexOf', 'lastIndexOf', 'charAt', 'charCodeAt' ], true, false); + mixin(YString, { donor:String, wrap:YString, + names:'slice split substr substring concat replace toLowerCase toUpperCase'.split(' ') }); + mixin(YString, { donor:String, + names:'indexOf lastIndexOf charAt charCodeAt'.split(' ') }); function trim(val){ var s = this._o+''; @@ -46,7 +45,7 @@ Y.YCollection.subclass('YString', function(YString){ howMany = Number(howMany > 0 ? howMany : 0); var prefix = s.slice(0, idx) - , insert = Y(arguments, 2).join('') + , insert = slice.call(arguments, 2).join('') , suffix = s.slice(idx+howMany) ; this._o = prefix + insert + suffix; @@ -60,18 +59,9 @@ Y.YCollection.subclass('YString', function(YString){ * Negative values for start and/or end are allowed. */ mutate : function mutate(start, end){ - return this.splice.apply(this, [start, end-start].concat(Y(arguments, 2)) ); - // var s = this._o, len = s.length ; - // - // if (start < 0) start += len; - // if (end < 0) end += len; - // - // var prefix = s.slice(0, start) - // , insert = Y(arguments, 2).join('') - // , suffix = s.slice(end) - // ; - // this._o = prefix + insert + suffix; - // return this; + // var args = slice.call(arguments); + arguments[1] = end-start; + return this.splice.apply(this, arguments); }, strip: function strip(){ @@ -116,9 +106,9 @@ Y.YCollection.subclass('YString', function(YString){ this.set = function set(key, value, def){ var s = this._o, _val = (value !== undefined ? value : def); - if ( Y.isNumber(key) ) + if ( isNumber(key) ) return this.splice(key, 1, _val); - if ( Y.isArray(key) ) + if ( isArray(key) ) return this.splice.apply(this, key.slice(0,2).concat([_val]) ); // TODO: Should cache the new properties and re-applied them whenever we mutate _o, @@ -131,19 +121,19 @@ Y.YCollection.subclass('YString', function(YString){ var s = this._o; // set if ( value !== undefined || def !== undefined ) - return Y.attr(this, key, value, def); + return core.dattr(this, key, value, def); // get else { - if ( Y.isNumber(key) ) + if ( isNumber(key) ) return s.charAt(key); - if ( Y.isArray(key) ) + if ( isArray(key) ) return s.slice.apply(s, key); return s[key]; } }; - this.attr.__wraps__ = Y.attr; + this.attr.__wraps__ = core.dattr; this.reduce = function reduce(fn, acc){ fn = Function.toFunction(fn); diff --git a/src/Y/utils.cjs b/src/Y/utils.cjs new file mode 100644 index 0000000..9886733 --- /dev/null +++ b/src/Y/utils.cjs @@ -0,0 +1,68 @@ +var YFunction = require('Y/types/function').YFunction +, isFunction = require('Y/type').isFunction +, core = require('Y/core') +, op = require('Y/op') +; + + +function bindName(k){ + var v = this[k]; + if ( isFunction(v) ) + this[k] = YFunction(v).bind(this); +} + +function bindAll(o, names){ + if (!o) + return o; + if (arguments.length === 1) + names = core.map(o, op.nth(1)); + else + names = slice.call(arguments, 1); + names.forEach(bindName, o); + return o; +} + + +var defaults = { + 'donor' : null, + 'names' : null, + 'override' : true, + 'wrap' : false, + 'chain' : false +}; +function mixin(target, options){ + var opt = op.extend({}, defaults, options), Donor = opt.donor + , target = ( isFunction(target) ? target.prototype : target ) + , proto = ( isFunction(Donor) ? Donor.prototype : Donor ) + , names = opt.names + ; + + // Need a closure to capture the name + names.forEach(function(name){ + var fn = proto[name]; + if ( isFunction(fn) && (opt.override || !(name in target)) ) + target[name] = function(){ + var r = fn.apply(this._o || target, arguments); + return (opt.chain ? this : (opt.wrap ? opt.wrap(r) : r)); + }; + }); + + return o; +} + + +// function chainDelegates(type, names){ +// var proto = type.prototype; +// names.forEach(function(name){ +// proto[name] = function(){ +// var o = this._o || this; +// o[name].apply(o, arguments); +// return this; +// }; +// }); +// return type; +// } +// exports['chainDelegates'] = chainDelegates; + +exports['bindAll'] = bindAll; +exports['mixin'] = mixin; diff --git a/src/Y/y.cjs b/src/Y/y.cjs index 3241611..a9018a8 100644 --- a/src/Y/y.cjs +++ b/src/Y/y.cjs @@ -1,3 +1,4 @@ +// -*- mode: JavaScript; tab-width: 4; indent-tabs-mode: nil; -*- var undefined , globals = (function(){ return this; })() , _Object = globals.Object diff --git a/src/evt/evt.class.js b/src/evt/evt.class.js index 07422ef..dfc3701 100644 --- a/src/evt/evt.class.js +++ b/src/evt/evt.class.js @@ -1,4 +1,3 @@ -(function(undefined){ // Inspired by John Resig's "Simple Class Inheritence" -- http://ejohn.org/blog/simple-javascript-inheritance/ /* Metaprogramming API @@ -24,11 +23,11 @@ Class Methods Note: Metaprogramming events cannot depend on Class. */ +var Y = require('Y').Y +, Emitter = require('Y/modules/y.event').Emitter - -var Evt = this.Evt = (this.Evt || {}) -, KNOWN_CLASSES = Class.KNOWN_CLASSES = {} , isFunction = Y.isFunction +, KNOWN_CLASSES = Class.KNOWN_CLASSES = exports['KNOWN_CLASSES'] = {} , getProto = Object.getPrototypeOf , hasOwn = Object.prototype.hasOwnProperty , objToString = Object.prototype.toString @@ -38,13 +37,13 @@ var Evt = this.Evt = (this.Evt || {}) // Private delegating constructor -- must be defined for every // new class to prevent shared state. All construction is // actually done in the init method. -Evt.ConstructorTemplate = ConstructorTemplate; +exports['ConstructorTemplate'] = ConstructorTemplate; function ConstructorTemplate() { var cls = arguments.callee , instance = this; // Not subclassing - if ( cls.caller !== Evt.Class.fabricate ) { + if ( cls.caller !== Class.fabricate ) { cls.fire('create', instance, { 'instance' : instance, @@ -154,7 +153,7 @@ function Class(className, Parent, members){ , init = NewClass.prototype.init ; - instance.__emitter__ = new Y.event.Emitter(instance, NewClass); + instance.__emitter__ = new Emitter(instance, NewClass); if (init) { var result = init.apply(instance, arguments); @@ -172,7 +171,7 @@ function Class(className, Parent, members){ // Add class emitter var ParentEmitter = (Parent.__emitter__ ? Parent : ClassFactory) - , ClassEmitter = NewClass.__emitter__ = new Y.event.Emitter(NewClass, ParentEmitter) + , ClassEmitter = NewClass.__emitter__ = new Emitter(NewClass, ParentEmitter) ; // Either invoke body constructor... @@ -204,7 +203,7 @@ function Class(className, Parent, members){ // Decorate with emitter methods and // add metaprogramming data to Class object Class.__super__ = Object; -Class.__emitter__ = new Y.event.Emitter(Class); +Class.__emitter__ = new Emitter(Class); Class.fn = Class.prototype; Class.fn.__class__ = Class; Class.className = Class.fn.className = "Class"; @@ -242,9 +241,6 @@ Class.fn.subclass = // Expose -Evt.Class = -Evt.subclass = Class; - - +exports['Class'] = +exports['subclass'] = Class; -})(); \ No newline at end of file diff --git a/src/ezl/index.cjs b/src/ezl/index.cjs new file mode 100644 index 0000000..955dc17 --- /dev/null +++ b/src/ezl/index.cjs @@ -0,0 +1,5 @@ +// -*- mode: JavaScript; tab-width: 4; indent-tabs-mode: nil; -*- +//@require('jquery') +//@require('lessly/future') +//@require('Y') + diff --git a/src/ezl/layer.js b/src/ezl/layer.cjs similarity index 96% rename from src/ezl/layer.js rename to src/ezl/layer.cjs index b6cd536..063a740 100644 --- a/src/ezl/layer.js +++ b/src/ezl/layer.cjs @@ -1,16 +1,24 @@ -(function($, undefined){ +//@require('jquery') -var CONTEXT_ATTRS = Y([ +var undefined +, Y = require('Y').Y +, Vec = require('ezl/math/vec').Vec +, loc = require('ezl/loc') +, Loc = loc.Loc +, BoundingBox = loc.BoundingBox +, +CONTEXT_ATTRS = Y([ 'globalAlpha', 'globalCompositeOperation', 'strokeStyle', 'fillStyle', 'lineWidth', 'lineCap', 'lineJoin', 'miterLimit', 'shadowOffsetX', 'shadowOffsetY', 'shadowBlur', 'shadowColor' -]); +]) +, - - -Layer = Y.subclass('Layer', { - _cssClasses : 'portal layer', +Layer = +exports['Layer'] = +Y.subclass('Layer', { + _cssClasses : 'ezl layer', canvas : null, @@ -503,11 +511,9 @@ function makeDelegate(name, dirties, prop){ $(function(){ $('