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 55     55   273 use strict;
  55         93  
  55         1331  
3 55     55   271 use warnings;
  55         100  
  55         1312  
4 55     55   28840 use Gnuplot::Builder::PartiallyKeyedList;
  55         149  
  55         1847  
5 55     55   27897 use Gnuplot::Builder::Util qw(quote_gnuplot_str);
  55         136  
  55         3657  
6 55     55   288 use List::Util 1.28 qw(pairs);
  55         1588  
  55         94610  
7              
8             sub new {
9 1422     1422 1 3181 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 1422   100     4103 }, $class;
17 1422         6444 return $self;
18             }
19              
20             sub _trim_whitespaces {
21 67     67   101 my ($val) = @_;
22 67         148 $val =~ s/^\s+//g;
23 67         154 $val =~ s/\s+$//g;
24 67         192 return $val;
25             }
26              
27             sub _parse_pairs {
28 15     15   32 my ($pairs_str) = @_;
29 15         30 my @pairs = ();
30 15         24 my $carried = "";
31 15         69 foreach my $line (split /^/, $pairs_str) {
32 62         212 $line =~ s/[\r\n]+$//g;
33 62 100       178 if($line =~ /\\$/) {
34 6         12 $carried .= substr($line, 0, -1);
35 6         9 next;
36             }
37 56         94 $line = $carried . $line;
38 56         94 $carried = "";
39 56 100       129 next if $line =~ /^#/;
40 52         103 $line =~ s/^\s+//g;
41 52 100       132 next if $line eq "";
42 40 100       132 if($line =~ /^([^=]*)=(.*)$/) {
43 27         72 my ($name, $value) = ($1, $2);
44 27         60 push(@pairs, _trim_whitespaces($name), _trim_whitespaces($value));
45             }else {
46 13         71 my $name = _trim_whitespaces($line);
47 13 100       58 if($name =~ /^-/) {
48 6         24 push(@pairs, substr($name, 1), undef);
49             }else {
50 7         28 push(@pairs, $name, "");
51             }
52             }
53             }
54 15         42 return \@pairs;
55             }
56              
57             sub set_entry {
58 229     229 1 676 my ($self, %args) = @_;
59 229 100       733 my $prefix = defined($args{key_prefix}) ? $args{key_prefix} : "";
60 229         488 my $quote = $args{quote};
61 229         332 my $entries = $args{entries};
62 229 100       611 if(@$entries == 1) {
63 15         46 $entries = _parse_pairs($entries->[0]);
64             }
65            
66             ## Multiple occurrences of the same key are combined into an array-ref value.
67 229         723 my $temp_list = Gnuplot::Builder::PartiallyKeyedList->new;
68 229         1769 foreach my $entry_pair (pairs @$entries) {
69 330         1015 my ($given_key, $value) = @$entry_pair;
70 330         660 my $key = $prefix . $given_key;
71 330 100       1045 if($temp_list->exists($key)) {
72 2         3 push(@{$temp_list->get($key)}, $value);
  2         9  
73             }else {
74 328         1152 $temp_list->set($key, [$value]);
75             }
76             }
77             $temp_list->each(sub {
78 328     328   585 my ($key, $value_arrayref) = @_;
79 328 100       857 my $value = (@$value_arrayref == 1) ? $value_arrayref->[0] : $value_arrayref;
80 328 100       1338 $self->{list}->set($key, $quote ? _wrap_value_with_quote($value) : $value);
81 229         1704 });
82             }
83              
84             sub _wrap_value_with_quote {
85 90     90   137 my ($value) = @_;
86 90         162 my $ref = ref($value);
87 90 100       297 if($ref eq "ARRAY") {
    100          
88 10         29 return [map { quote_gnuplot_str($_) } @$value];
  15         41  
89             }elsif($ref eq "CODE") {
90             return sub {
91 34     34   94 return map { quote_gnuplot_str($_) } $value->(@_);
  49         6217  
92 17         112 };
93             }else {
94 63         223 return quote_gnuplot_str($value);
95             }
96             }
97              
98             sub add_entry {
99 20     20 1 39 my ($self, @entries) = @_;
100 20         94 $self->{list}->add($_) foreach @entries;
101             }
102              
103 13     13 1 57 sub delete_entry { $_[0]->{list}->delete($_[1]) }
104              
105 1204     1204 1 3439 sub has_own_entry { return $_[0]->{list}->exists($_[1]) }
106              
107 1037     1037 1 2341 sub set_parent { $_[0]->{parent} = $_[1] }
108              
109 2912     2912 1 8750 sub get_parent { return $_[0]->{parent} }
110              
111             sub _create_inheritance_stack {
112 350     350   553 my ($self) = @_;
113 350         714 my @pdata_stack = ($self);
114 350         460 my $current = $self;
115 350         758 while(defined(my $parent = $current->get_parent)) {
116 1029         1240 push(@pdata_stack, $parent);
117 1029         1822 $current = $parent;
118             }
119 350         828 return \@pdata_stack;
120             }
121              
122             sub _create_merged_pkl {
123 350     350   497 my ($self) = @_;
124 350         1086 my $result = Gnuplot::Builder::PartiallyKeyedList->new;
125 350         837 my $pdata_stack = $self->_create_inheritance_stack();
126 350         1142 while(defined(my $cur_pdata = pop(@$pdata_stack))) {
127 1379         4091 $result->merge($cur_pdata->{list});
128             }
129 350         774 return $result;
130             }
131              
132             sub _normalize_value {
133 599     599   982 my ($raw_value, $evaluator, $key) = @_;
134 599         885 my $ref = ref($raw_value);
135 599 100 66     2161 if($ref eq "ARRAY") {
    100          
136 88         324 return @$raw_value;
137             }elsif($ref eq "CODE" && defined($evaluator)) {
138 90         270 return $evaluator->($key, $raw_value);
139             }else {
140 421         1568 return ($raw_value);
141             }
142             }
143              
144             sub get_resolved_entry {
145 167     167 1 339 my ($self, $key) = @_;
146 167         216 my $pdata_with_key = $self;
147 167   100     616 while(defined($pdata_with_key) && !$pdata_with_key->has_own_entry($key)) {
148 1049         2068 $pdata_with_key = $pdata_with_key->get_parent;
149             }
150 167 100       394 if(!defined($pdata_with_key)) {
151 12 100       91 return wantarray ? () : undef;
152             }
153 155         470 my $raw_value = $pdata_with_key->{list}->get($key);
154 155         388 my @normalized_values = _normalize_value($raw_value, $self->{entry_evaluator}, $key);
155 155 100       6208 return wantarray ? @normalized_values : $normalized_values[0];
156             }
157              
158             sub each_resolved_entry {
159 350     350 1 569 my ($self, $code) = @_;
160 350         1330 my $merged = $self->_create_merged_pkl();
161             $merged->each(sub {
162 444     444   809 my ($key, $raw_value) = @_;
163 444         1018 $code->($key, [_normalize_value($raw_value, $self->{entry_evaluator}, $key)]);
164 350         1844 });
165             }
166              
167             sub set_attribute {
168 145     145 1 454 my ($self, %args) = @_;
169 145 100       734 $self->{attributes}{$args{key}} = $args{quote} ? _wrap_value_with_quote($args{value}) : $args{value};
170             }
171              
172             sub get_resolved_attribute {
173 585     585 1 951 my ($self, $name) = @_;
174 585         731 my $pdata_with_attr = $self;
175 585   100     1984 while(defined($pdata_with_attr) && !$pdata_with_attr->has_own_attribute($name)) {
176 484         1130 $pdata_with_attr = $pdata_with_attr->get_parent;
177             }
178 585 100       2104 return undef if not defined $pdata_with_attr;
179 172         327 my $raw_value = $pdata_with_attr->{attributes}{$name};
180 172 100 100     638 if(ref($raw_value) eq "CODE" && defined($self->{attribute_evaluator}{$name})) {
181 11         37 my ($result) = $self->{attribute_evaluator}{$name}->($name, $raw_value);
182 11         1107 return $result;
183             }else {
184 161         587 return $raw_value;
185             }
186             }
187              
188 656     656 1 3075 sub has_own_attribute { exists $_[0]->{attributes}{$_[1]} }
189              
190 20     20 1 75 sub delete_attribute { delete $_[0]->{attributes}{$_[1]} }
191              
192              
193             1;
194              
195             __END__