Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Parsing concise argument sequences to nice Clojure data structures.
Clojure
branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
src/parsargs
test/parsargs
.gitignore
.travis.yml
README.md
project.clj

README.md

parsargs

Parse convenient to specify function arguments into Clojure data structures that are easy to process.

Build Status

Clojars Project

Include a dependency as show above to your project.clj

API docs

Motivation

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:

(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

  • in most cases formatter and parser would take default values str and identity.
  • the keywords like :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])) 

API overview

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:

  • value -- Return element if predicate holds, otherwise fail.
  • optval -- Return element if predicate holds, otherwise default value.
  • omit -- Skip element if predicate holds.
  • some -- Apply parser-fn subsequently and create vector of parsed values.
  • sequence -- Apply parser-fns subsequently and create map of parsed values.
  • alternative -- Apply first matching parser-fn or fail.
  • descent-with -- Apply parser-fn to nested data structure.
  • map -- Apply parser-fn and apply transformation to the parsed value.
  • optional -- Apply parser-fn, continue if it fails.

See also core.clj for more details.

License

Copyright 2013 F.Riemenschneider

Distributed under the Eclipse Public License, the same as Clojure.

Something went wrong with that request. Please try again.