Trainerflow Docs trainerflow.com
The language › Imports

The language

Imports

Splitting a program into several files and using what the standard library already defines.

A small program fits comfortably in main.cl. A bigger one, say a twelve-week cycle with a warm-up, three different days and a deload, reads much better when it is split into several files. And almost every program wants to use what the standard library already defines rather than write its own bench press. Both are done with import.

Importing a file

An import names the file to bring in, as a string:

import "coach/common/rest.cl"

rest(2|day|)

Everything the imported file declares, i.e. its actions, inputs, outputs, execs, groups and top-level variables, becomes available as if it had been written in the importing file. Above, rest comes from coach/common/rest.cl.

A few rules apply:

  • Imports go at the very top of a file, before anything else.
  • The path includes the .cl extension.
  • Paths start from the src folder of your program, whichever file the import is written in. A file at src/weeks/week1.cl is imported as "weeks/week1.cl", both from main.cl and from src/weeks/week2.cl.
  • Paths that start with coach/ point into the standard library.

Example

Let us move the days of our program into a file of their own, src/days.cl:

import "coach/strength/squat.cl"
import "coach/strength/push.cl"

let logged = [reps: true, weight: true]

group day_a() {
    @title = "Day A"
    squat([weight: 80|kg|, reps: 5], logged, [location: true])
    bench_press([weight: 60|kg|, reps: 5], logged, [location: true])
}

main.cl then only has to import it and say when each day happens:

import "days.cl"
import "coach/common/rest.cl"

repeat 4 {
    day_a()
    rest(2|day|)
}

Notice that main.cl imports coach/common/rest.cl itself. Imports are not passed along: a file sees what it declares and what it imports, but not what the files it imports have imported in turn. main.cl above can call day_a, but not squat, unless it imports coach/strength/squat.cl too.

It is perfectly fine for two files to import each other, or for several files to import the same one.

Naming an import

Sometimes two files declare the same name. The standard library’s coach/athlete.cl and coach/strength/elements.cl, for example, both declare an input called weight: one is the athlete’s body weight, the other the weight on the bar. To keep them apart, give an import a name with as:

import "coach/athlete.cl" as athlete

exec weigh_in() {
    @title = "Weigh-in"
    measure athlete.weight
}

weigh_in()

Everything from an import named this way is reached through its name, with a dot: athlete.weight, athlete.age. Nothing from it is available without the prefix.

Naming imports also makes it obvious, when you read a program months later, where each name comes from.

The standard library

Every program depends on the standard library, called coach. It is there from the moment you create a program, so there is nothing to install: an import is all it takes. The library is released in versions, and a new program uses the latest release. All of the library’s files are documented under Standard library, along with the exact path to import each one from.