File Coverage

web/cgi-bin/yatt.lib/YATT/LRXML.pm
Criterion Covered Total %
statement 100 116 86.2
branch 15 28 53.5
condition 2 2 100.0
subroutine 27 31 87.1
pod 0 3 0.0
total 144 180 80.0


line stmt bran cond sub pod time code
1             # -*- mode: perl; coding: utf-8 -*-
2             package YATT::LRXML;
3 7     7   27 use strict;
  7         9  
  7         214  
4 7     7   23 use warnings FATAL => qw(all);
  7         9  
  7         188  
5              
6 7     7   21 use YATT::Util qw(call_type);
  7         7  
  7         379  
7              
8             require YATT::LRXML::Node;
9              
10             sub Parser () { 'YATT::LRXML::Parser' }
11              
12 7     7   22 use Carp;
  7         10  
  7         1261  
13              
14             # Returns YATT::LRXML::Cursor
15             sub read_string {
16 2     2 0 698 my $pack = shift;
17 2         11 my $parser = $pack->call_type(Parser => 'new');
18 2         8 $parser->parse_string(@_);
19             }
20              
21             sub read_handle {
22 0     0 0 0 my $pack = shift;
23 0         0 my $parser = $pack->call_type(Parser => 'new');
24 0         0 $parser->parse_handle(@_);
25             }
26              
27             sub read {
28 0     0 0 0 my ($pack, $filename) = splice @_, 0, 2;
29 0         0 my $fh;
30 0 0       0 if (ref $filename) {
31 0         0 $fh = $filename;
32             } else {
33 0 0       0 open $fh, '<', $filename or croak "Can't open '$filename': $!";
34 0         0 unshift @_, filename => $filename;
35             }
36 0         0 $pack->read_handle($fh, @_);
37             }
38              
39             #========================================
40              
41             package YATT::LRXML::Scanner; # To scan tokens.
42 7     7   25 use strict;
  7         18  
  7         220  
43 7     7   22 use warnings FATAL => qw(all);
  7         10  
  7         207  
44 7     7   21 use base qw(YATT::Class::ArrayScanner);
  7         8  
  7         2520  
45             use YATT::Fields
46 7         24 (['^cf_linenum' => 1]
47             , ['^cf_last_nol' => 0] # last number of lines
48             , qw(cf_last_linenum
49 7     7   29 cf_path cf_metainfo));
  7         9  
50              
51             sub expect {
52 635     635   710 (my MY $path, my ($patterns)) = @_;
53 635 50       1017 return unless $path->readable;
54 635         1007 my $value = $path->{cf_array}[$path->{cf_index}];
55 635         556 my @match;
56 635         872 foreach my $desc (@$patterns) {
57 2453         2402 my ($toktype, $pat) = @$desc;
58 2453 100       11447 next unless @match = $value =~ $pat;
59 635         1389 $path->after_read($path->{cf_index}++);
60 635         2214 return ($toktype, @match);
61             }
62 0         0 return;
63             }
64              
65             sub number_of_lines {
66 156     156   220 (my MY $path, my ($pos)) = @_;
67 156 50       512 $pos = $path->{cf_index} unless defined $pos;
68 156 50       167 return 0 unless @{$path->{cf_array}};
  156         467  
69 156 50       526 defined (my $tok = $path->{cf_array}[$pos])
70             or return undef;
71 156         810 $tok =~ tr:\n::;
72             }
73              
74             sub after_read {
75 1450     1450   1320 (my MY $path, my ($pos)) = @_;
76 1450 50       2078 if (defined $pos) {
77 1450         2261 $$path{cf_last_nol} = $path->{cf_array}[$pos] =~ tr:\n::;
78             }
79 1450         1546 $path->{cf_last_linenum} = $path->{cf_linenum};
80 1450 50       2201 unless (defined $$path{cf_linenum}) {
81 0         0 $$path{cf_linenum} = 1;
82             } else {
83 1450   100     4178 $$path{cf_linenum} += $$path{cf_last_nol} || 0;
84             }
85             }
86              
87 7     7   1087 use YATT::Exception qw(Exception);
  7         8  
  7         618  
88              
89             sub token_error {
90 0     0   0 (my MY $self, my ($mesg)) = @_;
91 0         0 $self->Exception->new(error_fmt => $mesg
92             , file => $self->{cf_metainfo}->in_file
93             , line => $self->{cf_linenum});
94             }
95              
96             #========================================
97             package YATT::LRXML::Builder; # To build tree.
98 7     7   27 use strict;
  7         6  
  7         168  
99 7     7   21 use warnings FATAL => qw(all);
  7         8  
  7         162  
100 7     7   20 use base qw(YATT::Class::Configurable);
  7         7  
  7         391  
101 7         21 use YATT::Fields qw(^product ^parent ^is_switched
102 7     7   28 cf_endtag cf_startpos cf_startline cf_linenum);
  7         7  
103              
104 7     7   28 use YATT::LRXML::Node qw(node_set_nlines);
  7         7  
  7         1070  
105             sub Scanner () {'YATT::LRXML::Scanner'}
106              
107 0     0   0 sub initargs {qw(product parent)}
108              
109             sub new {
110 323     323   470 my $pack = shift;
111 323         988 my MY $path = $pack->SUPER::new;
112 323 50       1213 $path->init(@_) if @_;
113 323         2181 $path;
114             }
115              
116             sub init {
117 323     323   406 my MY $path = shift;
118 323         606 @{$path}{qw(product parent)} = splice @_, 0, 2;
  323         666  
119 323 50       1029 $path->configure(@_) if @_;
120 323         296 $path;
121             }
122              
123             sub open {
124 67     67   139 (my MY $parent, my ($product)) = splice @_, 0, 2;
125 67         219 ref($parent)->new($product, $parent, $parent->configure
126             , startline => $parent->{cf_linenum}
127             , @_);
128             }
129              
130 7     7   27 use YATT::Exception qw(Exception);
  7         8  
  7         1645  
131              
132             sub error {
133 1     1   3 (my MY $self, my ($mesg, $param, @other)) = @_;
134 1         11 $self->Exception->new(error_fmt => $mesg
135             , error_param => $param
136             , @other);
137             }
138              
139             sub verify_close {
140 64     64   147 (my MY $self, my ($tagname, $scan)) = @_;
141 64 50       206 unless (defined $self->{cf_endtag}) {
142 0         0 die $self->error("TAG '/%s' without open", [$tagname]
143             , file => $scan->cget('metainfo')->filename
144             , line => $scan->linenum);
145             }
146 64 100       245 unless ($tagname eq $self->{cf_endtag}) {
147 1         11 die $self->error("TAG '%s' line %d closed by /%s"
148             , [$self->{cf_endtag}, $self->{cf_startline}, $tagname]
149             , file => $scan->cget('metainfo')->filename
150             , line => $scan->linenum);
151             }
152             }
153              
154             sub add {
155 996     996   1366 (my MY $self, my Scanner $scan) = splice @_, 0, 2;
156 996         729 push @{$self->{product}}, @_;
  996         1835  
157 996         1121 $self->{cf_linenum} = $scan->{cf_linenum};
158 996         1685 $self;
159             }
160              
161             sub switch {
162 16     16   25 (my MY $self, my ($elem)) = @_;
163 16 100       40 unless ($self->{is_switched}) {
164 11         26 $self->{is_switched} = $self->{product};
165             }
166 16         15 push @{$self->{is_switched}}, $elem;
  16         31  
167 16         19 $self->{product} = $elem;
168 16         64 $self;
169             }
170              
171             sub DESTROY {
172 323     323   408 my MY $self = shift;
173             # switch した場合は?
174 323         1187 node_set_nlines($self->{product}
175             , $self->{cf_linenum} - $self->{cf_startline});
176             }
177              
178             1;