6.1.1 Core
On this page:
defstep
defstep/  study
defstudy
put/  identity
require
button
with-bot
6.1.1.1 Views
defview
~current-view-uri
6.1.1.2 Boxes
defbox
define-var-box
6.1.1.3 Logging
log-conscript-debug
log-conscript-info
log-conscript-warning
log-conscript-error
log-conscript-fatal

6.1.1 Core🔗

 (require conscript/base) package: conscript

The bindings provided by this module are also provided by #lang conscript.

syntax

(defstep (step-id) step-body)

Defines a study step. The step-body must be an expression that evaluates to a study page — usually md or html.

syntax

(defstep/study step-id #:study child-study-expr
               maybe-require-bindings
               maybe-provide-bindings)
 
maybe-require-bindings = 
  | #:require-bindings ([child-id parent-id] ...)
     
maybe-provide-bindings = 
  | #:provide-bindings ([parent-id child-id] ...)

Defines a study step that runs child-study-expr when reached.

The step step-id is said to be part of the “parent” study, of which child-study-expr becomes a “child” study.

The #:require-bindings argument is used to map identifiers required by the child study to identifiers available in the current study context if their names differ. Any identifiers required by the child study that are not mapped here are assumed to be named identically to identifiers in the parent study context, and defstep/study will attempt to map them accordingly.

The #:provide-bindings argument can be used to map identifiers in the parent study to particular identifiers provided by child-study-expr upon completion. When #:provide-bindings is not specified, no values are assigned.

syntax

(defstudy study-id
          maybe-requires
          maybe-provides
          transition-clause ...+)
 
maybe-requires = 
  | #:requires (value-id-sym ...)
     
maybe-provides = 
  | #:provides (value-id-sym ...)
     
transition-clause = [step --> transition ... maybe-lambda]
     
transition = --> step
  | --> {step-id step}
     
maybe-lambda = 
  | --> ,(lambda () transition-expr)
     
transition-expr = done
  | (goto step)
  | '(fail _)
  | 'step-id
  | expr
Defines a study in terms of steps joined by transitions. Each step should be a step defined with defstep or defstep/study.

The use of #:requires and #:provides arguments is deprecated and included for compatibility. Use defvar* and defvar*/instance to share study variables between parent/child studies.

An unquoted lambda at the end of a transition-clause can include arbitrary expr, but this but must evaluate to one of the other possible transition-exprs:

(defstudy college-try
  [attempt --> ,(lambda () (if success
                               (goto good-ending)
                               (goto bad-ending)))]
  [bad-ending --> ,(lambda () '(fail 0))]
  [good-ending --> good-ending])

For any “final” step (that is, a step that, once reached, should prevent the participant from taking any further step) you need to include a separate transition-clause with the step at both ends, or a maybe-lambda expression that returns done:

(defstudy mystudy
  [intro --> question --> final]
  [final --> final])
; OR:
(defstudy mystudy
  [intro --> question --> final --> ,(lambda () done)])

You can reuse the same step function as separate steps with the --> {step-id step} form of transition:

(defstudy repeating-step-study
  [intro --> {message1 message}
         --> {message2 message}
         --> final]
  [final --> final])

procedure

(put/identity key value)  void?

  key : symbol?
  value : any/c
If the user enrolled in the study via an identity server, stores value under key within their enrollment on that server; if the user did not enroll through an identity server, it stores the value under key directly on the Congame server.

The point of enrolling via an identity server is to prevent the study author from connecting a participant’s answers with their identity — but there are cases where a well-designed study will still need to attach some data to their identity. For example, at the end of a study you might call (put/identity 'payment-due pay-amount) so that, despite not knowing the participant’s answers, you know how much you need to pay them.

syntax

(require require-spec ...)

Conscript provides its own binding for require that only allows modules from the whitelist below. This prevents unsafe code from running on Congame servers.

procedure

(button [action-proc]    
  label    
  [#:id id    
  #:to-step-id to-step-id    
  #:up-target up-target    
  #:up-transition up-transition])  xexpr?
  action-proc : (-> any/c) = void
  label : string?
  id : string? = ""
  to-step-id : (or/c identifier? #f) = #f
  up-target : string? = ".step"
  up-transition : string? = "none"
Returns a representation of an HTML <a> element styled as a button that navigates to the next step in the study when clicked.

If action-proc is provided, it will be called when the button is clicked, just before the next step in the study is loaded. Rather: before the transition is run.

The href attribute is dynamically set to the URL of a continuation that first calls action with no arguments, then returns the page provided by to-step-id (or that provided by the next step in the study if to-step-id is #f).

If #:id is provided, it sets the value of the data-widget-id attribute for the element.

syntax

(with-bot step-expr bot-expr)

Wraps step-expr so that its default bot is bot-expr.

(defstep (hello)
  (button "Continue..."))
(defstudy s
  [[hello (with-bot hello bot:continuer)] --> ,(lambda () done)])
6.1.1.1 Views🔗

A view is an additional set of content/functionality that can be associated with a step. Views can be used to provide additional instructions for a step, or to give admins a customized display of study outcomes.

The content of a view is provided by a view handler, which is a function which takes a single request argument (which can be inspected if the view needs to vary depending on the HTTP request) and returns a response. This function will be called by the Congame server when the view is accessed.

syntax

(defview (id req) body ...)

 
  req : request?
Defines a view handler. When the view is accessed, Congame will call the view handler, passing the HTTP request as the req argument.

As with defstep, the body of a defview expression should evaluate to a study page, usually using md or html. The defview form takes care of converting the page to an HTTP response.

Example:

(defview (instructions-popup _request)
  @md{#Instructions
 
      More detail.....})

procedure

(~current-view-uri)  string?

Returns the URI of the view handler page associated with the current step. Intended for use inside defstep.

6.1.1.2 Boxes🔗

syntax

(defbox id)

Defines two functions, get-id (which takes no arguments and returns the value of id) and set!-id (which takes one argument and updates the value of id).

Examples:
> (define flux 81)
> (defbox flux)
> (get-flux)

81

> (set!-flux "new")
> (get-flux)

"new"

> flux

"new"

syntax

(define-var-box id var)

Binds id to a function that can take zero arguments or one argument. If given no arguments, the function returns the current value of var (which must already be defined elsewhere); if given a single argument, the function set!s the value of var to that value.

The function id can be passed to other functions, allowing them to access or update a local variable.

Examples:
> (define flux #f)
> (define-var-box get-or-set flux)
> (get-or-set)

#f

> (get-or-set 'foo)
> (get-or-set)

'foo

> flux

'foo

6.1.1.3 Logging🔗

syntax

(log-conscript-debug string-expr)

(log-conscript-debug format-string-expr v ...)

syntax

(log-conscript-info string-expr)

(log-conscript-info format-string-expr v ...)

syntax

(log-conscript-warning string-expr)

(log-conscript-warning format-string-expr v ...)

syntax

(log-conscript-error string-expr)

(log-conscript-error format-string-expr v ...)

syntax

(log-conscript-fatal string-expr)

(log-conscript-fatal format-string-expr v ...)

See Logging in the Racket Reference for more information on logging.

Logs an event with the Conscript logger, evaluating string-expr or (format format-string-expr v ...). These forms are listed above in order of severity.

Logging functions are useful for debugging: for example, when you want to capture and surface state information in the middle of a process, or extra context about possible causes of a problem.

Logged events are printed on the console (stderr) of a running Congame server.

Note that since the result of a log-conscript-level form is #<void>, you can’t use it directly inside a study step. Instead, wrap it in a begin expression that returns an empty string:

(defstep (age-name-survey)
  @md{
    # Survey
 
    @form{
      What is your first name? @(set! first-name (input-text))
 
      @(begin
        (log-conscript-info "Hello")
        "")
      @submit-button
  }})