cfmljure 0.1.0 released!

4 views
Skip to first unread message

Sean Corfield

unread,
Jan 23, 2015, 8:05:40 PM1/23/15
to cfml...@googlegroups.com, framew...@googlegroups.com
https://github.com/framework-one/cfmljure/releases/tag/v0.1.0

This is a complete rewrite of the CFML/Clojure bridge to:

* Leverage Leiningen for dependency and classpath management
* Support Clojure 1.6 and later (via the new Java API)
* Remove the need for any classpath configuration changes in your CFML engine

Note: currently Railo-only - I need to get a ColdFusion test environment up and fix the compatibility issues (the main one I know about is calling cfexecute as cfscript using Railo-only syntax).

Now you can just create a Clojure project with Leiningen, anywhere, and then pull it into your CFML code and call any of the functions it implements.

All the examples are completely rewritten too. The Task example uses Clojure's java.jdbc library to interact with a Derby database: CFML for the views, Clojure for all the business logic! :)

Sean Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)



Sean Corfield

unread,
Feb 3, 2015, 2:47:25 PM2/3/15
to framew...@googlegroups.com, cfml...@googlegroups.com
On Feb 3, 2015, at 9:52 AM, John Berquist <jcber...@gmail.com> wrote:
> The lein script installs Leiningen to the user's home directory, so the tomcat user can't run it successfully in such cases. (This is easily fixed by making sure that the tomcat user has a home directory, but it did trip me up at first.)

In that case you could specify the full path to the lein script as an argument to the cfmljure constructor (it’s actually what we do at World Singles since our lein script is under version control so we can carefully control which version we’re using on our servers).

> I also like to turn on the setting to preserve dot notation casing in the admin for Railo/Lucee because I like to be able to use dot notation with structs without having serializeJSON() returning all upper case keys. Railo/Lucee still lets you reference struct keys with any casing (it doesn't have to match the original case), so you are not forced to be consistent in your key casing. But this is not the case for hash maps :D. This resulted in the task example not running correctly at first because task.name doesn't exist. I realized that the to-struct function in task.core.clj was upper casing the keys (makes complete sense given the default behavior of cfml).

Ah, yes. You’d be able to skip the upper-casing in your environment and just convert keywords to strings (or have your Clojure code create hashmaps with string keys instead).

> I have a couple of questions as well, resulting, I am sure, from my ignorance of clojure. Passing in a cfml struct to clojure seems to create an unusual situation. I am not sure how one would get values out of it in clojure?

The best way I’ve found is to do this:

var core = clj.clojure.core;
var structClj = core.into( core.hash_map(), structCFML );

That produces a Clojure-compatible struct with the same keys (strings) that your CFML struct had.

The underlying problem here is that the struct (in CFML) is not "associative" in the Clojure world. I could probably fix that by defining extending the struct types to implement the associative protocol - something that’s possible in Clojure and very powerful (you can extend any type to have additional methods that implement protocols - interfaces - making it easier to reuse code). The problem would be that ColdFusion, Railo, and possibly Lucee, would have different types and it would mean introducing some Clojure code (as a library) that you’d need to add to your project.clj file etc etc. In other words, the pain probably isn’t worth it.

> Also (here is a real newbie question!) how do you recommend reloading clojure in a joint cfml clojure project. Specifically, when testing passing cfml variables to clojure functions, I want to be able to change a clojure function, and reload it, to test the changes. What is the correct/recommended way to do this, short of restarting tomcat?

You can require the namespace with the :reload keyword to force Clojure to re-read it from disk and re-compile it on the fly. Here’s the code we use (variables.ns is the list of namespaces we pass to cfmljure's constructor):

public void function reload( string namespaces ) {
var core = this.clojure.core
if ( namespaces == "all" ) {
var nsList = variables.ns.filter( function( ns ) { return ns.startsWith( "worldsingles" ) } )
var reload = core.keyword( "reload" )
} else {
var nsList = listToArray( namespaces )
var reload = core.keyword( "reload-all" )
}
core.apply( core._require(), core.keyword( reload ), core.map( core._symbol(), nsList ) )
}

This is a CFC that wraps cfmljure. We install( variables.ns, this ) so that the CFC itself is our Clojure root and we inject it as a dependency into our CFML code (as variables.clj). So we can say clj.reload( "all" ) to do a simple reload of each namespace that starts with worldsingles, or we can say clj.reload( "my.ns, my.other.ns" ) to do a full dependency-level reload of those specified namespaces (reload does not refresh dependencies, reload-all does - but is slower since it recompiles all dependencies in the specified namespace).
Reply all
Reply to author
Forward
0 new messages