File Coverage

blib/lib/Gnuplot/Builder/Script.pm
Criterion Covered Total %
statement 202 206 98.0
branch 59 72 81.9
condition 11 15 73.3
subroutine 47 47 100.0
pod 23 23 100.0
total 342 363 94.2


line stmt bran cond sub pod time code
1             package Gnuplot::Builder::Script;
2 35     35   691578 use strict;
  35         78  
  35         929  
3 35     35   182 use warnings;
  35         62  
  35         907  
4 35     35   19935 use Gnuplot::Builder::PrototypedData;
  35         88  
  35         1085  
5 35     35   203 use Gnuplot::Builder::Util qw(quote_gnuplot_str);
  35         54  
  35         1558  
6 35     35   19786 use Gnuplot::Builder::Process;
  35         102  
  35         1311  
7 35     35   188 use Scalar::Util qw(weaken blessed refaddr);
  35         71  
  35         3024  
8 35     35   172 use Carp;
  35         127  
  35         2110  
9 35     35   55353 use overload '""' => "to_string";
  35         38578  
  35         211  
10              
11             sub new {
12 1163     1163 1 51749 my ($class, @set_args) = @_;
13 1163         2968 my $self = bless {
14             pdata => undef,
15             parent => undef,
16             };
17 1163         2360 $self->_init_pdata();
18 1163 100       2578 if(@set_args) {
19 16         49 $self->set(@set_args);
20             }
21 1163         2857 return $self;
22             }
23              
24             sub _init_pdata {
25 1163     1163   1534 my ($self) = @_;
26 1163         2488 weaken $self;
27             $self->{pdata} = Gnuplot::Builder::PrototypedData->new(
28             entry_evaluator => sub {
29 41     41   93 my ($key, $value_code) = @_;
30 41 100       86 if(defined($key)) {
31 38         125 return $value_code->($self, substr($key, 1));
32             }else {
33 3         7 return $value_code->($self);
34             }
35             }
36 1163         6287 );
37             }
38              
39             sub add {
40 15     15 1 62 my ($self, @sentences) = @_;
41 15         33 foreach my $sentence (@sentences) {
42 20         75 $self->{pdata}->add_entry($sentence);
43             }
44 15         36 return $self;
45             }
46              
47             sub _set_entry {
48 109     109   270 my ($self, $prefix, $quote, @pairs) = @_;
49             $self->{pdata}->set_entry(
50 109         457 entries => \@pairs,
51             key_prefix => $prefix,
52             quote => $quote,
53             );
54 109         830 return $self;
55             }
56              
57             sub set {
58 73     73 1 842 my ($self, @pairs) = @_;
59 73         222 return $self->_set_entry("o", 0, @pairs);
60             }
61              
62             *set_option = *set;
63              
64             sub setq {
65 21     21 1 115 my ($self, @pairs) = @_;
66 21         63 return $self->_set_entry("o", 1, @pairs);
67             }
68              
69             *setq_option = *setq;
70              
71             sub unset {
72 2     2 1 12 my ($self, @names) = @_;
73 2         6 return $self->set(map { $_ => undef } @names);
  4         12  
74             }
75              
76             sub _get_entry {
77 75     75   126 my ($self, $prefix, $name) = @_;
78 75 50       174 croak "name cannot be undef" if not defined $name;
79 75         302 return $self->{pdata}->get_resolved_entry("$prefix$name");
80             }
81              
82             sub get_option {
83 62     62 1 156 my ($self, $name) = @_;
84 62         137 return $self->_get_entry("o", $name);
85             }
86              
87             sub _delete_entry {
88 9     9   22 my ($self, $prefix, @names) = @_;
89 9         20 foreach my $name (@names) {
90 11 50       36 croak "name cannot be undef" if not defined $name;
91 11         56 $self->{pdata}->delete_entry("$prefix$name");
92             }
93 9         32 return $self;
94             }
95              
96             sub delete_option {
97 5     5 1 17 my ($self, @names) = @_;
98 5         19 return $self->_delete_entry("o", @names);
99             }
100              
101             sub _create_statement {
102 250     250   374 my ($raw_key, $value) = @_;
103 250 100       599 return $value if !defined $raw_key;
104 205         434 my ($prefix, $name) = (substr($raw_key, 0, 1), substr($raw_key, 1));
105 205         367 my @words = ();
106 205 100       482 if($prefix eq "o") {
    50          
107 169 100       528 @words = defined($value) ? ("set", $name, $value) : ("unset", $name);
108             }elsif($prefix eq "d") {
109 36 100       114 @words = defined($value) ? ($name, "=", $value) : ("undefine", $name);
110             }else {
111 0         0 confess "Unknown key prefix: $prefix";
112             }
113 205         340 return join(" ", grep { "$_" ne "" } @words);
  587         1568  
114             }
115              
116             sub to_string {
117 222     222 1 1762 my ($self) = @_;
118 222         312 my $result = "";
119             $self->{pdata}->each_resolved_entry(sub {
120 238     238   5973 my ($raw_key, $values) = @_;
121 238         421 foreach my $value (@$values) {
122 250         599 my $statement = _create_statement($raw_key, $value);
123 250         502 $result .= $statement;
124 250 100       1657 $result .= "\n" if $statement !~ /\n$/;
125             }
126 222         1308 });
127 222         1802 return $result;
128             }
129              
130             sub define {
131 15     15 1 69 my ($self, @pairs) = @_;
132 15         51 return $self->_set_entry("d", 0, @pairs);
133             }
134              
135             *set_definition = *define;
136              
137             sub undefine {
138 1     1 1 7 my ($self, @names) = @_;
139 1         2 return $self->define(map { $_ => undef } @names);
  3         9  
140             }
141              
142             sub get_definition {
143 13     13 1 27 my ($self, $name) = @_;
144 13         30 return $self->_get_entry("d", $name);
145             }
146              
147             sub delete_definition {
148 4     4 1 11 my ($self, @names) = @_;
149 4         15 return $self->_delete_entry("d", @names);
150             }
151              
152             sub set_parent {
153 1009     1009 1 1326 my ($self, $parent) = @_;
154 1009 100       1803 if(!defined($parent)) {
155 1         2 $self->{parent} = undef;
156 1         4 $self->{pdata}->set_parent(undef);
157 1         4 return $self;
158             }
159 1008 50 33     5071 if(!blessed($parent) || !$parent->isa("Gnuplot::Builder::Script")) {
160 0         0 croak "parent must be a Gnuplot::Builder::Script"
161             }
162 1008         1579 $self->{parent} = $parent;
163 1008         2806 $self->{pdata}->set_parent($parent->{pdata});
164 1008         2124 return $self;
165             }
166              
167 5     5 1 46 sub get_parent { return $_[0]->{parent} }
168              
169             *parent = *get_parent;
170              
171             sub new_child {
172 1007     1007 1 3266 my ($self) = @_;
173 1007         2002 return Gnuplot::Builder::Script->new->set_parent($self);
174             }
175              
176             sub _collect_dataset_params {
177 69     69   95 my ($dataset_arrayref) = @_;
178 69         101 my @params_str = ();
179 69         92 my @dataset_objects = ();
180 69         114 foreach my $dataset (@$dataset_arrayref) {
181 84         128 my $ref = ref($dataset);
182 84 100       162 if(!$ref) {
183 65         152 push(@params_str, $dataset);
184             }else {
185 19 50 33     160 if(!$dataset->can("params_string") || !$dataset->can("write_data_to")) {
186 0         0 croak "You cannot use $ref object as a dataset.";
187             }
188 19         62 my ($param_str) = $dataset->params_string();
189 19         2266 push(@params_str, $param_str);
190 19         51 push(@dataset_objects, $dataset);
191             }
192             }
193 69         163 return (\@params_str, \@dataset_objects);
194             }
195              
196             sub _wrap_writer_to_detect_empty_data {
197 96     96   130 my ($writer) = @_;
198 96         109 my $ended_with_newline = 0;
199 96         121 my $data_written = 0;
200             my $wrapped_writer = sub {
201 37 100   37   211 my @nonempty_data = grep { defined($_) && $_ ne "" } @_;
  35         209  
202 37 100       95 return if !@nonempty_data;
203 30         40 $data_written = 1;
204 30         88 $ended_with_newline = ($nonempty_data[-1] =~ /\n$/);
205 30         101 $writer->(join("", @nonempty_data));
206 96         327 };
207 96         244 return ($wrapped_writer, \$data_written, \$ended_with_newline);
208             }
209              
210             sub _write_inline_data {
211 69     69   138 my ($writer, $dataset_objects_arrayref) = @_;
212 69         153 my ($wrapped_writer, $data_written_ref, $ended_with_newline_ref) =
213             _wrap_writer_to_detect_empty_data($writer);
214 69         389 foreach my $dataset (@$dataset_objects_arrayref) {
215 19         31 $$data_written_ref = $$ended_with_newline_ref = 0;
216 19         59 $dataset->write_data_to($wrapped_writer);
217 19 100       109 next if !$$data_written_ref;
218 11 100       40 $writer->("\n") if !$$ended_with_newline_ref;
219 11         38 $writer->("e\n");
220             }
221             }
222              
223             sub _wrap_commands_with_output {
224 147     147   248 my ($commands_ref, $output_filename) = @_;
225 147 100       364 if(defined($output_filename)) {
226 8         37 unshift @$commands_ref, "set output " . quote_gnuplot_str($output_filename);
227 8         23 push @$commands_ref, "set output";
228             }
229             }
230              
231             sub _draw_with {
232 69     69   197 my ($self, %args) = @_;
233 69         118 my $plot_command = $args{command};
234 69         100 my $dataset = $args{dataset};
235 69 50       197 croak "dataset parameter is mandatory" if not defined $dataset;
236 69 100       195 if(ref($dataset) ne "ARRAY") {
237 16         39 $dataset = [$dataset];
238             }
239 69 50       189 croak "at least one dataset is required" if !@$dataset;
240              
241             my $plotter = sub {
242 69     69   178 my $writer = shift;
243 69         149 my ($params, $dataset_objects) = _collect_dataset_params($dataset);
244 69         328 $writer->("$plot_command " . join(",", @$params) . "\n");
245 69         320 _write_inline_data($writer, $dataset_objects);
246 69         245 };
247 69         145 my @commands = ($plotter);
248             return $self->run_with(
249             do => \@commands,
250             writer => $args{writer},
251             async => $args{async},
252             output => $args{output},
253             no_stderr => $args{no_stderr}
254 69         366 );
255             }
256              
257             sub plot_with {
258 19     19 1 1326 my ($self, %args) = @_;
259 19         76 return $self->_draw_with(%args, command => "plot");
260             }
261              
262             sub splot_with {
263 5     5 1 1494 my ($self, %args) = @_;
264 5         17 return $self->_draw_with(%args, command => "splot");
265             }
266              
267             sub plot {
268 43     43 1 253 my ($self, @dataset) = @_;
269 43         106 return $self->_draw_with(command => "plot", dataset => \@dataset);
270             }
271              
272             sub splot {
273 2     2 1 10 my ($self, @dataset) = @_;
274 2         5 return $self->_draw_with(command => "splot", dataset => \@dataset);
275             }
276              
277             sub multiplot_with {
278 27     27 1 411 my ($self, %args) = @_;
279 27         45 my $do = $args{do};
280 27 50       56 croak "do parameter is mandatory" if not defined $do;
281 27 50       70 croak "do parameter must be a code-ref" if ref($do) ne "CODE";
282             my $wrapped_do = sub {
283 27     27   36 my $writer = shift;
284 27         85 my ($wrapped_writer, $data_written_ref, $ended_with_newline_ref) =
285             _wrap_writer_to_detect_empty_data($writer);
286 27         72 $do->($wrapped_writer);
287 26 100 100     3166 if($$data_written_ref && !$$ended_with_newline_ref) {
288 1         4 $writer->("\n");
289             }
290 27         90 };
291             my $multiplot_command =
292 27 100 100     124 (defined($args{option}) && $args{option} ne "")
293             ? "set multiplot $args{option}" : "set multiplot";
294 27         71 my @commands = ($multiplot_command, $wrapped_do, "unset multiplot");
295             return $self->run_with(
296             do => \@commands,
297             writer => $args{writer},
298             async => $args{async},
299             output => $args{output},
300             no_stderr => $args{no_stderr}
301 27         126 );
302             }
303              
304             sub multiplot {
305 2     2 1 12 my ($self, $option, $code) = @_;
306 2 50       6 if(@_ == 2) {
307 2         4 $code = $option;
308 2         3 $option = "";
309             }
310 2 50       5 croak "code parameter is mandatory" if not defined $code;
311 2 50       6 croak "code parameter must be a code-ref" if ref($code) ne "CODE";
312 2         8 return $self->multiplot_with(do => $code, option => $option);
313             }
314              
315             our $_context_writer = undef;
316              
317             sub run_with {
318 147     147 1 6019 my ($self, %args) = @_;
319 147         257 my $commands = $args{do};
320 147 100       529 if(!defined($commands)) {
    100          
321 2         4 $commands = [];
322             }elsif(ref($commands) ne "ARRAY") {
323 27         58 $commands = [$commands];
324             }
325 147         372 _wrap_commands_with_output($commands, $args{output});
326             my $do = sub {
327 147     147   196 my $writer = shift;
328 147 100 100     681 (!defined($_context_writer) || refaddr($_context_writer) != refaddr($writer))
329             and local $_context_writer = $writer;
330            
331 147         334 $writer->($self->to_string);
332 147         645 foreach my $command (@$commands) {
333 239 100       692 if(ref($command) eq "CODE") {
334 144         323 $command->($writer);
335             }else {
336 95         143 $command = "$command";
337 95         199 $writer->($command);
338 95 100       584 $writer->("\n") if $command !~ /\n$/;
339             }
340             }
341 147         559 };
342              
343 147         232 my $result = "";
344 147 100       340 if(defined($args{writer})) {
    50          
345 86         204 $do->($args{writer});
346             }elsif(defined($_context_writer)) {
347 61         118 $do->($_context_writer);
348             }else {
349 0         0 $result = Gnuplot::Builder::Process->with_new_process(async => $args{async}, do => $do, no_stderr => $args{no_stderr});
350             }
351 143         4418 return $result;
352             }
353              
354             sub run {
355 12     12 1 75 my ($self, @commands) = @_;
356 12         30 return $self->run_with(do => \@commands);
357             }
358              
359             1;
360              
361             __END__