File Coverage

blib/lib/Workflow/Condition/Evaluate.pm
Criterion Covered Total %
statement 32 33 96.9
branch 5 6 83.3
condition n/a
subroutine 8 8 100.0
pod 2 2 100.0
total 47 49 95.9


line stmt bran cond sub pod time code
1             package Workflow::Condition::Evaluate;
2              
3 30     30   1379184 use warnings;
  30         70  
  30         1931  
4 30     30   161 use strict;
  30         78  
  30         684  
5 30     30   363 use v5.14.0;
  30         104  
6 30     30   197 use parent qw( Workflow::Condition );
  30         88  
  30         219  
7 30     30   19960 use Safe;
  30         444905  
  30         3141  
8 30     30   295 use Workflow::Exception qw( configuration_error );
  30         65  
  30         14122  
9              
10             $Workflow::Condition::Evaluate::VERSION = '2.09';
11              
12             my @FIELDS = qw( test );
13             __PACKAGE__->mk_accessors(@FIELDS);
14              
15             # These get put into the safe compartment...
16             $Workflow::Condition::Evaluate::context = undef;
17              
18             sub init {
19 26     26 1 109 my ( $self, $params ) = @_;
20 26         180 $self->SUPER::init( $params );
21              
22 26         363 $self->test( $params->{test} );
23 26 50       350 unless ( $self->test ) {
24 0         0 configuration_error
25             "The evaluate condition must be configured with 'test'";
26             }
27 26         522 $self->log->info("Added evaluation condition with '$params->{test}'");
28             }
29              
30             sub evaluate {
31 37     37 1 106 my ( $self, $wf ) = @_;
32              
33 37         190 my $to_eval = $self->test;
34 37         673 $self->log->info("Evaluating '$to_eval' to see if it returns true...");
35              
36             # Assign our local stuff to package variables...
37 37         272 $Workflow::Condition::Evaluate::context = $wf->context->param;
38              
39             # Create the Safe compartment and safely eval the test...
40 37         334 my $safe = Safe->new();
41              
42 37         52446 $safe->share('$context');
43 37         3335 local $@;
44 37         170 my $rv = $safe->reval($to_eval);
45              
46 37 100       34304 $self->log->debug( "Safe eval ran ok, returned: '",
47             ( defined $rv ? $rv : '<undef>' ),
48             "'" );
49              
50 37 100       1286 return $rv ?
51             Workflow::Condition::IsTrue->new() :
52             Workflow::Condition::IsFalse->new();
53             }
54              
55             1;
56              
57             __END__
58              
59             =pod
60              
61             =head1 NAME
62              
63             Workflow::Condition::Evaluate - Inline condition that evaluates perl code for truth
64              
65             =head1 VERSION
66              
67             This documentation describes version 2.09 of this package
68              
69             =head1 SYNOPSIS
70              
71             state:
72             - name: foo
73             action:
74             - name: 'foo action'
75             condition:
76             - test: "$context->{foo} =~ /^Pita chips$/"
77              
78             =head1 DESCRIPTION
79              
80             If you've got a simple test you can use Perl code inline instead of
81             specifying a condition class. We differentiate by the 'test' attribute
82             -- if it's present we assume it's Perl code to be evaluated.
83              
84             While it's easy to abuse something like this with:
85              
86              
87             state:
88             - name: foo
89             action:
90             - name: 'foo action'
91             condition:
92             - test: |-
93             if ( $context->{foo} =~ /^Pita (chips|snacks|bread)$/" ) {
94             return $context->{bar} eq 'hummus';
95             }
96             else { ... }
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             ...
119             - action:
120             ...
121             - condition:
122             - test: "system( 'rm -rf /' )"
123              
124             The text has access to one variable, for the moment:
125              
126             =over 4
127              
128             =item B<$context>
129              
130             A hashref of all the parameters in the L<Workflow::Context> object
131              
132             =back
133              
134             =head1 SEE ALSO
135              
136             =over
137              
138             =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.
139              
140             =back
141              
142             =head1 COPYRIGHT
143              
144             Copyright (c) 2004-2021 Chris Winters. All rights reserved.
145              
146             This library is free software; you can redistribute it and/or modify
147             it under the same terms as Perl itself.
148              
149             Please see the F<LICENSE>
150              
151             =head1 AUTHORS
152              
153             Please see L<Workflow>
154              
155             =cut