Hi,

I really like cli4j and have a nice pattern I follow in creating CLI 
entry points for my project. I find it has a lot of advantages, 
including a declarative means of defining your CLI syntax using 
annotations.

So I thought it might be nice not to have to write all new interface 
wrappers to gain access to these command-oriented interfaces from a 
REPL context. It turned out to be remarkably easy to do this, and I 
thought I'd pass on my experience. It should be entirely applicable 
even for those not using cli4j.


Here's what I did:

1) Wrote a few helper functions to allow keywords such as :o or :option 
to stand in for "-o" or "--option" arguments. There are three variants 
(at least conceptually), to produce A) a list; B) a vector and C) a 
String[] holding the converted arguments.

To wit:

(defn make-cli-arglist
 "Create a list of strings encoding a CLI invocation from
  a sequence of keywords and other (atomic) values"
 [args]
 (map
  #(if (keyword? %)
       (let [opt-name (name %)]
        (if (> (.length opt-name) 1)
            (str "--" opt-name)
            (str \- opt-name)))
       (str %))
  args))

(defn make-cli-argvec
 "Create a vector of strings encoding a CLI invocation from
  a sequence of keywords and other (atomic) values"
 [args]
 (apply vector (make-cli-arglist args)))

(defn make-cli-argarray
 "Create a vector of strings encoding a CLI invocation from
  a sequence of keywords and other (atomic) values"
 [args]
 (into-array String (make-cli-arglist args)))


2) Wrote a top-level launcher function that converts its arguments using 
(1C) and calls the embedding entry point (see (3)) of the Java 
command-line class.

3) Wrote an alternate entry point to the Java main(String[] args) that 
returns its termination status rather than calling System.exit(status). 
(Naturally, I was both delighted and surprised when my first successful 
attempt dumped me out of Clojure upon completing its invocation.)

4) The last refinement I added was a macro version of (2), which means 
that for arguments that don't contain any characters that are special 
in Clojure, enclosing those arguments in quote marks is unnecessary. 
This is, of course, directly analogous to a similar requirement in any 
Unix shell.

Note: This actually obviates the keyword conversion aspect of the 
argument list synthesizer in (1), though conversion to all String 
instances is still necessary, of course. The one possibly still-useful 
thing that code does is blur the distinction between single-character 
options (which use a single hyphen) and multi-character options (which 
use two hyphens) by automatically choosing the proper syntax for the 
converted option name.


So far, the only visible "seam" I've noticed is that when you use the 
keyword-as-option mode and there's an error, the old CLI code, not ever 
having seen a Lisp keyword (nor having any notion of such things) 
prints diagnostics using hyphens.


Between this approach and Steve G.'s new REPL, I feel I'm going to get 
an interactive environment for my full suite of tools that is 
independent of a Unix shell virtually for free. Other advantages of 
this include platform independence (I have potential users on Windows) 
and the elimination of the JVM start-up overhead for each individual 
invocation.

I know this isn't barely actually Clojure programming, just an exercise 
of Clojure's very slick Java integration, but I found it gratifying.


Randall Schulz

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to