File Coverage

blib/lib/Gnuplot/Builder/PrototypedData.pm
Criterion Covered Total %
statement 123 123 100.0
branch 40 40 100.0
condition 13 14 92.8
subroutine 27 27 100.0
pod 13 13 100.0
total 216 217 99.5


line stmt bran cond sub pod time code
1             package Gnuplot::Builder::PrototypedData;
2 54     54   331 use strict;
  54         99  
  54         1434  
3 54     54   268 use warnings;
  54         104  
  54         1342  
4 54     54   28546 use Gnuplot::Builder::PartiallyKeyedList;
  54         142  
  54         1874  
5 54     54   27538 use Gnuplot::Builder::Util qw(quote_gnuplot_str);
  54         130  
  54         3431  
6 54     54   299 use List::Util 1.28 qw(pairs);
  54         1660  
  54         94614  
7              
8             sub new {
9 1411     1411 1 3165 my ($class, %args) = @_;
10             my $self = bless {
11             list => Gnuplot::Builder::PartiallyKeyedList->new,
12             attributes => {},
13             parent => undef,
14             entry_evaluator => $args{entry_evaluator},
15             attribute_evaluator => $args{attribute_evaluator} || {},
16 1411   100     4000 }, $class;
17 1411         6373 return $self;
18             }
19              
20             sub _trim_whitespaces {
21 67     67   95 my ($val) = @_;
22 67         191 $val =~ s/^\s+//g;
23 67         164 $val =~ s/\s+$//g;
24 67         178 return $val;
25             }
26              
27             sub _parse_pairs {
28 15     15   30 my ($pairs_str) = @_;
29 15         28 my @pairs = ();
30 15         27 my $carried = "";
31 15         65 foreach my $line (split /^/, $pairs_str) {
32 62         208 $line =~ s/[\r\n]+$//g;
33 62 100       192 if($line =~ /\\$/) {
34 6         12 $carried .= substr($line, 0, -1);
35 6         10 next;
36             }
37 56         95 $line = $carried . $line;
38 56         94 $carried = "";
39 56 100       135 next if $line =~ /^#/;
40 52         105 $line =~ s/^\s+//g;
41 52 100       128 next if $line eq "";
42 40 100       136 if($line =~ /^([^=]*)=(.*)$/) {
43 27         108 my ($name, $value) = ($1, $2);
44 27         59 push(@pairs, _trim_whitespaces($name), _trim_whitespaces($value));
45             }else {
46 13         34 my $name = _trim_whitespaces($line);
47 13 100       45 if($name =~ /^-/) {
48 6         23 push(@pairs, substr($name, 1), undef);
49             }else {
50 7         32 push(@pairs, $name, "");
51             }
52             }
53             }
54 15         45 return \@pairs;
55             }
56              
57             sub set_entry {
58 227     227 1 748 my ($self, %args) = @_;
59 227 100       698 my $prefix = defined($args{key_prefix}) ? $args{key_prefix} : "";
60 227         383 my $quote = $args{quote};
61 227         337 my $entries = $args{entries};
62 227 100       732 if(@$entries == 1) {
63 15         52 $entries = _parse_pairs($entries->[0]);
64             }
65            
66             ## Multiple occurrences of the same key are combined into an array-ref value.
67 227         731 my $temp_list = Gnuplot::Builder::PartiallyKeyedList->new;
68 227         1781 foreach my $entry_pair (pairs @$entries) {
69 328         1043 my ($given_key, $value) = @$entry_pair;
70 328         648 my $key = $prefix . $given_key;
71 328 100       1030 if($temp_list->exists($key)) {
72 2         38 push(@{$temp_list->get($key)}, $value);
  2         10  
73             }else {
74 326         1158 $temp_list->set($key, [$value]);
75             }
76             }
77             $temp_list->each(sub {
78 326     326   595 my ($key, $value_arrayref) = @_;
79 326 100       830 my $value = (@$value_arrayref == 1) ? $value_arrayref->[0] : $value_arrayref;
80 326 100       1284 $self->{list}->set($key, $quote ? _wrap_value_with_quote($value) : $value);
81 227         1729 });
82             }
83              
84             sub _wrap_value_with_quote {
85 90     90   148 my ($value) = @_;
86 90         156 my $ref = ref($value);
87 90 100       302 if($ref eq "ARRAY") {
    100          
88 10         26 return [map { quote_gnuplot_str($_) } @$value];
  15         43  
89             }elsif($ref eq "CODE") {
90             return sub {
91 34     34   95 return map { quote_gnuplot_str($_) } $value->(@_);
  49         4746  
92 17         104 };
93             }else {
94 63         243 return quote_gnuplot_str($value);
95             }
96             }
97              
98             sub add_entry {
99 20     20 1 41 my ($self, @entries) = @_;
100 20         96 $self->{list}->add($_) foreach @entries;
101             }
102              
103 13     13 1 62 sub delete_entry { $_[0]->{list}->delete($_[1]) }
104              
105 1204     1204 1 3319 sub has_own_entry { return $_[0]->{list}->exists($_[1]) }
106              
107 1035     1035 1 2155 sub set_parent { $_[0]->{parent} = $_[1] }
108              
109 2678     2678 1 8142 sub get_parent { return $_[0]->{parent} }
110              
111             sub _create_inheritance_stack {
112 341     341   474 my ($self) = @_;
113 341         691 my @pdata_stack = ($self);
114 341         472 my $current = $self;
115 341         780 while(defined(my $parent = $current->get_parent)) {
116 1029         1327 push(@pdata_stack, $parent);
117 1029         1824 $current = $parent;
118             }
119 341         661 return \@pdata_stack;
120             }
121              
122             sub _create_merged_pkl {
123 341     341   465 my ($self) = @_;
124 341         1067 my $result = Gnuplot::Builder::PartiallyKeyedList->new;
125 341         840 my $pdata_stack = $self->_create_inheritance_stack();
126 341         1092 while(defined(my $cur_pdata = pop(@$pdata_stack))) {
127 1370         4125 $result->merge($cur_pdata->{list});
128             }
129 341         737 return $result;
130             }
131              
132             sub _normalize_value {
133 591     591   955 my ($raw_value, $evaluator, $key) = @_;
134 591         883 my $ref = ref($raw_value);
135 591 100 66     2128 if($ref eq "ARRAY") {
    100          
136 88         316 return @$raw_value;
137             }elsif($ref eq "CODE" && defined($evaluator)) {
138 90         264 return $evaluator->($key, $raw_value);
139             }else {
140 413         1520 return ($raw_value);
141             }
142             }
143              
144             sub get_resolved_entry {
145 167     167 1 259 my ($self, $key) = @_;
146 167         215 my $pdata_with_key = $self;
147 167   100     666 while(defined($pdata_with_key) && !$pdata_with_key->has_own_entry($key)) {
148 1049         2109 $pdata_with_key = $pdata_with_key->get_parent;
149             }
150 167 100       403 if(!defined($pdata_with_key)) {
151 12 100       92 return wantarray ? () : undef;
152             }
153 155         502 my $raw_value = $pdata_with_key->{list}->get($key);
154 155         362 my @normalized_values = _normalize_value($raw_value, $self->{entry_evaluator}, $key);
155 155 100       6187 return wantarray ? @normalized_values : $normalized_values[0];
156             }
157              
158             sub each_resolved_entry {
159 341     341 1 559 my ($self, $code) = @_;
160 341         864 my $merged = $self->_create_merged_pkl();
161             $merged->each(sub {
162 436     436   757 my ($key, $raw_value) = @_;
163 436         998 $code->($key, [_normalize_value($raw_value, $self->{entry_evaluator}, $key)]);
164 341         1724 });
165             }
166              
167             sub set_attribute {
168 130     130 1 388 my ($self, %args) = @_;
169 130 100       639 $self->{attributes}{$args{key}} = $args{quote} ? _wrap_value_with_quote($args{value}) : $args{value};
170             }
171              
172             sub get_resolved_attribute {
173 349     349 1 556 my ($self, $name) = @_;
174 349         448 my $pdata_with_attr = $self;
175 349   100     1175 while(defined($pdata_with_attr) && !$pdata_with_attr->has_own_attribute($name)) {
176 259         608 $pdata_with_attr = $pdata_with_attr->get_parent;
177             }
178 349 100       1074 return undef if not defined $pdata_with_attr;
179 150         289 my $raw_value = $pdata_with_attr->{attributes}{$name};
180 150 100 100     572 if(ref($raw_value) eq "CODE" && defined($self->{attribute_evaluator}{$name})) {
181 11         36 my ($result) = $self->{attribute_evaluator}{$name}->($name, $raw_value);
182 11         1124 return $result;
183             }else {
184 139         459 return $raw_value;
185             }
186             }
187              
188 409     409 1 1944 sub has_own_attribute { exists $_[0]->{attributes}{$_[1]} }
189              
190 13     13 1 51 sub delete_attribute { delete $_[0]->{attributes}{$_[1]} }
191              
192              
193             1;
194              
195             __END__