File Coverage

blib/lib/Gnuplot/Builder/Script.pm
Criterion Covered Total %
statement 224 231 96.9
branch 67 80 83.7
condition 11 15 73.3
subroutine 53 54 98.1
pod 26 27 96.3
total 381 407 93.6


line stmt bran cond sub pod time code
1             package Gnuplot::Builder::Script;
2 37     37   765107 use strict;
  37         83  
  37         1039  
3 37     37   260 use warnings;
  37         70  
  37         979  
4 37     37   20987 use Gnuplot::Builder::PrototypedData;
  37         95  
  37         1234  
5 37     37   219 use Gnuplot::Builder::Util qw(quote_gnuplot_str);
  37         68  
  37         1680  
6 37     37   21309 use Gnuplot::Builder::Process;
  37         124  
  37         1407  
7 37     37   204 use Scalar::Util qw(weaken blessed refaddr);
  37         57  
  37         3079  
8 37     37   177 use Carp;
  37         67  
  37         2196  
9 37     37   59639 use overload '""' => "to_string";
  37         40622  
  37         285  
10              
11             sub new {
12 1174     1174 1 48867 my ($class, @set_args) = @_;
13 1174         2959 my $self = bless {
14             pdata => undef,
15             parent => undef,
16             };
17 1174         2418 $self->_init_pdata();
18 1174 100       2807 if(@set_args) {
19 18         56 $self->set(@set_args);
20             }
21 1174         2872 return $self;
22             }
23              
24             sub _init_pdata {
25 1174     1174   1500 my ($self) = @_;
26 1174         2598 weaken $self;
27             $self->{pdata} = Gnuplot::Builder::PrototypedData->new(
28             entry_evaluator => sub {
29 41     41   84 my ($key, $value_code) = @_;
30 41 100       78 if(defined($key)) {
31 38         128 return $value_code->($self, substr($key, 1));
32             }else {
33 3         8 return $value_code->($self);
34             }
35             }
36 1174         6315 );
37             }
38              
39             sub add {
40 15     15 1 63 my ($self, @sentences) = @_;
41 15         29 foreach my $sentence (@sentences) {
42 20         72 $self->{pdata}->add_entry($sentence);
43             }
44 15         38 return $self;
45             }
46              
47             sub _set_entry {
48 111     111   284 my ($self, $prefix, $quote, @pairs) = @_;
49             $self->{pdata}->set_entry(
50 111         553 entries => \@pairs,
51             key_prefix => $prefix,
52             quote => $quote,
53             );
54 111         776 return $self;
55             }
56              
57             sub set {
58 75     75 1 817 my ($self, @pairs) = @_;
59 75         230 return $self->_set_entry("o", 0, @pairs);
60             }
61              
62             *set_option = *set;
63              
64             sub setq {
65 21     21 1 110 my ($self, @pairs) = @_;
66 21         60 return $self->_set_entry("o", 1, @pairs);
67             }
68              
69             *setq_option = *setq;
70              
71             sub unset {
72 2     2 1 19 my ($self, @names) = @_;
73 2         5 return $self->set(map { $_ => undef } @names);
  4         12  
74             }
75              
76             sub _get_entry {
77 75     75   119 my ($self, $prefix, $name) = @_;
78 75 50       182 croak "name cannot be undef" if not defined $name;
79 75         357 return $self->{pdata}->get_resolved_entry("$prefix$name");
80             }
81              
82             sub get_option {
83 62     62 1 157 my ($self, $name) = @_;
84 62         144 return $self->_get_entry("o", $name);
85             }
86              
87             sub _delete_entry {
88 9     9   21 my ($self, $prefix, @names) = @_;
89 9         22 foreach my $name (@names) {
90 11 50       33 croak "name cannot be undef" if not defined $name;
91 11         57 $self->{pdata}->delete_entry("$prefix$name");
92             }
93 9         32 return $self;
94             }
95              
96             sub delete_option {
97 5     5 1 19 my ($self, @names) = @_;
98 5         20 return $self->_delete_entry("o", @names);
99             }
100              
101             sub _create_statement {
102 258     258   416 my ($raw_key, $value) = @_;
103 258 100       611 return $value if !defined $raw_key;
104 213         461 my ($prefix, $name) = (substr($raw_key, 0, 1), substr($raw_key, 1));
105 213         321 my @words = ();
106 213 100       481 if($prefix eq "o") {
    50          
107 177 100       602 @words = defined($value) ? ("set", $name, $value) : ("unset", $name);
108             }elsif($prefix eq "d") {
109 36 100       118 @words = defined($value) ? ($name, "=", $value) : ("undefine", $name);
110             }else {
111 0         0 confess "Unknown key prefix: $prefix";
112             }
113 213         343 return join(" ", grep { "$_" ne "" } @words);
  611         1740  
114             }
115              
116             sub to_string {
117 231     231 1 1864 my ($self) = @_;
118 231         354 my $result = "";
119             $self->{pdata}->each_resolved_entry(sub {
120 246     246   6420 my ($raw_key, $values) = @_;
121 246         434 foreach my $value (@$values) {
122 258         527 my $statement = _create_statement($raw_key, $value);
123 258         472 $result .= $statement;
124 258 100       1722 $result .= "\n" if $statement !~ /\n$/;
125             }
126 231         1399 });
127 231         1903 return $result;
128             }
129              
130             sub define {
131 15     15 1 68 my ($self, @pairs) = @_;
132 15         50 return $self->_set_entry("d", 0, @pairs);
133             }
134              
135             *set_definition = *define;
136              
137             sub undefine {
138 1     1 1 6 my ($self, @names) = @_;
139 1         3 return $self->define(map { $_ => undef } @names);
  3         8  
140             }
141              
142             sub get_definition {
143 13     13 1 28 my ($self, $name) = @_;
144 13         30 return $self->_get_entry("d", $name);
145             }
146              
147             sub delete_definition {
148 4     4 1 13 my ($self, @names) = @_;
149 4         13 return $self->_delete_entry("d", @names);
150             }
151              
152             sub set_parent {
153 1011     1011 1 1362 my ($self, $parent) = @_;
154 1011 100       2132 if(!defined($parent)) {
155 1         5 $self->{parent} = undef;
156 1         4 $self->{pdata}->set_parent(undef);
157 1         4 return $self;
158             }
159 1010 50 33     5063 if(!blessed($parent) || !$parent->isa("Gnuplot::Builder::Script")) {
160 0         0 croak "parent must be a Gnuplot::Builder::Script"
161             }
162 1010         1611 $self->{parent} = $parent;
163 1010         2628 $self->{pdata}->set_parent($parent->{pdata});
164 1010         2304 return $self;
165             }
166              
167 5     5 1 32 sub get_parent { return $_[0]->{parent} }
168              
169             *parent = *get_parent;
170              
171             sub new_child {
172 1008     1008 1 3417 my ($self) = @_;
173 1008         2106 return Gnuplot::Builder::Script->new->set_parent($self);
174             }
175              
176             sub _collect_dataset_params {
177 74     74   100 my ($dataset_arrayref) = @_;
178 74         117 my @params_str = ();
179 74         96 my @dataset_objects = ();
180 74         127 foreach my $dataset (@$dataset_arrayref) {
181 89         129 my $ref = ref($dataset);
182 89 100       176 if(!$ref) {
183 70         187 push(@params_str, $dataset);
184             }else {
185 19 50 33     155 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         69 my ($param_str) = $dataset->params_string();
189 19         2227 push(@params_str, $param_str);
190 19         47 push(@dataset_objects, $dataset);
191             }
192             }
193 74         172 return (\@params_str, \@dataset_objects);
194             }
195              
196             sub _wrap_writer_to_detect_empty_data {
197 103     103   144 my ($writer) = @_;
198 103         129 my $ended_with_newline = 0;
199 103         129 my $data_written = 0;
200             my $wrapped_writer = sub {
201 37 100   37   208 my @nonempty_data = grep { defined($_) && $_ ne "" } @_;
  35         204  
202 37 100       98 return if !@nonempty_data;
203 30         42 $data_written = 1;
204 30         91 $ended_with_newline = ($nonempty_data[-1] =~ /\n$/);
205 30         94 $writer->(join("", @nonempty_data));
206 103         363 };
207 103         302 return ($wrapped_writer, \$data_written, \$ended_with_newline);
208             }
209              
210             sub _write_inline_data {
211 74     74   121 my ($writer, $dataset_objects_arrayref) = @_;
212 74         147 my ($wrapped_writer, $data_written_ref, $ended_with_newline_ref) =
213             _wrap_writer_to_detect_empty_data($writer);
214 74         433 foreach my $dataset (@$dataset_objects_arrayref) {
215 19         30 $$data_written_ref = $$ended_with_newline_ref = 0;
216 19         55 $dataset->write_data_to($wrapped_writer);
217 19 100       110 next if !$$data_written_ref;
218 11 100       31 $writer->("\n") if !$$ended_with_newline_ref;
219 11         41 $writer->("e\n");
220             }
221             }
222              
223             sub _wrap_commands_with_output {
224 156     156   220 my ($commands_ref, $output_filename) = @_;
225 156 100       399 if(defined($output_filename)) {
226 12         58 unshift @$commands_ref, "set output " . quote_gnuplot_str($output_filename);
227 12         37 push @$commands_ref, "set output";
228             }
229             }
230              
231             sub _draw_with {
232 74     74   209 my ($self, %args) = @_;
233 74         166 my $plot_command = $args{command};
234 74         102 my $dataset = $args{dataset};
235 74 50       199 croak "dataset parameter is mandatory" if not defined $dataset;
236 74 100       236 if(ref($dataset) ne "ARRAY") {
237 19         43 $dataset = [$dataset];
238             }
239 74 50       163 croak "at least one dataset is required" if !@$dataset;
240              
241             my $plotter = sub {
242 74     74   114 my $writer = shift;
243 74         157 my ($params, $dataset_objects) = _collect_dataset_params($dataset);
244 74         353 $writer->("$plot_command " . join(",", @$params) . "\n");
245 74         323 _write_inline_data($writer, $dataset_objects);
246 74         258 };
247 74         147 my @commands = ($plotter);
248 74         188 return $self->run_with(
249             do => \@commands,
250             _pair_slice(\%args, qw(writer async output no_stderr))
251             );
252             }
253              
254             sub _pair_slice {
255 103     103   226 my ($hash_ref, @keys) = @_;
256 103 100       173 return map { exists($hash_ref->{$_}) ? ($_ => $hash_ref->{$_}) : () } @keys;
  412         1294  
257             }
258              
259             sub plot_with {
260 21     21 1 1086 my ($self, %args) = @_;
261 21         77 return $self->_draw_with(%args, command => "plot");
262             }
263              
264             sub splot_with {
265 6     6 1 1497 my ($self, %args) = @_;
266 6         24 return $self->_draw_with(%args, command => "splot");
267             }
268              
269             sub plot {
270 44     44 1 246 my ($self, @dataset) = @_;
271 44         116 return $self->_draw_with(command => "plot", dataset => \@dataset);
272             }
273              
274             sub splot {
275 3     3 1 11 my ($self, @dataset) = @_;
276 3         9 return $self->_draw_with(command => "splot", dataset => \@dataset);
277             }
278              
279             sub multiplot_with {
280 29     29 1 803 my ($self, %args) = @_;
281 29         50 my $do = $args{do};
282 29 50       68 croak "do parameter is mandatory" if not defined $do;
283 29 50       79 croak "do parameter must be a code-ref" if ref($do) ne "CODE";
284             my $wrapped_do = sub {
285 29     29   39 my $writer = shift;
286 29         66 my ($wrapped_writer, $data_written_ref, $ended_with_newline_ref) =
287             _wrap_writer_to_detect_empty_data($writer);
288 29         83 $do->($wrapped_writer);
289 28 100 100     3056 if($$data_written_ref && !$$ended_with_newline_ref) {
290 1         3 $writer->("\n");
291             }
292 29         97 };
293             my $multiplot_command =
294 29 100 100     155 (defined($args{option}) && $args{option} ne "")
295             ? "set multiplot $args{option}" : "set multiplot";
296 29         67 my @commands = ($multiplot_command, $wrapped_do, "unset multiplot");
297 29         73 return $self->run_with(
298             do => \@commands,
299             _pair_slice(\%args, qw(writer async output no_stderr))
300             );
301             }
302              
303             sub multiplot {
304 3     3 1 24 my ($self, $option, $code) = @_;
305 3 100       13 if(@_ == 2) {
306 2         3 $code = $option;
307 2         4 $option = "";
308             }
309 3 50       9 croak "code parameter is mandatory" if not defined $code;
310 3 50       12 croak "code parameter must be a code-ref" if ref($code) ne "CODE";
311 3         11 return $self->multiplot_with(do => $code, option => $option);
312             }
313              
314             our $_context_writer = undef;
315              
316             sub run_with {
317 156     156 1 6012 my ($self, %args) = @_;
318 156         241 my $commands = $args{do};
319 156 100       557 if(!defined($commands)) {
    100          
320 2         6 $commands = [];
321             }elsif(ref($commands) ne "ARRAY") {
322 28         61 $commands = [$commands];
323             }
324 156         367 _wrap_commands_with_output($commands, $self->_plotting_option(\%args, "output"));
325             my $do = sub {
326 156     156   220 my $writer = shift;
327 156 100 100     740 (!defined($_context_writer) || refaddr($_context_writer) != refaddr($writer))
328             and local $_context_writer = $writer;
329            
330 156         383 $writer->($self->to_string);
331 156         696 foreach my $command (@$commands) {
332 259 100       780 if(ref($command) eq "CODE") {
333 152         328 $command->($writer);
334             }else {
335 107         164 $command = "$command";
336 107         227 $writer->($command);
337 107 100       589 $writer->("\n") if $command !~ /\n$/;
338             }
339             }
340 156         617 };
341              
342 156         238 my $result = "";
343 156         366 my $got_writer = $self->_plotting_option(\%args, "writer");
344 156 100       381 if(defined($got_writer)) {
    50          
345 95         212 $do->($got_writer);
346             }elsif(defined($_context_writer)) {
347 61         132 $do->($_context_writer);
348             }else {
349 0         0 $result = Gnuplot::Builder::Process->with_new_process(
350             async => $self->_plotting_option(\%args, "async"),
351             do => $do,
352             no_stderr => $self->_plotting_option(\%args, "no_stderr")
353             );
354             }
355 152         4388 return $result;
356             }
357              
358             sub _plotting_option {
359 312     312   485 my ($self, $given_args_ref, $key) = @_;
360             return (exists $given_args_ref->{$key})
361 312 100       962 ? $given_args_ref->{$key}
362             : $self->get_plot($key);
363             }
364              
365             sub run {
366 13     13 1 80 my ($self, @commands) = @_;
367 13         34 return $self->run_with(do => \@commands);
368             }
369              
370             my %KNOWN_PLOTTING_OPTIONS = map { ($_ => 1) } qw(output no_stderr writer async);
371              
372             sub _check_plotting_option {
373 261     261   364 my ($arg_name) = @_;
374 261 100       1118 croak "Unknown plotting option: $arg_name" if !$KNOWN_PLOTTING_OPTIONS{$arg_name};
375             }
376              
377             sub set_plot {
378 13     13 1 112 my ($self, %opts) = @_;
379 13         38 foreach my $key (keys %opts) {
380 16         32 _check_plotting_option($key);
381             $self->{pdata}->set_attribute(
382             key => $key,
383 15         55 value => $opts{$key}
384             );
385             }
386 12         41 return $self;
387             }
388              
389             sub get_plot {
390 237     237 1 878 my ($self, $arg_name) = @_;
391 237         418 _check_plotting_option($arg_name);
392 236 50       506 croak "arg_name cannot be undef" if not defined $arg_name;
393 236         764 return $self->{pdata}->get_resolved_attribute($arg_name);
394             }
395              
396             sub delete_plot {
397 6     6 1 504 my ($self, @arg_names) = @_;
398 6         13 foreach my $arg_name (@arg_names) {
399 8         18 _check_plotting_option($arg_name);
400 7         25 $self->{pdata}->delete_attribute($arg_name)
401             }
402 5         14 return $self;
403             }
404              
405             sub Lens {
406 0     0 0   my ($self, $key) = @_;
407 0           require Gnuplot::Builder::Lens;
408 0           return Gnuplot::Builder::Lens->new(
409             "get_option", "set_option", $key
410             );
411             }
412              
413             1;
414              
415             __END__