# Opt reference

Triceps::Opt is not a class but a package with a set of functions that help with processing the arguments to the class constructors and other functions when these arguments are represented as options.

    &Triceps::Opt::parse($class, \%instance, \%optdescr, @opts);

Checks the options and copies their values into a class instance (or generally into a hash). Usually used with the class constructors, so the semantics of the arguments is oriented towards this usage. Confesses on errors.

    $class

is the calling class name, for the error messages.

    \%instance

is the reference to the object instance where to copy the options to.

    \%optdescr

is the reference to a hash describing the valid options.

    @opts

(all the remaining arguments) are the option name-value pairs passed through from the class constructor.

The entries in

    \%optdescr

are references to arrays, each of them describing an option. They are usually written in the form:

    optionName => [ $defaultValue, \&checkFunc ],

If there is no default value, it can be set to

    undef

.

    \&checkFunc

is a reference to a function that is used to check the option value. If the value is correct, the function returns, if incorrect, it confesses with a descriptive message. The default value is filled in for the missing options before the check function is called. If no checking is needed, the function reference may be

    undef

. The check function is called as:

    &$checkFunc($optionValue, $optionName, $class, $instance);

The class and instance are passed through from the arguments of

    parse()

.

A user-defined anonymous function can be used to combine multiple checking functions, for example:

    table => [ undef, sub {
    	&Triceps::Opt::ck_mandatory(@_);
    	&Triceps::Opt::ck_ref(@_, "Triceps::Table");
    } ],

A number of ready checking function is provided. When these functions require extra arguments, by convention they go after the common arguments, as shown for

    ck_ref()

above.

-     Triceps::Opt::ck_mandatory

  checks that the value is defined.

-     Triceps::Opt::ck_ref

  checks that the value is a reference to a particular class, or a class derived from it. Just give the class name as the extra argument. Or, to check that the reference is to array or hash, make the argument

      "ARRAY"

  or

      "HASH"

  . Or an empty string

      ""

  to check that it's not a reference at all. For the arrays and hashes it can also check the values contained in them for being references to the correct types: give that type as the second extra argument. But it doesn't go deeper than that, just one nesting level. It might be extended later, but for now one nesting level has been enough.

-     Triceps::Opt::ck_refscalar

  checks that the value is a reference to a scalar. This is designed to check the arguments which are used to return data back to the caller, and it would accept any previous value in that scalar: an actual scalar value, an

      undef

  or a reference, since it's about to be overwritten anyway.

The

    ck_ref()

and

    ck_refscalar()

allow the value to be undefined, so they can safely be used on the truly optional options. When I come up with more of the useful check functions, I'll add them.

A special case is the passing through of the options: you can accept the arbitrary options, typically if your function is a wrapper to another function, and you just want to process a few options and let the others through. The

    Triead::start()

is a good example, passing the options through to the main function of the thread.

The acceptance of the arbitrary options is specified by using an option named * in the

    Opt::parse()

arguments. For example:

      &Triceps::Opt::parse($myname, $opts, {
        app => [ undef, \&Triceps::Opt::ck_mandatory ],
        thread => [ undef, \&Triceps::Opt::ck_mandatory ],
        fragment => [ "", undef ],
        main => [ undef, sub { &Triceps::Opt::ck_ref(@_, "CODE") } ],
        '*' => [],
      }, @_);

The specification array for * is empty. The unknown options will be collected in the array referred to from

    $opts->{'*'}

, that is

    @{$opts->{'*'}}

.

From there on the wrapper has the choice of either passing through all the options to the wrapped function, using

    @_

, or explicitly specifying a few options and passing through the rest from

    @{$opts->{'*'}}

.

There is also the third possibility: filter out only some of the incoming options. This can be done with

    Opt::drop()

. It lets through only the options that are not present in the description:

    @filteredOpts = &Triceps::Opt::drop(\%optdescr, @opts);
    @filteredOpts = &Triceps::Opt::dropExcept(\%optdescr, @opts);

The

    Opt::drop()

takes the specification of the options to drop as a hash reference, the same as

    Opt::parse()

. The values in the hash are not important in this case, only the keys are used. But it's simpler to store the same specification of the options and reuse it for both

    parse()

and

    drop()

than to write it twice.

There is also an opposite function,

    Opt::dropExcept()

. It passes through only the listed options and drops the rest. It can come handy if your wrapper wants to pass different subsets of its incoming options to multiple functions.

The functions

    drop()

and

    dropExcept()

can really be used on any name-value arrays, not just the options as such. And the same goes for the

    Fields::filter()

and friends. So you can use them interchangeably: you can use

    Opt::drop()

on the row type specifications and

    Fields::filter()

on the options if you feel that it makes your code simpler.

For an example of

    drop()

,

    Triead::startHere()

works like this:

    # The options for start(). Keeping them in a variable allows the individual
    # thread main functions to copy and reuse their definition instead of
    # reinventing it.
    our @startOpts = (
    	app => [ undef, \&Triceps::Opt::ck_mandatory ],
    	thread => [ undef, \&Triceps::Opt::ck_mandatory ],
    	fragment => [ "", undef ],
    	main => [ undef, sub { &Triceps::Opt::ck_ref(@_, "CODE") } ],
    );

    sub startHere # (@opts)
    {
    	my $myname = "Triceps::Triead::start";
    	my $opts = {};
    	my @myOpts = ( # options that don't propagate through
    		harvest => [ 1, undef ],
    		makeApp => [ 1, undef ],
    	);

    	&Triceps::Opt::parse($myname, $opts, {
    		@startOpts,
    		@myOpts,
    		'*' => [],
    	}, @_);

    	my @args = &Triceps::Opt::drop({
    		@myOpts
    	}, \@_);
    	@_ = (); # workaround for threads leaking objects

    	# no need to declare the Triead, since all the code executes synchronously anyway
    	my $app;
    	if ($opts->{makeApp}) {
    		$app = &Triceps::App::make($opts->{app});
    	} else {
    		$app = &Triceps::App::resolve($opts->{app});
    	}
    	my $owner = Triceps::TrieadOwner->new(undef, undef, $app, $opts->{thread}, $opts->{fragment});
    	push(@args, "owner", $owner);
    	eval { &{$opts->{main}}(@args) };
    	$owner->abort($@) if ($@);
    	# In case if the thread just wrote some rows outside of nextXtray()
    	# and exited, flush to get the rows through. Otherwise things might
    	# get stuck in a somewhat surprising way.
    	eval { $owner->flushWriters(); };
    	$owner->markDead();
    	if ($opts->{harvest}) {
    		$app->harvester();
    	}
    }

The

    @startOpts

are both used by the

    startHere()

and passed through. The

    @myOpts

are only used in

    startHere()

and do not pass through. And the rest of the options pass through without being used in

    startHere()

. So the options from

    @myOpts

get dropped from

    @_

, and the result goes to the main thread.

The Opts package also provides the helper methods for processing the sets of options.

    &Triceps::Opt::handleUnitTypeLabel($caller,
    	$nameUnit, \$refUnit,
    	$nameRowType, \$refRowType,
    	$nameLabel, \$refLabel);

A special post-processing that takes care of sorting out the compatibility of the options for the unit, input row type and the input label. Usually called after

    parse()

. Confesses on errors.

    $caller

is the description of the caller, for the error messages. The rest are the pairs of the option names and the references to the option values in the instance hash.

Treats the options for input row type and input label as mutually exclusive but with exactly one of them required. If the input row type is used then the unit option is also required. If the input label is used, the unit is optional, but if it's specified anyway, the unit in the option must match the unit of the input label. If the input label is used, the values for the input row type and the unit are extracted from the input label and set into the references.

    $which = &Triceps::Opt::checkMutuallyExclusive(
    	$caller, $mandatory, $optName1, optValue1, ...);

Checks a set of mutually exclusive options. Usually called after

    parse()

. Confesses on errors, returns the name of the only defined option on success. If no options are defined, returns

    undef

.

    $caller

is the description of the caller, for the error messages.

    $mandatory

is a flag telling that exactly one of the options must be defined; or the check will confess. The rest are the option name-value pairs (unlike

    handleUnitTypeLabel()

, these are values, not references to them).
Opt