> Now, I need to simplify it as much as possible, in order that even a
> mathematical professor can use it. First of all, I would like to avoid the
> $stash->get, which can be done by means of your plugin, but I would
> like also to be able to write
>
> r1 = Math.calc('sqrt(2*g*h)')
>
> or even better
>
> r1 = Math.calc('sqrt(2 g h)')
>
> or, possibly, distributing Math.calc
>
> ans = Math.calc({ r => ['sqrt(2 g h)'],
> w => ['sqrt(2 m h)','sqrt(g h)',...]})
>
> which would indeed be the best solution.
Ok, just add this to Andy's Math plugin:
sub calc
{
my ($self, $arg) = @_;
my $ans;
if ( ref $arg eq 'HASH' ) {
foreach my $key ( keys(%$arg) ) {
$ans->{$key} = $self->calc($arg->{$key});
}
} elsif ( ref $arg eq 'ARRAY' ) {
$ans = [];
while ( @$arg ) {
push(@$ans, $self->calc(shift(@$arg)));
}
} else {
my $stash = $self->{context}->stash;
$arg =~ s{([A-Za-z_][\w\.]*)}{
$stash->get($1) ne '' ? "\$stash->get('$1')" : $1
}eg;
$ans = eval($arg);
}
return $ans;
}
This allows things like:
r1 = Math.calc('sqrt(2*g*h)')
ans = Math.calc({
r => ['sqrt(2*g*h)'],
w => ['sqrt(2*m*h)','sqrt(g*h)',...]});
and even things like:
ans = Math.calc({
r => {
phi => ['(sqrt(5)+1)/2', '1+1/(1+1/(1+1/(1+1/(1+1))))'],
}
w => [
{
a1 => '1+1',
a2 => '2+2',
},
{
b1 => '3+3',
b2 => '4+4',
}
]
});
Two caveats:
- this does an eval() and should really check the EVAL_PERL option
first.
- since Math.pm also defines sub sqrt(), perl correctly warns that
eval('sqrt(2)') is ambiguous: do you mean CORE::sqrt or Math.pm's
sqrt? You can fix this by removing sqrt() from Math.pm (and always
just use calc), better yet fix up calc() to precede function calls
with CORE:: if CORE::func exists.
Also, you could use the latex filter to wrap your template.
Craig