Once I was reasonably happy with ABC::Duration and ABC::Note, I went ahead and added ABC::Rest, which was truly easy thanks to the magic of code reuse. It actually turned out to be quite a struggle to implement, but that was only because I accidentally typed is $.type rather than has $.type and spent a couple hours trying to sort out what the LTA error message meant.
class ABC::Rest does ABC::Duration {
has $.type;
method new($type, ABC::Duration $duration) {
self.bless(*, :$type, :ticks($duration.ticks));
}
method Str() {
$.type ~ self.duration-to-str;
}
}
There are several sorts of rests in ABC, which is why ABC::Rest has a $type attribute. In practice, I’ve only implemented “z” rests so far, as they are the basic type.
Rests were already in the grammar, and adding an action to support them was dead easy:
method rest($/) {
make ABC::Rest.new(~$<rest_type>, $<note_length>.ast);
}
After a trivial refactor to make the Lilypond duration handling code easily available, it was just took one line to add rests to the Lilypond output:
when “rest” { print ” r{ DurationToLilypond($context, $element.value) } ” }
That’s for the output section of the code. No changes were required to make rests work in the “figure out the overall duration” section of the code, because it looks for elements which do ABC::Duration, and so it automatically found the rests and correctly handled them.
To me, this looks like a solid win for treating duration as a role.