File Coverage

blib/lib/App/BoolFindGrep/Bool.pm
Criterion Covered Total %
statement 108 109 99.0
branch 27 34 79.4
condition 5 6 83.3
subroutine 14 14 100.0
pod 5 5 100.0
total 159 168 94.6


line stmt bran cond sub pod time code
1             package App::BoolFindGrep::Bool;
2              
3 2     2   827 use common::sense;
  2         3  
  2         13  
4 2     2   5684 use charnames q(:full);
  2         35833  
  2         11  
5 2     2   353 use Carp;
  2         2  
  2         173  
6 2     2   10 use English qw[-no_match_vars];
  2         4  
  2         12  
7 2     2   877 use List::Util qw[first];
  2         3  
  2         117  
8 2     2   1859 use Text::Balanced qw[extract_delimited extract_multiple];
  2         27160  
  2         208  
9 2     2   854 use Moo;
  2         15737  
  2         12  
10              
11             our $VERSION = '0.04'; # 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 43     43 1 553 my $self = shift;
33              
34 43 50       137 return 1 unless defined $self->expression();
35 43 50       107 return 1 if $self->expression() eq q();
36              
37 43         119 $self->operands(undef);
38 43         130 $self->parse(undef);
39              
40 43         131 my @token = $self->tokenizer( $self->expression() );
41              
42 39 50       112 return unless $self->lazy_checker(@token);
43              
44 36         130 $self->operands_collector(@token);
45 34         75 my @expression = @token;
46              
47 34         83 $self->parse( [@expression] );
48              
49 34         128 return 1;
50             } ## end sub parse_expr
51              
52             sub tokenizer {
53 43     43 1 49 my $self = shift;
54 43         68 my $expression = shift;
55              
56 43         46 my $op = join qq(\N{VERTICAL LINE}), keys %{ $self->operators() };
  43         200  
57              
58 43         55 my @expression;
59 43 100       963 if ( $self->slash_as_delim() ) {
60             @expression = extract_multiple(
61             $expression, #
62 32     328   381 [ sub { extract_delimited( $_[0], '/' ) } ], #
  328         16768  
63             );
64             }
65             else {
66 11         601 @expression = $expression;
67 11         31 $expression[0] =~ s{\N{SOLIDUS}}{\N{REVERSE SOLIDUS}\N{SOLIDUS}}gmsx;
68             }
69              
70 43         2037 foreach (@expression) {
71              
72 47         129 s{\A\p{IsSpace}}{}msx;
73 47         106 s{\p{IsSpace}\z}{}msx;
74              
75 47 100 66     192 if ( m{\A\N{SOLIDUS}}msx
76             && m{(?
77             {
78 8 100       946 croak sprintf q(Syntax Error in expression: '%s'),
79             $self->expression()
80             if length() < 3;
81 4         7 next;
82             }
83              
84             s{(?
85 39         223 {\N{LINE FEED}$1\N{LINE FEED}}gmsx;
86              
87 39         843 s{(?:\A|\s)(${op})(?=\s|\z)} # OPERATORS
88             {\N{LINE FEED}$1\N{LINE FEED}}gimsx;
89              
90 39         230 s{\A\p{IsSpace}+}{}msx;
91 39         208 s{\p{IsSpace}+\z}{}msx;
92              
93 39         351 s{\N{SPACE}*\N{LINE FEED}+\N{SPACE}*}
94             {\N{LINE FEED}}gmsx;
95              
96             } ## end foreach (@expression)
97              
98 39         72 my @token = map { split m{\N{LINE FEED}}msx } @expression;
  43         260  
99 39 50       65 @token = grep { defined && $_ ne q() } @token;
  172         672  
100              
101 39         63 foreach my $token (@token) {
102 161 100 100     763 if ( $token eq qq(\N{LEFT PARENTHESIS})
    100          
103             || $token eq qq(\N{RIGHT PARENTHESIS}) )
104             {
105 40         91 $token = [ q(PARENTHESIS), $token ];
106             }
107             elsif ( exists $self->operators->{uc $token} ) {
108 48         115 $token = [ q(OPERATOR), uc $token ],;
109             }
110             else {
111 73 100       170 if ($token =~ #
112             m{\A\N{SOLIDUS}
113             (?.*?)
114             (?
115             }msx
116             )
117             {
118 4         27 $token = $LAST_PAREN_MATCH{token};
119             }
120 73         92 $token =~ s{\N{REVERSE SOLIDUS}\N{SOLIDUS}}
121             {\N{SOLIDUS}}gmsx;
122              
123 73         181 $token = [ q(OPERAND), $token ];
124             } ## end else [ if ( $token eq qq(\N{LEFT PARENTHESIS})...)]
125             } ## end foreach my $token (@token)
126              
127 39         164 return @token;
128             } ## end sub tokenizer
129              
130             sub lazy_checker {
131 39     39 1 62 my $self = shift;
132 39         101 my @token = splice @_;
133              
134 39         40 my $status;
135              
136 39         64 foreach my $token (@token) {
137 161         239 my ( $name, $value ) = @$token;
138 161 100       272 if ( $name eq q(OPERAND) ) {
    100          
139 73         135 $token = 1;
140             }
141             elsif ( $name eq q(OPERATOR) ) {
142 48         127 $token = $self->operators->{$value};
143             }
144 40         74 else { $token = $value; }
145             }
146              
147 39         115 my $expression = join qq(\N{SPACE}), @token;
148 39         51 $EVAL_ERROR = q();
149 39         3905 eval $expression;
150 39 100       282 if ($EVAL_ERROR) {
151 3         395 croak sprintf q(Syntax Error in expression: '%s'),
152             $self->expression();
153             }
154 36         64 else { $status = 1; }
155              
156 36         128 return $status;
157             } ## end sub lazy_checker
158              
159             sub operands_collector {
160 36     36 1 69 my $self = shift;
161 36         94 my @token = splice @_;
162              
163 36         42 my %operand;
164 36         54 foreach my $token (@token) {
165 149         221 my ( $name, $value ) = @$token;
166 149 100       270 next if $name ne q(OPERAND);
167 69         168 $operand{$value} = 1;
168             }
169              
170 36 100       152 unless (%operand) {
171 2         356 croak sprintf q(Syntax Error in expression: '%s'),
172             $self->expression();
173             }
174              
175 34         165 $self->operands( [ keys %operand ] );
176              
177 34         91 return 1;
178             } ## end sub operands_collector
179              
180             sub lazy_solver {
181 3960     3960 1 4103 my $self = shift;
182 3960         7734 my %operand = splice @_;
183              
184 3960         3461 my @expression;
185 3960         3028 foreach my $token ( @{ $self->parse() } ) {
  3960         7213  
186 3960         5068 my ( $name, $value ) = @$token;
187 3960 50       6221 if ( $name eq q(OPERAND) ) {
    0          
188 3960         4406 $value = $operand{$value};
189             }
190             elsif ( $name eq q(OPERATOR) ) {
191 0         0 $value = $self->operators->{$value};
192             }
193 3960         7351 push @expression, $value;
194             }
195 3960         7061 my $expression = join qq(\N{SPACE}), @expression;
196 3960         238542 my $result = eval $expression;
197              
198 3960         29541 return $result;
199             } ## end sub lazy_solver
200              
201 2     2   29977 no Moo;
  2         4  
  2         13  
202             __PACKAGE__->meta->make_immutable;
203              
204             1;
205              
206             __END__