I just launched a dead-simple web framework on top of node.js. It uses (abuses?) a lot of the dynamic nature of javascript to create a jQuery-inspired DSL that's pure javascript, allowing you to create really concise web apps like this:
( fab )
( "/time", function(){ return "the time is " + (new Date).toTimeString() } )
( "/date", function(){ return "the date is " + (new Date).toDateString() } )
( fab )
I'd love to hear any feedback from the folks here, so check it out and let me know what you think.I think I can say that this is the best (ab)use of the syntax I've ever seen, well done. :)
What if you want to dynamically create stuff? You can take the value of fab, use standard for loops and if statements and whatnot to apply things to it, then call fab again at the end and it'll all work fine. By hiding in a DSL here, you encourage people to not realize that, and take away the ability for these people to use the Javascript they already know to build the system. Another manifestation of this general principle is that you may get people who don't realize that they can define a function elsewhere then include it as an argument.
Please don't laugh or tell me this is impossible. I used to think that too. Experience has bludgeoned me over the head on this, rather against my will.
Magic really ought to be reserved for things that can't be done without magic. Method chaining is becoming a standard JS technique (even though I don't like it, for pretty much this same reason albeit more weakly as it is less of a departure) and I don't see a reason not to just use method chaining here.
If I don't miss my guess, as you develop this you're going to miss having it anyhow and have to switch to it anyhow. You're almost certain to end up having more than one type of thing go in those arguments, and the alternative will be either returning to method chaining, or using the first argument to do nothing other than switch on which method you actually call. (And that is honestly just silly because the language already has perfectly cromulent facilities for doing that.)
My original approach for (fab) was like jQuery:
fab()
.find( path )
.bind( method, handler )
.find( subpath )
.bind( method, handler )
.end()
.end()
.end()
but I realized that I could simplify things by getting rid of methods entirely, and reserving methods for HTTP methods and status codes.As for people not realizing they can define functions outside of the DSL, I'm hoping that the extensibility of middleware will mitigate that, just as the ecosystem of plugins did for jQuery.
Multi-line functions work okay, but it's definitely cleaner to name them and put them somewhere else so that your code ends up looking like a site map:
(by "long-polling stuff" I mean deferring response.finish())