Hi, all, News from the libfossil scripting front...
Consider this script output: Wiki pages: AmalgamationBuild @ 2014-03-28 19:56:08.191 by stephan size: 2431 bytes building @ 2014-02-26 17:12:27.403 by stephan size: 3996 bytes DbFunctions @ 2014-03-18 16:08:14.015 by stephan size: 4238 bytes download @ 2014-03-23 10:53:38.255 by stephan size: 1293 bytes f-tools @ 2014-05-30 18:32:29.051 by stephan size: 12498 bytes FossilApp @ 2014-02-11 14:36:06.290 by stephan size: 1378 bytes HackersGuide @ 2014-02-05 19:43:45.187 by stephan size: 2213 bytes home @ 2014-03-23 10:50:36.201 by stephan size: 8640 bytes scratchpad @ 2014-03-13 16:12:55.012 by stephan size: 314 bytes SQLSnippets @ 2014-05-07 18:31:05.070 by stephan size: 8508 bytes test-page @ 2013-08-27 20:49:55.964 by stephan size: 1073 bytes th1ish @ 2014-07-28 19:48:14.139 by stephan size: 3486 bytes The interesting thing is not the data, but how it's fetched and generated. Taking a few lessons from requirejs (http://requirejs.org), the implementation looks like: Fossil.require( ['fsl/context', 'fsl/wiki/util'], function(fsl, wikiUtil){ print('Wiki pages:'); wikiUtil.getPageNames().eachIndex(function(name){ var page = fsl.loadManifest( wikiUtil.getLatestRid(name) ); print('\t',page.L, '@', Fossil.time.julianToHuman(page.D,true), 'by', page.U, 'size:', page.W.lengthBytes(), 'bytes' ); }); }); Basically what that's doing is loading two "modules", called fsl/context and fsl/wiki/util. Each module's result is then passed on to the Function provided by the caller. The module loader caches each script it loads, so multiple calls to a given module will (unless it is configured otherwise) return the same instances. That means that multiple calls to Fossil.require() which use the same modules can share state even though they are many scopes removed from one another. In the above case, the fsl/context module provides the code with a shared Fossil.Context instance, so that all parts of the app can use the same instance without having to know a global symbol name for it (there isn't one). Here's a similar one for a basic timeline view: Most recent timeline entries: ci e54de856af @ 2014-08-09 16:52:32 by stephan latest s2, started work on a require.rs-based app prototype. ci a5a9733acd @ 2014-08-09 14:32:17 by stephan more s2. ci 23f20bb428 @ 2014-08-09 07:12:05 by stephan latest s2 for "this" changes in non-property func calls. ci a9d46c815a @ 2014-08-08 23:20:18 by stephan latest s2. ci 51413ceef4 @ 2014-08-04 18:13:29 by stephan latest upstream s2 for (new) do/while loop and updated unit tests. The code: Fossil.require( ['fsl/timeline/basic', 'ostream'], function(timelineList, os){ os << "Most recent timeline entries:\n"; timelineList.eachIndex(function(v){ os << v.type << ' ' << v.uuid.substr(0,10) << ' @ ' << Fossil.time.julianToHuman(v.mtime) << ' by ' << (v.euser ||| v.user) << '\n\t' << (v.ecomment ||| v.comment) << '\n'; }) }); (@Brad Harder: there goes the leaky db abstraction!) The 'ostream' module simply overloads the '<<' operator to send its arguments to the configured output channel, giving the caller a C++-like output streaming mechanism. It's trivial to add new modules this way, and require() supports requirejs-like plugins, so it can be used to load arbitrary things, not just script files: Fossil.require([ 'dll!cgimod', // load the CGI plugin from a DLL 'fsl-manifest!trunk', // loads a manifest in Object form 'fsl-wiki!Pagename', // loads the manifest for the given page 'fsl-blob!trunk', // loads blob content as a Buffer 'tmpl-compiled!my_template' // load a TH1-style text-file-with-embedded-script-code ], function( cgi, trunk, wikiPage, blob, template ){ ... eval -> template; // we just generated a web page }); The primary advantages to requirejs' async-like execution model, compared to linear procedural coding in JS/s2: - it abstracts away dependency loading. Any given module may require() other modules if they need them. If loading any module triggers an exception, the user's callback function is never called. i.e. the client has to do no error checking/handling for the dependencies. - it cleans up the namespace, effectively replacing global symbols (with fixed names) with local symbols (which the caller can name however he likes). If you want to call your copy of jQuery "abc", then go right ahead - the change is local to your function. - it incidentally plays very nicely with garbage collectors (be it JS or s2), providing lifetime "anchors" via the function call stack. It's more difficult to predict lifetimes (i.e. peak memory usage) in code which does all its work in a global scope. This model has memory overhead from the function calls, but the lifetimes are very predictable and generally briefer, allowing for more recycling of memory. At this point it's all experimentation - finding out what modules and structures are more useful - but i'm very pleased with how it's turning out so far. Happy Fossiling! -- ----- stephan beal http://wanderinghorse.net/home/stephan/ http://gplus.to/sgbeal "Freedom is sloppy. But since tyranny's the only guaranteed byproduct of those who insist on a perfect world, freedom will have to do." -- Bigby Wolf
_______________________________________________ fossil-users mailing list fossil-users@lists.fossil-scm.org http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users