Challenge: Implement CLI interface like that?
challenge.docopt.org
challenge.docopt.org
Given the elegance of that very solution I think this marketing stunt is entirely unneeded and actually harmful; it's confusing and you miss out on getting a descriptive headline such as "Generate OptParser from code comment!".
That said... Brilliant idea!
I'm definitely trying out docopt for my next project.
And I have a counter-challenge for you:
How about making docopt work with nested commands? I.e. multiple methods could have a docopt-style comment and they would smartly merge to enable usages such as "mygit remote show --help", where 'show' is a subcommand of 'remote', with its own set of parameters and a matching help-page.
If you can work that one out then docopt could become the defacto standard for generating even complex OptParsers.
Making possible several help-screens for different commands is on it's way. The only stopper—deciding on API: https://github.com/docopt/docopt/issues/17
But I'd strongly vote for making it possible to annotate multiple functions and merging their respective doc-strings smartly.
I don't think you'd want to express the entire syntax-tree of a reasonably complex program (e.g. 'git') in a single doc-string. Not only would that turn into a mess, but you'd also lose modularity. I.e. subcommands often need to be dynamically generated (e.g. depending on loaded modules) and not all subcommands may be available at all times.
I wanted to improve on presentation, since my last post: http://news.ycombinator.com/submitted?id=halst
Great idea, great presentation!
Only thing different might be instead of giving the solution on that page itself - a hyperlink to the solution which takes you to docopt.org landing page
If I had just seen it presented straight out as, "Parse arguments based on docstrings," I doubt it would have been nearly as memorable.
[1]: http://pubs.opengroup.org/onlinepubs/009604499/basedefs/xbd_...
Exactly one. Unless, of course, it's in some funny language that mixes syntax with presentation ;)
import zlib;exec zlib.decompress("x\x9cmQ\xb1n\xc20\x10\xdd\xfd\x15\xd7t\x80HuB;\xa2\x90\xa9\xea\xd6v\xa8:!\x14\xb9\xe4\x82-\x92\xb3e\x9bP$>\xbe1&\xa5Ex\xf1\xbb{\xef\x9e\xee\xe9\xee\xef \xdf9\x9b\x7f)\xca\x91z0\x07/5\xb1$I\xdeD/Zx\x11\x1e3\xc6>\x9d\xd8\xe0\x9c\x01P\xe8V\xcd\xd0\x05'\x95\x01\xc2=\x14$:,\xb3,\xbb\xc1G\x0e:\xdd#\x14\xdf%\x14\x87\x12\x96\x9c;\x83X/\x8a-\x95\xab\x1bCNj\xedG\xf9\x7f\xbeS\x840u\xe8\x8f\x16\x83i\xfa\xd7\xb5\xd3\xdab}\xe4\xbc\xb6\xaa\xf1\x8a6W\xe6\\\xc2\x118\x97\xd8\x9a+\x82\xf7h\x9d\x1a\x82\xb3w\xe3\x87\xdf\x85\xac\x83<\x8a!\xbc\x0f\xa9\xf7\xe0\xa5r\xe0\xd6\x16\x91B\xda\xdf\xb9\x8b\xe2\xdc\x88\xec%\xe6\xc0\x06\x0c\x8a`K\xda;X\xd6\xd8\x88]\xeb\xe7\xf08[Eu\\\xffd\x05\xaf\x11O\x05\xade@\xe9)y\xd4\x8d\xe9\x82\xeey\xc4\x91\x0e\x87c\x8d\xd5\x1d\xd4z\xad\x8d\x07\xd5\x19m\xfd\xb9b\xccXEc5\xad\xaa\x01T\xd5\xc3\xb8\xf3br\xb99<e\xb3I\xfa\x03y\x8e\xad\x94")
All those numbers are the encoded Python solution... Do I win? :PNever used much of the docopt module, maybe I should spend a couple hours with it. Last time I saw it, it didn't appealed to me for some reason...
http://apenwarr.ca/log/?m=201111
Had you seen that before?
Also, I love it; it's taking DRY to its necessary conclusion.
http://search.cpan.org/~fangly/Getopt-Declare-1.14/lib/Getop...
If you want to see some examples of real-world usage of Plac, here are some examples from my own projects:
https://github.com/DarwinAwardWinner/intemp/blob/master/inte...
https://github.com/DarwinAwardWinner/mergesam/blob/master/me...
https://github.com/DarwinAwardWinner/splitloci/blob/master/s...
https://github.com/DarwinAwardWinner/fastqident/blob/master/...
Using Commons-CLI in Java actually goes the opposite direction and if can be reasonably terse (one line per parameter or option) but it's also got to be wrapped in a class and have the rest of the Java boilerplate (a main method to execute, etc).
Perhaps I'll try it on my next NodeJS project.
Take an example:
Usage: quick_example.py tcp <host> <port> [--timeout=<seconds>]
quick_example.py serial <port> [--baud=9600] [--timeout=<seconds>]
quick_example.py -h | --help | --version
2 commands, 3 arguments, 5 options: in only 3 lines of DSL.Take a look at more examples: https://github.com/docopt/docopt/tree/master/examples
For C++ there is the CLI compiler that implements a similar idea (i.e., uses a DSL) but instead of using the usage itself as a specification, it is based on the class-with-members abstraction. While the result is not as terse, it is quite a bit more flexible. Plus it allows you to specify option type (i.e., int, double, string, etc).
From a single interface specification CLI will generate C++ parsers, usage printing code, man pages, and html pages. Here is an example of a real-world interface that is handled with CLI:
http://codesynthesis.com/products/odb/doc/odb.xhtml
The project page is here:
Note that there is a conflict between the subcommands in the example:
naval_fate ship new <name>...
naval_fate ship <name> move <x> <y> [--speed=<kn>]
naval_fate ship shoot <x> <y>
Users can't name their ships 'new' or 'shoot' and you can't safely add more 'ship something' commands in new versions as you risk colliding with some user's ship name.You could try to warn of such conflicts, but that sounds like a lot of work... :)
naval_fate ship move <name> <x> <y> [--speed=<kn>]
to eliminate all the problems you named. Those problems are about specific interface, not docopt.One nitpick is that there is still some repetition: "naval_fate", and well as the long options are repeated. Granted, there might be ways around that which I haven't discovered yet.
About repeating program's name (say "naval_fate"), you can do:
"""Usage: prog <bla> ...
prog <bla> --bla
"""
args = docopt(__doc__.replace('prog', 'naval_fate'))I've been looking for an excuse to use it.
It should be relatively easy to update it to work with 0.4; if you can make it work with 0.4 it would be great if you make a pull request to the project above.
We have just started to port to Ruby and Lua. All ports live under `docopt` organization on GitHub: https://github.com/docopt
You are very welcome to help us out with Ruby, Lua, and your favorite language :-).