File Coverage

blib/lib/Text/Split.pm
Criterion Covered Total %
statement 97 115 84.3
branch 48 66 72.7
condition 10 15 66.6
subroutine 16 20 80.0
pod 1 13 7.6
total 172 229 75.1


line stmt bran cond sub pod time code
1             package Text::Split;
2             BEGIN {
3 4     4   371944 $Text::Split::VERSION = '0.0013';
4             }
5             # ABSTRACT: Text splitting with fine-grained control
6              
7              
8 4     4   3112 use Any::Moose;
  4         161592  
  4         31  
9              
10             has data => qw/ reader data writer _data required 1 /;
11             has [qw/ start head tail mhead mtail /] => qw/ is rw required 1 isa Int default 0 /;
12             has _parent => qw/ is ro isa Maybe[Text::Split] init_arg parent /;
13              
14             has found => qw/ is ro required 1 isa Str /, default => '';
15             has content => qw/ is ro required 1 isa Str /, default => '';
16             has _matched => qw/ init_arg matched is ro isa ArrayRef /, default => sub { [] };
17 0     0 0 0 sub matched { return @{ $_[0]->matched } }
  0         0  
18             has matcher => qw/ is ro /, default => undef;
19              
20             has default => qw/ is ro lazy_build 1 isa HashRef /;
21             sub _build_default { {
22 7     7   222 slurp => '[)',
23             } }
24              
25             sub BUILD {
26 22     22 1 36 my $self = shift;
27 22         56 my $data = $self->data;
28 22 100       87 if ( ref $data ne 'SCALAR' ) {
29 7         19 chomp $data;
30 7 50       24 $data .= "\n" if length $data;
31 7         49 $self->_data( \$data );
32             }
33             }
34              
35             sub _fhead ($$) {
36 15     15   27 my ( $data, $from ) = @_;
37 15         33 my $i0 = rindex $$data, "\n", $from;
38 15 50       53 return $i0 + 1 unless -1 == $i0;
39 0         0 return 0;
40             }
41              
42             sub _ftail ($$) {
43 15     15   24 my ( $data, $from ) = @_;
44 15         22 my $i0 = index $$data, "\n", $from;
45 15 50       44 return $i0 unless -1 == $i0;
46 0         0 return -1 + length $$data;
47             }
48              
49             sub parent {
50 11     11 0 16 my $self = shift;
51 11 50       55 if ( my $parent = $self->_parent ) { return $parent }
  11         49  
52 0         0 return $self; # We are the base (root) split
53             }
54              
55             sub is_root {
56 5     5 0 6 my $self = shift;
57 5         31 return ! $self->_parent;
58             }
59              
60             sub _strip_edness ($) {
61 35     35   42 my $slurp = $_[0];
62 35 50 33     90 $slurp->{chomp} = delete $slurp->{chomped} if
63             exists $slurp->{chomped} && not exists $slurp->{chomp};
64 35 100 66     143 $slurp->{trim} = delete $slurp->{trimmed} if
65             exists $slurp->{trimmed} && not exists $slurp->{trim};
66             }
67              
68             sub _parse_slurp ($@) {
69 22     22   32 my $slurp = shift;
70 22         40 my %slurp = @_; # Can/will be overidden
71              
72 22         40 _strip_edness \%slurp;
73              
74 22 50       50 if ( ref $slurp eq 'HASH' ) {
75 0         0 $slurp = { %$slurp };
76 0         0 _strip_edness $slurp;
77 0         0 %slurp = ( %slurp, %$slurp );
78             }
79             else {
80 22 50       96 $slurp =~
81             m{^
82             ([\@\$])?
83             ([\(\[])
84             ([\)\]])
85             (/)?
86             }x or die "Invalid slurp pattern ($slurp)";
87              
88 22 100       84 $slurp{wantlist} = $1 eq '@' ? 1 : 0 if $1;
    100          
89 22 100       67 $slurp{slurpl} = $2 eq '[' ? 1 : 0;
90 22 100       54 $slurp{slurpr} = $3 eq ']' ? 1 : 0;
91 22 50       67 $slurp{chomp} = 1 if $4;
92             }
93              
94 22         105 return %slurp;
95             }
96              
97             sub find {
98 12     12 0 169 return shift->split( @_ );
99             }
100              
101             sub split {
102 16     16 0 33 my $self = shift;
103 16         34 my $matcher;
104 16 50       55 $matcher = shift if @_ % 2; # Odd number of arguments
105 16         35 my %given = @_;
106              
107 16         41 my $data = $self->data;
108 16         26 my $length = length $$data;
109 16 50       40 return unless $length; # Nothing to split
110              
111 16 100       73 my $from = $self->_parent ? $self->tail + 1 : 0;
112 16 100       44 return if $length <= $from; # Was already at end of data
113              
114 15         50 pos $data = $from;
115 15 50       479 return unless $$data =~ m/\G[[:ascii:]]*?($matcher)/mgc;
116 15         58 my @match = map { substr $$data, $-[$_], $+[$_] - $-[$_] } ( 0 .. -1 + scalar @- );
  36         209  
117 15         26 shift @match;
118 15         23 my $found = shift @match;
119 15         49 my ( $mhead, $mtail ) = ( $-[1], $+[1] - 1 );
120              
121 15         46 my $head = _fhead $data, $mhead;
122 15         36 my $tail = _ftail $data, $mtail;
123              
124             # TODO This is hacky
125 15         34 my @matched = @match;
126              
127 15         37 my $content = substr $$data, $head, 1 + $tail - $head;
128              
129 15         271 my $split = __PACKAGE__->new(
130             data => $data, parent => $self,
131             start => $from, mhead => $mhead, mtail => $mtail, head => $head, tail => $tail,
132             matcher => $matcher, found => $found, matched => \@matched,
133             content => $content,
134             default => $self->default,
135             );
136              
137 15 100 66     155 return $split unless wantarray && ( my $slurp = delete $given{slurp} );
138 3         11 return ( $split, $split->slurp( $slurp, %given ) );
139             }
140              
141             sub slurp {
142 13     13 0 35 my $self = shift;
143 13         18 my $slurp = 1;
144 13 100       46 $slurp = shift if @_ % 2; # Odd number of arguments
145 13         55 my %given = @_;
146              
147 13         19 my $split = $self;
148              
149 13         45 _strip_edness \%given;
150 13         58 my %slurp = _parse_slurp $self->default->{slurp};
151 13   66     86 exists $given{$_} and $slurp{$_} = $given{$_} for qw/ chomp trim /;
152 13 100       56 %slurp = _parse_slurp $slurp, %slurp unless $slurp eq 1;
153              
154 13         25 my @content;
155 13 100       52 push @content, $self->parent->content if $slurp{slurpl};
156 13         38 push @content, $split->preceding;
157 13 100       37 push @content, $split->content if $slurp{slurpr};
158              
159 13         27 my $content = join '', @content;
160 13 100       33 if ( $slurp{trim} ) {
161 3         29 s/^\s*//, s/\s*$//, for $content;
162             }
163              
164 13 100 100     63 if ( wantarray && $slurp{wantlist} ) {
165 4         30 @content = grep { $_ ne "\n" } split m/(\n)/, $content;
  30         59  
166 4 50       14 @content = map { "$_\n" } @content unless $slurp{chomp};
  0         0  
167 4         49 return @content;
168             }
169             else {
170 9         57 return $content;
171             }
172             }
173              
174             sub preceding {
175 17     17 0 38 my $self = shift;
176              
177 17         41 my $data = $self->data;
178 17         70 my $length = $self->head - $self->start;
179 17 100       55 return '' unless $length;
180 16         67 return substr $$data, $self->start, $length;
181             }
182 0     0 0 0 sub pre { return shift->preceding( @_ ) }
183              
184             sub remaining {
185 5     5 0 9 my $self = shift;
186              
187 5         15 my $data = $self->data;
188 5 100       16 return $$data if $self->is_root;
189              
190 4         14 my $from = $self->tail + 1;
191              
192 4         7 my $length = length( $$data ) - $from + 1;
193 4 50       10 return '' unless $length;
194 4         18 return substr $$data, $from, $length;
195             }
196 0     0 0 0 sub re { return shift->remaining( @_ ) }
197              
198             sub match {
199 4     4 0 18 my $self = shift;
200 4         21 my $ii = shift;
201 4 50       12 return $self->found if $ii == -1;
202 4         30 return $self->_matched->[$ii];
203             }
204              
205             sub is {
206 0     0 0   my $self = shift;
207 0           my $ii = shift;
208 0           my $is = shift;
209              
210 0 0         return unless defined ( my $match = $self->match( $ii ) );
211 0 0         if ( ref $is eq 'Regexp' ) { $match =~ $is }
  0            
212 0           else { return $match eq $is }
213             }
214              
215             1;
216              
217             __END__