-
Notifications
You must be signed in to change notification settings - Fork 0
/
fig.require.js.sdocp
1 lines (1 loc) · 3.75 KB
/
fig.require.js.sdocp
1
sdocp('sdoc::js::fig.require', 'Figment require() function | Spencer Tipping\nLicensed under the terms of the MIT source code license\n\nIntroduction.\nThis module enables dynamic Figment loading and translation by adding a require() method to Caterwaul. The same function can be used on either the client or the server; require() detects the\nenvironment and behaves accordingly. Usage is similar to configure() or clone():\n\n| caterwaul.clone(\'fig.require\').require(\'http://somewhere.com/path/library.fig /usr/share/figment/std.fig\');\n\nUnlike Javascript, the scripts that are require()d aren\'t executed in the global context. Rather, they\'re executed inside a closure with access to the evaluating caterwaul function. Libraries\ngenerally add some configuration to the function (but don\'t actually apply it), e.g. (in Figment):\n\n| this.configuration(\'cons-macro\', {qs[_x :: _y] :> qs[cons(_x, _y)]})\n\nThere is no need to use tconfiguration() because the requiring caterwaul function will automatically macroexpand the Figment source in the process of compiling it to Javascript.\n\nServer-side require.\nBecause requiring stuff is a fundamentally synchronous thing to do (and generally not done after app initialization), blocking methods are used to load things. The only mechanism for loading\nthings is the filesystem; loading files over HTTP isn\'t supported yet. Also, because I\'m being lazy, files are loaded synchronously rather than using CPS.\n\n caterwaul.tconfiguration(\'std seq continuation\', \'fig.require.nodejs\', function () {\n this.method(\'figment_require\', fn[files, cc][cc(seq[~files.split(/\\s+/) *[fs.readFileSync(_, \'utf8\')]].slice())])}, {fs: typeof require === \'undefined\' || require(\'fs\')}).\n\nClient-side require.\nThis is a bit more challenging because it involves AJAX. Basically we load the script using an AJAX request, then evaluate it as soon as the script comes back. To do this sensibly we need to\nhave a callback that executes once all of the code is loaded. For example:\n\n| caterwaul.clone(\'fig\').require(\'/path/to/source1.fig /path/to/source2.fig\', function () {\n // In here, \'this\' is set to a configured clone of the original requiring function.\n this.configure(\'source1-module\');\n this.module1.do_something();\n });\n\nThe callback function isn\'t run through caterwaul. This gives it the ability to refer to closure state.\n\n tconfiguration(\'std seq continuation\', \'fig.require.ajax\', function () {\n this.method(\'figment_require\', fn[files, cc][\n l*[file_list = seq[~files.split(/\\s+/)], contents = {}, requests_left = file_list.size(), got_everything() = cc(seq[file_list *[contents[_]]]),\n receive(filename)(data) = --requests_left /se[contents[filename] = data, _ || got_everything()]] in\n\n seq[file_list *![get(_, receive(_))]]]),\n\n where*[create_xhr() = window.XMLHttpRequest /re[_ ? new _() : new ActiveXObject(\'Microsoft.XMLHTTP\')],\n get(url, success) = create_xhr() /se[_.open(\'GET\', url, true), _.send(), _.onreadystatechange() = _.readyState === 4 && success(_.responseText)]]}).\n\nRequire shell.\nThis part manages the logic of configuring a caterwaul function once the source is retrieved. There isn\'t much involved; we just end up invoking a callback. The only thing is that your\ncaterwaul function should already be configured as a figment parser for this to work. (The \'fig\' configuration takes care of this for you.)\n\n tconfiguration(\'std seq continuation\', \'fig.require\', function () {\n this.configure(typeof window === \'undefined\' ? \'fig.require.nodejs\' : \'fig.require.ajax\').\n method(\'require\', fn[modules, cc][this.figment_require(modules, _) /cpb[seq[~_ *![c(_, {\'this\': c})]], cc && cc.call(c), where[c = this.clone()]]])});');