Pieter Breed
Pieter Breed

Reputation: 5689

How can I build up the #:usage-help string dynamically in racket lang's (command-line ...) function?

I am trying to build a git-style CLI application, eg racket-app command command-params .... This is similar to what you can do with thor's sub-command feature.

I have this code:

(define commands
  (hash
   "noop"   (list "Does nothing"
                  (lambda () (log-info "noop was called :)")))
   "render" (list "Prepares and renders the static HTML (hugo)"
                  render-proc)))

(define s1 (build-possible-commands-from-the-keys-of-commands))

(define command
  (command-line
   #:usage-help s1
   #:args (op) op))

(cond
 [(dict-has-key? commands command) ((second (dict-ref commands command)))]
 [else (log-error "Unknown command")])

It fails with command-line: #:usage-help clause contains non-string.

If I replace the reference to s1 with an actual string (eg "aoeu") then it works just fine. I would like to build up that string (s1 in this example) dynamically, but I can't figure out how to do that.

Upvotes: 3

Views: 67

Answers (2)

John Clements
John Clements

Reputation: 17203

I believe the issue here is that the usage-help must be a literal string and not one computed as the program runs, because this string should be available from the command-line without running the program. That is, raco help should be able to provide the help string without running the program.

You can sort of work around this; you need to provide the string at expansion time. Here's the most straightforward way:

#lang racket

(define-syntax my-cmd
  (syntax-rules ()
    [(_ str) 
     (define command
       (command-line
        #:usage-help str
        #:args (op) op))]))

(my-cmd "aoeu")

In this example, it's clear that I've separated the "command" call from the literal string, but it may not be so useful to you.

So, here's the question: what's the use case? How are you trying to abstract over the string?

EDIT

After reading over your use case, it totally looks to me like you want to use parse-command-line, as Jon Zeppieri suggested on the racket mailing list. This allows you to specify a procedure to be called when argument parsing fails, and you can emit any string you like.

Upvotes: 3

soegaard
soegaard

Reputation: 31147

The grammar for command-line says:

flag-clause = ...
              #:usage-help string ...

This means that the command-line will not accept general expressions after #:usage-help.

I can't think of a good reason for that restriction though. I too would expect an expression to be accepted.

I suggest asking at the Racket mailing list - maybe someone has an explanation - or if not maybe someone will change the behaviour of command-line.

Upvotes: 3

Related Questions