Hi all,

triggered by a new analysis.highlighters module that Klaus Blum shared
with me last week I had a few feature/functionality wishes that I
implemented, especially a kind of stylesheet support and selective
activation of elements. I quickly realized that this should be
generalized and factored out, and today I've implemented a new tool for
the oll-core package (i.e. available for any documents using
openLilyLib): properties.

Properties are related to OLL's existing option handling, but probably
superior in every aspect, so I might one day deprecate the whole
options feature (although that might be hard on existing code, so I'm
not sure about that yet).

The main features of the new properties are:

 * properties are type-checked
 * grouping in property sets may allow better organization and
   encapsulation
 * nice support for cascading behaviour
 * support for selective activation

If you are interested you can check out the "properties" branch in the
oll-core repo and play around with the attached file (also available in
the usage-examples folder in oll-core).

A "property set" is a group of properties with names, type check
predicates, and values.
When defining a property set, "design time defaults" are specified,
which can be retrieved or changed at any point throughout a document.

A property set might group openLilyLib package options, project
options, or the available properties for a music/scheme/void-function.

A macro "with-propset" allows the definition of functions that rely on
a property set, that is:

 * When called without options the properties of the propset are
   available with their current values
 * It is possible to define "presets", which are (type-checked) subsets
   of a property set. When used its values override the current
   property values.
 * When called with a \with {} block individual properties can be
   overridden, whether from the original properties or from a preset
 * Presets can have parents (I have not transferred the implementation
   to that new code base, but I had it in place in the original code).
   This allows cascading stylesheets, for example a default preset
   specifying a line thickness for a given function, and several child
   presets with different colors.
 * Also not transferred yet is support for a logic to use/ignore items
   based on presets. This makes it possible to easily control which
   items are shown or not, for example when doing presentations or
   teaching.

As a first step I'll make use of this in the Frames, Arrows and
Highlighters modules of anaLYsis. Second I will use it in new anaLYsis
modules which I have wanted to realize for a very long time: support
for harmonic analysis symbols in analysis.harmony.functional,
analysis.harmony.roman, and analysis.harmony.scale-degrees.

This is both sort-of an announcement and a request for comments before
I start building heavily on the new code base.

Best
Urs
\version "2.20.0"

% Use oll-core from the 'properties' branch
\include "oll-core/package.ily"

% Define a property set
% Properties hold a name, a type predicate and a default value.
% The default value (as well as later assignments) are type-checked
% against the predicate
\definePropset demo.props
#`((text ,string? "bar")
   (color ,color? ,red)
   (index ,integer? 4)
   ;(use-case ,symbol? "fail") ; fails on typecheck
   )

% Retrieve the property
\markup \getProperty demo.props text

% Set a property, this will be the new "current" value of the property
\setProperty demo.props text "baz"
\markup \getProperty demo.props text

% Set a property with wrong type -> no change, will be skipped
%\setProperty demo.props text #green
\markup \getProperty demo.props text

% Define a named preset (for a specific propset).
% When used the included overrides will take precedence
% over the current property values.
% (type checking is active too
\definePreset \with {
  text = boo
  color = #blue
%  index = invalid % fails type-check
} demo.props my-preset

% Define a function with the propset
% - Due to the optional \with block at least one mandatory
%   argument is required.
% - Within the function all properties are accessible
%   through the local (property '<prop-name>) function
% - If validation is necessary the effective properties
%   (after merging) can be accessed through the
%   props variable
testFunc =
#(with-propset define-scheme-function (dummy)(boolean?)
   `(demo props)
    (markup #:with-color
      (property 'color)
      (format "~a. ~a" (property 'index) (property 'text))))

% Invoke function with currently active properties
\testFunc ##t

% Invoke function with a preset
\testFunc \with {
  preset = my-preset
} ##t

% Invoke function with a preset plus individual override
\testFunc \with {
  preset = my-preset
  index = 5
  color = #magenta
} ##t

Reply via email to