File Coverage

lib/Workflow/Condition/Evaluate.pm
Criterion Covered Total %
statement 38 40 95.0
branch 6 8 75.0
condition n/a
subroutine 9 9 100.0
pod 1 1 100.0
total 54 58 93.1


line stmt bran cond sub pod time code
1             package Workflow::Condition::Evaluate;
2              
3 21     21   653 use warnings;
  21         39  
  21         760  
4 21     21   159 use strict;
  21         43  
  21         646  
5 21     21   132 use base qw( Workflow::Condition );
  21         57  
  21         2607  
6 21     21   146 use Log::Log4perl qw( get_logger );
  21         47  
  21         201  
7 21     21   13320 use Safe;
  21         353804  
  21         1058  
8 21     21   178 use Workflow::Exception qw( condition_error configuration_error );
  21         48  
  21         1200  
9 21     21   136 use English qw( -no_match_vars );
  21         73  
  21         154  
10              
11             $Workflow::Condition::Evaluate::VERSION = '1.62';
12              
13             my @FIELDS = qw( test );
14             __PACKAGE__->mk_accessors(@FIELDS);
15              
16             # These get put into the safe compartment...
17             $Workflow::Condition::Evaluate::context = undef;
18              
19             sub _init {
20 22     22   68 my ( $self, $params ) = @_;
21              
22 22         96 $self->test( $params->{test} );
23 22 50       245 unless ( $self->test ) {
24 0         0 configuration_error
25             "The evaluate condition must be configured with 'test'";
26             }
27 22         354 $self->log->info("Added evaluation condition with '$params->{test}'");
28             }
29              
30             sub evaluate {
31 59     59 1 117 my ( $self, $wf ) = @_;
32              
33 59         187 my $to_eval = $self->test;
34 59         763 $self->log->info("Evaluating '$to_eval' to see if it returns true...");
35              
36             # Assign our local stuff to package variables...
37 59         7726 $Workflow::Condition::Evaluate::context = $wf->context->param;
38              
39             # Create the Safe compartment and safely eval the test...
40 59         322 my $safe = Safe->new();
41              
42 59         59137 $safe->share('$context');
43 59         3643 local $EVAL_ERROR = undef;
44 59         174 my $rv = $safe->reval($to_eval);
45 59 50       38737 if ($EVAL_ERROR) {
46 0         0 condition_error
47             "Condition expressed in code threw exception: $EVAL_ERROR";
48             }
49              
50 59 100       501 $self->log->debug( "Safe eval ran ok, returned: '",
51             ( defined $rv ? $rv : '<undef>' ),
52             "'" );
53 59 100       8459 unless ($rv) {
54 37         239 condition_error "Condition expressed by test '$to_eval' did not ",
55             "return a true value.";
56             }
57 22         108 return $rv;
58             }
59              
60             1;
61              
62             __END__
63              
64             =pod
65              
66             =head1 NAME
67              
68             Workflow::Condition::Evaluate - Inline condition that evaluates perl code for truth
69              
70             =head1 VERSION
71              
72             This documentation describes version 1.62 of this package
73              
74             =head1 SYNOPSIS
75              
76             <state name="foo">
77             <action name="foo action">
78             <condition test="$context->{foo} =~ /^Pita chips$/" />
79              
80             =head1 DESCRIPTION
81              
82             If you've got a simple test you can use Perl code inline instead of
83             specifying a condition class. We differentiate by the 'test' attribute
84             -- if it's present we assume it's Perl code to be evaluated.
85              
86             While it's easy to abuse something like this with:
87              
88             <condition>
89             <test><![CDATA[
90             if ( $context->{foo} =~ /^Pita (chips|snacks|bread)$/" ) {
91             return $context->{bar} eq 'hummus';
92             }
93             else { ... }
94             ]]>
95             </test>
96             </condition>
97              
98             It should provide a good balance.
99              
100             =head1 OBJECT METHODS
101              
102             =head3 new( \%params )
103              
104             One of the C<\%params> should be 'test', which contains the text to
105             evaluate for truth.
106              
107             =head3 evaluate( $wf )
108              
109             Evaluate the text passed into the constructor: if the evaluation
110             returns a true value then the condition passes; if it throws an
111             exception or returns a false value, the condition fails.
112              
113             We use L<Safe> to provide a restricted compartment in which we
114             evaluate the text. This should prevent any sneaky bastards from doing
115             something like:
116              
117             <state...>
118             <action...>
119             <condition test="system( 'rm -rf /' )" />
120              
121             The text has access to one variable, for the moment:
122              
123             =over 4
124              
125             =item B<$context>
126              
127             A hashref of all the parameters in the L<Workflow::Context> object
128              
129             =back
130              
131             =head1 SEE ALSO
132              
133             =over
134              
135             =item * L<Safe> - From some quick research this module seems to have been packaged with core Perl 5.004+, and that's sufficiently ancient for me to not worry about people having it. If this is a problem for you shoot me an email.
136              
137             =back
138              
139             =head1 COPYRIGHT
140              
141             Copyright (c) 2004-2023 Chris Winters. All rights reserved.
142              
143             This library is free software; you can redistribute it and/or modify
144             it under the same terms as Perl itself.
145              
146             Please see the F<LICENSE>
147              
148             =head1 AUTHORS
149              
150             Please see L<Workflow>
151              
152             =cut