File Coverage

blib/lib/Pinto/Editor/Clip.pm
Criterion Covered Total %
statement 3 114 2.6
branch 0 66 0.0
condition 0 15 0.0
subroutine 1 19 5.2
pod 0 13 0.0
total 4 227 1.7


line stmt bran cond sub pod time code
1             # ABSTRACT: Internal class for Pinto::Editor
2              
3             package Pinto::Editor::Clip;
4              
5 57     57   370 use Moose;
  57         126  
  57         366  
6              
7             #-----------------------------------------------------------------------------
8              
9             our $VERSION = '0.14'; # VERSION
10              
11             #-----------------------------------------------------------------------------
12              
13             has data => qw/ reader data writer _data required 1 /;
14             has [qw/ start head tail mhead mtail /] => qw/ is rw required 1 isa Int default 0 /;
15             has _parent => qw/ is ro isa Maybe[Pinto::Editor::Clip] init_arg parent /;
16              
17             has found => qw/ is ro required 1 isa Str /, default => '';
18             has content => qw/ is ro required 1 isa Str /, default => '';
19             has _matched => qw/ init_arg matched is ro isa ArrayRef /, default => sub { [] };
20 0     0 0   sub matched { return @{ $_[0]->matched } }
  0            
21             has matcher => qw/ is ro /, default => undef;
22              
23             has default => qw/ is ro lazy_build 1 isa HashRef /;
24              
25             #-----------------------------------------------------------------------------
26              
27             sub _build_default { {
28 0     0     slurp => '[)',
29             } }
30              
31             #-----------------------------------------------------------------------------
32              
33             sub BUILD {
34 0     0 0   my $self = shift;
35 0           my $data = $self->data;
36 0 0         if ( ref $data ne 'SCALAR' ) {
37 0           chomp $data;
38 0 0         $data .= "\n" if length $data;
39 0           $self->_data( \$data );
40             }
41             }
42              
43             #-----------------------------------------------------------------------------
44              
45             sub _fhead ($$) {
46 0     0     my ( $data, $from ) = @_;
47 0           my $i0 = rindex $$data, "\n", $from;
48 0 0         return $i0 + 1 unless -1 == $i0;
49 0           return 0;
50             }
51              
52             #-----------------------------------------------------------------------------
53              
54             sub _ftail ($$) {
55 0     0     my ( $data, $from ) = @_;
56 0           my $i0 = index $$data, "\n", $from;
57 0 0         return $i0 unless -1 == $i0;
58 0           return -1 + length $$data;
59             }
60              
61             #-----------------------------------------------------------------------------
62              
63             sub parent {
64 0     0 0   my $self = shift;
65 0 0         if ( my $parent = $self->_parent ) { return $parent }
  0            
66 0           return $self; # We are the base (root) split
67             }
68              
69             #-----------------------------------------------------------------------------
70              
71             sub is_root {
72 0     0 0   my $self = shift;
73 0           return ! $self->_parent;
74             }
75              
76             #-----------------------------------------------------------------------------
77              
78             sub _strip_edness ($) {
79 0     0     my $slurp = $_[0];
80             $slurp->{chomp} = delete $slurp->{chomped} if
81 0 0 0       exists $slurp->{chomped} && not exists $slurp->{chomp};
82             $slurp->{trim} = delete $slurp->{trimmed} if
83 0 0 0       exists $slurp->{trimmed} && not exists $slurp->{trim};
84             }
85              
86             #-----------------------------------------------------------------------------
87              
88             sub _parse_slurp ($@) {
89 0     0     my $slurp = shift;
90 0           my %slurp = @_; # Can/will be overidden
91              
92 0           _strip_edness \%slurp;
93              
94 0 0         if ( ref $slurp eq 'HASH' ) {
95 0           $slurp = { %$slurp };
96 0           _strip_edness $slurp;
97 0           %slurp = ( %slurp, %$slurp );
98             }
99             else {
100 0 0         $slurp =~
101             m{^
102             ([\@\$])?
103             ([\(\[])
104             ([\)\]])
105             (/)?
106             }x or die "Invalid slurp pattern ($slurp)";
107              
108 0 0         $slurp{wantlist} = $1 eq '@' ? 1 : 0 if $1;
    0          
109 0 0         $slurp{slurpl} = $2 eq '[' ? 1 : 0;
110 0 0         $slurp{slurpr} = $3 eq ']' ? 1 : 0;
111 0 0         $slurp{chomp} = 1 if $4;
112             }
113              
114 0           return %slurp;
115             }
116              
117             #-----------------------------------------------------------------------------
118              
119             sub find {
120 0     0 0   return shift->split( @_ );
121             }
122              
123             #-----------------------------------------------------------------------------
124              
125             sub split {
126 0     0 0   my $self = shift;
127 0           my $matcher;
128 0 0         $matcher = shift if @_ % 2; # Odd number of arguments
129 0           my %given = @_;
130              
131 0           my $data = $self->data;
132 0           my $length = length $$data;
133 0 0         return unless $length; # Nothing to split
134              
135 0 0         my $from = $self->_parent ? $self->tail + 1 : 0;
136 0 0         return if $length <= $from; # Was already at end of data
137              
138 0           pos $data = $from;
139 0 0         return unless $$data =~ m/\G[[:ascii:]]*?($matcher)/mgc;
140 0           my @match = map { substr $$data, $-[$_], $+[$_] - $-[$_] } ( 0 .. -1 + scalar @- );
  0            
141 0           shift @match;
142 0           my $found = shift @match;
143 0           my ( $mhead, $mtail ) = ( $-[1], $+[1] - 1 );
144              
145 0           my $head = _fhead $data, $mhead;
146 0           my $tail = _ftail $data, $mtail;
147              
148             # TODO This is hacky
149 0           my @matched = @match;
150              
151 0           my $content = substr $$data, $head, 1 + $tail - $head;
152              
153 0           my $split = __PACKAGE__->new(
154             data => $data, parent => $self,
155             start => $from, mhead => $mhead, mtail => $mtail, head => $head, tail => $tail,
156             matcher => $matcher, found => $found, matched => \@matched,
157             content => $content,
158             default => $self->default,
159             );
160              
161 0 0 0       return $split unless wantarray && ( my $slurp = delete $given{slurp} );
162 0           return ( $split, $split->slurp( $slurp, %given ) );
163             }
164              
165             #-----------------------------------------------------------------------------
166              
167             sub slurp {
168 0     0 0   my $self = shift;
169 0           my $slurp = 1;
170 0 0         $slurp = shift if @_ % 2; # Odd number of arguments
171 0           my %given = @_;
172              
173 0           my $split = $self;
174              
175 0           _strip_edness \%given;
176 0           my %slurp = _parse_slurp $self->default->{slurp};
177 0   0       exists $given{$_} and $slurp{$_} = $given{$_} for qw/ chomp trim /;
178 0 0         %slurp = _parse_slurp $slurp, %slurp unless $slurp eq 1;
179              
180 0           my @content;
181 0 0         push @content, $self->parent->content if $slurp{slurpl};
182 0           push @content, $split->preceding;
183 0 0         push @content, $split->content if $slurp{slurpr};
184              
185 0           my $content = join '', @content;
186 0 0         if ( $slurp{trim} ) {
187 0           s/^\s*//, s/\s*$//, for $content;
188             }
189              
190 0 0 0       if ( wantarray && $slurp{wantlist} ) {
191 0           @content = grep { $_ ne "\n" } split m/(\n)/, $content;
  0            
192 0 0         @content = map { "$_\n" } @content unless $slurp{chomp};
  0            
193 0           return @content;
194             }
195             else {
196 0           return $content;
197             }
198             }
199              
200             #-----------------------------------------------------------------------------
201              
202             sub preceding {
203 0     0 0   my $self = shift;
204              
205 0           my $data = $self->data;
206 0           my $length = $self->head - $self->start;
207 0 0         return '' unless $length;
208 0           return substr $$data, $self->start, $length;
209             }
210              
211             #-----------------------------------------------------------------------------
212              
213 0     0 0   sub pre { return shift->preceding( @_ ) }
214              
215             #-----------------------------------------------------------------------------
216              
217             sub remaining {
218 0     0 0   my $self = shift;
219              
220 0           my $data = $self->data;
221 0 0         return $$data if $self->is_root;
222              
223 0           my $from = $self->tail + 1;
224              
225 0           my $length = length( $$data ) - $from + 1;
226 0 0         return '' unless $length;
227 0           return substr $$data, $from, $length;
228             }
229              
230             #-----------------------------------------------------------------------------
231              
232 0     0 0   sub re { return shift->remaining( @_ ) }
233              
234             #-----------------------------------------------------------------------------
235              
236             sub match {
237 0     0 0   my $self = shift;
238 0           my $ii = shift;
239 0 0         return $self->found if $ii == -1;
240 0           return $self->_matched->[$ii];
241             }
242              
243             #-----------------------------------------------------------------------------
244              
245             sub is {
246 0     0 0   my $self = shift;
247 0           my $ii = shift;
248 0           my $is = shift;
249              
250 0 0         return unless defined ( my $match = $self->match( $ii ) );
251 0 0         if ( ref $is eq 'Regexp' ) { $match =~ $is }
  0            
252 0           else { return $match eq $is }
253             }
254              
255             #-----------------------------------------------------------------------------
256             1;
257              
258             =pod
259              
260             =encoding UTF-8
261              
262             =for :stopwords Jeffrey Ryan Thalhammer
263              
264             =head1 NAME
265              
266             Pinto::Editor::Clip - Internal class for Pinto::Editor
267              
268             =head1 VERSION
269              
270             version 0.14
271              
272             =head1 DESCRIPTION
273              
274             This is a forked version of L<Text::Clip> which does not use the deprecated
275             module L<Any::Moose>. My thanks to Robert Krimen for authoring the original.
276             No user-servicable parts in here.
277              
278             =head1 AUTHOR
279              
280             Jeffrey Ryan Thalhammer <jeff@stratopan.com>
281              
282             =head1 COPYRIGHT AND LICENSE
283              
284             This software is copyright (c) 2015 by Jeffrey Ryan Thalhammer.
285              
286             This is free software; you can redistribute it and/or modify it under
287             the same terms as the Perl 5 programming language system itself.
288              
289             =cut
290              
291             __END__
292              
293             #-----------------------------------------------------------------------------
294