Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
324 | agaran | 1 | # Text::Table - Organize Data in Tables |
2 | package Text::Table; |
||
3 | use strict; |
||
4 | use warnings; |
||
5 | |||
6 | use Text::Aligner qw( align); |
||
7 | |||
8 | BEGIN { |
||
9 | use Exporter (); |
||
10 | our $VERSION = ('$Revision: 1.114 $' =~ /(\d+.\d+)/)[ 0]; |
||
11 | |||
12 | } |
||
13 | |||
14 | use overload |
||
15 | '""' => 'stringify', |
||
16 | ; |
||
17 | |||
18 | ### User interface: How to specify columns and column separators |
||
19 | |||
20 | sub _is_sep { |
||
21 | local $_ = shift; |
||
22 | defined and ( ref eq 'SCALAR' or ( ref eq 'HASH' and $_->{ is_sep})); |
||
23 | } |
||
24 | |||
25 | sub _parse_sep { |
||
26 | local $_ = shift; |
||
27 | defined $_ or $_ = ''; |
||
28 | my ( $title, $body); |
||
29 | if ( ref eq 'HASH' ) { |
||
30 | ( $title, $body) = @{ $_}{ qw( title body)}; |
||
31 | } else { |
||
32 | ( $title, $body) = split /\n/, $$_, -1; |
||
33 | } |
||
34 | $body = $title unless defined $body; |
||
35 | align( 'left', $title, $body); |
||
36 | { |
||
37 | is_sep => 1, |
||
38 | title => $title, |
||
39 | body => $body, |
||
40 | } |
||
41 | } |
||
42 | |||
43 | sub _parse_spec { |
||
44 | local $_ = shift; |
||
45 | defined $_ or $_ = ''; |
||
46 | my $alispec = qr/^ *(?:left|center|right|num|point|auto)/; |
||
47 | my ( $title, $align, $align_title, $align_title_lines, $sample); |
||
48 | if ( ref eq 'HASH' ) { |
||
49 | ( $title, $align, $align_title, $align_title_lines, $sample) = |
||
50 | @{ $_}{ qw( title align align_title align_title_lines sample)}; |
||
51 | } else { |
||
52 | my $alispec = qr/&(.*)/; |
||
53 | if ( $_ =~ $alispec ) { |
||
54 | ( $title, $align, $sample) = /(.*)^$alispec\n?(.*)/sm; |
||
55 | } else { |
||
56 | $title = $_; |
||
57 | } |
||
58 | defined and chomp for $title, $sample; |
||
59 | } |
||
60 | defined or $_ = [] for $title, $sample; |
||
61 | defined $align and length $align or $align = 'auto'; |
||
62 | ref eq 'ARRAY' or $_ = [ split /\n/, $_, -1] for $title, $sample; |
||
63 | unless ( |
||
64 | ref $align eq 'Regex' or |
||
65 | $align =~ /^(?:left|center|right|num\(?|point\(?|auto)/ |
||
66 | ) { |
||
67 | _warn( "Invalid align specification: '$align', using 'auto'"); |
||
68 | $align = 'auto'; |
||
69 | } |
||
70 | defined $align_title and length $align_title or $align_title = 'left'; |
||
71 | unless ( $align_title =~ /^(?:left|center|right)/ ) { |
||
72 | _warn( "Invalid align_title specification: " . |
||
73 | "'$align_title', using 'left'", |
||
74 | ); |
||
75 | $align_title = 'left'; |
||
76 | } |
||
77 | defined $align_title_lines and length $align_title_lines or |
||
78 | $align_title_lines = $align_title; |
||
79 | unless ( $align_title_lines =~ /^(?:left|center|right)/ ) { |
||
80 | _warn( "Invalid align_title_lines specification: " . |
||
81 | "'$align_title_lines', using 'left'", |
||
82 | ); |
||
83 | $align_title_lines = 'left'; |
||
84 | } |
||
85 | { |
||
86 | title => $title, |
||
87 | align => $align, |
||
88 | align_title => $align_title, |
||
89 | align_title_lines => $align_title_lines, |
||
90 | sample => $sample, |
||
91 | } |
||
92 | } |
||
93 | |||
94 | ### table creation |
||
95 | |||
96 | sub new { |
||
97 | my $tb = bless {}, shift; |
||
98 | $tb->_entitle( @_); |
||
99 | } |
||
100 | |||
101 | sub _entitle { |
||
102 | my $tb = shift; # will be completely overwritten |
||
103 | # find active separators and, well separate them from col specs. |
||
104 | # n+1 separators for n cols |
||
105 | my ( @seps, @spec); # separators and column specifications |
||
106 | my $sep; |
||
107 | for ( @_ ) { |
||
108 | if ( _is_sep ( $_) ) { |
||
109 | $sep = _parse_sep( $_); |
||
110 | } else { |
||
111 | push @seps, $sep; |
||
112 | push @spec, _parse_spec( $_); |
||
113 | undef $sep; |
||
114 | } |
||
115 | } |
||
116 | push @seps, $sep; |
||
117 | # build sprintf formats from separators |
||
118 | my $title_form = |
||
119 | _compile_format( map defined() ? $_->{ title} : undef, @seps); |
||
120 | my $body_form = |
||
121 | _compile_format( map defined() ? $_->{ body} : undef, @seps); |
||
122 | |||
123 | # pre_align titles |
||
124 | my @titles = map [ @{ $_->{ title}}], @spec; |
||
125 | my $title_height = 0; |
||
126 | _to_max( $title_height, scalar @$_) for @titles; |
||
127 | push @$_, ( '') x ( $title_height - @$_) for @titles; |
||
128 | # align( 'left', @$_) for @titles; # ready for use' |
||
129 | my @styles = map $_->{ align_title_lines}, @spec; |
||
130 | align( shift @styles, @$_) for @titles; # in-place alignment |
||
131 | |||
132 | # build data structure |
||
133 | %$tb = ( |
||
134 | spec => \ @spec, # column spec for reuse |
||
135 | titles => \ @titles, # titles, pre-aligned |
||
136 | cols => [ map [], 1 .. @spec], # data columns |
||
137 | forms => [ $title_form, $body_form], # separators condensed |
||
138 | ); |
||
139 | $tb->_clear_cache; |
||
140 | } |
||
141 | |||
142 | # sprintf-format for line assembly, using separators |
||
143 | sub _compile_format { |
||
144 | my @seps = @_; # mix of strings and undef (for default) |
||
145 | defined or $_ = '' for @seps[ 0, -1]; # first and last default to empty |
||
146 | defined or $_ = ' ' for @seps; # others default to single space |
||
147 | s/%/%%/g for @seps; # protect against sprintf |
||
148 | join '%s', @seps; |
||
149 | } |
||
150 | |||
151 | # reverse format compilation (used by colrange()) |
||
152 | sub _recover_separators { |
||
153 | my $format = shift; |
||
154 | my @seps = split /(?<!%)%s/, $format, -1; |
||
155 | s/%%/%/g for @seps; |
||
156 | @seps; |
||
157 | } |
||
158 | |||
159 | # select some columns, (optionally if in [...]), and add new separators |
||
160 | # (the other table creator) |
||
161 | sub select { |
||
162 | my $tb = shift; |
||
163 | my @args = map $tb->_select_group( $_), @_; |
||
164 | # get column selection, checking indices (some have been checked by |
||
165 | # _select_group, but not all) |
||
166 | my @sel = map $tb->_check_index( $_), grep !_is_sep( $_), @args; |
||
167 | # replace indices with column spec to create subtable |
||
168 | ! _is_sep( $_) and $_ = $tb->{ spec}->[ $_] for @args; |
||
169 | my $sub = ref( $tb)->new( @args); |
||
170 | # sneak in data columns |
||
171 | @{ $sub->{ cols}} = map [ @$_ ], @{ $tb->{ cols}}[ @sel]; |
||
172 | $sub; |
||
173 | } |
||
174 | |||
175 | # the first non-separator column in the group is tested if it has any data |
||
176 | # if so, the group is returned, else nothing |
||
177 | sub _select_group { |
||
178 | my ( $tb, $group) = @_; |
||
179 | return $_ unless ref $group eq 'ARRAY'; |
||
180 | for ( @$group ) { |
||
181 | next if _is_sep( $_); |
||
182 | $tb->_check_index( $_); |
||
183 | return @$group if grep $_, @{ $tb->{ cols}->[ $_]}; |
||
184 | return; # no more tries after non-sep was found |
||
185 | } |
||
186 | return; # no column index in group, no select |
||
187 | } |
||
188 | |||
189 | # check index for validity, return arg if returns at all |
||
190 | sub _check_index { |
||
191 | my $tb = shift; |
||
192 | my ( $i) = @_; |
||
193 | my $n = $tb->n_cols; |
||
194 | my $ok = eval { |
||
195 | use warnings FATAL => 'numeric'; |
||
196 | -$n <= $i and $i < $n; # in range of column array? |
||
197 | }; |
||
198 | _warn( "Invalid column index '$_'") if $@ or not $ok; |
||
199 | shift; |
||
200 | } |
||
201 | |||
202 | ### data entry |
||
203 | |||
204 | sub _clear_cache { @{ $_[ 0]}{ qw( lines blank)} = (); $_[ 0] } |
||
205 | |||
206 | # add one data line or split the line into follow-up lines |
||
207 | sub add { |
||
208 | my $tb = shift; |
||
209 | $tb->_entitle( ( '') x @_) unless $tb->n_cols; |
||
210 | |||
211 | $tb->_add( @$_) for _transpose( map [ defined() ? split( $/ ) : '' ], @_); |
||
212 | $tb->_clear_cache; |
||
213 | } |
||
214 | |||
215 | # add one data line |
||
216 | sub _add { |
||
217 | my $tb = shift; |
||
218 | push @$_, shift for @{ $tb->{ cols}}; |
||
219 | $tb->_clear_cache; |
||
220 | $tb; |
||
221 | } |
||
222 | |||
223 | # add one or more data lines |
||
224 | sub load { |
||
225 | my $tb = shift; |
||
226 | for ( @_ ) { |
||
227 | defined $_ or $_ = ''; |
||
228 | ref eq 'ARRAY' ? $tb->add( @$_) : $tb->add( split); |
||
229 | } |
||
230 | $tb; |
||
231 | } |
||
232 | |||
233 | sub clear { |
||
234 | my $tb = shift; |
||
235 | $_ = [] for @{ $tb->{ cols}}; |
||
236 | $tb->_clear_cache; |
||
237 | $tb; |
||
238 | } |
||
239 | |||
240 | ### access to output area |
||
241 | |||
242 | ## sizes |
||
243 | |||
244 | # number of table clolumns |
||
245 | sub n_cols { scalar @{ $_[0]->{ spec}} } |
||
246 | |||
247 | # number of title lines |
||
248 | sub title_height { $_[ 0]->n_cols and scalar @{ $_[ 0]->{ titles}->[ 0]} } |
||
249 | |||
250 | # number of data lines |
||
251 | sub body_height { $_[ 0]->n_cols and scalar @{ $_[ 0]->{ cols}->[ 0]} } |
||
252 | |||
253 | # total height |
||
254 | sub table_height { $_[ 0]->title_height + $_[ 0]->body_height } |
||
255 | BEGIN { *height = \ &table_height} # alias |
||
256 | |||
257 | # number of characters in each table line. need to build the table to know |
||
258 | sub width { |
||
259 | $_[ 0]->height and length( ($_[ 0]->table( 0))[ 0]) - 1; |
||
260 | } |
||
261 | |||
262 | # start and width of each column |
||
263 | sub colrange { |
||
264 | my ( $tb, $col_index) = @_; |
||
265 | return ( 0, 0) unless $tb->width; # width called, $tb->{ blank} exists now |
||
266 | $col_index ||= 0; |
||
267 | $col_index += $tb->n_cols if $col_index < 0; |
||
268 | _to_max( $col_index, 0); |
||
269 | _to_min( $col_index, $tb->n_cols); |
||
270 | my @widths = map length, @{ $tb->{ blank}}, ''; |
||
271 | @widths = @widths[ 0 .. $col_index]; |
||
272 | my $width = pop @widths; |
||
273 | my $pos = 0; |
||
274 | $pos += $_ for @widths; |
||
275 | my @seps = _recover_separators( $tb->{ forms}->[ 0]); |
||
276 | $pos += length for @seps[ 0 .. $col_index]; |
||
277 | return ( $pos, $width); |
||
278 | } |
||
279 | |||
280 | ## printable output |
||
281 | |||
282 | # whole table |
||
283 | sub table { |
||
284 | my $tb = shift; |
||
285 | $tb->_table_portion( $tb->height, 0, @_); |
||
286 | } |
||
287 | |||
288 | # only titles |
||
289 | sub title { |
||
290 | my $tb = shift; |
||
291 | $tb->_table_portion( $tb->title_height, 0, @_); |
||
292 | } |
||
293 | |||
294 | # only body |
||
295 | sub body { |
||
296 | my $tb = shift; |
||
297 | $tb->_table_portion( $tb->body_height, $tb->title_height, @_); |
||
298 | } |
||
299 | |||
300 | sub stringify { scalar shift()->table() } |
||
301 | |||
302 | ### common internals |
||
303 | |||
304 | # common representation of table(), title() and body() |
||
305 | sub _table_portion { |
||
306 | my $tb = shift; |
||
307 | my ( $total, $offset) = ( shift, shift); |
||
308 | my ( $from, $n) = ( 0, $total); # if no parameters |
||
309 | if ( @_ ) { |
||
310 | $from = shift; |
||
311 | $n = @_ ? shift : 1; # one line if not given |
||
312 | } |
||
313 | ( $from, $n) = _limit_range( $total, $from, $n); |
||
314 | my @lines = do { |
||
315 | my $limit = $tb->title_height; # title format below |
||
316 | $from += $offset; |
||
317 | map $tb->_assemble_line( $_ >= $limit, $tb->_table_line( $_)), |
||
318 | $from .. $from + $n - 1; |
||
319 | }; |
||
320 | return @lines if wantarray; |
||
321 | return join '', @lines; |
||
322 | } |
||
323 | |||
324 | sub _limit_range { |
||
325 | my ( $total, $from, $n) = @_; |
||
326 | $from ||= 0; |
||
327 | $from += $total if $from < 0; |
||
328 | $n = $total unless defined $n; |
||
329 | return ( 0, 0) if $from + $n < 0 or $from >= $total; |
||
330 | $from = 0 if $from < 0; |
||
331 | $n = $total - $from if $n > $total - $from; |
||
332 | ( $from, $n); |
||
333 | } |
||
334 | |||
335 | # get table line (formatted, including titles). fill cache if needed |
||
336 | sub _table_line { |
||
337 | my $tb = shift; |
||
338 | ($tb->{ lines} ||= [ $tb->_build_table_lines])->[ shift]; |
||
339 | } |
||
340 | |||
341 | # build array of lines of justified data items |
||
342 | sub _build_table_lines { |
||
343 | my $tb = shift; |
||
344 | |||
345 | # copy data columns, replacing undef with '' |
||
346 | my @cols = map [ map defined() ? $_ : '', @$_], @{ $tb->{ cols}}; |
||
347 | |||
348 | # add set of empty strings for blank line (needed to build horizontal rules) |
||
349 | push @$_, '' for @cols; |
||
350 | |||
351 | # add samples for minimum alignment |
||
352 | my @samples = map $_->{ sample}, @{ $tb->{ spec}}; |
||
353 | push @$_, @{ shift @samples} for @cols; |
||
354 | |||
355 | # align to style |
||
356 | my @styles = map $_->{ align}, @{ $tb->{ spec}}; |
||
357 | align( shift @styles, @$_) for @cols; |
||
358 | # trim off samples, but leave blank line |
||
359 | splice @$_, 1 + $tb->body_height for @cols; # + 1 for blank line (brittle) |
||
360 | |||
361 | # include titles |
||
362 | my @titles = @{ $tb->{ titles}}; |
||
363 | unshift @$_, @{ shift @titles} for @cols; # add pre-aligned titles |
||
364 | |||
365 | # align title and body portions of columns |
||
366 | # blank line will be there even with no data |
||
367 | @styles = map $_->{ align_title}, @{ $tb->{ spec}}; |
||
368 | align( shift @styles, @$_) for @cols; # in-place alignment |
||
369 | |||
370 | # deposit a blank line, pulling it off the columns. |
||
371 | # *_rule() knows this is done |
||
372 | $tb->{ blank} = [ map pop @$_, @cols]; |
||
373 | |||
374 | _transpose_n( $tb->height, @cols); # bye-bye, @cols |
||
375 | } |
||
376 | |||
377 | # destructively transpose a number of lines/cols from an array of arrayrefs |
||
378 | sub _transpose_n ($@) { |
||
379 | my $n = shift; |
||
380 | map [ map shift @$_, @_], 1 .. $n; |
||
381 | } |
||
382 | |||
383 | # like _transpose_n, but find the number to transpose from max of given |
||
384 | sub _transpose { |
||
385 | my $m; |
||
386 | _to_max( $m, scalar @$_) for @_, []; # make sure $m is defined |
||
387 | _transpose_n( $m, @_); |
||
388 | } |
||
389 | |||
390 | # make a line from a number of formatted data elements |
||
391 | sub _assemble_line { |
||
392 | my $tb = shift; |
||
393 | my $in_body = shift; # 0 for title, 1 for body |
||
394 | sprintf( $tb->{ forms}->[ !!$in_body], @{ shift()}) . "\n"; |
||
395 | } |
||
396 | |||
397 | # build a rule line |
||
398 | sub _rule { |
||
399 | my $tb = shift; |
||
400 | my $in_body = shift; |
||
401 | return '' unless $tb->width; # this builds the cache, hence $tb->{ blank} |
||
402 | my $rule = $tb->_assemble_line( $in_body, $tb->{ blank}); |
||
403 | my ( $char, $alt) = map /(.)/, @_; |
||
404 | ( defined $char and length $char) or $char = ' '; |
||
405 | # replace blanks with $char. If $alt is given, replace nonblanks with $alt |
||
406 | if ( defined $alt ) { |
||
407 | $rule =~ s/(.)/$1 eq ' ' ? $char : $alt/ge; |
||
408 | } else { |
||
409 | $rule =~ s/ /$char/g if $char ne ' '; |
||
410 | } |
||
411 | $rule; |
||
412 | } |
||
413 | |||
414 | sub rule { |
||
415 | my $tb = shift; |
||
416 | $tb->_rule( 0, @_); |
||
417 | } |
||
418 | |||
419 | sub body_rule { |
||
420 | my $tb = shift; |
||
421 | $tb->_rule( 1, @_); |
||
422 | } |
||
423 | |||
424 | # min/max utilitiess (modifying first argument) |
||
425 | |||
426 | sub _to_max { |
||
427 | defined $_[ 0] and $_[ 0] > $_[ 1] or $_[ 0] = $_[ 1] if defined $_[ 1]; |
||
428 | } |
||
429 | |||
430 | sub _to_min { |
||
431 | defined $_[ 0] and $_[ 0] < $_[ 1] or $_[ 0] = $_[ 1] if defined $_[ 1]; |
||
432 | } |
||
433 | |||
434 | ### warning behavior |
||
435 | use Carp; |
||
436 | |||
437 | { |
||
438 | my ( $warn, $fatal) = ( 0, 0); |
||
439 | |||
440 | sub warnings { |
||
441 | shift; # ignore class/object |
||
442 | local $_ = shift || 'on'; |
||
443 | if ( $_ eq 'off' ) { |
||
444 | ( $warn, $fatal) = ( 0, 0); |
||
445 | } elsif ( $_ eq 'fatal' ) { |
||
446 | ( $warn, $fatal) = ( 1, 1); |
||
447 | } else { |
||
448 | ( $warn, $fatal) = ( 1, 0); |
||
449 | } |
||
450 | return 'fatal' if $fatal; |
||
451 | return 'on' if $warn; |
||
452 | return 'off'; |
||
453 | } |
||
454 | |||
455 | sub _warn { |
||
456 | my $msg = shift; |
||
457 | return unless $warn; |
||
458 | croak( $msg) if $fatal; |
||
459 | carp( $msg); |
||
460 | } |
||
461 | } |
||
462 | |||
463 | __END__ |
||
464 | ########################################### main pod documentation begin ## |
||
465 | |||
466 | =head1 NAME |
||
467 | |||
468 | Text::Table - Organize Data in Tables |
||
469 | |||
470 | =head1 SYNOPSIS |
||
471 | |||
472 | use Text::Table; |
||
473 | my $tb = Text::Table->new( |
||
474 | "Planet", "Radius\nkm", "Density\ng/cm^3" |
||
475 | ); |
||
476 | $tb->load( |
||
477 | [ "Mercury", 2360, 3.7 ], |
||
478 | [ "Venus", 6110, 5.1 ], |
||
479 | [ "Earth", 6378, 5.52 ], |
||
480 | [ "Jupiter", 71030, 1.3 ], |
||
481 | ); |
||
482 | print $tb; |
||
483 | |||
484 | This prints a table from the given title and data like this: |
||
485 | |||
486 | Planet Radius Density |
||
487 | km g/cm^3 |
||
488 | Mercury 2360 3.7 |
||
489 | Venus 6110 5.1 |
||
490 | Earth 6378 5.52 |
||
491 | Jupiter 71030 1.3 |
||
492 | |||
493 | Note that two-line titles work, and that the planet names are aligned |
||
494 | differently than the numbers. |
||
495 | |||
496 | =head1 DESCRIPTION |
||
497 | |||
498 | Organization of data in table form is a time-honored and useful |
||
499 | method of data representation. While columns of data are trivially |
||
500 | generated by computer through formatted output, even simple tasks |
||
501 | like keeping titles aligned with the data columns are not trivial, |
||
502 | and the one-shot solutions one comes up with tend to be particularly |
||
503 | hard to maintain. Text::Table allows you to create and maintain |
||
504 | tables that adapt to alignment requirements as you use them. |
||
505 | |||
506 | =head2 Overview |
||
507 | |||
508 | The process is simple: you create a table (a Text::Table object) by |
||
509 | describing the columns the table is going to have. Then you load |
||
510 | lines of data into the table, and finally print the resulting output |
||
511 | lines. Alignment of data and column titles is handled dynamically |
||
512 | in dependence on the data present. |
||
513 | |||
514 | =head2 Table Creation |
||
515 | |||
516 | In the simplest case, if all you want is a number of (untitled) columns, |
||
517 | you create an unspecified table and start adding data to it. The number |
||
518 | of columns is taken fronm the first line of data. |
||
519 | |||
520 | To specify a table you specify its columns. A column description |
||
521 | can contain a title and alignment requirements for the data, both |
||
522 | optional. Additionally, you can specify how the title is aligned with |
||
523 | the body of a column, and how the lines of a multiline title are |
||
524 | aligned among themselves. |
||
525 | |||
526 | The columns are collected in the table in the |
||
527 | order they are given. On data entry, each column corresponds to |
||
528 | one data item, and in column selection columns are indexed left to |
||
529 | right, starting from 0. |
||
530 | |||
531 | Each title can be a multiline string which will be blank-filled to |
||
532 | the length of the longest partial line. The largest number of title |
||
533 | lines in a column determines how many title lines the table has as a |
||
534 | whole, including the case that no column has any titles. |
||
535 | |||
536 | On output, Columns are separated by a single blank. You can control |
||
537 | what goes between columns by specifying separators between (or before, |
||
538 | or after) columns. Separators don't contain any data and don't count |
||
539 | in column indexing. They also don't accumulate: in a sequence of only |
||
540 | separators and no columns, only the last one counts. |
||
541 | |||
542 | =head2 Status Information |
||
543 | |||
544 | The width (in characters), height (in lines), number of columns, and |
||
545 | similar data about the table is available. |
||
546 | |||
547 | =head2 Data Loading |
||
548 | |||
549 | Table data is entered line-wise, each time specifying data entries |
||
550 | for all table columns. A bulk loader for many lines at once is also |
||
551 | available. You can clear the data from the table for re-use (though |
||
552 | you will more likely just create another table). |
||
553 | |||
554 | =head2 Table Output |
||
555 | |||
556 | The output area of a table is divided in the title and the body. |
||
557 | |||
558 | The title contains the combined titles from the table columns, if |
||
559 | any. Its content never changes with a given table, but it may be |
||
560 | spread out differently on the page through alignment with the data. |
||
561 | |||
562 | The body contains the data lines, aligned column-wise as specified, |
||
563 | and left-aligned with the column title. |
||
564 | |||
565 | Each of these is arranged like a Perl array (counting from 0) and can |
||
566 | be accessed in portions by specifying a first line and the number |
||
567 | of following lines. Also like an array, giving a negative first line |
||
568 | counts from the end of the area. The whole table, the title followed |
||
569 | by the body, can also be accessed in this manner. |
||
570 | |||
571 | The subdivisions are there so you can repeat the title (or parts of |
||
572 | it) along with parts of the body on output, whether for screen paging |
||
573 | or printout. |
||
574 | |||
575 | A rule line is also available, which is the horizontal counterpart to |
||
576 | the separator columns you specify with the table. |
||
577 | It is basically a table line as it would appear if all data entries |
||
578 | in the line were empty, that is, a blank line except for where the |
||
579 | column separators have non-blank entries. If you print it between |
||
580 | data lines, it will not disrupt the vertical separator structure |
||
581 | as a plain blank line would. You can also request a solid rule |
||
582 | consisting of any character, and even one with the non-blank column |
||
583 | separators replaced by a character of your choice. This way you can |
||
584 | get the popular representation of line-crossings like so: |
||
585 | |||
586 | | |
||
587 | ----+--- |
||
588 | | |
||
589 | |||
590 | =head2 Warning Control |
||
591 | |||
592 | On table creation, some parameters are checked and warnings issued |
||
593 | if you allow warnings. You can also turn warnings into fatal errors. |
||
594 | |||
595 | =head1 SPECIFICATIONS |
||
596 | |||
597 | =head2 Column Specification |
||
598 | |||
599 | Each column specification is a single scalar. Columns can be either proper |
||
600 | data columns or column separators. Both can be specified either as |
||
601 | (possibly multi-line) strings, or in a more explicit form as hash-refs. |
||
602 | In the string form, proper columns are given as plain strings, and |
||
603 | separators are given as scalar references to strings. In hash form, |
||
604 | separators have a true value in the field C<is_sep> while proper columns |
||
605 | don't have this field. |
||
606 | |||
607 | =over 4 |
||
608 | |||
609 | =item Columns as strings |
||
610 | |||
611 | A column is given as a column title (any number of lines), |
||
612 | optionally followed by alignment requirements. Alignment requirements |
||
613 | start with a line that begins with an ampersamd "&". However, only the |
||
614 | last such line counts as such, so if you have title lines that begin |
||
615 | with "&", just append an ampersand on a line by itself as a dummy |
||
616 | alignment section if you don't have one anyway. |
||
617 | |||
618 | What follows the ampersand on its line is the alignment style (like |
||
619 | I<left>, I<right>, ... as described in L<"Alignment">), you want for |
||
620 | the data in this column. If nothing follows, the general default I<auto> |
||
621 | is used. If you specify an invalid alignment style, it falls back to |
||
622 | left alignment. |
||
623 | |||
624 | The lines that follow can contain sample data for this column. These |
||
625 | are considered for alignment in the column, but never actually appear |
||
626 | in the output. The effect is to guarantee a minimum width for the |
||
627 | column even if the current data doesn't require it. This helps dampen |
||
628 | the oscillations in the appearance of dynamically aligned tables. |
||
629 | |||
630 | =item Columns as Hashes |
||
631 | |||
632 | The format is |
||
633 | |||
634 | { |
||
635 | title => $title, |
||
636 | align => $align, |
||
637 | sample => $sample, |
||
638 | align_title => $align_title, |
||
639 | align_title_lines => $align_title_lines, |
||
640 | } |
||
641 | |||
642 | $title contains the title lines and $sample the sample data. Both can |
||
643 | be given as a string or as an array-ref to the list of lines. $align contains |
||
644 | the alignment style (without a leading ampersand), usually as a string. |
||
645 | You can also give a regular expression here, which specifies regex alignment. |
||
646 | A regex can only be specified in the hash form of a colunm specification. |
||
647 | |||
648 | In hash form you can also specify how the title of a column is aligned |
||
649 | with its body. To do this, you specify the keyword C<align_title> with |
||
650 | C<left>, C<right> or C<center>. Other alignment specifications are not |
||
651 | valid here. The default is C<left>. |
||
652 | |||
653 | C<align_title> also specifies how the lines of a multiline title are |
||
654 | aligned among themselves. If you want a different alignment, you |
||
655 | can specify it with the key C<align_title_lines>. Again, only C<left>, |
||
656 | C<right> or C<center> are allowed. |
||
657 | |||
658 | Do not put other keys than those mentioned above (I<title>, I<align>, |
||
659 | I<align_title>, I<align_title_lines>, and I<sample>) into a hash that |
||
660 | specifies a column. Most would be ignored, but some would confuse the |
||
661 | interpreter (in particular, I<is_sep> has to be avoided). |
||
662 | |||
663 | =item Separators as strings |
||
664 | |||
665 | A separator must be given as a reference to a string (often a literal, |
||
666 | like C<\' | '>), any string that is given directly describes a column. |
||
667 | |||
668 | It is usually just a (short) string that will be printed between |
||
669 | table columns on all table lines instead of the default single |
||
670 | blank. If you specify two separators (on two lines), the first one |
||
671 | will be used in the title and the other in the body of the table. |
||
672 | |||
673 | =item Separators as Hashes |
||
674 | |||
675 | The hash representation of a separator has the format |
||
676 | |||
677 | { |
||
678 | is_sep => 1, |
||
679 | title => $title, |
||
680 | body => $body, |
||
681 | } |
||
682 | |||
683 | $title is the separator to be used in the title area and $body |
||
684 | the one for the body. If only one is given, the other is used for |
||
685 | both. If none is given, a blank is used. If one is shorter than |
||
686 | the other, it is blank filled on the right. |
||
687 | |||
688 | The value of C<is_sep> must be set to a true value, this is the |
||
689 | distinguishing feature of a separator. |
||
690 | |||
691 | =back |
||
692 | |||
693 | =head2 Alignment |
||
694 | |||
695 | The original documentation to L<Text::Aligner> contains all the details |
||
696 | on alignment specification, but here is the rundown: |
||
697 | |||
698 | The possible alignment specifications are I<left>, I<right>, I<center>, |
||
699 | I<num> and I<point> (which are synonyms), and I<auto>. The first |
||
700 | three explain themselves. |
||
701 | |||
702 | I<num> (and I<point>) align the decimal point in the data, which is |
||
703 | assumed to the right if none is present. Strings that aren't |
||
704 | numbers are treated the same way, that is, they appear aligned |
||
705 | with the integers unless they contain a ".". Instead of the |
||
706 | decimal point ".", you can also specify any other string in |
||
707 | the form I<num(,)>, for instance. The string in parentheses |
||
708 | is aligned in the data. The synonym I<point> for I<num> may be |
||
709 | more appropriate in contexts that deal with arbitrary |
||
710 | strings, as in I<point(=E<gt>)> (which might be used to align certain |
||
711 | bits of Perl code). |
||
712 | |||
713 | I<regex alignment> is a more sophisticated form of point alignment. |
||
714 | If you specify a regular expression, as delivered by C<qr//>, the start |
||
715 | of the match is used as the alignment point. If the regex contains |
||
716 | capturing parentheses, the last submatch counts. [The usefulness of |
||
717 | this feature is under consideration.] |
||
718 | |||
719 | I<auto> alignment combines numeric alignment with left alignment. |
||
720 | Data items that look like numbers, and those that don't, form two |
||
721 | virtual columns and are aligned accordingly: C<num> for numbers and |
||
722 | C<left> for other strings. These columns are left-aligned with |
||
723 | each other (i.e. the narrower one is blank-filled) to form the |
||
724 | final alignment. |
||
725 | |||
726 | This way, a column that happens to have only numbers in the data gets |
||
727 | I<num> alignment, a column with no numbers appears I<left>-aligned, |
||
728 | and mixed data is presented in a reasonable way. |
||
729 | |||
730 | =head2 Column Selection |
||
731 | |||
732 | Besides creating tables from scratch, they can be created by |
||
733 | selecting columns from an existing table. Tables created this |
||
734 | way contain the data from the columns they were built from. |
||
735 | |||
736 | This is done by specifying the columns to select by their index |
||
737 | (where negative indices count backward from the last column). |
||
738 | The same column can be selected more than once and the sequence |
||
739 | of columns can be arbitrarily changed. Separators don't travel |
||
740 | with columns, but can be specified between the columns at selection |
||
741 | time. |
||
742 | |||
743 | You can make the selection of one or more columns dependent on |
||
744 | the data content of one of them. If you specify some of the columns |
||
745 | in angle brackets [...], the whole group is only included in the |
||
746 | selection if the first column in the group contains any data that |
||
747 | evaluates to boolean true. That way you can de-select parts of a |
||
748 | table if it contains no interesting data. Any column separators |
||
749 | given in brackets are selected or deselected along with the rest |
||
750 | of it. |
||
751 | |||
752 | =head1 PUBLIC METHODS |
||
753 | |||
754 | =head2 Table Creation |
||
755 | |||
756 | =over 4 |
||
757 | |||
758 | =item new() |
||
759 | |||
760 | my $tb = Text::Table->new( $column, ... ); |
||
761 | |||
762 | creates a table with the columns specified. A column can be proper column |
||
763 | which contains and displays data, or a separator which tells how to fill |
||
764 | the space between columns. The format of the parameters is described under |
||
765 | L<"Column Specification">. Specifying an invalid alignment for a column |
||
766 | results in a warning if these are allowed. |
||
767 | |||
768 | If no columns are specified, the number of columns is taken from the first |
||
769 | line of data added to the table. The effect is as if you had specified |
||
770 | C<Text::Table-E<gt>new( ( '') x $n)>, where C<$n> is the number of |
||
771 | columns. |
||
772 | |||
773 | =item select() |
||
774 | |||
775 | my $sub = $tb->select( $column, ...); |
||
776 | |||
777 | creates a table from the listed columns of the table $tb, including |
||
778 | the data. Columns are specified as integer indices which refer to |
||
779 | the data columns of $tb. Columns can be repeated and specified in any |
||
780 | order. Negative indices count from the last column. If an invalid |
||
781 | index is specified, a warning is issued, if allowed. |
||
782 | |||
783 | As with L<"new()">, separators can be interspersed among the column |
||
784 | indices and will be used between the columns of the new table. |
||
785 | |||
786 | If you enclose some of the arguments (column indices or separators) in |
||
787 | angle brackets C<[...]> (technically, you specify them inside an |
||
788 | arrayref), they form a group for conditional selection. The group is |
||
789 | only included in the resulting table if the first actual column inside |
||
790 | the group contains any data that evaluate to a boolean true. This way |
||
791 | you can exclude groups of columns that wouldn't contribute anything |
||
792 | interesting. Note that separators are selected and de-selected with |
||
793 | their group. That way, more than one separator can appear between |
||
794 | adjacent columns. They don't add up, but only the rightmost separator |
||
795 | is used. A group that contains only separators is never selected. |
||
796 | [Another feature whose usefulness is under consideration.] |
||
797 | |||
798 | =back |
||
799 | |||
800 | =head2 Status Information |
||
801 | |||
802 | =over 4 |
||
803 | |||
804 | =item n_cols() |
||
805 | |||
806 | $tb->n_cols |
||
807 | |||
808 | returns the number of columns in the table. |
||
809 | |||
810 | =item width() |
||
811 | |||
812 | $tb->width |
||
813 | |||
814 | returns the width (in characters) of the table. All table lines have |
||
815 | this length (not counting a final "\n" in the line), as well as the |
||
816 | separator lines returned by $tb->rule() and $b->body_rule(). |
||
817 | The width of a table can potentially be influenced by any data item |
||
818 | in it. |
||
819 | |||
820 | =item height() |
||
821 | |||
822 | $tb->height |
||
823 | |||
824 | returns the total number of lines in a table, including title lines |
||
825 | and body lines. For orthogonality, the synonym table_height() also |
||
826 | exists. |
||
827 | |||
828 | =item title_height() |
||
829 | |||
830 | $tb->title_height |
||
831 | |||
832 | returns the number of title lines in a table. |
||
833 | |||
834 | =item body_height() |
||
835 | |||
836 | $tb->body_height |
||
837 | |||
838 | returns the number of lines in the table body. |
||
839 | |||
840 | =item colrange() |
||
841 | |||
842 | $tb->colrange( $i) |
||
843 | |||
844 | returns the start position and width of the $i-th column (counting from 0) |
||
845 | of the table. If $i is negative, counts from the end of the table. If $i |
||
846 | is larger than the greatest column index, an imaginary column of width 0 |
||
847 | is assumed right of the table. |
||
848 | |||
849 | =back |
||
850 | |||
851 | =head2 Data Loading |
||
852 | |||
853 | =over 4 |
||
854 | |||
855 | =item add() |
||
856 | |||
857 | $tb->add( $col1, ..., $colN) |
||
858 | |||
859 | adds a data line to the table, returns the table. |
||
860 | |||
861 | C<$col1>, ..., C<$colN> are scalars that |
||
862 | correspond to the table columns. Undefined entries are converted to '', |
||
863 | and extra data beyond the number of table columns is ignored. |
||
864 | |||
865 | Data entries can be multi-line strings. The partial strings all go into |
||
866 | the same column. The corresponding fields of other columns remain empty |
||
867 | unless there is another multi-line entry in that column that fills the |
||
868 | fieds. Adding a line with multi-line entries is equivalent to adding |
||
869 | multiple lines. |
||
870 | |||
871 | Every call to C<add()> increases the body height of the table by the |
||
872 | number of effective lines, one in the absence of multiline entries. |
||
873 | |||
874 | =item load() |
||
875 | |||
876 | $tb->load( $line, ...) |
||
877 | |||
878 | loads the data lines given into the table, returns the table. |
||
879 | |||
880 | Every argument to C<load()> represents a data line to be added to the |
||
881 | table. The line can be given as an array(ref) containing the data |
||
882 | items, or as a string, which is split on whitespace to retrieve the |
||
883 | data. If an undefined argument is given, it is treated as an |
||
884 | empty line. |
||
885 | |||
886 | =item clear() |
||
887 | |||
888 | $tb->clear; |
||
889 | |||
890 | deletes all data from the table and resets it to the state after |
||
891 | creation. Returns the table. The body height of a table is 0 after |
||
892 | C<clear()>. |
||
893 | |||
894 | =back |
||
895 | |||
896 | =head2 Table Output |
||
897 | |||
898 | The three methods C<table()>, C<title()>, and C<body()> are very similar. |
||
899 | They access different parts of the printable output lines of a table with |
||
900 | similar methods. The details are described with the C<table()> method. |
||
901 | |||
902 | =over 4 |
||
903 | |||
904 | =item table() |
||
905 | |||
906 | The C<table()> method returns lines from the entire table, starting |
||
907 | with the first title line and ending with the last body line. |
||
908 | |||
909 | In array context, the lines are returned separately, in scalar context |
||
910 | they are joined together in a single string. |
||
911 | |||
912 | my @lines = $tb->table; |
||
913 | my $line = $tb->table( $line_number); |
||
914 | my @lines = $tb->table( $line_number, $n); |
||
915 | |||
916 | The first call returns all the lines in the table. The second call |
||
917 | returns one line given by $line_number. The third call returns $n |
||
918 | lines, starting with $line_number. If $line_number is negative, it |
||
919 | counts from the end of the array. Unlike the C<select()> method, |
||
920 | C<table()> (and its sister methods C<title()> and C<body()>) is |
||
921 | protected against large negative line numbers, it truncates the |
||
922 | range described by $line_number and $n to the existing lines. If |
||
923 | $n is 0 or negative, no lines are returned (an empty string in scalar |
||
924 | context). |
||
925 | |||
926 | =item title() |
||
927 | |||
928 | Returns lines from the title area of a table, where the column titles |
||
929 | are rendered. Parameters and response to context are as with C<table()>, |
||
930 | but no lines are returned from outside the title area. |
||
931 | |||
932 | =item body() |
||
933 | |||
934 | Returns lines from the body area of a table, that is the part where |
||
935 | the data content is rendered, so that $tb->body( 0) is the first data |
||
936 | line. Parameters and response to context are as with C<table()>. |
||
937 | |||
938 | =item rule() |
||
939 | |||
940 | $tb->rule; |
||
941 | $tb->rule( $char); |
||
942 | $tb->rule( $char, $char1); |
||
943 | |||
944 | Returns a rule for the table. |
||
945 | |||
946 | A rule is a line of table width that can be used between table lines |
||
947 | to provide visual horizontal divisions, much like column separators |
||
948 | provide vertical visual divisions. In its basic form (returned by the |
||
949 | first call) it looks like a table line with no data, hence a blank |
||
950 | line except for the non-blank parts of any column-separators. If |
||
951 | one character is specified (the second call), it replaces the blanks |
||
952 | in the first form, but non-blank column separators are retained. If |
||
953 | a second character is specified, it replaces the non-blank parts of |
||
954 | the separators. So specifying the same character twice gives a solid |
||
955 | line of table width. Another useful combo is C<$tb-E<lt>rule( '-', '+')>, |
||
956 | together with separators that contain a single nonblank "|", for a |
||
957 | popular representation of line crossings. |
||
958 | |||
959 | C<rule()> uses the column separators for the title section if there |
||
960 | is a difference. |
||
961 | |||
962 | =item body_rule() |
||
963 | |||
964 | C<body_rule()> works like <rule()>, except the rule is generated using |
||
965 | the column separators for the table body. |
||
966 | |||
967 | =back |
||
968 | |||
969 | =head2 Warning Control |
||
970 | |||
971 | =over 4 |
||
972 | |||
973 | =item warnings() |
||
974 | |||
975 | Text::Table->warnings(); |
||
976 | Text::Table->warnings( 'on'); |
||
977 | Text::Table->warnings( 'off'): |
||
978 | Text::Table->warnings( 'fatal'): |
||
979 | |||
980 | The C<warnings()> method is used to control the appearance of warning |
||
981 | messages while tables are manipulated. When Text::Table starts, warnings |
||
982 | are disabled. The default action of C<warnings()> is to turn warnings |
||
983 | on. The other possible arguments are self-explanatory. C<warnings()> |
||
984 | can also be called as an object method (C<$tb-E<gt>warnings( ...)>). |
||
985 | |||
986 | =back |
||
987 | |||
988 | =head1 VERSION |
||
989 | |||
990 | This document pertains to Text::Table version 1.107 |
||
991 | |||
992 | =head1 BUGS |
||
993 | |||
994 | =over 4 |
||
995 | |||
996 | =item o |
||
997 | |||
998 | I<auto> alignment doesn't support alternative characters for the decimal |
||
999 | point. This is actually a bug in the underlying Text::Aligner by the |
||
1000 | same author. |
||
1001 | |||
1002 | =back |
||
1003 | |||
1004 | =head1 AUTHOR |
||
1005 | |||
1006 | Anno Siegel |
||
1007 | CPAN ID: ANNO |
||
1008 | siegel@zrz.tu-berlin.de |
||
1009 | http://www.tu-berlin.de/~siegel |
||
1010 | |||
1011 | =head1 COPYRIGHT |
||
1012 | |||
1013 | Copyright (c) 2002 Anno Siegel. All rights reserved. |
||
1014 | This program is free software; you can redistribute |
||
1015 | it and/or modify it under the same terms as Perl itself. |
||
1016 | |||
1017 | The full text of the license can be found in the |
||
1018 | LICENSE file included with this module. |
||
1019 | |||
1020 | =head1 SEE ALSO |
||
1021 | |||
1022 | Text::Aligner, perl(1). |
||
1023 | |||
1024 | =cut |
||
1025 | |||
1026 | 1; |