Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
tatsuhiro-t committed Dec 13, 2011
0 parents commit d0cff1e
Show file tree
Hide file tree
Showing 6 changed files with 487 additions and 0 deletions.
23 changes: 23 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2011 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
39 changes: 39 additions & 0 deletions README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Argparse4clj - The command line argument parser library for Clojure

The argparse4clj is a command line argument parser library for
Clojure. Argparse4clj is actually a wrapper library for argparse4j.

Project has just started and no documentation at the moment.

Here is summary of features:

* Supported positional arguments and optional arguments.

* Variable number of arguments.

* Generates well formatted line-wrapped help message.

* Suggests optional arguments/sub-command if unrecognized
arguments/sub-command were given, e.g. "unrecognized argument
'--tpye'. Did you mean: --type".

* Takes into account East Asian Width ambiguous characters when
line-wrap.

* Sub-commands like, git add.

* Customizable option prefix characters, e.g. '+f' and '/h'.

* Print default values in help message.

* Choice from given collection of values.

* Type conversion from option strings.

* Can directly assign values into user defined classes using
annotation.

* Group arguments so that it will be printed in help message in more
readable way.

* Read additional arguments from file.
16 changes: 16 additions & 0 deletions demo.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(ns demo (:use [net.sourceforge.argparse4clj]))

(def args
(parse-args
*command-line-args*
{:prog "prog", :description "Process some integers."}
(add-argument "integers" {:metavar "N"
:type Long
:nargs "+"
:help "an integer for the accumulator"})
(add-argument "--sum" {:dest "accumulate"
:action :store-const
:const +
:default max
:help "sum the integers (default: find the max)"})))
(println (reduce (args :accumulate) (args :integers)))
129 changes: 129 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>net.sourceforge.argparse4clj</groupId>
<artifactId>argparse4clj</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>clojure</packaging>

<name>argparse4clj</name>
<url>http://argparse4j.sourceforge.net</url>
<description>The command line argument parser Argparse4j wrapper for Clojure</description>
<inceptionYear>2011</inceptionYear>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>7</version>
</parent>

<licenses>
<license>
<name>MIT</name>
<url>https://raw.github.com/tatsuhiro-t/argparse4clj/master/LICENSE.txt</url>
</license>
</licenses>

<developers>
<developer>
<id>tatsuhiro_t</id>
<name>Tatsuhiro Tsujikawa</name>
<timezone>+9</timezone>
</developer>
</developers>

<issueManagement>
<system>sourceforge.net</system>
<url>http://sourceforge.net/p/argparse4j/tickets/</url>
</issueManagement>

<scm>
<connection>scm:git:git://github.com/tatsuhiro-t/argparse4clj.git</connection>
<developerConnection>scm:git:git@github.com:tatsuhiro-t/argparse4clj.git</developerConnection>
<url>https://github.com/tatsuhiro-t/argparse4clj</url>
</scm>

<dependencies>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>net.sourceforge.argparse4j</groupId>
<artifactId>argparse4j</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>

<build>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>com.theoryinpractise</groupId>
<artifactId>clojure-maven-plugin</artifactId>
<version>1.3.8</version>
<extensions>true</extensions>
<configuration>
<script>demo.clj</script>
<args>-h</args>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>bin</descriptorRef>
<descriptorRef>src</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.8</version>
<configuration>
<locale>en</locale>
<stylesheet>maven</stylesheet>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.2</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.2.1</version>
<configuration>
</configuration>
</plugin>
</plugins>
</build>

</project>
180 changes: 180 additions & 0 deletions src/main/clojure/net/sourceforge/argparse4clj.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
(ns net.sourceforge.argparse4clj
(:import (java.util HashMap)
(net.sourceforge.argparse4j ArgumentParsers)
(net.sourceforge.argparse4j.impl Arguments)
(net.sourceforge.argparse4j.inf ArgumentParserException)
(net.sourceforge.argparse4j.inf ArgumentType)
(net.sourceforge.argparse4j.inf FeatureControl))
(:require [clojure.walk])
(:gen-class))

(defn- va [val-or-vec]
(if (vector? val-or-vec) val-or-vec
[val-or-vec]))

(defn- nil-to [val default]
(if (nil? val) default val))

(defn- handle-type [type]
(cond
(instance? Class type) type
(map? type) (proxy [ArgumentType]
[]
(convert [parser arg value]
((type :convert) parser arg value)))
true type))

(def actions
{:store (. Arguments store)
:store-const (. Arguments storeConst)
:store-true (. Arguments storeTrue)
:store-false (. Arguments storeFalse)
:append (. Arguments append)
:append-const (. Arguments appendConst)
:version (. Arguments version)
:help (. Arguments help)})

(defn- handle-action [action]
(cond
(keyword? action) (actions action)
true action))

(defn- handle-defaults [defaults]
(let [res (new HashMap)]
(doseq [[dest value] defaults]
(. res put (name dest) value))
res))

(defn arg-range [min-value max-value]
(. Arguments range min-value max-value))

(declare setup-parser)

(defn- build-argument [parser arg-spec]
(let [name-or-flags (into-array String (first arg-spec))
params (fnext arg-spec)
arg (. parser addArgument name-or-flags)]
(doseq [[key value] params]
(condp = key
:action (. arg action (handle-action value))
:choices (. arg choices value)
:dest (. arg dest (name value))
:const (. arg setConst value)
:default (. arg setDefault
(if (= value :argparse-suppress)
(. FeatureControl SUPPRESS)
value))
:help (. arg help value)
:metavar (. arg metavar (into-array (va value)))
:nargs (. arg nargs value)
:required (. arg required value)
:type (. arg type (handle-type value))
nil
))))

(defn- build-group [parser group-spec]
(let [params (first group-spec)
arg-specs (fnext group-spec)
group (. parser addArgumentGroup (params :title))]
(doseq [[key value] params]
(condp = key
:description (. group description value)
nil))
(doseq [spec arg-specs]
(condp = (first spec)
:add-argument (build-argument group (next spec))))))

(defn- build-subparser [parser subparsers subparser-spec]
(let [command (first subparser-spec)
params (fnext subparser-spec)
parser-specs (fnext (next subparser-spec))
subparser (. subparsers addParser command
(nil-to (params :add-help) true)
(if (nil? (params :prefix-chars))
(. parser getPrefixChars) (params :prefix-chars)))]
(doseq [[key value] params]
(condp = key
:help (. subparser help value)
nil))
(setup-parser subparser params parser-specs)))

(defn- build-subparsers [parser subparsers-spec]
(let [subparsers (. parser addSubparsers)
params (first subparsers-spec)
subparser-specs (fnext subparsers-spec)]
(doseq [[key value] params]
(condp = key
:description (. subparsers description value)
:dest (. subparsers dest value)
:help (. subparsers help value)
:metavar (. subparsers metavar value)
:title (. subparsers title value)
nil))
(doseq [spec subparser-specs]
(condp = (first spec)
:add-parser
(build-subparser parser subparsers (next spec))))))

(defn- setup-parser [parser params parser-specs]
(doseq [[key value] params]
(condp = key
:default-help (. parser defaultHelp value)
:description (. parser description value)
:epilog (. parser epilog value)
:defaults (. parser setDefaults (handle-defaults value))
:version (. parser version value)
nil))
(doseq [spec parser-specs]
(let [method (first spec)]
(condp = method
:add-argument (build-argument parser (next spec))
:add-argument-group (build-group parser (next spec))
:add-subparsers (build-subparsers parser (next spec))
))))

(defn- build-parser [params specs]
(let [parser (. ArgumentParsers newArgumentParser
(params :prog)
(nil-to (params :add-help) true)
(nil-to (params :prefix-chars) "-"))]
(setup-parser parser params specs)
parser))

(defn new-argument-parser [params & specs]
(build-parser params specs))

(defn parse-args
([args params & specs] (parse-args args (build-parser params specs)))
([args parser]
(let [result (new HashMap)]
(try
(. parser parseArgs (into-array String args) result)
(clojure.walk/keywordize-keys (into {} result))
(catch ArgumentParserException e
(. parser handleError e)
(. System exit 1))
(catch RuntimeException e
;; If ArgumentParserException is thrown in delegated method,
;; it is wrapped with RuntimeException.
(let [cause (. e getCause)]
(if (instance? ArgumentParserException cause)
(do
(. parser handleError cause)
(. System exit 1))
(throw e))))))))

(defn add-argument
([name-or-flags & [params]]
[:add-argument (va name-or-flags) params]))

(defn add-argument-group
[params & arg-specs]
[:add-argument-group params arg-specs])

(defn add-parser
([command & [params & parser-specs]]
[:add-parser command params parser-specs]))

(defn add-subparsers
[params & subparser-specs]
[:add-subparsers params subparser-specs])
Loading

0 comments on commit d0cff1e

Please sign in to comment.