# Top-level functions reference

The function

    Triceps::now()

is similar to Perl

    time()

but returns the current time as a floating point number, with the fractional seconds:

    $time = &Triceps:now();

This time format is used by a few Triceps methods, mostly in the multithreading support.

The function

    Triceps::wrapfess()

takes care of wrapping the confessions in the templates. It's very much like the try/catch, only it has the hardcoded catch logic that adds the extra error information and then re-throws the exception.

    Triceps::wrapfess($message, $code);

    $code

is the code to execute in an

    eval

, the try part.

    $message

is the message that is prepended to the error if the code confesses. The original message will be indented to create the nice-looking messages when the errors propagate up a chain of nested

    wrapfess()

. The stack trace doesn't get indented or duplicated, it's preserved as-is during the propagation.

The goal of

    wrapfess()

is to make the errors reported from the Triceps templates more user-friendly. When some part of the template's code generation fails, the error message that talks about the low-level details may be difficult to connect to the error in teh template arguments. The wrapping allows to prepend the high-level message about what template arguments were wrong.

    $message

may be either a string or a code reference, or a reference to a scalar variable containing either. If it's a code reference, it will be evaluated, and its result will be used as a string. The code as message can be useful if the message is expensive to generate, and thus it would be generated only if an error is encountered. The reference to a scalar can be used to wrap the code into a single

    wrapfess

but then replace the actual value to print as needed. This might be too flexible, and it's not clear yet if the reference message is a good idea.

Examples of usage:

    my $result_rt = Triceps::wrapfess
    	"$myname: Invalid result row type specification:",
    	sub { Triceps::RowType->new(@rowdef); };

    my $result_rt = Triceps::wrapfess sub {
    		"$myname: Invalid result row type specification:"
    	},
    	sub { Triceps::RowType->new(@rowdef); };

    my $eref;
    return Triceps::wrapfess \$eref,
    	sub {
    		$eref = "Bad argument foo";
    		buildTemplateFromFoo();
    		$eref = sub {
    			my $bardump = $argbar->dump();
    			$bardump =~ s/^/    /mg;
    			return "Bad argument bar:\n  bar value is:\n$bardump";
    		};
    		buildTemplateFromBar();
    		...
       };

An example of produced error message:

    Triceps::Fields::makeTranslation: Invalid result row type specification:
      Triceps::RowType::new: incorrect specification:
        duplicate field name 'f1' for fields 3 and 2
        duplicate field name 'f2' for fields 4 and 1
      Triceps::RowType::new: The specification was: {
        f2 => int32[]
        f1 => string
        f1 => string
        f2 => float64[]
      } at blib/lib/Triceps/Fields.pm line 209.
    	Triceps::Fields::__ANON__ called at blib/lib/Triceps.pm line 192
    	Triceps::wrapfess('Triceps::Fields::makeTranslation: Invalid result row type spe...', 'CODE(0x1c531e0)') called at blib/lib/Triceps/Fields.pm line 209
    	Triceps::Fields::makeTranslation('rowTypes', 'ARRAY(0x1c533d8)', 'filterPairs', 'ARRAY(0x1c53468)') called at t/Fields.t line 186
    	eval {...} called at t/Fields.t line 185

The nested error lines are differentiated from the stack trace lines by assuming that the stack trace lines always start with a tab character. Thus the lines in the errors caught by

    wrapfess()

that start with a tab character don't get indented, and the resf ot them get indented by two spaces.

Note also that even though

    wrapfess()

uses

    eval()

, there is no

    eval

above it in the stack trace. That's the other part of the magic: since that

    eval

is not meaningful, it gets cut from the stack trace, and

    wrapfess()

also uses it to find its own place in the stack trace, the point from which a simple re-confession would dump the duplicate of the stack. So it cuts the

    eval

and everything under it in the original stack trace, and then does its own confession, inserting the stack trace again. This works very well for the traces thrown by the XS code, which actually doesn't write anything below that

    eval

;

    wrapfess()

then adds the missing part of the stack.

Internally,

    wrapfess()

uses the function

    Triceps::nestfess()

to re-throw the error.

    Nestfess()

can also be used directly:

    Triceps::nestfess($message, $nested_message);

    $message

is the high level message to prepend to the low-level message, same as in

    wrapfess()

.

    $nested_message

is the low-level message to be wrapped.

    Nestfess()

is responsible for all the smart processing of the indenting and stack traces,

    wrapfess()

is really just a bit of syntactic sugar on top of it.

The typical usage is:

    eval {
    	buildTemplatePart();
    };
    if ($@) {
    	Triceps::nestfess("High-level error message", $@);
    }

now
wrapfess
nestfess