søndag 16. februar 2014

A Groovy Light Table client - Step 1: Connecting the client

Building a plugin i Light Table

This is the first post in (hopefully) a series of blog posts about the various steps I go through when trying to create a plugin for Light Table. I have decided to try to create a Groovy plugin. I chose Groovy to ensure there was at least one technology fairly familiar to me. I have just started using Light Table, I have no previous experience with ClojureScript and I have just recently started writing some Clojure beyond the basic tutorials.

The short term goal is for the plugin to provide inline results and maybe an instarepl of some sort for groovy scripts.

LightTable-Groovy is the name of my plugin project and you can find the latest source there. It might be a couple of steps ahead of the blog posts though ! 

Documentation

Light Table was made open source in january and documentation for plugin developers is a little sparse.  So to have something to go by I decided to use some of the other language plugins as inspiration:
I haven't worked with any of the above mentioned languages, but they did provide enough inspiration to deduce how a Light Table client might interact.

BTW. A quick starter just to get you up an running with a hello world plugin could be this screen cast by Mike Haney.


Connecting a client - Process overview

Before we dwelve into the code It's a good idea to have a high level understanding of what we are trying to achieve ! 

A couple of use cases that needs to be supported:
  • Evaluate current selection or current line of groovy code and present results (preferably inline)
  • Evaluate contents of current editor and present results
    • Provide as much info about the results of each statement as possible
    • (Maybe need to evaluate line/statement by statement)
  • For a future instarepl, any change in the editor will trigger an evaluation
It becomes evident that our plugin needs to provide some kind of process that reacts to events from light table. A default pattern for achieving this has been devised for Light Table and roughly equates to the following steps:
  1. A connect event is triggered from Light Table (you need to set up your plugin to trigger that event…). Typically the connect event can be invoked manually from the connect bar in light table, or it can be triggered implicetly when evaluating code. 
  2. You fire of a process - Using inbuilt support from Light Table you start a process either a shell script or whatever really. I created a shell script that sets some environment stuff and then basically kicks off a groovy script. Light table provides a tcp/ip port and a unique client id which you need to forward to the process.
  3. Create a tcp client: In your process you create a tcp client using the given port 
  4. Send ack message: Send a json message with client id and an event name (behavior) to Light Table (through the tcp connection!)
  5. Confirm handshake for process: In your process (i.e. not the tcp connection!) write "Connected" to standard out. ("Connected" is just what the other plugins use, you could use  anything you like as long as it matches the connect behaviors(handlers) you provide inside light table.)
  6. Listen for events: Now you are connected and given you have set up your behaviors in Light Table correctly, your new connection should be reported as connected and shown in the Light Table connect bar. Now you listen for events on your tcp client and provides appropriate responses back to Light Table accordingly. (Handling this is the subject of a future blog post)

Behaviors for connecting (from groovy.cljs): 


(defn run-groovy[{:keys [path name client] :as info}]
  (let [obj (object/create ::connecting-notifier info)
        client-id (clients/->id client)
        project-dir (files/parent path)]
    (object/merge! client {:port tcp/port
                           :proc obj})
    (notifos/working "Connecting..")
    (proc/exec {:command binary-path
                :args [tcp/port client-id project-dir]
                :cwd plugin-dir
                :env {"GROOVY_PATH" (files/join (files/parent path))}
                :obj obj})))

(defn check-groovy[obj]
  (assoc obj :groovy (or (::groovy-exe @groovy)
                         (.which shell "groovy"))))

(defn check-server[obj]
  (assoc obj :groovy-server (files/exists? server-path)))

(defn handle-no-groovy [client]
  (clients/rem! client)
  (notifos/done-working)
  (popup/popup! {:header "We couldn't find Groovy."
                 :body "In order to evaluate in Groovy files, Groovy must be installed and on your system PATH."
                 :buttons [{:label "Download Groovy"
                            :action (fn []
                                      (platform/open "http://gvmtool.net/"))}
                           {:label "ok"}]}))

(defn notify [obj]
  (let [{:keys [groovy path groovy-server client]} obj]
    (cond
     (or (not groovy) (empty? groovy)) (do (handle-no-groovy client))
     :else (run-groovy obj))
    obj))

(defn check-all [obj]
  (-> obj
      (check-groovy)
      (check-server)
      (notify)))

(defn try-connect [{:keys [info]}]
  (.log js/console (str "try connect" info))
  (let [path (:path info)
        client (clients/client! :groovy.client)]
    (check-all {:path path
                :client client})
    client))


(object/object* ::groovy-lang
                :tags #{:groovy.lang})


(def groovy (object/create ::groovy-lang))

(scl/add-connector {:name "Groovy"
                    :desc "Select a directory to serve as the root of your groovy project... then again it might not be relevant..."
                    :connect (fn []
                               (dialogs/dir groovy :connect))})
(behavior ::connect
                  :triggers #{:connect}
                  :reaction (fn [this path]
                              (try-connect {:info {:path path}})))



  • scl/add-connector: This statement adds a connect dialog to our groovy plugin. You select a root directory and upon selection the ::connect behavior is triggered
  • ::connect basically responds with invoking a method for connecting. This does some sanity checks and if all goes well ends up invoking  run-groovy.
  • run-groovy : Fires up our groovy (server) process
  • def groovy   is basically the "mother" object of our plugin. It helps us scope behaviors and commands

The server part (LTServer.groovy)

import groovy.json.*

params = [
  ltPort:   args[0].toInteger(),
  clientId: args[1].toInteger() // light table generated id for the client (connection)
]

logFile = new File("server.log")

def log(msg) {
  logFile << "${new Date().format('dd.MM.yyyy mm:hh:sss')} - $msg\n"
}

client = null
try {
  client = new Socket("127.0.0.1", params.ltPort)
} catch (Exception e) {
  log "Could not connect to port: ${params.ltPort}"
  throw e
}

def sendData(data) {
  client << new JsonBuilder(data).toString() + "\n"
}
// ack to Light Table
sendData (
  [
    name: "Groovy",
    "client-id": params.clientId,
    dir: new File("").absolutePath,
    commands: ["editor.eval.groovy"],
    type: "groovy"
  ]
)
println "Connected" // tells lighttable we're good

client.withStreams {input, output ->
  while(true) {
  // insert code to listen for events from light table and respond to those (eval code etc)
  }
}


Notification of successful conncetion


(behavior ::on-out
          :triggers #{:proc.out}
          :reaction (fn [this data]
                      (let [out (.toString data)]
                        (object/update! this [:buffer] str out)
                        (if (> (.indexOf out "Connected") -1)
                          (do
                            (notifos/done-working)
                            (object/merge! this {:connected true}))
                          (object/update! this [:buffer] str data)))))

(behavior ::on-error
          :triggers #{:proc.error}
          :reaction (fn [this data]
                      (let [out (.toString data)]
                        (when-not (> (.indexOf (:buffer @this) "Connected") -1)
                          (object/update! this [:buffer] str data)
                          ))
                      ))

(behavior ::on-exit
          :triggers #{:proc.exit}
          :reaction (fn [this data]
                      ;(object/update! this [:buffer] str data)
                      (when-not (:connected @this)
                        (notifos/done-working)
                        (popup/popup! {:header "We couldn't connect."
                                       :body [:span "Looks like there was an issue trying to connect
                                              to the project. Here's what we got:" [:pre (:buffer @this)]]
                                       :buttons [{:label "close"}]})
                        (clients/rem! (:client @this)))
                      (proc/kill-all (:procs @this))
                      (object/destroy! this)
                      ))

(object/object* ::connecting-notifier
                :triggers []
                :behaviors [::on-exit ::on-error ::on-out]
                :init (fn [this client]
                        (object/merge! this {:client client :buffer ""})
                        nil))



The above behaviors basically handles signaling success, error or connection exits for our groovy client. As you can see in ::on-out this is where we check standard out from the process for the string "Connected", to signal success.


Wiring up behaviors (behaviors.groovy)


{:+ {:app [(:lt.objs.plugins/load-js ["codemirror/groovy.js", "groovy_compiled.js"])]
     :clients []
     :editor.groovy []
     :files [(:lt.objs.files/file-types
              [{:name "Groovy" :exts [:groovy] :mime "text/x-groovy" :tags [:editor.groovy]}])]
     :groovy.lang [:lt.plugins.groovy/connect]}}

The important part in terms on the connection is the wiring of the connect behavior to ":groovy.lang". This is needed for groovy to appear as a connection item in the light table connect bar.

"codemirror/groovy.js" deserves a special mention. This is what provides syntax highlighting for our groovy files (defined in the :files vector). The syntax highlighting is provided by the groovy mode module from CodeMirror. 

Wrapping up

So what have we achieved. Well we now have a connection to Light Table from an external process that can listen and respond to events from Light Table. For the purposes of this blog post series, its a Groovy client that hopefully pretty soon will be able to evaluate groovy scripts and respond with evaluation results. We didn't pay much attention to it, but we also got syntax highlighting of our Groovy files complements of CodeMirror. 

It took a while to grok how the connection part worked. Once I did understand roughly what was needed I was a bit annoyed with myself for messing about so much. I'm hoping this post might help others to avoid some of the mistakes I stumbled into.

søndag 9. februar 2014

Getting my feet wet with Clojure using Light Table

Background

I've been meaning to get into Clojure for quite some time now. I have been reading books, played with 4clojure and even went to a Clojure workshop with Stuart Sierra. But I never really found time and inspiration to percolate a hobby project to try it out in anger… Until my company (Kodemaker) decided to start a project to rewrite our website in RYO style using Clojure. I asked if I could have a go at one of the features (a really tiny one).

The last time I decided to properly learn a language I tried to learn Emacs at the same time. That didn't end all that well, or rather somewhere along the road I lost sight of Emacs. I'm a IntelliJ user in my day job so I've tried both LaClojure and Cursive a little bit. A couple of my colleagues have mentioned Light Table in the past and after watching some presentations and tutorials I was intrigued. When Light Table went open source I was determined to give it a good go.


The first steps

I already had Leiningen installed (and its just a "brew install leiningen" away on my mac anyway). So installing Light Table was a breeze and when I started it and I tried a few commands, it quickly became apparent that I was quite a few keyboard shortcuts short. There are plugins for Emacs and Vim shortcuts, but I figured I'd assign my own. That freedom proved daunting as well, and I'm pretty sure my setup will change a lot before it stabilizes.

ctrl + space and type "user key" and select User keymap

{:+ {:app {
           "ctrl-shift-t" [:tabset.new]
           "ctrl-shift-left" [:tabs.prev]
           ;; etc
           }
     :editor {"alt-w" [:editor.watch.watch-selection]
              "alt-shift-w" [:editor.watch.unwatch]
              "ctrl-k" [:editor.kill-line]
              ;; etc
             }}}



The first map :app defines shortcuts that available across editors. Ie if you have focus in an inline browser window, these shortcuts will still work. The :editor map are shortcuts that requires an editor to have focus. It's really nice that there is code completion (and instant docs) for all available actions and saved changes are immediately applied. And yes you could do fancy stuff by doing multiple actions for one shortcut, its a clojure vector !
I have created a github project for my current settings to keep things in synch across machines.

The paredit shortcuts are worth a special mention. You'll quickly discover that keeping those pesky parenthesizes in order can prove to be a challenge. Light Table comes bundled with a plugin that provides some support to make your life easier. You might need to update the plugin through the plugin manager (ctrl + space in case you were wondering how to find it).

I assume that from now on that either you have a shortcut or use ctrl+space to find the appropriate actions…


Get my project up and running

Summarized it goes like this:
  1. Open folder and select project folder for your clojure project
  2. "Connect: Add connection"
  3. Select clojure and then your leiningen project.clj file
  4. Open a clj file (mac-hint: cmd+o). And evaluate it (mac-hint: cmd+shift+enter). Behold the inline results !
  5. Assuming you have a ring app, you might want to start your web server and be able to change things on the fly:
    1. Create a repl file (see sample below)
    2. Open an clojure instarepl 
    3. enter: (use '<the_name_space:for_the_repl_file>) 
    4. enter: (start-server)
    5. voila, you can now kill/clear the instarepl if you like
  6. Add a browser tab (if you have the space why not assign it to a separate tabset so you can have code and browser side by side !) 
  7. Start hacking your clojure and evaluate statement (mac-hint: cmd+enter) or evaluate the whole clojure file. Refresh your browser to see the changes (mac-hint: cmd+r) 
It is really neat once you get into it. Not quite like my old WebSphere days. If you aren't sure what a function actually returns ? Just fire up an instarepl and try it out ! Can't remember exactly how that clojure function works… instarepl. Curious about the documentation for a clojure function try out : "Docs: Toggle documentation at cursor". 


Don't have a (web) project ? Try opening a terminal and type "lein new compojure-app sample".


Sample repl file

(ns repl
  (:require [mycompany-com.web :refer [app]]
            [ring.adapter.jetty]))

(defn start-server []
  (defonce server (ring.adapter.jetty/run-jetty #'app {:port 3000 :join? false}))
  (.start server))

(defn stop-server []
  (.stop server))


Plugins

Light Table comes bundled with a few plugins, but there are already quite a few others out there that are definitely worth a look. I've already installed Claire which is a emacs inspired file browser/finder. There are ruby, python and haskell plugins out there and probably many more coming.

Wrap-up

It really didn't take that long to get up and running with Light Table. Fumbled around a bit before I grasped how to get live code reloading in my running web app from the IDE. The instarepl is really nice for a Clojure noob, and the inline watches (results) are neat as well. Learning Clojure will obviously depend on much more than the editor, but cool tools that help you along the way can't be wrong.

Light Table is supposed to be super extensible, so I'm planning to delve into that. I've already started playing around with a Groovy plugin for Light Table and it's great fun. But anyways that belongs to another blog post.



mandag 19. august 2013

Javascript testing in your JVM projects using Gradle and BusterJS

Introduction

When I first started looking at testing in javascript land a while back I quickly felt lost in space. Filled with questions like;
  • which framework(s) to choose ?
  • how do I get framework x to work from my IDE ?
  • more importantly how to I manage to include the javascript tests in my CI builds ?
  • how can I avoid repetitive setup pain across projects ?
  • why is it such a hassle getting started ?
I can't say I have answered any of the questions above fully, but I have taken some strides in the right direction.

Buster.JS

Buster is a flexible and modularized framework for writing and running your JavaScript tests.
There are others out there, but from what I could gather and based on advice from my frontend wizard colleagues I decided to give it a good go. It's still in beta, but from my experiences so far its more than mature enough for proper use in projects.

A few important aspects about Buster.JS:
  • Tests are run in real browsers (phantomjs for headless). No emulation bull
  • You can run tests in multiple browsers in parallell
  • Its really really fast
  • Write tests in the fashion that suits you (xUnit or spec)
  • Nice assertion library and integrated with Sinon.JS (powerful stubbing and spying)
  • ... and lots more

Gradle buster plugin

For my jvm project builds I use Gradle. Maven and Ant projects that spend time with me a few weeks tend to find themselves converted. So I set out to create a buster plugin for gradle, aptly named gradle-buster-plugin. Still early days, but already it has started to prove quite valuable.
The plugin has two high-level goals;
  • Allow you to easily run javascripts as part of your CI builds
  • Provide you with a smooth development experience by adding value on top of whats already present in Buster.JS.

What do I have to do ? (aka getting started)

Installing preconditions

  1. Install node.js/npm - Mac: $ brew install node
  2. Install Buster.JS  - $ npm install buster -g
  3. Install Phantom.JS  - Mac: $ brew install phantomjs

Set up the buster plugin in your gradle config

buildscript {
    repositories { jcenter() }
    dependencies {
        classpath  'org.gradle.buster:gradle-buster-plugin:0.2.0'
    }
}

apply plugin: 'war' // just assuming you have a war project
apply plugin: 'buster'

build.dependsOn busterTest // hook up javascript task in the build

Set up a buster.js configuration file

var config = module.exports;

config["Sample JSTests"] = {
    environment: "browser",
    
    libs: ["src/main/webaapp/js/libs/jquery-1.10.2.js"],
    sources: ["src/main/web-app/js/app/**/*.js"],
    tests: ["src/test/js/**/*-test.js"]
};

Sample unit

So you could create a file like src/main/webapp/js/app/dummy-service.js
var myapp = this.myapp || {};
myapp.services = app.services || {};
(function () {
    myapp.services.DummyService = function (my) {
        my.listTodos = function(success, error) {
            $.get('/todos/list')
               .done(function(data) {
                  success(data);
               })
               .fail(function(jqXHR, textStatus, errorThrown) {
                  error("Error getting todos")
               });
        };
        return my;
    }(myapp.services.DummyService || {});
}());

 

Sample unit test

Create a corresponding unit test in src/test/js/app/dummy-service-test.js
(function () {
    buster.testCase("DummyService", {
        setUp: function() {
            this.service = myapp.services.DummyService;
            this.server = sinon.fakeServer.create();
            this.success = this.spy();
            this.error = this.spy();
        },
        tearDown: function () {
            this.server.restore();
        },
        "should successfully list todos": function () {
            this.service.listTodos(this.success, this.error);
            this.server.requests[0].respond(
                200,
                { "Content-Type": "application/json" },
                JSON.stringify([{ id: 1, text: "Provide examples", done: true }])
            );

            assert.calledOnce(this.success);
        },
        "should invoke error callback on errors": function () {
            this.service.listTodos(this.success, this.error);
            this.server.requests[0].respond(
                500,
                { "Content-Type": "application/json" },
                JSON.stringify([{ id: 1, text: "dummy", done: true }])
            );

            assert.calledOnce(this.error);
        }
    });
}());


 

Running the tests locally

$ gradle busterTest

Test results are found in : build/busterTest-results/bustertests.xml


Autotesting

When doing your tdd cycles its quite useful to use the autotest feature (kinda like infinitest).
$ gradle busterAutoTest

Will leave the server running and listen for file changes in the patterns specified by the buster.js file above. So if I change the test or unit above a test run will automatically be fired off and results reported to the console. Its pretty fast so you should be able to keep a good flow going !
Just do Ctrl + C to kill the autotesting.

Multiple browsers

Its quite easy to set up just see the readme for the plugin 


CI Server

Obviously you will need to set up the preconditions. If you're server isn't headless you have the option of testing with a few proper browsers(firefox and chrome on linux, safari if your server is mac... which I doubt).


Conclusion

Its certainly not perfect, but with the above you have a pretty good start. Once you get over the hurdle of setting up the preconditions it really is quite pleasant to work with. You should be amazed by the performance of the tests runs if you are from a jvm background.
What about IDE integration ? With the autotest feature I can't say I have missed it much. I have my IDE and a visible console available and get instant feedback on saves in my IDE.

Smooth !

lørdag 8. september 2012

java.jar to .Net.dll with Gradle and IKVM

If you ever (for whatever reason) find your self in need of creating .Net DLLs from java jar files. Not to despair. IKVM might just be the tool you are looking for. Its pretty neat stuff and I was amazed how much that actually worked. Debugging into my javacode from Visual Studio .Net was rather impressive I have to admit.

 Now what if you need to integrate the generation of DLLs as part of your Gradle multi project ?  A little while back I was on a project that had this particular need so I thought I'd share some harvested knowledge.

I ended up solving this in a gradle script, but it would probably benefit from being packaged as a plugin. Anyways here goes:

I added the following to a ikvm.gradle

ext.executeIkvm = {ikvmDll, args ->
  def ikvmExec = new File(System.getenv()['IKVM_HOME'] , 'bin/ikvmc.exe')
  assert ikvmExec.exists(), "You must install Ikvm and set IKVM_HOME env variable"

  def commandLineArgs = [ikvmExec] + args
  println commandLineArgs
  exec {
    commandLine = commandLineArgs
  }
}

ext.addIkvmTask = {ikvmProject->
  if(ikvmProject.getTasksByName("ikvm", false)) return
  
  ikvmProject.task("ikvm", dependsOn: ikvmProject.jar) {
  description = "Generates Ikvm dll for given project"
  ext.ikvmOutDir = file("${ikvmProject.buildDir}/ikvm")
  ext.ikvmDll = new File(ikvmOutDir, "${ikvmProject.name}.dll")
  ext.referencedDlls = [] as Set

  inputs.files ikvmProject.jar.archivePath
  outputs.files ikvmOutDir

  doFirst {
    if (!ikvmOutDir.exists()) ikvmOutDir.mkdir()
  }

  doLast {
    def commandLineArgs = [
 "-out:$ikvmDll", "-version:$version", 
 ikvmProject.jar.archivePath] + referencedDlls.collect{"-reference:$it"}
      executeIkvm(ikvmDll, commandLineArgs)
    }
  }
  ikvmProject.build.dependsOn ikvmProject.ikvm
}

ext.configureIkvmProject = {ikvmProject ->
  addIkvmTask(ikvmProject)
    
  def runtimeDeps = ikvmProject.configurations.runtime.allDependencies
  def referencedSubDlls = runtimeDeps.collect {dependency ->
    if (dependency instanceof ProjectDependency) {
      def ikvmSubProject = project(":${dependency.name}")
      addIkvmTask(ikvmSubProject)
      ikvmProject.ikvm.dependsOn ikvmSubProject.ikvm
      return [ikvmSubProject.ikvm.ikvmDll] + configureIkvmProject(ikvmSubProject)
    } else {
      throw new RuntimeException("Sorry not supporting third party deeps")
    }
  }.flatten()
    
  ikvmProject.ikvm.referencedDlls += referencedSubDlls
}
(actually I added some more stuff to deal with the outputstream from exec, but it just muddles the implementation example above)


In my root build.gradle I added the following:

subprojects{
  //...
  apply from: "$rootDir/ikvm.gradle"
  afterEvaluate { project ->
    configureIkvmProject project
  }
  //...
}

Now you basically have the ability to generate a 1-1 mapping between your jar projects and .Net dlls. As far as I know there is no such thing as transitive dependencies in .Net, so we opted to add any transitives into the linking metainfo for the dlls.

Not shown, but we also added the ability to

  • generate dll's for transitive 3.rd party jar files 
  • the ability to generate .net debug info (pdb files)
  • checking in generated dlls to VCS to trigger .Net build on TeamCity
  • convenience tasks for copying generated artifacts to lib folder in .Net project(s)

onsdag 23. november 2011

Show gradle dependencies as graphwiz png

A few weeks ago I needed to show my team an overview of all the dependencies between our sub projects. I found a solution where I generated a graphwiz dot file. The caveat here was that I had to install graphwiz and run another command to generate a png.

Today I was reading through "Making Java Groovy", MEAP authored by Ken Kousen. I saw an example using the googles charting api. A quick check revealed they had experimental support for creating a png from a dot graph !

So my gradle task ended up looking as follows:

reportsDir = new File("build/reports")
compileDepsPng = file("$reportsDir/compileDeps.png")

task dependenciesPng() {
  inputs.files subprojects.configurations.compile
  outputs.files compileDepsPng
  doFirst {
    if(compileDepsPng.exists()) compileDepsPng.delete()
    if(!reportsDir.exists()) reportsDir.mkdirs()
  
  }
  doLast {
    dotGraph = "digraph Compile{"
    subprojects.each {subproject ->
      subproject.configurations.compile.dependencies.each {dependency ->
      if(dependency instanceof ProjectDependency) {
 dotGraph += "\"$subproject.name\" -> \"$dependency.name\"" 
      }   }
    }
    dotGraph += "}"
  
    def chartParams = [cht: 'gv', chof: 'png', chl: dotGraph]
    def url = "http://chart.googleapis.com/chart?" 
    url += chartParams.collect {k,v -> "$k=${URLEncoder.encode(v)}"}.join('&')
  
    compileDepsPng.withOutputStream{out ->
      out << new URL(url).openStream()
    }   
  }
}





fredag 7. oktober 2011

Textmate made friendly for running Groovy snippets

I seem to remember Scott Davis doing a groovy presentation at JavaZone in 2008 or was it 2009, using Textmate. Didn't think much of it at the time. I had enough editor confusion going on,  switching from eclipse to idea.

Earlier this week a colleague and I was working on a Groovy introduction presentation and we had decided on using textmate. So we downloaded the capable Groovy textmate bundle from Github. I had been using the Groovy console and found the performance for running small groovy snippets to be rather unbearable with the textmate plugin though. You got the startup cost of firing up the jdk+groovy and it opened a new window. This was not what I remembered, and it certainly wouldn't work for a code driven presentation. A quick google found a youtube video with Dierk König. Aha of course Groovyserv to the rescue.


So the short version:
  1. Got Homebrew ? Well then just  brew install groovyserv
    1. No ? Install it (if you don´t have xcode either... I suggest you download groovyserv manually unless you have the time to spare. People complain about maven downloading the internet, xcode feels pretty close)
  2. In textmate select bundles->bundle editor->edit commands
  3. Add a command for running the current file. The following settings might work for you:
    1. Save current file (usually what I want)
    2. Commands : /usr/local/Cellar/groovyserv/0.9/libexec/bin/groovyclient -encoding "UTF-8" "$TM_FILEPATH"
    3. Input : Entire document
    4. Output: Show as tooltip (worked out real nice in the presentation)
    5. Activation : cmd+h (or something that suits you... that particular combination has a somewhat different behaviour in the GroovyConsole btw)
  4. Similarily if you just want to run a selection just change command to something like:
    1. /usr/local/Cellar/groovyserv/0.9/libexec/bin/groovyclient -c "UTF-8" -e  "$TM_SELECTED_TEXT"
  5. Unlike the console it doesn't output the last executed statement, so if you are doing oneliners you better remember println ! (If anyone has any tips for that one in Textmate, feel free to comment on the post)

You are all set to run nice little groovy snippets with near instant responses (well the first time you try it, groovyserv will incur a heavy startup cost. But after that you are good to go in kickass speed).

tirsdag 13. september 2011

Tapestry5 and GORM

So I've had some fun lately trying to get Tapestry and Gorm to play nicely together. To make the learning experience a bit more realistic I started doing a small sample app. Its loosely inspired by a domain I'm scratching the surface of in my current consulting gig. I've had a ball learning more about groovy and Gorm, and it has been a nice refresher on my already fading Tapestry skills.

Domain modeling with Gorm has been an absolute pleasure (especially from someone coming from hibernate/jpa). It's just so neat and concise... and there is also all these nice little freebies you keep discovering.  Working with Tapestry (and the cool jquery flavored add-on tapestry5-jquery) was about as productive as I remembered. With the ability to write my pages/components in Groovy, the experience was even better. When the limitations of the java api became a burden, I always had the option of putting a thin layer of groovy in front to DSL'ify it to meet my expectations better. I suspect I will keep playing with this app to see where it leads. I'm also tempted to do a cousin implementation using grails sometime soon as well.

Did I have any problems along the way ? Sure did, but mostly in terms of things like:

  • Unifying logging from all those external dependencies (yeah its a lot I'm afraid, and Gorm is the main culprit!). To make life hard I figured I wanted to use logback. Once I finally got my dependencies right, with bridges and all, it now works fine
  • Setting up Spock tests with transactional support (proved to be a lot simpler than I initially thought) 
  • Intellij compilation error (which isn't really and error, but disrupts the flow). Keep getting a system.err when compiling groovy code. Unfortunately intellij insists its an error even though the compile actually succeeds. Something todo with groovy stubs and/or ast transformations I think. 

If time permits I'm planning to do a few future posts that dig into some details from the sample app. 


If you are interested in the sample app, feel free to pull it from github at https://github.com/rundis/TapestryGorm