File Coverage

lib/Google/RestApi/SheetsApi4/Request/Spreadsheet/Worksheet/Range.pm
Criterion Covered Total %
statement 121 206 58.7
branch 14 20 70.0
condition 14 18 77.7
subroutine 64 106 60.3
pod 0 97 0.0
total 213 447 47.6


line stmt bran cond sub pod time code
1             package Google::RestApi::SheetsApi4::Request::Spreadsheet::Worksheet::Range;
2              
3             our $VERSION = '1.0.4';
4              
5 1     1   577 use Google::RestApi::Setup;
  1         2  
  1         8  
6              
7 1     1   13305 use Scalar::Util qw( looks_like_number );
  1         3  
  1         75  
8 1     1   7 use aliased "Google::RestApi::SheetsApi4::Range";
  1         4  
  1         6  
9 1     1   186 use parent "Google::RestApi::SheetsApi4::Request::Spreadsheet::Worksheet";
  1         3  
  1         8  
10              
11 0     0 0 0 sub range { LOGDIE "Pure virtual function 'range' must be overridden"; }
12              
13 0     0 0 0 sub left { shift->horizontal_alignment('LEFT'); }
14 1     1 0 15 sub center { shift->horizontal_alignment('CENTER'); }
15 0     0 0 0 sub right { shift->horizontal_alignment('RIGHT'); }
16 1     1 0 17 sub horizontal_alignment { shift->user_entered_format({ horizontalAlignment => shift }); }
17              
18 0     0 0 0 sub top { shift->vertical_alignment('TOP'); }
19 0     0 0 0 sub middle { shift->vertical_alignment('MIDDLE'); }
20 0     0 0 0 sub bottom { shift->vertical_alignment('BOTTOM'); }
21 0     0 0 0 sub vertical_alignment { shift->user_entered_format({ verticalAlignment => shift }); }
22              
23 2     2 0 1562 sub font_family { shift->text_format({ fontFamily => shift }); }
24 3     3 0 1604 sub font_size { shift->text_format({ fontSize => shift }); }
25 4     4 0 1743 sub bold { shift->text_format({ bold => bool(shift) }); }
26 2     2 0 1567 sub italic { shift->text_format({ italic => bool(shift) }); }
27 2     2 0 1487 sub strikethrough { shift->text_format({ strikethrough => bool(shift) }); }
28 2     2 0 1504 sub underline { shift->text_format({ underline => bool(shift) }); }
29              
30 11   100 11   72 sub _rgba { shift->color({ (shift) => (shift // 1) }); }
31 6     6 0 1683 sub red { shift->_rgba('red' => shift); }
32 2     2 0 1705 sub blue { shift->_rgba('blue' => shift); }
33 2     2 0 1682 sub green { shift->_rgba('green' => shift); }
34 1     1 0 1702 sub alpha { shift->_rgba('alpha' => shift); }
35 1     1 0 1773 sub black { shift->color(cl_black()); }
36 1     1 0 2527 sub white { shift->color(cl_white()); }
37 13     13 0 52 sub color { shift->text_format({ foregroundColor => shift }); }
38              
39 4   50 4   29 sub _bk_rgba { shift->bk_color({ (shift) => (shift // 1) }); }
40 1     1 0 57 sub bk_red { shift->_bk_rgba('red' => shift); }
41 1     1 0 1591 sub bk_blue { shift->_bk_rgba('blue' => shift); }
42 1     1 0 1495 sub bk_green { shift->_bk_rgba('green' => shift); }
43 1     1 0 1576 sub bk_alpha { shift->_bk_rgba('alpha' => shift); }
44 2     2 0 1554 sub bk_black { shift->bk_color(cl_black()); }
45 2     2 0 3064 sub bk_white { shift->bk_color(cl_white()); }
46 8     8 0 37 sub bk_color { shift->user_entered_format({ backgroundColor => shift }); }
47              
48 0     0 0 0 sub text { shift->number_format('TEXT', @_); }
49 0     0 0 0 sub number { shift->number_format('NUMBER', @_); }
50 0     0 0 0 sub percent { shift->number_format('PERCENT', @_); }
51 0     0 0 0 sub currency { shift->number_format('CURRENCY', @_); }
52 0     0 0 0 sub date { shift->number_format('DATE', @_); }
53 0     0 0 0 sub time { shift->number_format('TIME', @_); }
54 0     0 0 0 sub date_time { shift->number_format('DATE_TIME', @_); }
55 0     0 0 0 sub scientific { shift->number_format('SCIENTIFIC', @_); }
56             sub number_format {
57             shift->user_entered_format(
58             {
59 0 0   0 0 0 numberFormat => {
60             type => shift,
61             defined $_[0] ? (pattern => shift) : ()
62             }
63             },
64             );
65             }
66              
67 1     1 0 26 sub padding { my $s = shift; my %p = @_; $s->user_entered_format({ padding => \%p }); }
  1         5  
  1         11  
68              
69 0     0 0 0 sub overflow { shift->wrap_strategy('OVERFLOW_CELL'); }
70 1     1 0 1583 sub clip { shift->wrap_strategy('CLIP'); }
71 0     0 0 0 sub wrap { shift->wrap_strategy('WRAP'); }
72 1     1 0 7 sub wrap_strategy { shift->user_entered_format({ wrapStrategy => shift }); }
73              
74 0     0 0 0 sub left_to_right { shift->text_direction('LEFT_TO_RIGHT'); }
75 1     1 0 1487 sub right_to_left { shift->text_direction('RIGHT_TO_LEFT'); }
76 1     1 0 7 sub text_direction { shift->user_entered_format({ textDirection => shift }); }
77              
78 1     1 0 1573 sub rotate { shift->text_rotation({ angle => shift }); }
79 1     1 0 1748 sub vertical { shift->text_rotation({ vertical => bool(shift) }); }
80 2     2 0 16 sub text_rotation { shift->user_entered_format({ textRotation => shift }); }
81              
82 1     1 0 1526 sub hyper_linked { shift->user_entered_format({ hyperlinkDisplayType => 'LINKED' }); }
83 0     0 0 0 sub hyper_plain { shift->user_entered_format({ hyperlinkDisplayType => 'PLAIN_TEXT' }); }
84              
85             sub text_format {
86 28     28 0 57 my $self = shift;
87 28         75 my ($format, $fields) = @_;
88 28 50       114 ($fields) = each %$format if !defined $fields;
89 28         147 $self->user_entered_format(
90             { textFormat => $format },
91             'textFormat.' . $fields,
92             );
93             }
94              
95             sub user_entered_format {
96 44     44 0 96 my $self = shift;
97 44         103 my ($format, $fields) = @_;
98 44 100       151 ($fields) = each %$format if !defined $fields;
99 44         271 $self->repeat_cell(
100             cell => {
101             userEnteredFormat => $format,
102             },
103             fields => 'userEnteredFormat.' . $fields,
104             );
105 44         351 return $self;
106             }
107              
108             sub repeat_cell {
109 44     44 0 78 my $self = shift;
110              
111 44         93 state $check = compile_named(
112             cell => HashRef,
113             fields => Str, { optional => 1 },
114             );
115 44         3503 my $p = $check->(@_);
116              
117 44         1688 my $cell = $p->{cell};
118 44   33     166 my $fields = $p->{fields} || join(',', sort keys %$cell);
119              
120 44         168 $self->batch_requests(
121             repeatCell => {
122             range => $self->range_to_index(),
123             cell => $cell,
124             fields => $fields,
125             },
126             );
127              
128 44         161 return $self;
129             }
130              
131             sub heading {
132 0     0 0 0 my $self = shift;
133 0         0 $self->center()->bold()->white()->bk_black()->font_size(12);
134 0         0 return $self;
135             }
136              
137 30   100 30   115 sub _bd { shift->borders(properties => shift, border => (shift||'')); };
138 5     5 0 166 sub bd_red { shift->_bd_rbga('red' => shift, @_); }
139 1     1 0 1416 sub bd_blue { shift->_bd_rbga('blue' => shift, @_); }
140 1     1 0 1408 sub bd_green { shift->_bd_rbga('green' => shift, @_); }
141 1     1 0 1389 sub bd_alpha { shift->_bd_rbga('alpha' => shift, @_); }
142 2     2 0 1326 sub bd_black { shift->bd_color(cl_black(), @_); }
143 2     2 0 2629 sub bd_white { shift->bd_color(cl_white(), @_); }
144 12     12 0 48 sub bd_color { shift->_bd({ color => shift }, @_); }
145              
146 12     12 0 7868 sub bd_dotted { shift->bd_style('DOTTED', @_); }
147 1     1 0 1177 sub bd_dashed { shift->bd_style('DASHED', @_); }
148 1     1 0 1166 sub bd_solid { shift->bd_style('SOLID', @_); }
149 1     1 0 1161 sub bd_medium { shift->bd_style('SOLID_MEDIUM', @_); }
150 1     1 0 1123 sub bd_thick { shift->bd_style('SOLID_THICK', @_); }
151 1     1 0 1116 sub bd_double { shift->bd_style('DOUBLE', @_); }
152 1     1 0 1179 sub bd_none { shift->bd_style('NONE', @_); }
153 18     18 0 74 sub bd_style { shift->_bd({ style => shift }, @_); }
154              
155             # allows:
156             # bd_red() turns it all on
157             # bd_red(0) turns it all off
158             # bd_red(0.3, 'top')
159             # bd_red(0.3)
160             # bd_red('top')
161             sub _bd_rbga {
162 8     8   20 my $self = shift;
163 8         15 my $color = shift;
164 8         16 my $value;
165 8 100       39 $value = shift if looks_like_number($_[0]);
166 8   100     32 $value //= 1;
167 8         37 return $self->bd_color({ $color => $value }, @_);
168             }
169              
170             # borders can be set for a range or each individual cell
171             # in a range. bd_repeat_cell is turned on to redirect
172             # border calls to repeat_cell above.
173             sub bd_repeat_cell {
174 1     1 0 43 my $self = shift;
175 1         4 $self->{bd_repeat_cell} = shift;
176 1   50     9 $self->{bd_repeat_cell} //= 1; # bd_repeat_cell() turns it on, bd_repeat_cell(0) turns it off.
177 1 50       6 delete $self->{bd_repeat_cell} if !$self->{bd_repeat_cell};
178 1         9 return $self;
179             }
180              
181             sub borders {
182 57     57 0 107 my $self = shift;
183              
184             # allow an array of borders to be passed, recurse with each one.
185 57         202 my %p = @_;
186 57 100 100     292 if ($p{border} && ref($p{border}) eq 'ARRAY') {
187             $self->borders(border => $_, properties => $p{properties})
188 1         4 foreach (@{ $p{border} });
  1         7  
189 1         11 return $self;
190             }
191              
192 56         119 state $check = compile_named(
193             border =>
194             StrMatch[qr/^(top|bottom|left|right|around|vertical|horizontal|inner|all|)$/],
195             { default => 'around' },
196             properties => HashRef,
197             );
198 56         4783 my $p = $check->(@_);
199 56   100     2271 $p->{border} ||= 'around';
200              
201             # recurse with border groups.
202 56         280 my %groups = (
203             around => [qw(top bottom left right)],
204             inner => [qw(vertical horizontal)],
205             all => [qw(around inner)],
206             );
207 56         157 my $group = $groups{ $p->{border} };
208 56 100       138 if ($group) {
209             $self->borders(border => $_, properties => $p->{properties})
210 9         45 foreach (@$group);
211 8         75 return $self;
212             }
213              
214             # now we finally get to the guts of the borders.
215             # if these borders are to be part of repeatCell request, redirect
216             # the borders to it.
217 47 100       134 if ($self->{bd_repeat_cell}) {
218             LOGDIE "Cannot use vertical|horizontal|inner when bd_repeat_cell is turned on"
219 4 100       30 if $p->{border} =~ /^(vertical|horizontal|inner)$/;
220             return $self->user_entered_format(
221             {
222             borders => {
223             $p->{border} => $p->{properties},
224             }
225             },
226 1         9 );
227             }
228              
229             # change vertical to innerVertical. horizontal same same.
230 43         158 $p->{border} =~ s/^(vertical|horizontal)$/"'inner' . '" . ucfirst($1) . "'"/ee;
  8         932  
231              
232             $self->batch_requests(
233             updateBorders => {
234             range => $self->range_to_index(),
235             $p->{border} => $p->{properties},
236             }
237 43         176 );
238              
239 43         356 return $self;
240             }
241              
242 1     1 0 7 sub merge_cols { shift->merge_cells(merge_type => 'col'); }
243 1     1 0 2171 sub merge_rows { shift->merge_cells(merge_type => 'row'); }
244 1     1 0 5 sub merge_all { shift->merge_cells(merge_type => 'all'); }
245 1     1 0 1762 sub merge_both { merge_all(@_); }
246             sub merge_cells {
247 3     3 0 9 my $self = shift;
248              
249 3         12 state $check = compile_named(
250             merge_type => DimColRow | DimAll,
251             );
252 3         40408 my $p = $check->(@_);
253 3         157 $p->{merge_type} = dims_all($p->{merge_type});
254              
255 3         15 $self->batch_requests(
256             mergeCells => {
257             range => $self->range_to_index(),
258             mergeType => "MERGE_$p->{merge_type}",
259             },
260             );
261              
262 3         14 return $self;
263             }
264              
265 0     0 0   sub unmerge { unmerge_cells(@_); }
266             sub unmerge_cells {
267 0     0 0   my $self = shift;
268 0           $self->batch_requests(
269             unmergeCells => {
270             range => $self->range_to_index(),
271             },
272             );
273 0           return $self;
274             }
275              
276 0     0 0   sub insert_d { shift->insert_dimension(dimension => shift, inherit => shift); }
277             sub insert_dimension {
278 0     0 0   my $self = shift;
279              
280 0           state $check = compile_named(
281             dimension => Str,
282             inherit => Bool, { default => 0 }
283             );
284 0           my $p = $check->(@_);
285              
286             $self->batch_requests(
287             insertDimension => {
288             range => $self->range_to_dimension($p->{dimension}),
289             inheritFromBefore => $p->{inherit},
290             },
291 0           );
292              
293 0           return $self;
294             }
295              
296 0     0 0   sub insert_r { shift->insert_dimension(dimension => shift); }
297             sub insert_range {
298 0     0 0   my $self = shift;
299              
300 0           state $check = compile_named(
301             dimension => Str,
302             );
303 0           my $p = $check->(@_);
304              
305             $self->batch_requests(
306             insertRange => {
307             range => $self->range_to_dimension($p->{dimension}),
308             },
309             shiftDimension => $p->{dimension},
310 0           );
311              
312 0           return $self;
313             }
314              
315 0     0 0   sub move { shift->move_dimension(dimension => shift, destination => shift); }
316             sub move_dimension {
317 0     0 0   my $self = shift;
318              
319 0           state $check = compile_named(
320             dimension => Str,
321             destination => HasMethods['range_to_index'],
322             );
323 0           my $p = $check->(@_);
324              
325             $self->batch_requests(
326             insertDimension => {
327             range => $self->range_to_dimension($p->{dimension}),
328             destinationIndex => $p->{destination},
329             },
330 0           );
331              
332 0           return $self;
333             }
334              
335             sub copy_paste {
336 0     0 0   my $self = shift;
337              
338 0           state $check = compile_named(
339             destination => HasMethods['range_to_index'],
340             type => Str, { default => 'normal' },
341             orientation => Str, { default => 'normal' },
342             );
343 0           my $p = $check->(@_);
344 0           $p->{type} = "PASTE_" . uc($p->{type});
345 0           $p->{orientation} = uc($p->{orientation});
346              
347             $self->batch_requests(
348             copyPaste => {
349             source => $self->range_to_index(),
350             destination => $p->{destination}->range_to_index(),
351             type => $p->{type},
352             orientation => $p->{orientation},
353             },
354 0           );
355              
356 0           return $self;
357             }
358              
359             sub cut_paste {
360 0     0 0   my $self = shift;
361              
362 0           state $check = compile_named(
363             destination => HasMethods['range_to_index'],
364             type => Str, { default => 'normal' },
365             );
366 0           my $p = $check->(@_);
367 0           $p->{type} = "PASTE_" . uc($p->{type});
368              
369             $self->batch_requests(
370             cutPaste => {
371             source => $self->range_to_index(),
372             destination => $p->{destination}->range_to_index(),
373             type => $p->{type},
374             },
375 0           );
376              
377 0           return $self;
378             }
379              
380 0     0 0   sub delete_d { shift->delete_dimension(dimension => shift); }
381             sub delete_dimension {
382 0     0 0   my $self = shift;
383              
384 0           state $check = compile_named(dimension => Str);
385 0           my $p = $check->(@_);
386              
387             $self->batch_requests(
388             deleteDimension => {
389 0           range => $self->range_to_dimension($p->{dimension}),
390             },
391             );
392              
393 0           return $self;
394             }
395              
396 0     0 0   sub delete_r { shift->delete_range(dimension => shift); }
397             sub delete_range {
398 0     0 0   my $self = shift;
399              
400 0           state $check = compile_named(dimension => Str);
401 0           my $p = $check->(@_);
402              
403             $self->batch_requests(
404             deleteRange => {
405             range => $self->range_to_dimension($p->{dimension}),
406             },
407             shiftDimension => $p->{dimension},
408 0           );
409              
410 0           return $self;
411             }
412              
413 0     0 0   sub named_a { shift->add_named(name => shift); }
414             sub add_named {
415 0     0 0   my $self = shift;
416              
417 0           state $check = compile_named(name => Str);
418 0           my $p = $check->(@_);
419              
420             $self->batch_requests(
421             addNamedRange => {
422             namedRange => {
423             name => $p->{name},
424 0           range => $self->range_to_index(),
425             },
426             }
427             );
428              
429 0           return $self;
430             }
431              
432 0     0 0   sub named_d { shift->delete_named(); }
433             sub delete_named {
434 0     0 0   my $self = shift;
435              
436 0 0         my $named = $self->named() or LOGDIE "Not a named range";
437 0           $self->batch_requests(
438             deleteNamedRange => {
439             namedRangeId => $named,
440             },
441             );
442              
443 0           return $self;
444             }
445              
446             sub _clear {
447 0     0     my $self = shift;
448 0           return $self->SUPER::_clear(@_, $self->range_to_index());
449             }
450              
451 0     0 0   sub range_to_index { shift->range()->range_to_index(@_); }
452 0     0 0   sub range_to_dimension { shift->range()->range_to_dimension(@_); }
453              
454             1;
455              
456             __END__
457              
458             =head1 NAME
459              
460             Google::RestApi::SheetsApi4::Request::Spreadsheet::Worksheet::Range - Build Google API's batchRequests for a Range.
461              
462             =head1 DESCRIPTION
463              
464             Deriving from the Request::Spreadsheet::Worksheet object, this adds the ability to create
465             requests that have to do with ranges (formatting, borders etc).
466              
467             See the description and synopsis at Google::RestApi::SheetsApi4::Request.
468             and Google::RestApi::SheetsApi4.
469              
470             =head1 AUTHORS
471              
472             =over
473              
474             =item
475              
476             Robin Murray mvsjes@cpan.org
477              
478             =back
479              
480             =head1 COPYRIGHT
481              
482             Copyright (c) 2021, Robin Murray. All rights reserved.
483              
484             This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself.