File Coverage

blib/lib/Text/Clip.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::Clip;
2             BEGIN {
3 4     4   355525 $Text::Clip::VERSION = '0.0014';
4             }
5             # ABSTRACT: Clip and extract text in clipboard-like way
6              
7              
8 4     4   3606 use Any::Moose;
  4         153584  
  4         26  
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::Clip] 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   205 slurp => '[)',
23             } }
24              
25             sub BUILD {
26 22     22 1 38 my $self = shift;
27 22         60 my $data = $self->data;
28 22 100       75 if ( ref $data ne 'SCALAR' ) {
29 7         18 chomp $data;
30 7 50       24 $data .= "\n" if length $data;
31 7         43 $self->_data( \$data );
32             }
33             }
34              
35             sub _fhead ($$) {
36 15     15   25 my ( $data, $from ) = @_;
37 15         31 my $i0 = rindex $$data, "\n", $from;
38 15 50       57 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         25 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 15 my $self = shift;
51 11 50       51 if ( my $parent = $self->_parent ) { return $parent }
  11         41  
52 0         0 return $self; # We are the base (root) split
53             }
54              
55             sub is_root {
56 5     5 0 7 my $self = shift;
57 5         36 return ! $self->_parent;
58             }
59              
60             sub _strip_edness ($) {
61 35     35   42 my $slurp = $_[0];
62 35 50 33     96 $slurp->{chomp} = delete $slurp->{chomped} if
63             exists $slurp->{chomped} && not exists $slurp->{chomp};
64 35 100 66     104 $slurp->{trim} = delete $slurp->{trimmed} if
65             exists $slurp->{trimmed} && not exists $slurp->{trim};
66             }
67              
68             sub _parse_slurp ($@) {
69 22     22   31 my $slurp = shift;
70 22         49 my %slurp = @_; # Can/will be overidden
71              
72 22         54 _strip_edness \%slurp;
73              
74 22 50       47 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       86 $slurp =~
81             m{^
82             ([\@\$])?
83             ([\(\[])
84             ([\)\]])
85             (/)?
86             }x or die "Invalid slurp pattern ($slurp)";
87              
88 22 100       71 $slurp{wantlist} = $1 eq '@' ? 1 : 0 if $1;
    100          
89 22 100       60 $slurp{slurpl} = $2 eq '[' ? 1 : 0;
90 22 100       56 $slurp{slurpr} = $3 eq ']' ? 1 : 0;
91 22 50       59 $slurp{chomp} = 1 if $4;
92             }
93              
94 22         95 return %slurp;
95             }
96              
97             sub find {
98 12     12 0 143 return shift->split( @_ );
99             }
100              
101             sub split {
102 16     16 0 146 my $self = shift;
103 16         61 my $matcher;
104 16 50       71 $matcher = shift if @_ % 2; # Odd number of arguments
105 16         29 my %given = @_;
106              
107 16         46 my $data = $self->data;
108 16         26 my $length = length $$data;
109 16 50       37 return unless $length; # Nothing to split
110              
111 16 100       110 my $from = $self->_parent ? $self->tail + 1 : 0;
112 16 100       40 return if $length <= $from; # Was already at end of data
113              
114 15         50 pos $data = $from;
115 15 50       434 return unless $$data =~ m/\G[[:ascii:]]*?($matcher)/mgc;
116 15         59 my @match = map { substr $$data, $-[$_], $+[$_] - $-[$_] } ( 0 .. -1 + scalar @- );
  36         213  
117 15         25 shift @match;
118 15         27 my $found = shift @match;
119 15         50 my ( $mhead, $mtail ) = ( $-[1], $+[1] - 1 );
120              
121 15         45 my $head = _fhead $data, $mhead;
122 15         34 my $tail = _ftail $data, $mtail;
123              
124             # TODO This is hacky
125 15         27 my @matched = @match;
126              
127 15         41 my $content = substr $$data, $head, 1 + $tail - $head;
128              
129 15         252 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     136 return $split unless wantarray && ( my $slurp = delete $given{slurp} );
138 3         12 return ( $split, $split->slurp( $slurp, %given ) );
139             }
140              
141             sub slurp {
142 13     13 0 31 my $self = shift;
143 13         16 my $slurp = 1;
144 13 100       43 $slurp = shift if @_ % 2; # Odd number of arguments
145 13         31 my %given = @_;
146              
147 13         29 my $split = $self;
148              
149 13         40 _strip_edness \%given;
150 13         77 my %slurp = _parse_slurp $self->default->{slurp};
151 13   66     87 exists $given{$_} and $slurp{$_} = $given{$_} for qw/ chomp trim /;
152 13 100       53 %slurp = _parse_slurp $slurp, %slurp unless $slurp eq 1;
153              
154 13         23 my @content;
155 13 100       48 push @content, $self->parent->content if $slurp{slurpl};
156 13         31 push @content, $split->preceding;
157 13 100       34 push @content, $split->content if $slurp{slurpr};
158              
159 13         24 my $content = join '', @content;
160 13 100       32 if ( $slurp{trim} ) {
161 3         30 s/^\s*//, s/\s*$//, for $content;
162             }
163              
164 13 100 100     64 if ( wantarray && $slurp{wantlist} ) {
165 4         30 @content = grep { $_ ne "\n" } split m/(\n)/, $content;
  30         61  
166 4 50       16 @content = map { "$_\n" } @content unless $slurp{chomp};
  0         0  
167 4         49 return @content;
168             }
169             else {
170 9         51 return $content;
171             }
172             }
173              
174             sub preceding {
175 17     17 0 39 my $self = shift;
176              
177 17         39 my $data = $self->data;
178 17         63 my $length = $self->head - $self->start;
179 17 100       39 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 10 my $self = shift;
186              
187 5         16 my $data = $self->data;
188 5 100       16 return $$data if $self->is_root;
189              
190 4         15 my $from = $self->tail + 1;
191              
192 4         8 my $length = length( $$data ) - $from + 1;
193 4 50       11 return '' unless $length;
194 4         20 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         8 my $ii = shift;
201 4 50       33 return $self->found if $ii == -1;
202 4         35 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__