Re: implicit :required behavior in Tools.cli is deceptive

2014-05-16 Thread guns
On Thu 15 May 2014 at 10:45:52AM -0700, Bob Larrick wrote:

 A single element in the cli-options can be as brief as

 [-p --port A port number]

 What is non-obvious is that specifying

 --port PORT

 has entirely different semantics than specifying

 --port

Like I mentioned on the issue page, this is just a shortcut around
passing a `:required` entry with the same information.

The motivation behind this is that the resulting option summary mirrors
the option vectors:

  [[-p --port PORT A port number :parse-fn #(Integer/parseInt %)]
   [-q --quiet Shhh]]

  -p, --port PORT  A port number
  -q, --quiet  Shhh

It is easy to tell at a glance that --port requires an option argument,
while --quiet does not.

If you dislike this syntax (which I borrowed from Ruby), you may replace
it with:

  [-p --port A port number
   :required PORT
   :parse-fn #(Integer/parseInt %)]

 In the first case the command lein run -p 3000 will result in an options
 map of {:options {:port 3000}}.

 Can you guess what the same command would produce given the second case?

I would expect that an option flag that has not been marked as requiring
an argument to be a boolean toggle. This is the convention in C's
getopt(1), bash's getopts builtin, Perl's GetOpt::Long, and Ruby's
OptionParser.

 If you're like me, you wouldn't guess {:options {:port true}}. :-/
 It is worth noting that in earlier versions of this library --port did
 result in {:options {:port 3000}}, so this is a change in behavior from
 previous versions.

Yes, this is a change. The old tools.cli/cli still exists for people who
do not want to bother with learning a new API (I can sympathize). It has
also been upgraded to use the new option tokenizer.

 The current behavior is neither simple nor easy to understand, and
 complects the behavior of the flag with the definition of the long option.

Again, this is optional sugar. The option vectors are actually compiled
to maps:

(#'clojure.tools.cli/compile-option-specs
  [[-p --port PORT A port number]
   [nil  --host :required HOST]])

-

({:id :port
  :short-opt -p
  :long-opt --port
  :required PORT
  :desc A port number}
 {:id :host
  :short-opt nil
  :long-opt --host
  :required HOST
  :desc nil})

You may, if you like, supply the underlying maps instead of the option
vectors to parse-opts. The option specification is documented here:

https://github.com/clojure/tools.cli/blob/master/src/main/clojure/clojure/tools/cli.clj#L265-L309

 I suggest that this implicit behavior be removed and that all options be
 treated as required unless :required false is explicitly declared.

 Or perhaps there should be :boolean flag similar to :parse-fn or :default,
 since :required feels a little overloaded.
 That way given lein run -p 3000, [-p --port A port number] would
 result in {:options {:port 3000}} and
 [-p --port A port number :boolean true] would result in {:options
 {:port true}}.

 That would make when a flag will be treated as a boolean explicit
 and obvious, and make this library a little less frustrating and
 foot-gunish.

You are suggesting that options require arguments by default is less
implicit than options are boolean toggles by default. This is unclear
to me.

As to which default is preferable and less surprising, I prefer the
latter since it matches the conventions in C, bash, Perl, and Ruby. My
understanding is that the former is the default on Python. Perhaps this
is the source of our disagreement?

I do agree that the documentation is not clear enough on this matter; I
will ameliorate this later today.

guns


pgp60HSRLzVmo.pgp
Description: PGP signature


implicit :required behavior in Tools.cli is deceptive

2014-05-15 Thread Bob Larrick

A single element in the cli-options can be as brief as 

[-p --port A port number]

What is non-obvious is that specifying

--port PORT

has entirely different semantics than specifying

--port

In the first case the command lein run -p 3000 will result in an options 
map of {:options {:port 3000}}.
Can you guess what the same command would produce given the second case?  

If you're like me, you wouldn't guess {:options {:port true}}. :-/
It is worth noting that in earlier versions of this library --port did 
result in {:options {:port 3000}}, so this is a change in behavior from 
previous versions.  


The current behavior is neither simple nor easy to understand, and 
complects the behavior of the flag with the definition of the long option.  

I suggest that this implicit behavior be removed and that all options be 
treated as required unless :required false is explicitly declared. 

Or perhaps there should be :boolean flag similar to :parse-fn or :default, 
since :required feels a little overloaded. 
That way given lein run -p 3000, [-p --port A port number] would 
result in {:options {:port 3000}} and 
[-p --port A port number :boolean true] would result in {:options 
{:port true}}.

That would make when a flag will be treated as a boolean explicit and 
obvious, and make this library a little less frustrating and foot-gunish.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.