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   4125947 use strict;
  37         85  
  37         1545  
3 37     37   210 use warnings;
  37         94  
  37         2481  
4 37     37   20298 use Gnuplot::Builder::PrototypedData;
  37         165  
  37         1672  
5 37     37   255 use Gnuplot::Builder::Util qw(quote_gnuplot_str);
  37         67  
  37         2291  
6 37     37   19688 use Gnuplot::Builder::Process;
  37         151  
  37         1935  
7 37     37   275 use Scalar::Util qw(weaken blessed refaddr);
  37         90  
  37         3188  
8 37     37   291 use Carp;
  37         72  
  37         2782  
9 37     37   25721 use overload '""' => "to_string";
  37         78045  
  37         295  
10              
11             sub new {
12 1177     1177 1 5953811 my ($class, @set_args) = @_;
13 1177         2537 my $self = bless {
14             pdata => undef,
15             parent => undef,
16             };
17 1177         2339 $self->_init_pdata();
18 1177 100       2930 if(@set_args) {
19 19         99 $self->set(@set_args);
20             }
21 1177         2446 return $self;
22             }
23              
24             sub _init_pdata {
25 1177     1177   1552 my ($self) = @_;
26 1177         1603 weaken $self;
27             $self->{pdata} = Gnuplot::Builder::PrototypedData->new(
28             entry_evaluator => sub {
29 41     41   92 my ($key, $value_code) = @_;
30 41 100       90 if(defined($key)) {
31 38         162 return $value_code->($self, substr($key, 1));
32             }else {
33 3         27 return $value_code->($self);
34             }
35             }
36 1177         7449 );
37             }
38              
39             sub add {
40 15     15 1 81 my ($self, @sentences) = @_;
41 15         39 foreach my $sentence (@sentences) {
42 20         83 $self->{pdata}->add_entry($sentence);
43             }
44 15         48 return $self;
45             }
46              
47             sub _set_entry {
48 113     113   354 my ($self, $prefix, $quote, @pairs) = @_;
49             $self->{pdata}->set_entry(
50 113         631 entries => \@pairs,
51             key_prefix => $prefix,
52             quote => $quote,
53             );
54 113         1155 return $self;
55             }
56              
57             sub set {
58 77     77 1 1163 my ($self, @pairs) = @_;
59 77         295 return $self->_set_entry("o", 0, @pairs);
60             }
61              
62             *set_option = *set;
63              
64             sub setq {
65 21     21 1 159 my ($self, @pairs) = @_;
66 21         64 return $self->_set_entry("o", 1, @pairs);
67             }
68              
69             *setq_option = *setq;
70              
71             sub unset {
72 2     2 1 18 my ($self, @names) = @_;
73 2         5 return $self->set(map { $_ => undef } @names);
  4         14  
74             }
75              
76             sub _get_entry {
77 75     75   158 my ($self, $prefix, $name) = @_;
78 75 50       208 croak "name cannot be undef" if not defined $name;
79 75         402 return $self->{pdata}->get_resolved_entry("$prefix$name");
80             }
81              
82             sub get_option {
83 62     62 1 227 my ($self, $name) = @_;
84 62         164 return $self->_get_entry("o", $name);
85             }
86              
87             sub _delete_entry {
88 9     9   25 my ($self, $prefix, @names) = @_;
89 9         18 foreach my $name (@names) {
90 11 50       32 croak "name cannot be undef" if not defined $name;
91 11         57 $self->{pdata}->delete_entry("$prefix$name");
92             }
93 9         37 return $self;
94             }
95              
96             sub delete_option {
97 5     5 1 19 my ($self, @names) = @_;
98 5         23 return $self->_delete_entry("o", @names);
99             }
100              
101             sub _create_statement {
102 262     262   579 my ($raw_key, $value) = @_;
103 262 100       613 return $value if !defined $raw_key;
104 217         688 my ($prefix, $name) = (substr($raw_key, 0, 1), substr($raw_key, 1));
105 217         430 my @words = ();
106 217 100       545 if($prefix eq "o") {
    50          
107 181 100       664 @words = defined($value) ? ("set", $name, $value) : ("unset", $name);
108             }elsif($prefix eq "d") {
109 36 100       102 @words = defined($value) ? ($name, "=", $value) : ("undefine", $name);
110             }else {
111 0         0 confess "Unknown key prefix: $prefix";
112             }
113 217         465 return join(" ", grep { "$_" ne "" } @words);
  623         1697  
114             }
115              
116             sub to_string {
117 234     234 1 3551 my ($self) = @_;
118 234         433 my $result = "";
119             $self->{pdata}->each_resolved_entry(sub {
120 250     250   12111 my ($raw_key, $values) = @_;
121 250         482 foreach my $value (@$values) {
122 262         566 my $statement = _create_statement($raw_key, $value);
123 262         546 $result .= $statement;
124 262 100       1658 $result .= "\n" if $statement !~ /\n$/;
125             }
126 234         1647 });
127 234         2326 return $result;
128             }
129              
130             sub define {
131 15     15 1 74 my ($self, @pairs) = @_;
132 15         43 return $self->_set_entry("d", 0, @pairs);
133             }
134              
135             *set_definition = *define;
136              
137             sub undefine {
138 1     1 1 9 my ($self, @names) = @_;
139 1         3 return $self->define(map { $_ => undef } @names);
  3         9  
140             }
141              
142             sub get_definition {
143 13     13 1 40 my ($self, $name) = @_;
144 13         44 return $self->_get_entry("d", $name);
145             }
146              
147             sub delete_definition {
148 4     4 1 16 my ($self, @names) = @_;
149 4         16 return $self->_delete_entry("d", @names);
150             }
151              
152             sub set_parent {
153 1012     1012 1 1277 my ($self, $parent) = @_;
154 1012 100       1470 if(!defined($parent)) {
155 1         4 $self->{parent} = undef;
156 1         5 $self->{pdata}->set_parent(undef);
157 1         5 return $self;
158             }
159 1011 50 33     2833 if(!blessed($parent) || !$parent->isa("Gnuplot::Builder::Script")) {
160 0         0 croak "parent must be a Gnuplot::Builder::Script"
161             }
162 1011         1226 $self->{parent} = $parent;
163 1011         2028 $self->{pdata}->set_parent($parent->{pdata});
164 1011         1673 return $self;
165             }
166              
167 5     5 1 89 sub get_parent { return $_[0]->{parent} }
168              
169             *parent = *get_parent;
170              
171             sub new_child {
172 1009     1009 1 2306 my ($self) = @_;
173 1009         1464 return Gnuplot::Builder::Script->new->set_parent($self);
174             }
175              
176             sub _collect_dataset_params {
177 76     76   183 my ($dataset_arrayref) = @_;
178 76         211 my @params_str = ();
179 76         123 my @dataset_objects = ();
180 76         147 foreach my $dataset (@$dataset_arrayref) {
181 91         175 my $ref = ref($dataset);
182 91 100       183 if(!$ref) {
183 72         174 push(@params_str, $dataset);
184             }else {
185 19 50 33     204 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         82 my ($param_str) = $dataset->params_string();
189 19         3699 push(@params_str, $param_str);
190 19         59 push(@dataset_objects, $dataset);
191             }
192             }
193 76         210 return (\@params_str, \@dataset_objects);
194             }
195              
196             sub _wrap_writer_to_detect_empty_data {
197 106     106   208 my ($writer) = @_;
198 106         180 my $ended_with_newline = 0;
199 106         184 my $data_written = 0;
200             my $wrapped_writer = sub {
201 38 100   38   285 my @nonempty_data = grep { defined($_) && $_ ne "" } @_;
  36         210  
202 38 100       91 return if !@nonempty_data;
203 31         50 $data_written = 1;
204 31         139 $ended_with_newline = ($nonempty_data[-1] =~ /\n$/);
205 31         113 $writer->(join("", @nonempty_data));
206 106         494 };
207 106         340 return ($wrapped_writer, \$data_written, \$ended_with_newline);
208             }
209              
210             sub _write_inline_data {
211 76     76   205 my ($writer, $dataset_objects_arrayref) = @_;
212 76         160 my ($wrapped_writer, $data_written_ref, $ended_with_newline_ref) =
213             _wrap_writer_to_detect_empty_data($writer);
214 76         504 foreach my $dataset (@$dataset_objects_arrayref) {
215 19         67 $$data_written_ref = $$ended_with_newline_ref = 0;
216 19         85 $dataset->write_data_to($wrapped_writer);
217 19 100       119 next if !$$data_written_ref;
218 11 100       42 $writer->("\n") if !$$ended_with_newline_ref;
219 11         40 $writer->("e\n");
220             }
221             }
222              
223             sub _wrap_commands_with_output {
224 159     159   288 my ($commands_ref, $output_filename) = @_;
225 159 100       339 if(defined($output_filename)) {
226 12         62 unshift @$commands_ref, "set output " . quote_gnuplot_str($output_filename);
227 12         38 push @$commands_ref, "set output";
228             }
229             }
230              
231             sub _draw_with {
232 76     76   292 my ($self, %args) = @_;
233 76         221 my $plot_command = $args{command};
234 76         150 my $dataset = $args{dataset};
235 76 50       223 croak "dataset parameter is mandatory" if not defined $dataset;
236 76 100       213 if(ref($dataset) ne "ARRAY") {
237 19         59 $dataset = [$dataset];
238             }
239 76 50       188 croak "at least one dataset is required" if !@$dataset;
240              
241             my $plotter = sub {
242 76     76   127 my $writer = shift;
243 76         211 my ($params, $dataset_objects) = _collect_dataset_params($dataset);
244 76         435 $writer->("$plot_command " . join(",", @$params) . "\n");
245 76         409 _write_inline_data($writer, $dataset_objects);
246 76         328 };
247 76         189 my @commands = ($plotter);
248 76         228 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 106     106   267 my ($hash_ref, @keys) = @_;
256 106 100       221 return map { exists($hash_ref->{$_}) ? ($_ => $hash_ref->{$_}) : () } @keys;
  424         1189  
257             }
258              
259             sub plot_with {
260 21     21 1 1529 my ($self, %args) = @_;
261 21         109 return $self->_draw_with(%args, command => "plot");
262             }
263              
264             sub splot_with {
265 6     6 1 2503 my ($self, %args) = @_;
266 6         22 return $self->_draw_with(%args, command => "splot");
267             }
268              
269             sub plot {
270 46     46 1 312 my ($self, @dataset) = @_;
271 46         128 return $self->_draw_with(command => "plot", dataset => \@dataset);
272             }
273              
274             sub splot {
275 3     3 1 15 my ($self, @dataset) = @_;
276 3         13 return $self->_draw_with(command => "splot", dataset => \@dataset);
277             }
278              
279             sub multiplot_with {
280 30     30 1 1386 my ($self, %args) = @_;
281 30         65 my $do = $args{do};
282 30 50       76 croak "do parameter is mandatory" if not defined $do;
283 30 50       133 croak "do parameter must be a code-ref" if ref($do) ne "CODE";
284             my $wrapped_do = sub {
285 30     30   44 my $writer = shift;
286 30         116 my ($wrapped_writer, $data_written_ref, $ended_with_newline_ref) =
287             _wrap_writer_to_detect_empty_data($writer);
288 30         119 $do->($wrapped_writer);
289 29 100 100     4656 if($$data_written_ref && !$$ended_with_newline_ref) {
290 1         3 $writer->("\n");
291             }
292 30         121 };
293             my $multiplot_command =
294 30 100 100     146 (defined($args{option}) && $args{option} ne "")
295             ? "set multiplot $args{option}" : "set multiplot";
296 30         97 my @commands = ($multiplot_command, $wrapped_do, "unset multiplot");
297 30         99 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 21 my ($self, $option, $code) = @_;
305 3 100       15 if(@_ == 2) {
306 2         4 $code = $option;
307 2         5 $option = "";
308             }
309 3 50       11 croak "code parameter is mandatory" if not defined $code;
310 3 50       11 croak "code parameter must be a code-ref" if ref($code) ne "CODE";
311 3         15 return $self->multiplot_with(do => $code, option => $option);
312             }
313              
314             our $_context_writer = undef;
315              
316             sub run_with {
317 159     159 1 13422 my ($self, %args) = @_;
318 159         346 my $commands = $args{do};
319 159 100       594 if(!defined($commands)) {
    100          
320 2         5 $commands = [];
321             }elsif(ref($commands) ne "ARRAY") {
322 28         66 $commands = [$commands];
323             }
324 159         452 _wrap_commands_with_output($commands, $self->_plotting_option(\%args, "output"));
325             my $do = sub {
326 159     159   276 my $writer = shift;
327 159 100 100     561 (!defined($_context_writer) || refaddr($_context_writer) != refaddr($writer))
328             and local $_context_writer = $writer;
329            
330 159         396 $writer->($self->to_string);
331 159         787 foreach my $command (@$commands) {
332 264 100       838 if(ref($command) eq "CODE") {
333 155         353 $command->($writer);
334             }else {
335 109         190 $command = "$command";
336 109         269 $writer->($command);
337 109 100       582 $writer->("\n") if $command !~ /\n$/;
338             }
339             }
340 159         726 };
341              
342 159         354 my $result = "";
343 159         392 my $got_writer = $self->_plotting_option(\%args, "writer");
344 159 100       443 if(defined($got_writer)) {
    50          
345 96         204 $do->($got_writer);
346             }elsif(defined($_context_writer)) {
347 63         153 $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 155         5704 return $result;
356             }
357              
358             sub _plotting_option {
359 318     318   614 my ($self, $given_args_ref, $key) = @_;
360             return (exists $given_args_ref->{$key})
361 318 100       1027 ? $given_args_ref->{$key}
362             : $self->get_plot($key);
363             }
364              
365             sub run {
366 13     13 1 94 my ($self, @commands) = @_;
367 13         39 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 266     266   481 my ($arg_name) = @_;
374 266 100       1240 croak "Unknown plotting option: $arg_name" if !$KNOWN_PLOTTING_OPTIONS{$arg_name};
375             }
376              
377             sub set_plot {
378 13     13 1 178 my ($self, %opts) = @_;
379 13         66 foreach my $key (keys %opts) {
380 16         50 _check_plotting_option($key);
381             $self->{pdata}->set_attribute(
382             key => $key,
383 15         80 value => $opts{$key}
384             );
385             }
386 12         48 return $self;
387             }
388              
389             sub get_plot {
390 242     242 1 2377 my ($self, $arg_name) = @_;
391 242         649 _check_plotting_option($arg_name);
392 241 50       463 croak "arg_name cannot be undef" if not defined $arg_name;
393 241         800 return $self->{pdata}->get_resolved_attribute($arg_name);
394             }
395              
396             sub delete_plot {
397 6     6 1 941 my ($self, @arg_names) = @_;
398 6         15 foreach my $arg_name (@arg_names) {
399 8         24 _check_plotting_option($arg_name);
400 7         27 $self->{pdata}->delete_attribute($arg_name)
401             }
402 5         37 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__