File Coverage

blib/lib/App/BoolFindGrep/Bool.pm
Criterion Covered Total %
statement 94 109 86.2
branch 25 34 73.5
condition 5 6 83.3
subroutine 13 14 92.8
pod 5 5 100.0
total 142 168 84.5


line stmt bran cond sub pod time code
1             package App::BoolFindGrep::Bool;
2              
3 1     1   574 use common::sense;
  1         1  
  1         7  
4 1     1   527 use charnames q(:full);
  1         36715  
  1         6  
5 1     1   217 use Carp;
  1         2  
  1         93  
6 1     1   6 use English qw[-no_match_vars];
  1         2  
  1         6  
7 1     1   536 use List::Util qw[first];
  1         2  
  1         77  
8 1     1   654625 use Text::Balanced qw[extract_delimited extract_multiple];
  1         185432  
  1         85  
9 1     1   591 use Moo;
  1         313553  
  1         6  
10              
11             our $VERSION = '0.03'; # VERSION
12              
13             has slash_as_delim => (
14             is => q(rw),
15             isa => sub { ( $_[0] == 0 || $_[0] == 1 ) or die },
16             default => 0,
17             );
18             has operators => (
19             is => q(ro),
20             default => sub {
21             { AND => q(&&), #
22             OR => q(||), #
23             NOT => q(!), #
24             };
25             },
26             );
27             has expression => ( is => q(rw), default => undef );
28             has operands => ( is => q(rw), default => sub { []; }, );
29             has parse => ( is => q(rw), default => sub { []; }, );
30              
31             sub parse_expr {
32 32     32 1 511 my $self = shift;
33              
34 32 50       96 return 1 unless defined $self->expression();
35 32 50       91 return 1 if $self->expression() eq q();
36              
37 32         80 $self->operands(undef);
38 32         94 $self->parse(undef);
39              
40 32         98 my @token = $self->tokenizer( $self->expression() );
41              
42 28 50       102 return unless $self->lazy_checker(@token);
43              
44 25         86 $self->operands_collector(@token);
45 23         56 my @expression = @token;
46              
47 23         73 $self->parse( [@expression] );
48              
49 23         95 return 1;
50             } ## end sub parse_expr
51              
52             sub tokenizer {
53 32     32 1 44 my $self = shift;
54 32         39 my $expression = shift;
55              
56 32         40 my $op = join qq(\N{VERTICAL LINE}), keys %{ $self->operators() };
  32         157  
57              
58 32         48 my @expression;
59 32 50       768 if ( $self->slash_as_delim() ) {
60             @expression = extract_multiple(
61             $expression, #
62 32     328   368 [ sub { extract_delimited( $_[0], '/' ) } ], #
  328         16840  
63             );
64             }
65             else {
66 0         0 @expression = $expression;
67 0         0 $expression[0] =~ s{\N{SOLIDUS}}{\N{REVERSE SOLIDUS}\N{SOLIDUS}}gmsx;
68             }
69              
70 32         2220 foreach (@expression) {
71              
72 36         100 s{\A\p{IsSpace}}{}msx;
73 36         75 s{\p{IsSpace}\z}{}msx;
74              
75 36 100 66     160 if ( m{\A\N{SOLIDUS}}msx
76             && m{(?
77             {
78 8 100       844 croak sprintf q(Syntax Error in expression: '%s'),
79             $self->expression()
80             if length() < 3;
81 4         8 next;
82             }
83              
84             s{(?
85 28         210 {\N{LINE FEED}$1\N{LINE FEED}}gmsx;
86              
87 28         455 s{(?:\A|\s)(${op})(?=\s|\z)} # OPERATORS
88             {\N{LINE FEED}$1\N{LINE FEED}}gimsx;
89              
90 28         157 s{\A\p{IsSpace}+}{}msx;
91 28         182 s{\p{IsSpace}+\z}{}msx;
92              
93 28         277 s{\N{SPACE}*\N{LINE FEED}+\N{SPACE}*}
94             {\N{LINE FEED}}gmsx;
95              
96             } ## end foreach (@expression)
97              
98 28         69 my @token = map { split m{\N{LINE FEED}}msx } @expression;
  32         207  
99 28 50       66 @token = grep { defined && $_ ne q() } @token;
  161         615  
100              
101 28         49 foreach my $token (@token) {
102 150 100 100     760 if ( $token eq qq(\N{LEFT PARENTHESIS})
    100          
103             || $token eq qq(\N{RIGHT PARENTHESIS}) )
104             {
105 40         94 $token = [ q(PARENTHESIS), $token ];
106             }
107             elsif ( exists $self->operators->{uc $token} ) {
108 48         111 $token = [ q(OPERATOR), uc $token ],;
109             }
110             else {
111 62 100       136 if ($token =~ #
112             m{\A\N{SOLIDUS}
113             (?.*?)
114             (?
115             }msx
116             )
117             {
118 4         32 $token = $LAST_PAREN_MATCH{token};
119             }
120 62         74 $token =~ s{\N{REVERSE SOLIDUS}\N{SOLIDUS}}
121             {\N{SOLIDUS}}gmsx;
122              
123 62         146 $token = [ q(OPERAND), $token ];
124             } ## end else [ if ( $token eq qq(\N{LEFT PARENTHESIS})...)]
125             } ## end foreach my $token (@token)
126              
127 28         147 return @token;
128             } ## end sub tokenizer
129              
130             sub lazy_checker {
131 28     28 1 103 my $self = shift;
132 28         82 my @token = splice @_;
133              
134 28         28 my $status;
135              
136 28         42 foreach my $token (@token) {
137 150         178 my ( $name, $value ) = @$token;
138 150 100       309 if ( $name eq q(OPERAND) ) {
    100          
139 62         106 $token = 1;
140             }
141             elsif ( $name eq q(OPERATOR) ) {
142 48         122 $token = $self->operators->{$value};
143             }
144 40         73 else { $token = $value; }
145             }
146              
147 28         89 my $expression = join qq(\N{SPACE}), @token;
148 28         36 $EVAL_ERROR = q();
149 28         2722 eval $expression;
150 28 100       240 if ($EVAL_ERROR) {
151 3         636 croak sprintf q(Syntax Error in expression: '%s'),
152             $self->expression();
153             }
154 25         34 else { $status = 1; }
155              
156 25         100 return $status;
157             } ## end sub lazy_checker
158              
159             sub operands_collector {
160 25     25 1 207 my $self = shift;
161 25         82 my @token = splice @_;
162              
163 25         30 my %operand;
164 25         49 foreach my $token (@token) {
165 138         162 my ( $name, $value ) = @$token;
166 138 100       297 next if $name ne q(OPERAND);
167 58         155 $operand{$value} = 1;
168             }
169              
170 25 100       103 unless (%operand) {
171 2         356 croak sprintf q(Syntax Error in expression: '%s'),
172             $self->expression();
173             }
174              
175 23         115 $self->operands( [ keys %operand ] );
176              
177 23         71 return 1;
178             } ## end sub operands_collector
179              
180             sub lazy_solver {
181 0     0 1   my $self = shift;
182 0           my %operand = splice @_;
183              
184 0           my @expression;
185 0           foreach my $token ( @{ $self->parse() } ) {
  0            
186 0           my ( $name, $value ) = @$token;
187 0 0         if ( $name eq q(OPERAND) ) {
    0          
188 0           $value = $operand{$value};
189             }
190             elsif ( $name eq q(OPERATOR) ) {
191 0           $value = $self->operators->{$value};
192             }
193 0           push @expression, $value;
194             }
195 0           my $expression = join qq(\N{SPACE}), @expression;
196 0           my $result = eval $expression;
197              
198 0           return $result;
199             } ## end sub lazy_solver
200              
201 1     1   14745 no Moo;
  1         3  
  1         9  
202             __PACKAGE__->meta->make_immutable;
203              
204             1;
205              
206             __END__