File Coverage

lib/Google/RestApi/SheetsApi4/Worksheet.pm
Criterion Covered Total %
statement 163 239 68.2
branch 23 60 38.3
condition 14 25 56.0
subroutine 44 60 73.3
pod 34 45 75.5
total 278 429 64.8


line stmt bran cond sub pod time code
1              
2             our $VERSION = '1.0.2';
3              
4             use Google::RestApi::Setup;
5 1     1   548  
  1         2  
  1         5  
6             use List::MoreUtils qw( first_index );
7 1     1   19347  
  1         8601  
  1         6  
8             use aliased 'Google::RestApi::SheetsApi4';
9 1     1   919 use aliased 'Google::RestApi::SheetsApi4::Range';
  1         2  
  1         6  
10 1     1   162 use aliased 'Google::RestApi::SheetsApi4::Range::Col';
  1         2  
  1         4  
11 1     1   111 use aliased 'Google::RestApi::SheetsApi4::Range::Row';
  1         2  
  1         6  
12 1     1   160 use aliased 'Google::RestApi::SheetsApi4::Range::Cell';
  1         2  
  1         4  
13 1     1   147 use aliased 'Google::RestApi::SheetsApi4::Range::All';
  1         3  
  1         4  
14 1     1   152 use aliased 'Google::RestApi::SheetsApi4::RangeGroup::Tie';
  1         3  
  1         3  
15 1     1   86 use aliased 'Google::RestApi::SheetsApi4::RangeGroup::Iterator';
  1         2  
  1         6  
16 1     1   101  
  1         3  
  1         4  
17             use parent 'Google::RestApi::SheetsApi4::Request::Spreadsheet::Worksheet';
18 1     1   152  
  1         2  
  1         3  
19             my $class = shift;
20              
21 118     118 1 8096 my $qr_worksheet_uri = SheetsApi4->Worksheet_Uri;
22             state $check = compile_named(
23 118         504 spreadsheet => HasApi,
24 118         256 id => Str, { optional => 1 }, # the worksheet id (1, 2, 3 etc).
25             name => Str, { optional => 1 }, # the name of the worksheet.
26             title => Str, { optional => 1 },
27             uri => StrMatch[qr|$qr_worksheet_uri|], { optional => 1 },
28             );
29             my $self = $check->(@_);
30             $self = bless $self, $class;
31 118         2916  
32 118         4521 $self->{name} ||= $self->{title};
33             delete $self->{title};
34 118   66     1003  
35 118         446 defined $self->{id} || defined $self->{name} || $self->{uri}
36             or LOGDIE "At least one of id, name, or uri must be specified";
37              
38 118 100 100     902 return $self->spreadsheet()->_register_worksheet($self);
      100        
39             }
40 117         531  
41             # work out the id from the uri or the name.
42             my $self = shift;
43             if (!defined $self->{id}) {
44             if ($self->{uri}) {
45 223     223 1 415 my $qr_worksheet_uri = SheetsApi4->Worksheet_Uri;
46 223 100       930 ($self->{id}) = $self->{uri} =~ m|$qr_worksheet_uri|;
47 1 50       8 LOGDIE "Unable to extract a worksheet id from URI '$self->{uri}'" if !defined $self->{id};
48 1         6 } else {
49 1         80 my $worksheets = $self->spreadsheet()->worksheet_properties('(title,sheetId)'); # potential recursion if $self->properties()
50 1 50       9 my ($worksheet) = grep { $_->{title} eq $self->{name}; } @$worksheets;
51             $worksheet or LOGDIE "Worksheet '$self->{name}' not found";
52 0         0 $self->{id} = $worksheet->{sheetId};
53 0         0 }
  0         0  
54 0 0       0 DEBUG("Got worksheet id '$self->{id}'");
55 0         0 }
56             return $self->{id};
57 1         13 }
58              
59 223         1546 my $self = shift;
60             $self->{name} //= $self->properties('title')->{title};
61             return $self->{name};
62             }
63 1016     1016 1 1758  
64 1016   66     3169 # https://docs.google.com/spreadsheets/d/spreadsheetId/edit#gid=0
65 1016         2837 my $self = shift;
66             if (!$self->{uri}) {
67 0     0 0 0 my $id = $self->worksheet_id();
68             $self->{uri} = "/edit#gid=$id";
69             }
70             return $self->spreadsheet()->spreadsheet_uri() . "/$self->{uri}";
71 0     0 1 0 }
72 0 0       0  
73 0         0 my $self = shift;
74 0         0 my $what = shift;
75             my $id = $self->worksheet_id();
76 0         0 my $worksheets = $self->spreadsheet()->worksheet_properties("($what,sheetId)");
77             my ($worksheet) = grep { $_->{sheetId} eq $id; } @$worksheets;
78             $worksheet or LOGDIE "Worksheet '$id' not found";
79             return $worksheet;
80 116     116 1 225 }
81 116         276  
82 116         355 # the following don't return ranges and don't use any batch, they are immediate.
83 116         395 # first arg is a range in any format. allow the range_col call to verify it.
84 116         365 my $self = shift;
  116         705  
85 116 50       501 state $check = compile(Defined, ArrayRef[Str], { optional => 1 }); # A or 1
86 116         919 my ($col, $values) = $check->(@_);
87             my $range = $self->range_col($col);
88             return $range->values(defined $values ? (values => $values) : ());
89             }
90              
91             my $self = shift;
92 3     3 1 72  
93 3         18 state $check = compile(ArrayRef[Defined], ArrayRef[ArrayRef[Str]], { optional => 1 });
94 3         1646 my ($cols, $values) = $check->(@_);
95 3         63  
96 2 100       21 my $range_group = $self->range_group_cols($cols);
97             return $range_group->values() if !$values;
98              
99             my @ranges = $range_group->ranges();
100 3     3 1 2670 foreach my $i (0..$#ranges) {
101             $ranges[$i]->batch_values(
102 3         18 values => $values->[$i],
103 3         2566 );
104             }
105 3         83  
106 2 100       101 return $range_group->submit_values();
107             }
108 1         7  
109 1         6 my $self = shift;
110 3         16 state $check = compile(Defined, ArrayRef[Str], { optional => 1 });
111             my ($row, $values) = $check->(@_);
112             my $range = $self->range_row($row);
113             return $range->values(defined $values ? (values => $values) : ());
114             }
115 1         8  
116             my $self = shift;
117              
118             state $check = compile(ArrayRef[Defined], ArrayRef[ArrayRef[Str]], { optional => 1 });
119 3     3 1 69 my ($rows, $values) = $check->(@_);
120 3         17  
121 3         1692 my $range_group = $self->range_group_rows($rows);
122 3         66 return $range_group->values() if !$values;
123 2 100       17  
124             my @ranges = $range_group->ranges();
125             foreach my $i (0..$#ranges) {
126             $ranges[$i]->batch_values(
127 3     3 1 1258 values => $values->[$i],
128             );
129 3         15 }
130 3         2130  
131             return $range_group->submit_values();
132 3         81 }
133 2 100       104  
134             my $self = shift;
135 1         7 state $check = compile(Defined, Str, { optional => 1 });
136 1         7 my ($cell, $value) = $check->(@_);
137 3         15 my $range = $self->range_cell($cell);
138             return $range->values(defined $value ? (values => $value) : ());
139             }
140              
141             my $self = shift;
142 1         11  
143             state $check = compile(ArrayRef[Defined], ArrayRef[Str], { optional => 1 });
144             my ($cells, $values) = $check->(@_);
145              
146 48     48 1 131 my $range_group = $self->range_group_cells($cells);
147 48         91 return $range_group->values() if !$values;
148 48         1000  
149 48         616 my @ranges = $range_group->ranges();
150 48 50       208 foreach my $i (0..$#ranges) {
151             $ranges[$i]->batch_values(
152             values => $values->[$i],
153             );
154 0     0 0 0 }
155              
156 0         0 return $range_group->submit_values();
157 0         0 }
158              
159 0         0 # the 'ranges' key is poorly named since we can also submit requests for
160 0 0       0 # worksheets and spreadsheets. minor since this is all internal anyway.
161             my $self = shift;
162 0         0 return $self->spreadsheet()->submit_requests(ranges => [ $self ], @_);
163 0         0 }
164 0         0  
165             # this is used by range to see if there is a match for a header col or row.
166             my $self = shift;
167             return
168             $self->resolve_header_range_col(@_) ||
169 0         0 $self->resolve_header_range_row(@_);
170             }
171              
172             my $self = shift;
173              
174             state $check = compile(RangeNamed);
175 0     0 1 0 my ($header) = $check->(@_);
176 0         0
177             my $headers = $self->header_col() or return;
178             my $i = first_index { $_ eq $header; } @$headers;
179             return [{col => 2, row => $i}, {row => $i}] if ++$i > 0;
180              
181 1     1 0 4 return;
182             }
183 1   33     6  
184             my $self = shift;
185              
186             state $check = compile(RangeNamed);
187             my ($header) = $check->(@_);
188 1     1 0 3
189             my $headers = $self->header_row() or return;
190 1         6 my $i = first_index { $_ eq $header; } @$headers;
191 1         736 return [{col => $i, row => 2}, {col => $i}] if ++$i > 0;
192              
193 1 50       21 return;
194 0     0   0 }
  0         0  
195 0 0       0  
196             # call this before calling tie_rows or header_col.
197 0         0 # ('i really want to do this') turns it on, (false) turns it off.
198             # you must pass 'i really want to do this' to enable it. this is because you
199             # may have a worksheet with thousands of rows that end up being 'headers'.
200             # this is less of an issue with header row.
201 1     1 0 3 my $self = shift;
202             my $enable = shift // 1;
203 1         4 if ($enable =~ qr/i really want to do this/i) {
204 1         675 $self->{header_col_enabled} = 1;
205             } elsif ($enable) {
206 1 50       22 LOGDIE("You must enable header column by passing 'I really want to do this'");
207 0     0   0 } else {
  0         0  
208 0 0       0 delete @{$self}{qw(header_col header_col_enabled)};
209             }
210 0         0 return $enable;
211             }
212              
213             # call with true to refresh.
214             my $self = shift;
215             my $refresh = shift;
216              
217             if (!$self->{header_col_enabled}) {
218             DEBUG("Header column is not enabled, call 'enable_header_col' first.");
219 0     0 1 0 delete $self->{header_col};
220 0   0     0 return;
221 0 0       0 }
    0          
222 0         0  
223             delete $self->{header_col} if $refresh;
224 0         0  
225             if (!$self->{header_col}) {
226 0         0 $self->{header_col} = $self->col(1);
  0         0  
227             DEBUG("Header col found:\n", Dump($self->{header_col}));
228 0         0 }
229              
230             return $self->{header_col};
231             }
232              
233 1     1 1 4 # call this before calling tie_cols (to use headings) or header_row.
234 1         2 # () or (true) turns it on, (false) turns it off.
235             my $self = shift;
236 1 50       6 my $enable = shift // 1;
237 1         6 if ($enable) {
238 1         12 $self->{header_row_enabled} = 1;
239 1         15 } else {
240             delete @{$self}{qw(header_row header_row_enabled)};
241             }
242 0 0       0 return $enable;
243             }
244 0 0       0  
245 0         0 # call with 1 to refresh.
246 0         0 my $self = shift;
247             my $refresh = shift;
248              
249 0         0 if (!$self->{header_row_enabled}) {
250             DEBUG("Header row is not enabled, call 'enable_header_row' first.");
251             delete $self->{header_row};
252             return;
253             }
254              
255 3     3 1 17 delete $self->{header_row} if $refresh;
256 3   50     19  
257 3 50       14 if (!$self->{header_row}) {
258 3         10 $self->{header_row} = $self->row(1);
259             DEBUG("Header row found:\n", Dump($self->{header_row}));
260 0         0 }
  0         0  
261             return $self->{header_row};
262 3         8 }
263              
264              
265             my $self = shift;
266              
267 1     1 1 3 state $check = compile(RangeNamed);
268 1         3 my ($named_range_name) = $check->(@_);
269              
270 1 50       6 my ($sheet_id, $range) = $self->spreadsheet()->normalize_named($named_range_name);
271 1         5 my $this_sheet_id = $self->worksheet_id();
272 1         10 LOGDIE "Named range '$named_range_name' sheet ID is '$sheet_id', this sheet ID is '$this_sheet_id'"
273 1         8 if $sheet_id && $sheet_id != $this_sheet_id;
274              
275             return $range;
276 0 0       0 }
277              
278 0 0       0 # create a hash of name => value pairs from two columns in a worksheet.
279 0         0 my $self = shift;
280 0         0  
281             state $check = compile(
282 0         0 Defined, { default => 1 }, # column of names (hash keys).
283             Defined, { default => 2 }, # column of values.
284             );
285 0     0 0 0 my ($name_col, $value_col) = $check->(@_);
286 0     0 0 0  
287             my $cols = $self->cols([$name_col, $value_col]);
288             my %pairs = map {
289 1     1 0 3 defined $cols->[0]->[$_]
290             ?
291 1         4 ( strip($cols->[0]->[$_]) => strip($cols->[1]->[$_]) )
292 1         702 :
293             ();
294 1         18 } (($self->header_row_enabled() ? 1 : 0)..$#{ $cols->[0] });
295 1         4  
296 1 50 33     7 return \%pairs;
297             }
298              
299 1         6  
300             my $self = shift;
301              
302             state $check = compile(
303             Str->where( sub { /^range/ && $self->can($_) or die "Must be a 'range' method"; } ),
304 0     0 1 0 slurpy HashRef,
305             );
306 0         0 my ($method, $ranges) = $check->(@_);
307              
308             my %ranges = map { $_ => $self->$method( $ranges->{$_} ); } keys %$ranges;
309             return $self->tie(%ranges);
310 0         0 }
311              
312 0         0 my $self = shift;
313             my $tie = $self->spreadsheet()->tie(@_);
314 0 0       0 tied(%$tie)->default_worksheet($self);
315             return $tie;
316             }
317              
318             my $self = shift;
319 0 0       0 state $check = compile(ArrayRef[Defined]);
  0         0  
320             my ($cols) = $check->(@_);
321 0         0 my @cols = map { $self->range_col($_); } @$cols;
322             return $self->spreadsheet()->range_group(@cols);
323             }
324 3     3 1 40  
325 1     1 1 5 my $self = shift;
326 3     3 1 14 state $check = compile(ArrayRef[Defined]);
327 4     4 1 10 my ($rows) = $check->(@_);
328             my @rows = map { $self->range_row($_); } @$rows;
329             return $self->spreadsheet()->range_group(@rows);
330 11     11   20 }
331              
332             my $self = shift;
333 11 50 33 11   28 state $check = compile(ArrayRef[Defined]);
  11         262  
334             my ($cells) = $check->(@_);
335             my @cells = map { $self->range_cell($_); } @$cells;
336 11         1151 return $self->spreadsheet()->range_group(@cells);
337             }
338 11         249  
  25         96  
339 11         51 # an arbitrary mix of ranges.
340             my $self = shift;
341             state $check = compile(ArrayRef[Defined]);
342             my ($ranges) = $check->(@_);
343 15     15 1 45 my @ranges = map { $self->range_factory($_); } @$ranges;
344 15         45 return $self->spreadsheet()->range_group(@ranges);
345 15         73 }
346 15         114  
347             # can't use aliased here for some reason.
348              
349             # create these spcific subclasses so that invalid ranges will get caught.
350 3     3 1 8  
351 3         14 1;
352 3         819  
353 3         40  
  7         35  
354 2         16 =head1 NAME
355              
356             Google::RestApi::SheetsApi4::Worksheet - Represents a Worksheet within a Google Spreadsheet.
357              
358 3     3 1 8 =head1 DESCRIPTION
359 3         13  
360 3         986 See the description and synopsis at L<Google::RestApi::SheetsApi4>.
361 3         48  
  7         30  
362 2         13 =head1 NAVIGATION
363              
364             =over
365              
366 0     0 1 0 =item * L<Google::RestApi::SheetsApi4>
367 0         0  
368 0         0 =item * L<Google::RestApi::SheetsApi4::Spreadsheet>
369 0         0  
  0         0  
370 0         0 =item * L<Google::RestApi::SheetsApi4::Worksheet>
371              
372             =item * L<Google::RestApi::SheetsApi4::Range>
373              
374             =item * L<Google::RestApi::SheetsApi4::Range::All>
375 0     0 1 0  
376 0         0 =item * L<Google::RestApi::SheetsApi4::Range::Col>
377 0         0  
378 0         0 =item * L<Google::RestApi::SheetsApi4::Range::Row>
  0         0  
379 0         0  
380             =item * L<Google::RestApi::SheetsApi4::Range::Cell>
381              
382             =item * L<Google::RestApi::SheetsApi4::RangeGroup>
383 59     59 0 487  
384             =item * L<Google::RestApi::SheetsApi4::RangeGroup::Iterator>
385 43     43 1 221  
386             =item * L<Google::RestApi::SheetsApi4::RangeGroup::Tie>
387 32     32 1 432  
388 28     28 1 380 =item * L<Google::RestApi::SheetsApi4::RangeGroup::Tie::Iterator>
389 74     74 1 405  
390 0     0 1 0 =item * L<Google::RestApi::SheetsApi4::Request::Spreadsheet>
391 55     55 1 157  
392 0     0 1 0 =item * L<Google::RestApi::SheetsApi4::Request::Spreadsheet::Worksheet>
393 7     7 0 66  
394 322     322 1 1944 =item * L<Google::RestApi::SheetsApi4::Request::Spreadsheet::Worksheet::Range>
395 0     0 1    
396 0     0 0   =back
397              
398             =head1 SUBROUTINES
399              
400             =over
401              
402             =item new(spreadsheet => <object>, (id => <string> | name => <string> | uri => <string>));
403              
404             Creates a new instance of a Worksheet object. You would not normally
405             call this directly, you would obtain it from the
406             Spreadsheet->open_worksheet routine.
407              
408             spreadsheet: The parent object that represents the collection of worksheets.
409             id: The id of the worksheet (0, 1, 2 etc).
410             name: The name of the worksheet (as shown on the tab).
411             uri: The worksheet ID extracted from the overall URI.
412              
413             Only one of id/name/uri should be specified and this API will derive the others
414             as necessary.
415              
416             =item worksheet_id()
417              
418             Returns the worksheet id.
419              
420             =item worksheet_name()
421              
422             Returns the worksheet name or title.
423              
424             =item worksheet_uri()
425              
426             Returns the worksheet URL (URL);
427              
428             =item properties(what<string>);
429              
430             Returns the specific properties of this worksheet, such as the title or sheet id (sheetId).
431              
432             =item col(range<range>, values<arrayref>);
433              
434             Positional args consist of:
435              
436             =over
437              
438             =item * C<<range>>: A range representing a column.
439              
440             =item * C<<arrayref<str>>>: An array of strings of column values.
441              
442             =back
443              
444             Gets or sets the column values.
445              
446             $ws->col('A', [1, 2, 3]);
447             $values = $ws->col('A');
448              
449             Note: the Google API is called immediately, so this is the easiest but least efficient way of getting/setting spreadsheet values.
450              
451             Returns the values for the specified column.
452              
453             =item cols(cols, values); Positional args consist of:
454              
455             =over
456              
457             =item C<<arrayref<range>>>: An array of ranges that represent columns.
458              
459             =item C<<arrayref<arrayref<string>>>>: An optional array of values to set the columns to.
460              
461             =back
462              
463             Gets or sets a group of columns, see note for 'col' above.
464              
465             $ws->cols(['A', 2, 'Id'], [[1, 2, 3, 4], [5], [6, 7]]);
466             $values = $ws->cols(['A', 2, 'Id']);
467              
468             Returns the values for the specified columns.
469              
470             =item row(range<range>, values<arrayref<string>>);
471              
472             Same as 'col' above, but operates on a row.
473              
474             =item rows(rows<arrayref<range>>, values<arrayref<arrayref<string>>>)
475              
476             Same as 'cols' above, but operates on rows.
477              
478             =item cell(col<range>, row<range>|range<range>), value<string>);
479              
480             Same as above, but operates on a cell.
481              
482             =item enable_header_row(enable<boolean>)
483              
484             This turns on/off the header row so that column headings can be used as keys to tied hashes. See header_row.
485              
486             =item header_row(refresh<boolean>)
487              
488             Returns an array of values in the first row that act as simple
489             headers for the columns. The values are cached in the worksheet
490             so that multiple calls will only invoke the API once, unless you
491             pass a true value to the routine to refresh them.
492              
493             This is used internally to check for indexed column names such as
494             'Id', 'Name' or 'Address' etc. It may be of limited use externally.
495              
496             This will only work on simple headers that don't use fancy formatting
497             spread over multiple merged cells/rows.
498              
499             =item enable_header_col(enable<boolean>)
500              
501             This turns on/off the header row so that column headings can be used as keys to tied hashes. See header_col.
502              
503             You must pass C<i really want to do this> to turn it on. This is because you may have a worksheet with thousands of rows that end up being 'headers'. This is less of an issue with header row.
504              
505             =item header_col(refresh<boolean>)
506              
507             A less practical version of header_row, uses the first column to
508             label each row. Since this is cached, if the spreadsheet is large,
509             this can potentially use a lot of memory. Therefore, you must call
510             enable_header_col first, with C<i really want to do this> value, to obtain these column values.
511              
512             =item name_value_pairs(name_col<range>, value_col<range>);
513              
514             A utility to convert two columns into a simple hash.
515              
516             name_col: A range pointing to the keys of the hash.
517             value_col: A range pointing to the values of the hash.
518              
519             A spreadsheet with the values:
520              
521             Name Value
522             Fred 1
523             Charlie 2
524            
525             ...will return the hash:
526              
527             Fred => 1,
528             Charlie => 2,
529              
530             This allows you to store and retrieve a hash with little muss or fuss.
531              
532             =item tie_ranges(ranges<array<hash|<string>>>...);
533              
534             Ties the given ranges into a tied range group. Specify
535             either a 'key => range<range>' or a plain <range<string>>.
536              
537             $tied = $ws->tie_ranges({id => 'A2'}, 'B2', 'A5:B6');
538             $tied->{id} = [['1001']];
539             $tied->{B2} = [['Herb Ellis']];
540             $tied->{A5:B6} = [[1, 2], [3, 4]];
541             tied(%$tied)->submit_values();
542              
543             If you need to represent the range as anything but a string, you must
544             specify the key=>range format ({id => [1, 2]} or {id => {col => 1, row => 1}}).
545              
546             =item tie_cols(ranges<array<range>>...);
547              
548             Same as tie_ranges (above), but ties Range::Col objects. Specify
549             range strings, or column headings to represent the columns.
550              
551             $tied = $ws->tie_cols({id => 'A'}, 'Name');
552             $tied->{id} = [1001, 1002, 1003];
553             $tied->{Name} = ['Herb Ellis', 'Bela Fleck', 'Freddie Mercury'];
554             tied(%$tied)->submit_values();
555              
556             =item tie_rows(ranges<array<range>>...);
557              
558             Same as tie_cols (above), but ties Range::Row objects.
559              
560             $tied = $ws->tie_rows({herb => 2}, {bela => 3});
561             $tied->{herb} = ['Herb Ellis'];
562             $tied->{bela} = ['Bela Fleck'];
563             tied(%$tied)->submit_values();
564              
565             To use row 'headings' as ranges (assuming 'Herb Ellis' is in column 1),
566             you must call 'enable_header_col' to enable the row headers first
567             (see below).
568              
569             =item tie_cells(ranges<array<range>>...);
570              
571             Same as above, but ties Range::Cell objects.
572              
573             $tied = $ws->tie_cells(qw({id => A2}, B2));
574             $tied->{id} = 1001;
575             $tied->{B2} = 'Herb Ellis';
576             tied(%$tied)->submit_values();
577              
578             =item tie(ranges<hash>);
579              
580             Ties the given 'key => range' pairs into a tied range group, and sets
581             the default worksheet, for any new keys later added, to this worksheet.
582              
583             $tied = $ws->tie(id => $range_cell);
584             $tied->{id} = 1001;
585             $teid->{B2} = 'Herb Ellis'; # autocreated for this worksheet.
586             tied(%$tied)->submit_values();
587              
588             New keys that are added later are assumed to address cells if there is
589             no ':' (A1), or a general range if a ':' is found (A1:B2). It is better
590             to explicitly set all the ranges you expect to use on the call to 'tie'
591             rather than auto-creating the ranges later to avoid unexpected behaviour.
592              
593             See also L<Google::RestApi::SheetsApi4::Spreadsheet> C<tie>.
594              
595             =item submit_requests(%args)
596              
597             Submits any outstanding requests (API batchRequests) for this worksheet.
598             %args are any args to be passed to the RestApi's 'api' routine (content,
599             params etc).
600              
601             =item range(range<range>);
602              
603             Returns a Range object or one of its subclasses (Col, Row etc) representing the passed range. If you specify a range that
604             represents a column (A:A), you will get back a Range::Col object. To guaranty a particular subclass returned, use the below routines (range_col,
605             range_row, etc).
606              
607             =item range_col(range<range>);
608              
609             Returns a L<Google::RestApi::SheetsApi4::Range::Col> object representing the passed range. If you pass a non-column range, your script will die.
610              
611             =item range_row(range<range>);
612              
613             Returns a L<Google::RestApi::SheetsApi4::Range::Row> object representing the passed range.
614              
615             =item range_cell(range<range>);
616              
617             Returns a L<Google::RestApi::SheetsApi4::Range::Cell> object representing the passed range.
618              
619             =item range_all();
620              
621             Returns a L<Google::RestApi::SheetsApi4::Range::All> object that represents the whole worksheet. Caution: this class has not been fully tested.
622              
623             =item range_group_cols
624              
625             Returns a L<Google::RestApi::SheetsApi4::RangeGroup> object that represents a group of columns.
626              
627             =item range_group_rows(ranges<arrayref>);
628              
629             Returns a L<Google::RestApi::SheetsApi4::RangeGroup> object that represents a group of rows.
630              
631             =item range_group_cells(ranges<arrayref>);
632              
633             Returns a L<Google::RestApi::SheetsApi4::RangeGroup> object that represents a group of cells.
634              
635             =item range_group(ranges<arrayref>);
636              
637             Returns a L<Google::RestApi::SheetsApi4::RangeGroup> object that represents a group of arbitrary ranges.
638              
639             =item api(%args);
640              
641             A passthrough to the parent Spreadsheet object's 'api' routine.
642              
643             =item sheets_api();
644              
645             Returns the SheetsApi4 object.
646              
647             =item spreadsheet();
648              
649             Returns the parent Spreadsheet object.
650              
651             =item spreadsheet_id();
652              
653             Returns the parent Spreadsheet id.
654              
655             =back
656              
657             =head1 AUTHORS
658              
659             =over
660              
661             =item
662              
663             Robin Murray mvsjes@cpan.org
664              
665             =back
666              
667             =head1 COPYRIGHT
668              
669             Copyright (c) 2021, Robin Murray. All rights reserved.
670              
671             This program is free software; you may redistribute it and/or modify it under the same terms as Perl itself.