hlship / cascade Goto Github PK
View Code? Open in Web Editor NEWSimple, fast, easy web applications in idiomatic Clojure.
Home Page: http://github.com/hlship/cascade
Simple, fast, easy web applications in idiomatic Clojure.
Home Page: http://github.com/hlship/cascade
This is partly because of the nature of Clojure being lazy, but it is also because some exceptions (such as incorrect return value from a rendering function) is reported outside the function; some link to the function itself (via meta-data) should be made available.
Cascade should have a mechanism for adding assets (context or classpath) to the Javascript profile of a page. Further, it should be possible to combine multiple JavaScript libraries into fewer (ideally one or two) virtual assets, combining the contents of the underlying files.
Having a production mode vs. development mode distinction would be quite nice, mostly for exception reporting, but going forward, for other tricks like JavaScript aggregation.
It seems that it will be common to extend view or action behavior based on meta data on the view or action function, and that a transforming function could be used to apply those aspects.
The cascade.filter should check init params (from the web.xml) to load some list of namespaces at startup. These will typically be the namespaces containing views and actions.
Both using the run-jetty function (for testing or embedded) or the standard way, by writing a web.xml.
Cascade should automatically compress content sent to the client.
Tapestry handles this quite well, including caching of compressed static assets.
I put in place a basic namespace reloader, but I'm sure it could use some work.
The current approach is fragile; it reloads it immediately (I don't always save working code). If the code doesn't reload the first time, it's no longer tracked for changes.
A better approach might be to record which namespaces need reloading, and to do the reload at the start of the next incoming request.
Still tricky; Tapestry solution serializes all threads for the duration of a check and reload, and I want to avoid that ... but in a busy server, you might have multiple threads competing to reload changed namespaces. May still need some careful work on this.
Text nodes that contains XML entities (<, >, &, etc.) should be filtered to expand those characters to the corresponding entities (&tl;, >, &).
Further, where possible, this conversion should occur statically (at view construction time), necessating an additional DOM node type, :raw-text.
I'm thinking that the current implementationof pipelines is overly complex. I think pipelines can and should be implemented as decorations on a core function. A simple decorate macro could rebind a var's root binding, adding a filter function in front:
(decorate fn-symbol filter)
This would create a new function that passes the existing function to the filter (as the first parameter) followed by any other parameters and rebind the fn-symbol's root value to the filter.
Order of operations counts, you want to work from the inside out; that's a function of the order in which decorate is called.
It would also be interesting to have a defpipeline:
(defpipeline render render-view render-view-as-xml (fn ...))
This would define a series of functions, each of which calls the next with whatever parameters are passed to it. This provides a rich set of extension points for adding filters via decoration.
Need additional targets for building Cascade, installing it to the local repository, and deploying it to the Tapestry360 Maven snapshot repository.
The current code looks ugly outside of Eclipse because the Clojure editor uses tabs, not spaces, when indenting. We should be using two spaces for each tab. Not worth fixing until the Clojure plugin for Eclipse evolves a bit, to support formatting, etc.
The DOM node constructor functions should add meta-data to identify the map as a DOM node: { :cascade-dom-node true }
I've had difficult to trace errors where other maps accidentally "leaked" into the DOM tree causing evil problems downstream where the maps didn't fit the mold of the rendering and streaming functions.
Namespaces containing views and actions should automatically reload when changed.
This will involve a thread of some sort that maps functions to namespaces and namespaces to underlying source files (.clj). When such a file changes, Cascade should reload it.
There are issues with reloading; I'm not sure how to do it properly, there are issues with path mappings changing on reload (the old path mapping will hold a reference to the old function, possibly).
So, the qualifier might be "IE 5" and the <script> or would be wrapped with <!--[If IE 5]> ... <![endif]> --->
This hasn't made it to the wiki yet, but can place a request path deconstructor just after the parameters vector.
There are a number of places where information inside the configuration is used to compute some expensive(?) result. The result must be constantly recomputed in case the configuration changes between executions.
Instead, a mechanism to link the calculation to the configuration such that the value is lazily computed, and invalidated when the configuration changes. This could be built on top of the watcher mechanism for atoms (watching @configuration for changes) and another atom to store the lazily computed value (resetting it to nil when the configuration is changed).
Make it easy to create and render a response as a stream of JSON characters, using the support built into clojure.contrib
Often the output of combine is passed up a level back into combine; it should mark its output with meta data, and when it sees that meta data, it knows it can shortcut or entirely avoid the combine.
Like Tapestry ... further, mimic its ability to guess at which properties are paths and break them up into
I suspect it has to do with the thread that is started to detect changed files.
The viewbulider (the center of the template, defview, etc. macros) should be able to do some static analysis of the views being constructed. Some portions of the generated code will be rendering invariant portions of the template: sections where everything is a fixed keyword or string with no calculation or external dependencies (such as symbols or function calls).
Using meta data we can tag the generated code to identify which forms are invariant, and which are truly dynamic. At an appropriate point, we can wrap the invariant parts in a global singleton, to render it once (on demand) and keep the rendered portion.
Should be tunable, since its probably more efficient to keep rendering small portions of markup than to introduce the overhead of managing an atom to cache the invariant result.
Just recording a hunch that multiple calls to extend-dom may be a costly way to do the post-processing. It might be better if only a single zipper was created and was passed around to a number of functions in a row .. right now we're up to four zippers (generator meta, JavaScript libraries, JavaScript block, and stylesheets).
A mechanism is needed to allow the rendered DOM to be manipulated after being rendered. This is a powerful feature of Tapestry and is necessary to support some of the other planned features.
Mapping the DOM tree to zipper would be a help for doing some manipulations, but there's probably a higher-level approach for the things commonly needed (such as adding new <script> and tags).
This is probably a smaller hit than intransient DOM nodes, but could add up: the combine function can use a transient vector when combining render results into a vector of DOM nodes.
I'm pretty sure that the slim JAR (such .clj sources) is not useful, as cascade.filter is not pre-compiled. Probably need to special-case that particular class.
As with JavaScript aggregation, a declarative mechanism to include CSS style sheets is needed, that would add elements to the final document before streaming.
Cascade's DOM currently only models elements and text nodes, but many applications will want to render a specific DOCTYPE and XHTML applications may want to render CDATA.
Currently, marking a namespace as requiring reload is linked to defview & defaction; there should be another macro that can be put into an arbitrary namespace to enable the same reload logic.
Access to classpath assets should be subject to a blacklist or resources that should not be allowed to be downloaded.
By default, ".class" and ".clj" files should not be accessible by the client.
I accidentally stripped off the leading ':' of a keyword (representing an element in the DSL). Took me a while to track down the error:
Caused by: java.lang.RuntimeException: Incomplete parse of (:p {:class :c-exception-controls} [:input {:type :checkbox, :id :omitted-toggle} " " :label {:for :omitted-toggle} ["Display hidden detail"]] ul {:class :c-exception-report} [(template-for [m (expand-exception-stack exception)] :li {:class (if (nil? (m :stack-trace)) :c-omitted)} [(render-exception-map m)])] (render-environment env)), 3 forms remain, starting with {:class :c-exception-report}.
at cascade.fail$fail__9.doInvoke(fail.clj:21)
at clojure.lang.RestFn.invoke(RestFn.java:460)
at cascade.internal.parser$run_parse__425.invoke(parser.clj:95)
at cascade.internal.viewbuilder$parse_embedded_template__517.invoke(viewbuilder.clj:112)
at cascade$template__429.doInvoke(cascade.clj:26)
at clojure.lang.RestFn.invoke(RestFn.java:522)
at clojure.lang.Var.invoke(Var.java:384)
at clojure.lang.AFn.applyToHelper(AFn.java:205)
at clojure.lang.Var.applyTo(Var.java:476)
at clojure.lang.Compiler.macroexpand1(Compiler.java:4485)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:4559)
First, having an explit error-catching case of a free-floating map inside the DSL might help, as would using meta-data to identify the source line more clearly.
You should be able to map a view or action to root: {:path ""} but this doesn't work ... strangely if you make the URL http://localhost:8080// (two slashes) it does.
It's tripping people up that you need to have the Maven Ant Tasks in $(ANT_HOME)/lib.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.