diff --git a/README.md b/README.md index e4f12d7f..9cb1e0a3 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,7 @@ namespaces. If not all vars are available, they are enumerated explicitly. From Java the following is available: +- `Integer`: `Integer/parseInt` - `File`: `.canRead`, `.canWrite`, `.delete`, `.deleteOnExit`, `.exists`, `.getAbsoluteFile`, `.getCanonicalFile`, `.getCanonicalPath`, `.getName`, `.getParent`, `.getParentFile`, `.getPath`, `.isAbsolute`, `.isDirectory`, @@ -259,6 +260,32 @@ $ cat script.clj ("hello" "1" "2" "3") ``` +## Parsing command line arguments + +Babashka ships with `clojure.tools.cli`: + +``` clojure +(require '[clojure.tools.cli :refer [parse-opts]]) + +(def cli-options + ;; An option with a required argument + [["-p" "--port PORT" "Port number" + :default 80 + :parse-fn #(Integer/parseInt %) + :validate [#(< 0 % 0x10000) "Must be a number between 0 and 65536"]] + ;; A non-idempotent option (:default is applied first) + ["-h" "--help"]]) + +(:options (parse-opts *command-line-args* cli-options)) +``` + +``` shellsession +$ bb script.clj +{:port 80} +$ bb script.clj -h +{:port 80, :help true} +``` + ## Preloads The environment variable `BABASHKA_PRELOADS` allows to define code that will be diff --git a/src/babashka/impl/Integer.clj b/src/babashka/impl/Integer.clj new file mode 100644 index 00000000..75002bf8 --- /dev/null +++ b/src/babashka/impl/Integer.clj @@ -0,0 +1,17 @@ +(ns babashka.impl.Integer + {:no-doc true} + (:refer-clojure :exclude [list])) + +(set! *warn-on-reflection* true) + +(defn parseInt + ([^String x] (Integer/parseInt x)) + ([^String x ^long radix] + (Integer/parseInt x radix))) + +(def integer-bindings + {'Integer/parseInt parseInt}) + +(comment + + ) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 00f134dc..8b664696 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -2,6 +2,7 @@ {:no-doc true} (:require [babashka.impl.File :refer [file-bindings]] + [babashka.impl.Integer :refer [integer-bindings]] [babashka.impl.System :refer [system-bindings]] [babashka.impl.Thread :refer [thread-bindings]] [babashka.impl.async :refer [async-namespace]] @@ -144,7 +145,8 @@ Everything after that is bound to *command-line-args*.")) (merge core-bindings system-bindings file-bindings - thread-bindings)) + thread-bindings + integer-bindings)) (defn read-edn [] (edn/read {;;:readers *data-readers* diff --git a/test/babashka/main_test.clj b/test/babashka/main_test.clj index a6e230a0..546d5872 100644 --- a/test/babashka/main_test.clj +++ b/test/babashka/main_test.clj @@ -187,4 +187,4 @@ first :out str/trim println)")))) (deftest tools-cli-test - (is (= {:file "README.md"} (bb nil "test/babashka/scripts/tools.cli.bb")))) + (is (= {:result 8080} (bb nil "test/babashka/scripts/tools.cli.bb")))) diff --git a/test/babashka/scripts/tools.cli.bb b/test/babashka/scripts/tools.cli.bb index 733d67f5..011b1158 100644 --- a/test/babashka/scripts/tools.cli.bb +++ b/test/babashka/scripts/tools.cli.bb @@ -1,2 +1,16 @@ (require '[clojure.tools.cli :refer [parse-opts]]) -(:options (parse-opts ["-f" "README.md"] [["-f" "--file FILE" "file"]])) + +(def cli-options + [["-p" "--port PORT" "Port number" + :default 80 + :parse-fn #(Integer/parseInt %) + :validate [#(< 0 % 0x10000) "Must be a number between 0 and 65536"]]]) + +(defn -main [& args] + (let [{:keys [:options :summary]} (parse-opts args cli-options) + port (:port options)] + (case port + 8080 {:result 8080} + summary))) + +(-main "-p" "8080")