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 57     57   292 use strict;
  57         104  
  57         1439  
3 57     57   297 use warnings;
  57         113  
  57         1423  
4 57     57   31101 use Gnuplot::Builder::PartiallyKeyedList;
  57         150  
  57         2067  
5 57     57   29272 use Gnuplot::Builder::Util qw(quote_gnuplot_str);
  57         140  
  57         3811  
6 57     57   372 use List::Util 1.28 qw(pairs);
  57         1877  
  57         100329  
7              
8             sub new {
9 1422     1422 1 3208 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     4012 }, $class;
17 1422         6607 return $self;
18             }
19              
20             sub _trim_whitespaces {
21 67     67   99 my ($val) = @_;
22 67         149 $val =~ s/^\s+//g;
23 67         158 $val =~ s/\s+$//g;
24 67         183 return $val;
25             }
26              
27             sub _parse_pairs {
28 15     15   31 my ($pairs_str) = @_;
29 15         26 my @pairs = ();
30 15         24 my $carried = "";
31 15         68 foreach my $line (split /^/, $pairs_str) {
32 62         209 $line =~ s/[\r\n]+$//g;
33 62 100       166 if($line =~ /\\$/) {
34 6         11 $carried .= substr($line, 0, -1);
35 6         9 next;
36             }
37 56         99 $line = $carried . $line;
38 56         88 $carried = "";
39 56 100       131 next if $line =~ /^#/;
40 52         109 $line =~ s/^\s+//g;
41 52 100       119 next if $line eq "";
42 40 100       132 if($line =~ /^([^=]*)=(.*)$/) {
43 27         73 my ($name, $value) = ($1, $2);
44 27         61 push(@pairs, _trim_whitespaces($name), _trim_whitespaces($value));
45             }else {
46 13         66 my $name = _trim_whitespaces($line);
47 13 100       46 if($name =~ /^-/) {
48 6         30 push(@pairs, substr($name, 1), undef);
49             }else {
50 7         21 push(@pairs, $name, "");
51             }
52             }
53             }
54 15         44 return \@pairs;
55             }
56              
57             sub set_entry {
58 229     229 1 719 my ($self, %args) = @_;
59 229 100       732 my $prefix = defined($args{key_prefix}) ? $args{key_prefix} : "";
60 229         480 my $quote = $args{quote};
61 229         339 my $entries = $args{entries};
62 229 100       597 if(@$entries == 1) {
63 15         43 $entries = _parse_pairs($entries->[0]);
64             }
65            
66             ## Multiple occurrences of the same key are combined into an array-ref value.
67 229         725 my $temp_list = Gnuplot::Builder::PartiallyKeyedList->new;
68 229         1847 foreach my $entry_pair (pairs @$entries) {
69 330         978 my ($given_key, $value) = @$entry_pair;
70 330         641 my $key = $prefix . $given_key;
71 330 100       1118 if($temp_list->exists($key)) {
72 2         4 push(@{$temp_list->get($key)}, $value);
  2         8  
73             }else {
74 328         1211 $temp_list->set($key, [$value]);
75             }
76             }
77             $temp_list->each(sub {
78 328     328   582 my ($key, $value_arrayref) = @_;
79 328 100       860 my $value = (@$value_arrayref == 1) ? $value_arrayref->[0] : $value_arrayref;
80 328 100       1332 $self->{list}->set($key, $quote ? _wrap_value_with_quote($value) : $value);
81 229         1723 });
82             }
83              
84             sub _wrap_value_with_quote {
85 90     90   176 my ($value) = @_;
86 90         162 my $ref = ref($value);
87 90 100       300 if($ref eq "ARRAY") {
    100          
88 10         33 return [map { quote_gnuplot_str($_) } @$value];
  15         46  
89             }elsif($ref eq "CODE") {
90             return sub {
91 34     34   95 return map { quote_gnuplot_str($_) } $value->(@_);
  49         7327  
92 17         103 };
93             }else {
94 63         242 return quote_gnuplot_str($value);
95             }
96             }
97              
98             sub add_entry {
99 20     20 1 42 my ($self, @entries) = @_;
100 20         90 $self->{list}->add($_) foreach @entries;
101             }
102              
103 13     13 1 77 sub delete_entry { $_[0]->{list}->delete($_[1]) }
104              
105 1204     1204 1 3421 sub has_own_entry { return $_[0]->{list}->exists($_[1]) }
106              
107 1037     1037 1 2148 sub set_parent { $_[0]->{parent} = $_[1] }
108              
109 2912     2912 1 8711 sub get_parent { return $_[0]->{parent} }
110              
111             sub _create_inheritance_stack {
112 350     350   574 my ($self) = @_;
113 350         697 my @pdata_stack = ($self);
114 350         462 my $current = $self;
115 350         754 while(defined(my $parent = $current->get_parent)) {
116 1029         1220 push(@pdata_stack, $parent);
117 1029         2048 $current = $parent;
118             }
119 350         802 return \@pdata_stack;
120             }
121              
122             sub _create_merged_pkl {
123 350     350   517 my ($self) = @_;
124 350         1040 my $result = Gnuplot::Builder::PartiallyKeyedList->new;
125 350         874 my $pdata_stack = $self->_create_inheritance_stack();
126 350         1212 while(defined(my $cur_pdata = pop(@$pdata_stack))) {
127 1379         4032 $result->merge($cur_pdata->{list});
128             }
129 350         851 return $result;
130             }
131              
132             sub _normalize_value {
133 599     599   984 my ($raw_value, $evaluator, $key) = @_;
134 599         916 my $ref = ref($raw_value);
135 599 100 66     2206 if($ref eq "ARRAY") {
    100          
136 88         326 return @$raw_value;
137             }elsif($ref eq "CODE" && defined($evaluator)) {
138 90         267 return $evaluator->($key, $raw_value);
139             }else {
140 421         1563 return ($raw_value);
141             }
142             }
143              
144             sub get_resolved_entry {
145 167     167 1 288 my ($self, $key) = @_;
146 167         248 my $pdata_with_key = $self;
147 167   100     730 while(defined($pdata_with_key) && !$pdata_with_key->has_own_entry($key)) {
148 1049         2096 $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         512 my $raw_value = $pdata_with_key->{list}->get($key);
154 155         390 my @normalized_values = _normalize_value($raw_value, $self->{entry_evaluator}, $key);
155 155 100       7878 return wantarray ? @normalized_values : $normalized_values[0];
156             }
157              
158             sub each_resolved_entry {
159 350     350 1 655 my ($self, $code) = @_;
160 350         814 my $merged = $self->_create_merged_pkl();
161             $merged->each(sub {
162 444     444   769 my ($key, $raw_value) = @_;
163 444         1032 $code->($key, [_normalize_value($raw_value, $self->{entry_evaluator}, $key)]);
164 350         1747 });
165             }
166              
167             sub set_attribute {
168 145     145 1 452 my ($self, %args) = @_;
169 145 100       759 $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 913 my ($self, $name) = @_;
174 585         721 my $pdata_with_attr = $self;
175 585   100     1998 while(defined($pdata_with_attr) && !$pdata_with_attr->has_own_attribute($name)) {
176 484         1170 $pdata_with_attr = $pdata_with_attr->get_parent;
177             }
178 585 100       2123 return undef if not defined $pdata_with_attr;
179 172         344 my $raw_value = $pdata_with_attr->{attributes}{$name};
180 172 100 100     636 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         1169 return $result;
183             }else {
184 161         569 return $raw_value;
185             }
186             }
187              
188 656     656 1 3494 sub has_own_attribute { exists $_[0]->{attributes}{$_[1]} }
189              
190 20     20 1 79 sub delete_attribute { delete $_[0]->{attributes}{$_[1]} }
191              
192              
193             1;
194              
195             __END__