File Coverage

blib/lib/Cucumber/TagExpressions/Node.pm
Criterion Covered Total %
statement 41 61 67.2
branch 2 8 25.0
condition 1 6 16.6
subroutine 15 24 62.5
pod 12 12 100.0
total 71 111 63.9


line stmt bran cond sub pod time code
1              
2             package Cucumber::TagExpressions::Node;
3             $Cucumber::TagExpressions::Node::VERSION = '6.0.0';
4             =head1 NAME
5              
6             Cucumber::TagExpressions::Node - Cucumber Tag expression components
7              
8             =head1 SYNOPSIS
9              
10             use Cucumber::TagExpressions;
11              
12             my $expr = Cucumber::TagExpressions->parse( '@a and @b' );
13             if ( $expr->evaluate( qw/x y z/ ) ) {
14             say "The evaluation returned false";
15             }
16              
17             =head1 DESCRIPTION
18              
19             This module defines the components making up the tag expressions.
20              
21             =head1 METHODS
22              
23             =cut
24              
25 2     2   925 use Moo;
  2         20886  
  2         10  
26             # 'use Moo' implies 'use strict; use warnings;'
27              
28             =head2 evaluate( @tags )
29              
30             Returns C when the tag set specified in C<$tags> satisfies the
31             condition(s) of the expression, C otherwise.
32              
33             C<@tags> can be a list of tags to be used in the expression. It can
34             also be a reference to a hash with the keys being the tags and the
35             values being considered boolean values indicating whether the tag (key)
36             is considered part of the tagset (true) or not (false).
37              
38             =cut
39              
40             sub evaluate {
41 0     0 1 0 die 'Abstract superclass; override "evaluate" method';
42             }
43              
44              
45             =head2 stringify
46              
47             Returns a string representation of the expression node.
48              
49             =cut
50              
51       0 1   sub stringify { }
52              
53             =head1 NODE CLASSES
54              
55             =cut
56              
57             package Cucumber::TagExpressions::LiteralNode {
58             $Cucumber::TagExpressions::LiteralNode::VERSION = '6.0.0';
59             =head2 Cucumber::TagExpressions::LiteralNode
60              
61             =head3 DESCRIPTION
62              
63             This node class returns C if the literal tag is specified as part of
64             the tag-list in the expression evaluation.
65              
66             =head3 ATTRIBUTES
67              
68             =head4 tag
69              
70             The tag to test presence for.
71              
72             =cut
73              
74 2     2   2775 use Moo;
  2         4  
  2         10  
75             # 'use Moo' implies 'use strict; use warnings;'
76             extends 'Cucumber::TagExpressions::Node';
77              
78             has tag => ( is => 'ro', required => 1 );
79              
80             sub evaluate {
81 83     83 1 120 my ( $self, $tags ) = @_;
82              
83 83         472 return $tags->{ $self->tag };
84             }
85              
86             sub stringify {
87 0     0 1 0 my ( $self ) = @_;
88              
89 0         0 return ($self->tag =~ s/([ ()\\])/\\$1/gr);
90             }
91             }
92              
93             package Cucumber::TagExpressions::AndNode {
94             $Cucumber::TagExpressions::AndNode::VERSION = '6.0.0';
95             =head2 Cucumber::TagExpressions::AndNode
96              
97             =head3 DESCRIPTION
98              
99             This node class type evaluates one or more sub-expressions ("terms") and
100             returns C if any of the terms does. It returns C if all of
101             the terms return C.
102              
103             =head3 ATTRIBUTES
104              
105             =head4 terms
106              
107             The sub-expressions to evaluate.
108              
109             =cut
110              
111 2     2   822 use Moo;
  2         5  
  2         7  
112             # 'use Moo' implies 'use strict; use warnings;'
113             extends 'Cucumber::TagExpressions::Node';
114              
115 2     2   608 use List::Util qw( all reduce );
  2         5  
  2         498  
116              
117             has terms => ( is => 'ro', required => 1 );
118              
119             sub evaluate {
120 24     24 1 32 my ( $self, $tags ) = @_;
121              
122 24     38   67 return all { $_->evaluate( $tags ) } @{ $self->terms };
  38         66  
  24         86  
123             }
124              
125             sub stringify {
126 0     0 1 0 my ( $self ) = @_;
127              
128             return
129 0     0   0 reduce { '( ' . $a . ' and ' . $b . ' )' }
130 0         0 map { $_->stringify }
131 0         0 @{ $self->terms };
  0         0  
132             }
133             }
134              
135             package Cucumber::TagExpressions::OrNode {
136             $Cucumber::TagExpressions::OrNode::VERSION = '6.0.0';
137             =head2 Cucumber::TagExpressions::OrNode
138              
139             =head3 DESCRIPTION
140              
141             This node class type evaluates one or more sub-expressions ("terms") and
142             returns C if any of the terms does. It returns C if all of
143             the terms return C.
144              
145             =head3 ATTRIBUTES
146              
147             =head4 terms
148              
149             The sub-expressions to evaluate.
150              
151             =cut
152              
153 2     2   14 use Moo;
  2         3  
  2         14  
154             # 'use Moo' implies 'use strict; use warnings;'
155             extends 'Cucumber::TagExpressions::Node';
156              
157 2     2   618 use List::Util qw( any reduce );
  2         5  
  2         499  
158              
159             has terms => ( is => 'ro', required => 1 );
160              
161             sub evaluate {
162 34     34 1 50 my ( $self, $tags ) = @_;
163              
164 34     55   97 return any { $_->evaluate( $tags ) } @{ $self->terms };
  55         108  
  34         86  
165             }
166              
167             sub stringify {
168 0     0 1 0 my ( $self ) = @_;
169              
170             return
171 0     0   0 reduce { '( ' . $a . ' or ' . $b . ' )' }
172 0         0 map { $_->stringify }
173 0         0 @{ $self->terms };
  0         0  
174             }
175             }
176              
177             package Cucumber::TagExpressions::NotNode {
178             $Cucumber::TagExpressions::NotNode::VERSION = '6.0.0';
179             =head2 Cucumber::TagExpressions::NotNode
180              
181             =head3 DESCRIPTION
182              
183             This class wraps one of the other node class types, negating its
184             result on evaluation.
185              
186             =head3 ATTRIBUTES
187              
188             =head4 expression
189              
190             The wrapped node class instance for which to negate the result.
191              
192             =cut
193              
194 2     2   14 use Moo;
  2         4  
  2         10  
195             # 'use Moo' implies 'use strict; use warnings;'
196             extends 'Cucumber::TagExpressions::Node';
197              
198             has expression => ( is => 'ro', required => 1 );
199              
200             sub evaluate {
201 19     19 1 32 my ( $self, $tags ) = @_;
202              
203 19         36 return not $self->expression->evaluate( $tags );
204             }
205              
206             sub stringify {
207 0     0 1 0 my ( $self ) = @_;
208 0 0 0     0 if ($self->expression->isa('Cucumber::TagExpressions::AndNode') ||
209             $self->expression->isa('Cucumber::TagExpressions::OrNode')) {
210             # -- HINT: Binary Operators already have already '( ... )'.
211 0         0 return 'not ' . $self->expression->stringify;
212             }
213 0         0 return 'not ( ' . $self->expression->stringify . ' )';
214             }
215             }
216              
217             package Cucumber::TagExpressions::ExpressionNode {
218             $Cucumber::TagExpressions::ExpressionNode::VERSION = '6.0.0';
219             =head2 Cucumber::TagExpressions::ExpressionNode
220              
221             =head3 DESCRIPTION
222              
223             This class models the outer-most node in the tag expression; it wraps all
224             other nodes and is the entry-point for tag expression evaluation.
225              
226             =head3 ATTRIBUTES
227              
228             =head4 sub_expression
229              
230             An instance of one of the other node class types.
231              
232             =cut
233              
234 2     2   911 use Moo;
  2         4  
  2         9  
235             # 'use Moo' implies 'use strict; use warnings;'
236             extends 'Cucumber::TagExpressions::Node';
237              
238             has sub_expression => ( is => 'ro', required => 1 );
239              
240             sub evaluate {
241 48     48 1 8361 my ( $self, @tags ) = @_;
242             my $tags = (ref $tags[0] and ref $tags[0] eq 'HASH') ? $tags[0]
243 48 50 33     129 : { map { $_ => 1 } @tags };
  63         173  
244              
245 48 50       139 return 1==1 if not defined $self->sub_expression;
246 48         130 return not not $self->sub_expression->evaluate( $tags );
247             }
248              
249             sub stringify {
250 0     0 1   my ( $self ) = @_;
251              
252 0 0         return 'true' if not defined $self->sub_expression;
253 0           return $self->sub_expression->stringify;
254             }
255             }
256              
257              
258             1;
259              
260             __END__