File Coverage

blib/lib/Language/FormulaEngine/Formula.pm
Criterion Covered Total %
statement 38 42 90.4
branch 11 26 42.3
condition 1 6 16.6
subroutine 11 12 91.6
pod 5 5 100.0
total 66 91 72.5


line stmt bran cond sub pod time code
1             package Language::FormulaEngine::Formula;
2 7     7   52 use Moo;
  7         18  
  7         50  
3 7     7   2247 use Carp;
  7         23  
  7         644  
4 7     7   52 use overload '""' => sub { shift->to_string };
  7     14   26  
  7         62  
  14         3405  
5              
6              
7             has engine => ( is => 'rw', required => 1 );
8             has orig_text => ( is => 'rw' );
9             has parse_tree => ( is => 'rw', required => 1 );
10             has functions => ( is => 'lazy' );
11             has symbols => ( is => 'lazy' );
12              
13             sub _count_refs {
14 2     2   5 my $node= shift;
15 2         6 my (%fn_set, %var_set, @todo);
16 2         45 while (defined $node) {
17 5 100       30 $var_set{$node->symbol_name}++ if $node->can('symbol_name');
18 5 100       22 if ($node->can('function_name')) {
19 2         7 $fn_set{$node->function_name}++;
20 2         4 push @todo, @{ $node->parameters };
  2         6  
21             }
22 5         36 $node= pop @todo;
23             }
24 2         8 (\%fn_set, \%var_set);
25             }
26              
27             sub _build_symbols {
28 0     0   0 my $self= shift;
29 0         0 @{$self}{'functions','symbols'}= _count_refs( $self->parse_tree );
  0         0  
30 0         0 $self->{symbols};
31             }
32              
33             sub _build_functions {
34 2     2   23 my $self= shift;
35 2         8 @{$self}{'functions','symbols'}= _count_refs( $self->parse_tree );
  2         8  
36 2         11 $self->{functions};
37             }
38              
39              
40             sub evaluate {
41 2     2 1 1170 my ($self, $ns_or_vars)= @_;
42 2 0 33     74 my $ns= !$ns_or_vars? $self->engine->namespace
    0          
    50          
    50          
43             : !ref $ns_or_vars && @_ > 2? $self->engine->namespace->clone_and_merge(variables => { @_[1..$#_] })
44             : ref $ns_or_vars eq 'HASH'? $self->engine->namespace->clone_and_merge(variables => $ns_or_vars)
45             : ref($ns_or_vars)->can('get_function')? $ns_or_vars
46             : croak "Can't evaluate for $ns_or_vars";
47 2         84 return $self->parse_tree->evaluate($ns);
48             }
49              
50              
51             sub simplify {
52 2     2 1 3536 my ($self, $ns_or_vars)= @_;
53 2 0 0     57 my $ns= !$ns_or_vars? $self->engine->namespace
    0          
    0          
    50          
54             : !ref $ns_or_vars && @_ > 2? $self->engine->namespace->clone_and_merge(variables => { @_[1..$#_] })
55             : ref $ns_or_vars eq 'HASH'? $self->engine->namespace->clone_and_merge(variables => $ns_or_vars)
56             : ref($ns_or_vars)->can('get_function')? $ns_or_vars
57             : croak "Can't evaluate for $ns_or_vars";
58 2         24 my $parse_tree= $self->parse_tree->simplify($ns);
59 2 50       11 return $self if $parse_tree == $self->parse_tree;
60 2         96 return Language::FormulaEngine::Formula->new(
61             engine => $self->engine,
62             parse_tree => $parse_tree,
63             );
64             }
65              
66              
67             sub compile {
68 2     2 1 7 my ($self, $subname)= @_;
69 2 50       52 $self->engine->compiler->compile($self->parse_tree, $subname)
70             or croak $self->engine->compiler->error;
71             }
72              
73              
74             sub deparse {
75 8     8 1 46 my $self= shift;
76 8         192 $self->parse_tree->deparse($self->engine->parser);
77             }
78              
79              
80             sub to_string {
81 14     14 1 35 my $orig= $_[0]->orig_text;
82 14 100       71 return defined $orig? $orig : $_[0]->deparse;
83             }
84              
85             1;
86              
87             __END__
88              
89             =pod
90              
91             =encoding UTF-8
92              
93             =head1 NAME
94              
95             Language::FormulaEngine::Formula
96              
97             =head1 VERSION
98              
99             version 0.08
100              
101             =head1 SYNOPSIS
102              
103             $formula= $engine->parse($text_expression);
104            
105             $value= $formula->evaluate(x => 1);
106            
107             $formula2= $formula->simplify(y => 2);
108            
109             $coderef= $formula2->compile;
110              
111             =head1 DESCRIPTION
112              
113             This is a convenient way to carry around the details of a parsed formula and later
114             evaluate it, simplify it, or compile it. It's simply a wrapper around the engine
115             that created it + the parse tree.
116              
117             =head1 ATTRIBUTES
118              
119             =head2 engine
120              
121             Reference to a L<Language::FormulaEngine> instance.
122              
123             =head2 orig_text
124              
125             Original string of text that was parsed into this formula. This may be
126             C<undef> if the formula was generated. In that case, see L</deparse>
127             or L</to_string>.
128              
129             =head2 parse_tree
130              
131             Reference to the output of L<Language::FormulaEngine::Parser/parse>
132              
133             =head2 functions
134              
135             A set of { $name => 1 } for each named function used in this formula.
136              
137             =head2 symbols
138              
139             A set of { $name => 1 } for each named variable used in this formula.
140              
141             =head1 CONSTRUCTOR
142              
143             Standard Moo constructor accepts any of the attributes above.
144              
145             =head1 METHODS
146              
147             =head2 evaluate
148              
149             $raw_value= $formula->evaluate;
150             $raw_value= $formula->evaluate(\%alt_vars);
151             $raw_value= $formula->evaluate($alt_namespace);
152              
153             Evaluate the formula, optionally specifying variables or a different namespace in which
154             to evaluate it.
155              
156             =head2 simplify
157              
158             $formula2= $formula1->simplify;
159             $formula2= $formula1->simplify(\%alt_vars);
160             $formula2= $formula1->simplify($alt_namespace);
161              
162             Simplify the formula by substituting known variable values and evaluating pure functions.
163             You can optionally specify variables or a different namespace which should be used.
164              
165             =head2 compile
166              
167             my $sub= $formula->compile;
168             my $sub= $formula->compile($subname);
169              
170             Return an optimized perl coderef for the formula. The signature of the coderef
171             depends on the settings of the C<< $formula->engine->compiler >>. Throws an
172             exception if the compile fails.
173              
174             =head2 deparse
175              
176             Re-stringify the formula, using C<< $self->engine->parser >>.
177              
178             =head2 to_string
179              
180             Return either C<orig_text>, or C<deparse>. This is used when stringifying the object.
181              
182             =head1 AUTHOR
183              
184             Michael Conrad <mconrad@intellitree.com>
185              
186             =head1 COPYRIGHT AND LICENSE
187              
188             This software is copyright (c) 2023 by Michael Conrad, IntelliTree Solutions llc.
189              
190             This is free software; you can redistribute it and/or modify it under
191             the same terms as the Perl 5 programming language system itself.
192              
193             =cut