A Domain Specific Language (DSL) for creating ERG and MRC files

(click here to jump straight to the parser)

Background

My workouts were given to me in the form of a pdf file containing minutes and intensity levels. I was struggling with graphical workout creation tools, and with manually creating MRC files line by line. Being lazy, I decided to create a domain specific language which would let me specify these files in another way.

The Language

Both an interval and workout are made up of a sequence of sub-components, namely intervals, ramps or steady states.

Both ramps and steady states specify the amount of power that occur for some duration. Ramps smoothly move between two power levels over that duration, while steady states maintain that power for the entire duration.

For example, a steady state requiring one to hold a power of 35 for 60 seconds can be specified as

steady duration: 60, power: 35

or equivalently

steady(duration: 60, power: 35)

A ramp takes a start and finish power, for example,

ramp(duration: 480,start:40,finish:80)

which creates an 8 minute long ramp starting at a power of 40, and finishing at a power of 80.

To allow for reuse, one can associate these states with labels, e.g.,

rest=steady duration: 60, power: 35

An interval is a combination of states (written within square brackets), which can be specified using labels or by declaring the interval itself. For example,

rest=steady duration: 60, power: 35
sprint=interval([steady(duration: 20,power: 105), steady(duration: 40,power: 35)])
warmup=interval( [ramp(duration: 480,start:40,finish:80), steady(duration: 60, power: 40), repeat(sprint,3), rest])

Note that the repeat keyword can be used to create an interval by repeating its component.

Intervals, ramps and steady states can also be associated with comments. Here is an example:

plusrpm=steady duration: 60, power:90, comments: [comment("+5 RPM")]

Whenever this steady session starts, the comment will appear (for 10 seconds by default). One can control the duration the comment is displayed for, and when it is displayed as follows

interval1=interval [base,plusgear,base2,plusrpm,base3,plusrpm,base2,plusgear,base],comments: [comment("start interval",time:3,duration:5)]

Here, the comment will only appear for 5 seconds, 3 seconds after the interval starts. Note that time: or duration: can be left out for default behaviour to occur.

Finally, a workout is a special interval which captures the entire training session, e.g.,

workout([warmup,interval1,recovery,interval2,recovery,interval1,cooldown])

By default, power is specified as a percent of max power, to change this to an absolute value, use

workout([warmup,interval1,recovery,interval2,recovery,interval1,cooldown],power:"WATTS")

Other parameters that can be passed (which affect the contents of the resulting file are

Finally, text starting with a hash (#) will be ignored by the system.

The Parser

If you input a workout into the left hand box, and click the button at the bottom, a valid ERG or MRC file will appear in the output box on the right. You can then cut and paste that into a file, and import it into your favourite software. Note that Chrome doesn't seem to display the content of the output textbox correctly, but if you cut and paste it, it seems to come out fine.

Input: Output:

Click here to generate output:

Technical Details and Small Print

The language itself is actually a ruby program, which invokes other (very hacky) ruby functions. For the webpage, I converted the Ruby to Javascript via Opal, which allows it to run in your browser. The ruby code can be downloaded from GitHub.

Use this software at your own risk. I've tested it on my setup (a creaky MBP with Chrome and Firefox), but disavow all responsibilty for any bugs in the code, and any problems that this code could cause.

If you have any questions, you can contact me at "nir at jhudsy dot org".


Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License.