Command Line Subcommands in Racket

Here’s the translation of the Go code to Racket, with explanations in Markdown format suitable for Hugo:

Our first program demonstrates how to create command-line subcommands with their own set of flags. This is similar to tools like git where different subcommands (git commit, git push) have their own flags.

#lang racket

(require racket/cmdline)

(define (main)
  (define args (current-command-line-arguments))
  
  ; We declare subcommands and their flags using command-line-parser
  (define-values (foo-cmd foo-args)
    (command-line-parser
     #:program "foo"
     #:args args
     #:once-each
     [("-e" "--enable") "Enable option" (enable #t)]
     [("-n" "--name") name "Set name" (name #f)]))
  
  (define-values (bar-cmd bar-args)
    (command-line-parser
     #:program "bar"
     #:args args
     #:once-each
     [("-l" "--level") level "Set level" (level 0)]))
  
  ; The subcommand is expected as the first argument to the program
  (when (< (vector-length args) 1)
    (displayln "expected 'foo' or 'bar' subcommands")
    (exit 1))
  
  ; Check which subcommand is invoked
  (case (vector-ref args 0)
    [("foo")
     (foo-cmd)
     (printf "subcommand 'foo'~n")
     (printf "  enable: ~a~n" enable)
     (printf "  name: ~a~n" name)
     (printf "  tail: ~a~n" foo-args)]
    [("bar")
     (bar-cmd)
     (printf "subcommand 'bar'~n")
     (printf "  level: ~a~n" level)
     (printf "  tail: ~a~n" bar-args)]
    [else
     (displayln "expected 'foo' or 'bar' subcommands")
     (exit 1)]))

(main)

To run the program, save it as command-line-subcommands.rkt and use racket.

First, invoke the foo subcommand:

$ racket command-line-subcommands.rkt foo --enable --name=joe a1 a2
subcommand 'foo'
  enable: #t
  name: joe
  tail: (a1 a2)

Now try bar:

$ racket command-line-subcommands.rkt bar --level 8 a1
subcommand 'bar'
  level: 8
  tail: (a1)

But bar won’t accept foo’s flags:

$ racket command-line-subcommands.rkt bar --enable a1
bar: unknown switch: --enable

In Racket, we use the command-line-parser function from the racket/cmdline module to define subcommands and their flags. This approach provides similar functionality to the flag package in the original example.

The structure of the program remains similar, with separate definitions for each subcommand and their respective flags. The main difference is in the syntax and the way we handle command-line arguments in Racket.

Next, we’ll look at environment variables, another common way to parameterize programs.