File Coverage

blib/lib/Gherkin/Line.pm
Criterion Covered Total %
statement 37 87 42.5
branch 5 24 20.8
condition 5 9 55.5
subroutine 11 15 73.3
pod 0 8 0.0
total 58 143 40.5


line stmt bran cond sub pod time code
1             package Gherkin::Line;
2             $Gherkin::Line::VERSION = '25.0.2';
3 2     2   12 use strict;
  2         4  
  2         55  
4 2     2   9 use warnings;
  2         4  
  2         63  
5              
6 2         12 use Class::XSAccessor accessors =>
7 2     2   11 [ qw/line_text line_number indent _trimmed_line_text/, ];
  2         3  
8              
9             sub new {
10 38     38 0 77 my ( $class, $options ) = @_;
11 38         67 my $self = bless $options, $class;
12              
13 38   66     138 $self->{'_trimmed_line_text'} ||= $self->_build__trimmed_line_text;
14 38   66     129 $self->{'indent'} ||= $self->_build_indent;
15              
16 38         86 return $self;
17             }
18              
19             sub _build__trimmed_line_text {
20 38     38   53 my $self = shift;
21 38         68 my $trimmed = $self->line_text;
22 38 50       183 $trimmed =~ s/^\s+// if defined $trimmed;
23 38         136 return $trimmed;
24             }
25              
26             sub _build_indent {
27 38     38   57 my $self = shift;
28 38         167 return length( $self->line_text ) - length( $self->_trimmed_line_text );
29             }
30              
31             sub get_rest_trimmed {
32 21     21 0 41 my ( $self, $from ) = @_;
33 21         46 my $rest = substr( $self->_trimmed_line_text, $from );
34 21         98 $rest =~ s/^\s*//;
35 21         118 $rest =~ s/\s*$//;
36 21         49 return $rest;
37             }
38              
39             sub get_line_text {
40 5     5 0 11 my ( $self, $indent_to_remove ) = @_;
41 5 50       15 $indent_to_remove = -1 unless defined $indent_to_remove;
42              
43 5 50 33     20 if ( $indent_to_remove < 0 or $indent_to_remove > $self->indent ) {
44 5         64 return $self->_trimmed_line_text;
45             } else {
46 0         0 return substr( $self->line_text, $indent_to_remove );
47             }
48             }
49              
50             sub is_empty {
51 24     24 0 31 my $self = shift;
52 24         75 return !$self->_trimmed_line_text;
53             }
54              
55             sub startswith {
56 273     273 0 404 my ( $self, $prefix ) = @_;
57 273 50       507 return unless defined $self->_trimmed_line_text;
58 273         1029 return !index( $self->_trimmed_line_text, $prefix );
59             }
60              
61             sub startswith_title_keyword {
62 75     75 0 110 my ( $self, $prefix ) = @_;
63 75 50       153 return unless defined $self->_trimmed_line_text;
64 75         284 return !index( $self->_trimmed_line_text, $prefix . ':' );
65             }
66              
67             sub _split_table_cells_iterator {
68 0     0     my ( $self, $row ) = @_;
69 0           my $col = 0;
70 0           my $first_cell = 1;
71              
72             return sub {
73 0     0     my $cell = '';
74 0           my $start_col = $col + 1 + $first_cell;
75              
76 0           while (1) {
77 0 0         ( $row =~ s/^(.)// ) || return;
78 0           my $char = $1;
79 0           $col += 1;
80 0 0         if ( $char eq '|' ) {
    0          
    0          
81 0 0         if ($first_cell) {
82 0           $first_cell = 0;
83             } else {
84 0           return ( $cell, $start_col );
85             }
86             } elsif ( $char eq "\\" ) {
87 0 0         $row =~ s/^(.)// || die "Unpossible";
88 0           $col += 1;
89 0           $cell .= '\\' . $1;
90             } elsif ( defined $char ) {
91 0           $cell .= $char;
92             } else {
93 0           die "WHAT?";
94             }
95             }
96             }
97 0           }
98              
99             my %unescape_map = ( '\\\\' => '\\', '\\|' => '|', '\\n' => "\n" );
100              
101             sub table_cells {
102 0     0 0   my ($self) = @_;
103 0           my $cells = [];
104 0           my $text = $self->_trimmed_line_text;
105 0           $text =~ s/^\s*//;
106 0           $text =~ s/\s*$//;
107              
108 0           my $i = $self->_split_table_cells_iterator($text);
109 0           while (1) {
110 0           my ( $cell, $col ) = $i->();
111 0 0         last unless defined $col;
112              
113 0           my $stripped_cell = $cell;
114 0           $stripped_cell =~ s/^\s+//;
115 0           my $cell_indent = length($cell) - length($stripped_cell);
116 0           $stripped_cell =~ s/\s+$//;
117 0           $stripped_cell =~ s/(\\\\|\\\||\\n)/$unescape_map{$1}/g;
118 0           push(
119             @$cells,
120             {
121             column => $col + $self->indent + $cell_indent,
122             text => $stripped_cell
123             }
124             );
125             }
126              
127 0           return $cells;
128             }
129              
130             sub tags {
131 0     0 0   my $self = shift;
132 0           my $column = $self->indent + 1;
133 0           my $items_line = $self->_trimmed_line_text;
134 0           $items_line =~ s/\s+(#.*)?$//;
135              
136 0           my @tags;
137 0           my @items = split( /@/, $items_line );
138 0           shift(@items); # Blank first item
139              
140 0           for my $item (@items) {
141 0           my $original_item = $item;
142 0           $item =~ s/^\s*//;
143 0           $item =~ s/\s*$//;
144              
145 0           push(
146             @tags,
147             {
148             column => $column,
149             text => '@' . $item,
150             }
151             );
152              
153 0           $column += length($original_item) + 1;
154             }
155              
156 0           return \@tags;
157             }
158              
159             1;