https://github.com/friemen/parsargs.git
git clone 'https://github.com/friemen/parsargs.git'
(ql:quickload :friemen.parsargs)
Parse convenient to specify function arguments into Clojure data structures that are easy to process.
Include a dependency as show above to your project.clj
When creating an API there is always a tension between ease of its use and its implementation. Ease-of-use demands a flexible and concise notation for those who use the API, including specifying function arguments.
The API function implementation demands data structures that it can easily work with. Although the notation of Clojure data structures is indeed very light-weight there are times when you want to offer an even simpler way for specifying arguments.
As an example let's assume you're creating an API for mappings between Clojure data and UI components. Obviously you need to specify at least two things per mapping: the path within the data structure and the path of the visual components property. So you could start with a simple map:
(def m {:name ["Name" :text]
:street ["Street" :text]
:zipcode ["Zipcode" :text]
:city ["City" :text]})
No visual noise, great. But unfortunately that is not enough.
You'll need to also specify a parser and a formatter function to deal with
dates and numeric data.
Ideally the code that implements the mapping would work on something like this:
clojure
(def m [{:data-path :name
:signal-path ["Name" :text]
:formatter str
:parser identity},
; ...
; more mapping specifications
; ...
])
But this is a lot of boilerplate to read and write because
str
and identity
.:data-path
visually create more noise than signal.Now you're in a dilemma. Either the data structure representing the specification would become cumbersome, or the data structure the data mapper works on would make implementation more complicated and therefore harder to comprehend.
Here parsargs offers a way to specify how the concise notation is mapped to an easy-to-work-with data structure.
(require [parsargs.core :as p])
(def mapping-parser
(p/some
(p/sequence :data-path (p/alternative
(p/value vector?)
(p/value keyword?))
:signal-path (p/alternative
(p/value #(and (vector? %) (string? (last %))))
(p/value string?))
:formatter (p/optval fn? str)
:parser (p/optval fn? identity))))
(defn mapping [& args]
(p/parse mapping-parser args))
The mapping function is now your factory to create full blown data structures from a concise notation:
(def m (mapping :name ["Name" :text]
:street ["Street" :text]
:zipcode ["Zipcode" :text] :parser to-number
:city ["City" :text]))
The core namespace provides a set of parser generating functions
and the parse
function that applies a parser function to a
sequence.
The following parser factories are provided:
See also core.clj for more details.
Copyright 2013 F.Riemenschneider
Distributed under the Eclipse Public License, the same as Clojure.