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 [email protected]
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
-~----------~----~----~----~------~----~------~--~---