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   590 use common::sense;
  2         4  
  2         10  
4 2     2   560 use charnames q(:full);
  2         23805  
  2         9  
5 2     2   290 use Carp;
  2         3  
  2         116  
6 2     2   8 use English qw[-no_match_vars];
  2         3  
  2         9  
7 2     2   619 use List::Util qw[first];
  2         4  
  2         113  
8 2     2   1311 use Text::Balanced qw[extract_delimited extract_multiple];
  2         21074  
  2         167  
9 2     2   569 use Moo;
  2         11410  
  2         12  
10              
11             our $VERSION = '0.06'; # 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 449 my $self = shift;
33              
34 43 50       127 return 1 unless defined $self->expression();
35 43 50       113 return 1 if $self->expression() eq q();
36              
37 43         103 $self->operands(undef);
38 43         100 $self->parse(undef);
39              
40 43         118 my @token = $self->tokenizer( $self->expression() );
41              
42 39 50       117 return unless $self->lazy_checker(@token);
43              
44 36         111 $self->operands_collector(@token);
45 34         64 my @expression = @token;
46              
47 34         77 $self->parse( [@expression] );
48              
49 34         105 return 1;
50             } ## end sub parse_expr
51              
52             sub tokenizer {
53 43     43 1 54 my $self = shift;
54 43         53 my $expression = shift;
55              
56 43         58 my $op = join qq(\N{VERTICAL LINE}), keys %{ $self->operators() };
  43         202  
57              
58 43         60 my @expression;
59 43 100       815 if ( $self->slash_as_delim() ) {
60             @expression = extract_multiple(
61             $expression, #
62 32     328   319 [ sub { extract_delimited( $_[0], '/' ) } ], #
  328         13645  
63             );
64             }
65             else {
66 11         532 @expression = $expression;
67 11         33 $expression[0] =~ s{\N{SOLIDUS}}{\N{REVERSE SOLIDUS}\N{SOLIDUS}}gmsx;
68             }
69              
70 43         1694 foreach (@expression) {
71              
72 47         127 s{\A\p{IsSpace}}{}msx;
73 47         98 s{\p{IsSpace}\z}{}msx;
74              
75 47 100 66     193 if ( m{\A\N{SOLIDUS}}msx
76             && m{(?
77             {
78 8 100       577 croak sprintf q(Syntax Error in expression: '%s'),
79             $self->expression()
80             if length() < 3;
81 4         8 next;
82             }
83              
84             s{(?
85 39         185 {\N{LINE FEED}$1\N{LINE FEED}}gmsx;
86              
87 39         945 s{(?:\A|\s)(${op})(?=\s|\z)} # OPERATORS
88             {\N{LINE FEED}$1\N{LINE FEED}}gimsx;
89              
90 39         173 s{\A\p{IsSpace}+}{}msx;
91 39         197 s{\p{IsSpace}+\z}{}msx;
92              
93 39         287 s{\N{SPACE}*\N{LINE FEED}+\N{SPACE}*}
94             {\N{LINE FEED}}gmsx;
95              
96             } ## end foreach (@expression)
97              
98 39         71 my @token = map { split m{\N{LINE FEED}}msx } @expression;
  43         219  
99 39 50       63 @token = grep { defined && $_ ne q() } @token;
  172         602  
100              
101 39         70 foreach my $token (@token) {
102 161 100 100     689 if ( $token eq qq(\N{LEFT PARENTHESIS})
    100          
103             || $token eq qq(\N{RIGHT PARENTHESIS}) )
104             {
105 40         80 $token = [ q(PARENTHESIS), $token ];
106             }
107             elsif ( exists $self->operators->{uc $token} ) {
108 48         84 $token = [ q(OPERATOR), uc $token ],;
109             }
110             else {
111 73 100       168 if ($token =~ #
112             m{\A\N{SOLIDUS}
113             (?.*?)
114             (?
115             }msx
116             )
117             {
118 4         30 $token = $LAST_PAREN_MATCH{token};
119             }
120 73         92 $token =~ s{\N{REVERSE SOLIDUS}\N{SOLIDUS}}
121             {\N{SOLIDUS}}gmsx;
122              
123 73         152 $token = [ q(OPERAND), $token ];
124             } ## end else [ if ( $token eq qq(\N{LEFT PARENTHESIS})...)]
125             } ## end foreach my $token (@token)
126              
127 39         140 return @token;
128             } ## end sub tokenizer
129              
130             sub lazy_checker {
131 39     39 1 49 my $self = shift;
132 39         105 my @token = splice @_;
133              
134 39         39 my $status;
135              
136 39         68 foreach my $token (@token) {
137 161         176 my ( $name, $value ) = @$token;
138 161 100       257 if ( $name eq q(OPERAND) ) {
    100          
139 73         111 $token = 1;
140             }
141             elsif ( $name eq q(OPERATOR) ) {
142 48         88 $token = $self->operators->{$value};
143             }
144 40         55 else { $token = $value; }
145             }
146              
147 39         102 my $expression = join qq(\N{SPACE}), @token;
148 39         53 $EVAL_ERROR = q();
149 39         3569 eval $expression;
150 39 100       282 if ($EVAL_ERROR) {
151 3         500 croak sprintf q(Syntax Error in expression: '%s'),
152             $self->expression();
153             }
154 36         54 else { $status = 1; }
155              
156 36         133 return $status;
157             } ## end sub lazy_checker
158              
159             sub operands_collector {
160 36     36 1 55 my $self = shift;
161 36         99 my @token = splice @_;
162              
163 36         44 my %operand;
164 36         61 foreach my $token (@token) {
165 149         154 my ( $name, $value ) = @$token;
166 149 100       277 next if $name ne q(OPERAND);
167 69         148 $operand{$value} = 1;
168             }
169              
170 36 100       140 unless (%operand) {
171 2         341 croak sprintf q(Syntax Error in expression: '%s'),
172             $self->expression();
173             }
174              
175 34         148 $self->operands( [ keys %operand ] );
176              
177 34         87 return 1;
178             } ## end sub operands_collector
179              
180             sub lazy_solver {
181 3960     3960 1 3931 my $self = shift;
182 3960         7237 my %operand = splice @_;
183              
184 3960         3138 my @expression;
185 3960         3200 foreach my $token ( @{ $self->parse() } ) {
  3960         6104  
186 3960         4552 my ( $name, $value ) = @$token;
187 3960 50       5820 if ( $name eq q(OPERAND) ) {
    0          
188 3960         4250 $value = $operand{$value};
189             }
190             elsif ( $name eq q(OPERATOR) ) {
191 0         0 $value = $self->operators->{$value};
192             }
193 3960         6376 push @expression, $value;
194             }
195 3960         5852 my $expression = join qq(\N{SPACE}), @expression;
196 3960         208527 my $result = eval $expression;
197              
198 3960         25647 return $result;
199             } ## end sub lazy_solver
200              
201 2     2   25956 no Moo;
  2         5  
  2         14  
202             __PACKAGE__->meta->make_immutable;
203              
204             1;
205              
206             __END__