global:   Global variables with command-line interaction
1 Globals
make-global
define-global
define-global:  boolean
define-global:  string
define-global:  natural0
define-global:  natural1
define-global:  integer
define-global:  real
define-global:  rational
define-global:  category
global?
global-name
global-help
global-valid?
global-string->value
global-more-commands
global-get
global-set!
global-update!
global-unsafe-set!
global-unsafe-update!
global-set-from-string!
get-globals
globals->assoc
string->boolean
with-globals
2 Command line
default-name->string
globals->command-line
global->cmd-line-rule
3 Text interaction
globals-interact
8.12

global: Global variables with command-line interaction🔗ℹ

Laurent Orseau

 (require global) package: global

Usage: Use define-global to define global variables (possibly in different modules) with cross-module getters and setters. globals->command-line automatically generates a command line parser for all the globals defined in modules that are transitively required, and globals-interact generates and textual interaction for reading and writing globals.

Here’s a minimal expample that defines the global *burgers* and generates a command-line parser:

Globals can be used without a command-line parser.

"burger.rkt"

#lang racket/base
(require global)
 
(define-global *burgers*     ; name
  1                          ; initial value
  "Number of burgers"        ; help string for the command line
  exact-nonnegative-integer? ; validation
  string->number)            ; conversion from input string
 
(void (globals->command-line))
 
(printf "You ordered ~a burgers.\n" (*burgers*))

Save this example as burger.rkt, then on the command line (in the corresponding directory), type:
racket burger.rkt --help
then try
racket burger.rkt --burgers 10
and maybe
racket burger.rkt --burgers a

Note: A similar example is included with the package and can be run with
racket -l global/examples/minimal -- --help

For a more extensive example, including a use of globals-interact, try
racket -l global/examples/example -- --help

Additional remarks:

A global variable defined with define-global in a module A is shared between all modules that require A.

Note that a global defined in module A that is transitively required by module B can be fully accessed in module B even if A does not export any identifier. Globals can be removed from the command line with (globals->command-line (remove *my-global* (get-globals))).

By convention, globals’ identifiers are surrounded by *. The value of a global *my-global* can be retrieved with (*my-global*) and set with (*my-global* some-new-value).

By contrast to parameters, globals
  • always have a single value at any time,

  • are not thread safe.

Suggestions, questions or issues? File an issue.

1 Globals🔗ℹ

procedure

(make-global name    
  init    
  help    
  valid?    
  string->value    
  [more-commands])  global?
  name : symbol?
  init : any/c
  help : (or/c string? (listof string?))
  valid? : (-> any/c any/c)
  string->value : (-> any/c any/c)
  more-commands : (listof string?) = '()
Returns a global variable with initial value init. The name is for printing purposes.

The procedure valid? is used when setting or updating the value of the global to check if the new value is valid. Note that valid? is not used on init: this can be useful to set the initial value to #f for example while only allowing certain values when set by the user.

The procedure string->value is used to convert command line arguments to values that are checked with valid? before setting the corresponding global to this value. (They could also be used for example in text-field% in GUI applications.)

more-commands is an optional list of additional command-line flags, which can be used in particular to specify short flags.

syntax

(define-global var init help valid? string->value [more-commands])

Shorthand for (define var (make-global 'var ....)).

syntax

(define-global:boolean  id init help maybe-more-commands)

syntax

(define-global:string   id init help maybe-more-commands)

syntax

(define-global:natural0 id init help maybe-more-commands)

syntax

(define-global:natural1 id init help maybe-more-commands)

syntax

(define-global:integer  id init help maybe-more-commands)

syntax

(define-global:real     id init help maybe-more-commands)

syntax

(define-global:rational id init help maybe-more-commands)

Like define-global but specialize valid? to be, respectively, boolean?, string?, exact-nonnegative-integer?, exact-positive-integer?, exact-integer?, real?, rational?, and specializes string->value to string->boolean, values, and string->number.

syntax

(define-global:category id init vals help maybe-more-commands)

 
vals = (list expr ...)
Like define-global but specializes (valid? x) to (member x vals) where vals is a list of values, and uses read for string->value. The help string is also augmented to display the available set of values.

procedure

(global? g)  boolean?

  g : any/c
(global-name g)  symbol?
  g : global?
(global-help g)  (or/c string? (listof string?))
  g : global?
(global-valid? g)  (-> any/c boolean?)
  g : global?
(global-string->value g)  (-> string? any/c)
  g : global?
(global-more-commands g)  (listof string?)
  g : global?
Predicate and accessors. See make-global.

procedure

(global-get g)  any/c

  g : global?
(global-set! g v)  void?
  g : global?
  v : any/c
(global-update! g updater)  void?
  g : global?
  updater : (-> any/c any/c)
(global-get *g*) is equivalent to (*g*) and returns the value of the global. (global-set! *g* v) is equivalent to (*g* v). global-update! updates the value of the global based on its previous value. global-set! and global-update! raise an exception if global-valid? returns #f for the new value.

procedure

(global-unsafe-set! g v)  void?

  g : global?
  v : any?
(global-unsafe-update! g updater)  void?
  g : global?
  updater : (-> any/c any/c)
Forces setting and updating the value of the global without checking its validity with global-valid?.

procedure

(global-set-from-string! g str)  void?

  g : global?
  str : string?

procedure

(get-globals)  (listof global?)

Returns the list of globals that have not been GC’ed (even if they cannot be read directly by the module calling get-globals).

procedure

(globals->assoc [globals])  (listof (cons/c symbol? any/c))

  globals : (listof global?) = (get-globals)
Returns an association list of the global names and their values.

procedure

(string->boolean s)  boolean?

  s : string?
Interprets s as a boolean. Equivalent to
(and (member (string-downcase (string-trim s))
             '("#f" "#false" "false"))
     #t)

syntax

(with-globals ([g v] ...) body ...)

Changes the value of the global g to v for the dynamic extent of body .... Similar to parameterize, but for globals.

2 Command line🔗ℹ

procedure

(default-name->string sym)  string?

  sym : symbol?
Returns a string made of sym where the surrounding * and spaces have been removed. Used as the default argument for global->cmd-line-rule and globals->command-line.

procedure

(globals->command-line [#:globals globals    
  #:name->string name->string    
  #:boolean-valid? bool?    
  #:boolean-no-prefix no-prefix    
  #:mutex-groups mutex-groups    
  #:argv argv    
  #:program program    
  #:usage-help usage]    
  trailing-arg-name ...)  any
  globals : (listof global?) = (get-globals)
  name->string : (-> symbol? string?) = default-name->string
  bool? : (-> any/c any/c) = boolean?
  no-prefix : string? = "--no-~a"
  mutex-groups : (listof (listof global?)) = '()
  argv : (vectorof (and/c string? immutable?))
   = (current-command-line-arguments)
  program : string? = "<prog>"
  usage : (listof string?) = '()
  trailing-arg-name : string?
Produces a command line parser via parse-command-line for all the global variables globals.

See parse-command-line for general information. Each list of globals within mutex-groups are placed in a separate once-any group in parse-command-line. Multi flags are not supported by globals.

See global->cmd-line-rule for some of the keywords and for more information about boolean flags.

See also the note in (get-globals).

procedure

(global->cmd-line-rule g    
  #:name->string name->string    
  #:boolean-valid? bool?    
  #:boolean-no-prefix no-prefix)  list?
  g : global?
  name->string : default-name->string
  bool? : boolean?
  no-prefix : "--no-~a"
Returns a rule for parse-command-line. Used by globals->command-line.

Booleans are treated specially on the command line, as they don’t require arguments. If the validation of g is equal? to bool? then the returned rule corresponds to a boolean flag that inverts the current value of g. For example, if bool? is boolean?, then, for

(define-global:boolean *abool* #t "a boolean")

the call (global->cmd-line-rule *abool*) (only) produces a rule with the flag "--no-abool" which sets *abool* to #f if present on the command line, while for

(define-global:boolean *abool* #f "a boolean")

it (only) produces the flag "--abool" which sets *abool* to #t. The additional flags set in more-commands always invert the default value of the global. Setting bool? to #f treats boolean globals as normal flags that take one argument. By default, name->string removes some leading and trailing special characters.

3 Text interaction🔗ℹ

procedure

(globals-interact [globals])  void?

  globals : (listof global?) = (get-globals)
Produces a command-line interaction with the user to read and write values of globals.