> 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


Reply via email to