Showing posts with label clojure. Show all posts
Showing posts with label clojure. Show all posts

Saturday, February 27, 2010

Leiningen and VimClojure

Leiningen seems cool. It will take care of installing any jars you need for your clojure application, and setting up the classpath, so you don't have to worry about all the Java stuff and can get down to clojure hacking.

I spent some time yesterday getting Leiningen and VimClojure to work together. Here are the notes in case someone else has the same problem:

> mkdir code/clojure
> cd code/clojure

LEININGEN

I downloaded the install script from http://github.com/technomancy/leiningen and put it
in ~/code/clojure/lein.

> chmod a+x lein
> ./lein self-install
> ./lein new helloworld
> cd helloworld

NAILGUN server

Next step was to add the nailgun server needed by vimclojure. To do this I added these lines
to project.clj (which was generated by "lein new helloworld" before)
[org.clojars.ato/nailgun "0.7.1"]
[org.clojars.gilbertl/vimclojure "2.1.2"]

Now update the dependencies to generate a lib directory with all jars we need:

> ../lein deps

VIMCLOJURE

I already had the vimclojure vim plugin installed, but needed to add the nailgun client for VimClojure. For this I downloaded VimClojure (http://www.vim.org/scripts/script.php?script_id=2501), unpacked it somewhere and ran "make". This generated a file called "ng" which I copied to ~/code/clojure. I then added this line to .vimrc:
let vimclojure#NailgunClient = "/home/johan/code/clojure/ng"

I then put these alias definitions in .bashrc:
alias lein='/home/johan/code/clojure/lein'
alias ng='java -server -cp src:classes:lib/* com.martiansoftware.nailgun.NGServer 127.0.0.1'

TESTING AND RUNNING

> cd ~/code/clojure
> ng &
> vim src/helloworld.core.clj
You should now be able to type sr to open a REPL buffer (\sr if using the default settings)

Saturday, January 17, 2009

XmlRpc with Clojure

I know, I know... I really should update this blog more often. Brief recap: last year I've made a fairly big Common Lisp project (funmv), and played quite a bit with both Haskell and Clojure. Today I want to share some experiences using XmlRpc with Clojure.

Clojure has the advantage of running on JVM, which means that it can use Java libraries. The problem is that, being a Lisp with a functional flavour, it sometimes doesn't mix well with the object-oriented programming style mandatory in Java development. I needed to implement a Xml-Rpc server in clojure, but my first attempts with apache xmlrpc and others ended in failure since their addHandler methods required an object, and would match the XmlRpc message methods with the name of the member functions. It is possible to instantiate Java-objects with the proxy special form in Clojure, but this only allows you to implement or subclass already declared methods, and creating an object completely from scratch seemed too complicated.

Finally I found an XmlRpc library from redstone (download redstone-simple-xmlrpc-1.0.zip), which allows you to define your own dispatch routine. This allows me to inspect the method name and call normal Clojure functions, rather than relying on Java reflection magic. The server code is short and sweet:

(def server (new redstone.xmlrpc.simple.Server 8080))
(def h (proxy [redstone.xmlrpc.XmlRpcInvocationHandler] []
(invoke [method-name arguments]
(cond
(= method-name "add") (+ (nth arguments 0) (nth arguments 1))
true (throw (new Exception "No such method"))))))
(doto (.getXmlRpcServer server) (.addInvocationHandler "test" h))
(.start server)


Here is a Java test client

import redstone.xmlrpc.XmlRpcClient;
public class SampleClient
{
public static void main( String[] args ) throws Exception
{
XmlRpcClient client = new XmlRpcClient( "http://localhost:8080", false );
Object reply = client.invoke( "test.add", new Object[] {1, 2} );
System.out.println (reply); // should be 3
}
}


You will need to add the jar files to the classpath:

javac -cp xmlrpc-1.1.1.jar SampleClient.java
jar cf SampleClient.jar *class
java -cp SampleClient.jar:xmlrpc-1.1.1.jar SampleClient