3

I have written some libraries in clojure that scrape some search results as a small side project. I want to use these libraries in a cli where there would be a few different scripts that could run, like:

  • collect, run scraping job,
  • browse, browse previously collected results,
  • search-config, add or remove search parameters.

I would like to implement the solution as a command line interface as follows:

cljscrape [general flags] subcommand [flags] [args]

I know you can use the packages stated in this post, but it seems to only parse flags. If anyone could recommend how to structure the project, or a package that will allow me to best imitate the template format that would be awesome!

P.S

I am quite new to clojure so I apologise if I say anything stupid. Thanks! :)

jgeedev
  • 31
  • 2

1 Answers1

4

An example using babashka CLI:

(def args ["--general-flag" "subcommand" "--flag" "arg"])

(require '[babashka.cli :as cli])

The var args contains some example arguments. Normally you would get these from *command-line-args* or the arguments passed to a -main function.

First parse the general options:

(def parsed (cli/parse-args args {:coerce {:general-flag :boolean}}))
;;=> {:opts {:general-flag true}, :args ["subcommand" "--flag" "arg"]}

Note that in :opts we now have the parsed general options and the rest of the arguments, still unparsed, are saved inside :args.

When we parse those :args in turn again with parse-args, we get the subcommands, options and arguments:

(cli/parse-args (:args parsed) {:coerce {:flag :boolean}})
;;=> {:cmds ["subcommand"], :opts {:flag true}, :args ["arg"]}

So you can use this two-step process to support general arguments. To dispatch on the subcommands, you can read the documentation here. You can see the dispatch function in action in the neil project. For this example, it would be something like:

(def dispatch-table
  [{:cmds ["subcommand"] :fn handle-subcommand}])

(cli/dispatch dispatch-table (:args parsed) {:coerce {:flag :boolean}})

and function handle-subcommand would then be called with the arguments {:opts {:flag true}, :args ["arg"]}.

Michiel Borkent
  • 34,228
  • 15
  • 86
  • 149