[svn-inject] Installing original source of liblatex-table-perl
Salvatore Bonaccorso
14 years ago
0 | use 5.008; | |
1 | use strict; | |
2 | use warnings; | |
3 | use Module::Build; | |
4 | ||
5 | my $builder = Module::Build->new( | |
6 | module_name => 'LaTeX::Table', | |
7 | license => 'perl', | |
8 | dist_author => 'Markus Riester <mriester@gmx.de>', | |
9 | dist_version_from => 'lib/LaTeX/Table.pm', | |
10 | requires => { | |
11 | 'perl' => '5.8.0', | |
12 | 'English' => 0, | |
13 | 'Moose' => 0, | |
14 | 'Moose::Policy::FollowPBP' => 0, | |
15 | 'Module::Pluggable' => 0, | |
16 | 'Scalar::Util' => 0, | |
17 | 'Carp' => 0, | |
18 | 'version' => 0, | |
19 | 'Template' => 0, | |
20 | }, | |
21 | build_requires => { | |
22 | 'Test::More' => 0, | |
23 | 'Test::NoWarnings' => 0, | |
24 | 'File::Spec' => 0, | |
25 | }, | |
26 | recommends => { | |
27 | 'Text::CSV' => 0, | |
28 | 'LaTeX::Driver' => 0, | |
29 | 'LaTeX::Encode' => 0, | |
30 | 'Getopt::Long' => 0, | |
31 | 'Number::Format' => 0, | |
32 | }, | |
33 | script_files => [ 'bin/csv2pdf', 'bin/ltpretty' ], | |
34 | add_to_cleanup => [ 'LaTeX-Table-*' ], | |
35 | ); | |
36 | ||
37 | $builder->create_build_script(); |
0 | Revision history for LaTeX-Table | |
1 | ||
2 | 0.9.15 Fri May 29 10:00:00 2009 | |
3 | - MISSING_VALUE in coldef_strategy | |
4 | - width and longtable | |
5 | - removed deprecated feature textwrap | |
6 | - changed optional requirement from Text::CSV_XS to Text::CSV | |
7 | - csv2pdf: Meyrin default. | |
8 | - POD cleanups | |
9 | ||
10 | 0.9.14 Tue Feb 24 10:00:00 2009 | |
11 | - Meyrin now default theme | |
12 | - sideways now works also with xtab (lscape package) | |
13 | - longtable package | |
14 | - POD cleanups | |
15 | ||
16 | 0.9.13 Wed Feb 4 12:00:00 2009 | |
17 | - continued, continuedmsg options | |
18 | - Minor Bug fixed: maincaption required caption. | |
19 | - renamed *_LINES to *_RULES | |
20 | - RULES_CMD in themes | |
21 | - examples.pdf nicer | |
22 | ||
23 | 0.9.12 Fri Jan 30 15:00:00 2009 | |
24 | - fontfamily | |
25 | - API change: size renamed to fontsize | |
26 | - custom_template | |
27 | - themes can now define rule width and color (only global) | |
28 | - Muenchen, NYC3, NYC4, Redmond and Redmond2 Themes | |
29 | - Perl-Critic-1.094001 passes | |
30 | ||
31 | 0.9.11 Sat Jan 3 13:00:00 2009 | |
32 | - tabulary package | |
33 | - STUB_ALIGN in themes | |
34 | - POD corrections | |
35 | ||
36 | 0.9.10 Sun Nov 23 02:15:00 2008 | |
37 | - removed unnecessary blanks and spaces in LaTeX output | |
38 | - LaTeX output aligned | |
39 | - Meyrin Theme | |
40 | - POD corrections | |
41 | ||
42 | 0.9.9 Wed Nov 12 12:01:00 2008 | |
43 | - removed Readonly, caused cpantester fails | |
44 | - shortcaption | |
45 | - left | |
46 | - right | |
47 | - moved more code in templates | |
48 | - ctable now uses tabularx | |
49 | - NYC2 theme | |
50 | ||
51 | 0.9.8 Sat Nov 8 11:01:00 2008 | |
52 | - support for the ctable package | |
53 | - sideways option | |
54 | - star option | |
55 | ||
56 | 0.9.7 Wed Nov 5 11:01:00 2008 (Obama wins :)) | |
57 | - Switched to Moose | |
58 | - themes now definable as modules. | |
59 | - csv2pdf. Lots of new features. | |
60 | ||
61 | 0.9.6 Thu Oct 7 8:44:00 2008 | |
62 | - Bugfix: extracolsep after first column | |
63 | - removed Fatal dependency (which is deprecated) | |
64 | - Standard LONG regex now requires at least two words (thanks to salva on | |
65 | perlmonks) | |
66 | - removed color LaTeX package dependency. xcolor is enough | |
67 | ||
68 | 0.9.5 Thu Oct 2 18:30:00 2008 | |
69 | - POD corrections | |
70 | - new, common exception format for invalid option usage | |
71 | - environment must be true for xtab packages | |
72 | - \belowcaptionskip instead of 10pt in tablehead, caption_top | |
73 | - custom_tabular_environment (e.g. for mpxtabular) | |
74 | ||
75 | 0.9.4 Wed Oct 1 18:30:00 2008 | |
76 | - coldef_strategy: column types can be defined | |
77 | - empty rows in headers now also produce horizontal lines for consistency | |
78 | - now data is only analyzed once (was twice in xtab) | |
79 | - tableheadmsg | |
80 | - Bugfix: latex commands in data counted as line (problem for | |
81 | _MUST_MATCH_ALL) | |
82 | - Bugfix: columns_like_header columns always left-justified | |
83 | - a few more tests | |
84 | ||
85 | 0.9.3 Fri Sep 26 14:00:00 2008 | |
86 | - leading/trailing spaces in default NUMBER regex allowed | |
87 | - coldef_strategy: suffix _MUST_MATCH_ALL now defines whether the | |
88 | specified type must match all cells in a column (or at least one). | |
89 | - ltpretty: howtos for vim and emacs | |
90 | - EXTRA_ROW_HEIGHT. now NYC theme looks better | |
91 | - header_sideways | |
92 | - API change: * DEFAULT renamed to DEFAULT_COL | |
93 | * DEFAULT_X renamed to DEFAULT_COL_X | |
94 | * IS_A_NUMBER renamed to NUMBER | |
95 | * IS_LONG renamed to LONG and is now a regular | |
96 | expression | |
97 | ||
98 | Sorry, I think it is the last big change before 1.0. It was | |
99 | necessary because I will add the functionality to define column | |
100 | types (like NUMBER and LONG) and this needs a cleaner interface. | |
101 | - Bugfix: first column always left-justified | |
102 | - a few more tests | |
103 | ||
104 | 0.9.2 Thu Sep 18 14:00:00 2008 | |
105 | - POD corrections | |
106 | - added ltpretty. I use it in vim to format my tables with LaTeX::Table | |
107 | ||
108 | 0.9.1 Wed Aug 27 21:38:00 2008 | |
109 | - Bugfix: no midrule without header | |
110 | - Bugfix: calculation of column ids (callback, coldef_strategy) now | |
111 | supports multicolumn shortcuts | |
112 | - Bugfix: specified Latex commands in data (with single column arrays) | |
113 | counted as rows (problem for DATA_BG_COLOR_ODD/EVEN) | |
114 | - colums_like_header() | |
115 | - more tests | |
116 | - Paris Theme | |
117 | - POD corrections | |
118 | ||
119 | 0.9.0 Sat Aug 23 19:00:00 2008 | |
120 | - caption_top | |
121 | - themes can now define header font color and bgcolors | |
122 | - multicol shortcut now automatically adds vertical lines | |
123 | - resizebox | |
124 | - Bugfix: centering now only in std. | |
125 | - Bugfix: callback function could destroy our multicolumn shortcut | |
126 | - Bugfix: callback function in header only applied when HEADER_CENTERED | |
127 | in theme | |
128 | - API change: text_wrap now deprecated. tabularx produces so much nicer | |
129 | tables and it does not break the callback row ids. If you really think this | |
130 | is useful somehow, drop me a mail | |
131 | ||
132 | 0.8.0 Thu Aug 21 14:30:00 2008 | |
133 | - centering instead of center | |
134 | - Bugfix: callback function overwrote values in arrays | |
135 | - maincaption not bold in Zurich | |
136 | - API change: table_environment now environment, environment can be chosen, e.g. | |
137 | 'sidewaystable' | |
138 | - API change: tablepos renamed to position | |
139 | - API change: tabledef renamed to coldef | |
140 | - API change: tabledef_strategy renamed to coldef_strategy | |
141 | - tabularx package | |
142 | - default value for long col now 30 | |
143 | - POD updates | |
144 | - examples.pdf better | |
145 | ||
146 | 0.7.0 Tue Aug 19 21:15:00 2008 | |
147 | - plain theme | |
148 | - POD updates | |
149 | ||
150 | 0.6.3 Fri Jul 25 21:15:00 2008 | |
151 | - commands now printed without formatting | |
152 | - removed the simpsons synopsis | |
153 | - Perl::Critic passes again | |
154 | ||
155 | 0.6.2 Wed Apr 16 11:28:00 2008 | |
156 | - made new Perl::Critic happy | |
157 | - Bugfix: \hline in xtab/booktabs | |
158 | ||
159 | 0.6.1 Tue Mar 04 16:00:00 2008 | |
160 | - added kwalitee test | |
161 | - added perl 5.8 dependency | |
162 | - added licence in Makefile.PL | |
163 | - Bugfix: \hline instead of \midrule | |
164 | ||
165 | 0.6.0 Wed Nov 07 15:00:00 2007 | |
166 | - support for booktabs.sty | |
167 | - Zurich standard | |
168 | - width | |
169 | - regex IS_A_NUMBER compiled only once (same bug again) | |
170 | ||
171 | 0.5.2 Tue Nov 06 18:00:00 2007 | |
172 | - tests produced latextable.tex in / | |
173 | - replaced Regexp::Common with perlfaq4 regexes. MUCH faster now. | |
174 | - new theme Berlin | |
175 | - custom IS_A_NUMBER regex ignored | |
176 | - cvs2pdf: | |
177 | - support for themes | |
178 | - Berlin default (first column contains data in CSV) | |
179 | ||
180 | 0.5.1 Tue Nov 06 12:00:00 2007 | |
181 | - xtab: last page not centered when center=1 | |
182 | - csv2pdf: | |
183 | - typos in POD | |
184 | - --man not working | |
185 | - moved to directory bin | |
186 | - removed "continued on next page" tabletail | |
187 | - xentrystretch 0.001 (more rows per page) | |
188 | ||
189 | 0.5.0 Mon Nov 05 15:00:00 2007 | |
190 | - die when value in cell is undef (fixes many warnings and funny | |
191 | results) | |
192 | - tabletail should work now | |
193 | - added csv2pdf | |
194 | ||
195 | 0.4.0 Sat Oct 20 18:04:00 2007 | |
196 | - tabledef_strategy | |
197 | ||
198 | 0.3.0 Sat Oct 20 18:04:00 2007 | |
199 | - generate() tests data and header | |
200 | - themes test | |
201 | - pod corrections | |
202 | ||
203 | 0.2.1 Fri Oct 19 18:02:00 2007 | |
204 | - Bugfix: callback $is_header == 1 in data | |
205 | ||
206 | 0.2.0 Fri Oct 19 18:00:00 2007 | |
207 | - use Text::Wrap for wrapping lines | |
208 | - callback | |
209 | - xtab tests | |
210 | ||
211 | 0.1.1 Thu Sep 20 18:03:00 2007 | |
212 | - minor POD corrections | |
213 | - Bugfixes: | |
214 | * perlcritic optional, | |
215 | passes now with severity 1 | |
216 | ||
217 | 0.1.0 Thu Sep 20 12:30:00 2007 | |
218 | - API CHANGE: header and data now options | |
219 | - label optional | |
220 | - caption optional | |
221 | - maincaption optional | |
222 | - custom themes can be set in new() | |
223 | - POD improvements | |
224 | - more tests | |
225 | - table environment optional | |
226 | - added examples.pdf | |
227 | - Bugfixes: | |
228 | * META.yml missing | |
229 | ||
230 | 0.0.3 Thu Mar 5 18:10:11 2007 | |
231 | - t/perlcritic.t: required Test::Perl::Critic | |
232 | ||
233 | 0.0.2 Wed Feb 28 16:52:00 2007 | |
234 | - Added missing dependencies in Build.PL | |
235 | - Test::Perl::Critic passed | |
236 | ||
237 | 0.0.1 Thu Aug 3 12:10:07 2006 | |
238 | Initial release. | |
239 |
0 | Preamble | |
1 | ||
2 | The intent of this document is to state the conditions under which a Package | |
3 | may be copied, such that the Copyright Holder maintains some semblance of | |
4 | artistic control over the development of the package, while giving the users | |
5 | of the package the right to use and distribute the Package in a more-or-less | |
6 | customary fashion, plus the right to make reasonable modifications. | |
7 | ||
8 | Definitions: | |
9 | ||
10 | "Package" refers to the collection of files distributed by the Copyright | |
11 | Holder, and derivatives of that collection of files created through textual | |
12 | modification. | |
13 | ||
14 | "Standard Version" refers to such a Package if it has not been modified, or | |
15 | has been modified in accordance with the wishes of the Copyright Holder as | |
16 | specified below. | |
17 | ||
18 | "Copyright Holder" is whoever is named in the copyright or copyrights for the | |
19 | package. | |
20 | ||
21 | "You" is you, if you're thinking about copying or distributing this Package. | |
22 | ||
23 | "Reasonable copying fee" is whatever you can justify on the basis of media | |
24 | cost, duplication charges, time of people involved, and so on. (You will not | |
25 | be required to justify it to the Copyright Holder, but only to the computing | |
26 | community at large as a market that must bear the fee.) | |
27 | ||
28 | "Freely Available" means that no fee is charged for the item itself, though | |
29 | there may be fees involved in handling the item. It also means that recipients | |
30 | of the item may redistribute it under the same conditions they received it. | |
31 | ||
32 | 1. You may make and give away verbatim copies of the source form of the | |
33 | Standard Version of this Package without restriction, provided that you | |
34 | duplicate all of the original copyright notices and associated disclaimers. | |
35 | ||
36 | 2. You may apply bug fixes, portability fixes and other modifications derived | |
37 | from the Public Domain or from the Copyright Holder. A Package modified in | |
38 | such a way shall still be considered the Standard Version. | |
39 | ||
40 | 3. You may otherwise modify your copy of this Package in any way, provided | |
41 | that you insert a prominent notice in each changed file stating how and when | |
42 | you changed that file, and provided that you do at least ONE of the following: | |
43 | ||
44 | a) place your modifications in the Public Domain or otherwise make them Freely | |
45 | Available, such as by posting said modifications to Usenet or an equivalent | |
46 | medium, or placing the modifications on a major archive site such as | |
47 | uunet.uu.net, or by allowing the Copyright Holder to include your | |
48 | modifications in the Standard Version of the Package. b) use the modified | |
49 | Package only within your corporation or organization. c) rename any | |
50 | non-standard executables so the names do not conflict with standard | |
51 | executables, which must also be provided, and provide a separate manual page | |
52 | for each non-standard executable that clearly documents how it differs from | |
53 | the Standard Version. d) make other distribution arrangements with the | |
54 | Copyright Holder. 4.You may distribute the programs of this Package in object | |
55 | code or executable form, provided that you do at least ONE of the following: | |
56 | ||
57 | a) distribute a Standard Version of the executables and library files, | |
58 | together with instructions (in the manual page or equivalent) on where to get | |
59 | the Standard Version. b) accompany the distribution with the machine-readable | |
60 | source of the Package with your modifications. c) give non-standard | |
61 | executables non-standard names, and clearly document the differences in manual | |
62 | pages (or equivalent), together with instructions on where to get the Standard | |
63 | Version. d) make other distribution arrangements with the Copyright Holder. | |
64 | 5. You may charge a reasonable copying fee for any distribution of this | |
65 | Package. You may charge any fee you choose for support of this Package. You | |
66 | may not charge a fee for this Package itself. However, you may distribute this | |
67 | Package in aggregate with other (possibly commercial) programs as part of a | |
68 | larger (possibly commercial) software distribution provided that you do not | |
69 | advertise this Package as a product of your own. You may embed this Package's | |
70 | interpreter within an executable of yours (by linking); this shall be | |
71 | construed as a mere form of aggregation, provided that the complete Standard | |
72 | Version of the interpreter is so embedded. | |
73 | ||
74 | 6. The scripts and library files supplied as input to or produced as output | |
75 | from the programs of this Package do not automatically fall under the | |
76 | copyright of this Package, but belong to whoever generated them, and may be | |
77 | sold commercially, and may be aggregated with this Package. If such scripts or | |
78 | library files are aggregated with this Package via the so-called "undump" or | |
79 | "unexec" methods of producing a binary executable image, then distribution of | |
80 | such an image shall neither be construed as a distribution of this Package nor | |
81 | shall it fall under the restrictions of Paragraphs 3 and 4, provided that you | |
82 | do not represent such an executable image as a Standard Version of this | |
83 | Package. | |
84 | ||
85 | 7. C subroutines (or comparably compiled subroutines in other languages) | |
86 | supplied by you and linked into this Package in order to emulate subroutines | |
87 | and variables of the language defined by this Package shall not be considered | |
88 | part of this Package, but are the equivalent of input as in Paragraph 6, | |
89 | provided these subroutines do not change the language in any way that would | |
90 | cause it to fail the regression tests for the language. | |
91 | ||
92 | 8. Aggregation of this Package with a commercial distribution is always | |
93 | permitted provided that the use of this Package is embedded; that is, when no | |
94 | overt attempt is made to make this Package's interfaces visible to the end | |
95 | user of the commercial distribution. Such use shall not be construed as a | |
96 | distribution of this Package. | |
97 | ||
98 | 9. The name of the Copyright Holder may not be used to endorse or promote | |
99 | products derived from this software without specific prior written permission. | |
100 | ||
101 | 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED | |
102 | WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | |
103 | MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
104 | ||
105 | The End |
0 | Build.PL | |
1 | Changes | |
2 | MANIFEST | |
3 | LICENSE | |
4 | META.yml | |
5 | Makefile.PL | |
6 | README | |
7 | TODO | |
8 | bin/csv2pdf | |
9 | bin/ltpretty | |
10 | examples/generate_examples.pl | |
11 | examples/imdbtop40.dat | |
12 | examples/examples.pdf | |
13 | lib/LaTeX/Table.pm | |
14 | lib/LaTeX/Table/Types/TypeI.pm | |
15 | lib/LaTeX/Table/Types/Ctable.pm | |
16 | lib/LaTeX/Table/Types/Longtable.pm | |
17 | lib/LaTeX/Table/Types/Std.pm | |
18 | lib/LaTeX/Table/Types/Xtab.pm | |
19 | lib/LaTeX/Table/Themes/ThemeI.pm | |
20 | lib/LaTeX/Table/Themes/Beamer.pm | |
21 | lib/LaTeX/Table/Themes/Booktabs.pm | |
22 | lib/LaTeX/Table/Themes/Classic.pm | |
23 | lib/LaTeX/Table/Themes/Modern.pm | |
24 | t/00.load.t | |
25 | t/10.table-ctable.t | |
26 | t/10.table-custom.t | |
27 | t/10.table-std.t | |
28 | t/10.table-xtab.t | |
29 | t/20.mcdef.t | |
30 | t/30.exceptions.t | |
31 | t/40.miscprivates.t | |
32 | t/50.synopsis.t | |
33 | t/60.coldef.t | |
34 | t/70.callback.t | |
35 | t/80.themes.t | |
36 | t/90.combat.t | |
37 | t/lib/MyThemes/Custom.pm | |
38 | t/perlcritic.t | |
39 | t/perlcriticrc | |
40 | t/pod-coverage.t | |
41 | t/pod.t |
0 | --- | |
1 | name: LaTeX-Table | |
2 | version: 0.9.15 | |
3 | author: | |
4 | - 'Markus Riester <mriester@gmx.de>' | |
5 | abstract: Perl extension for the automatic generation of LaTeX tables. | |
6 | license: perl | |
7 | resources: | |
8 | license: http://dev.perl.org/licenses/ | |
9 | requires: | |
10 | Carp: 0 | |
11 | English: 0 | |
12 | Module::Pluggable: 0 | |
13 | Moose: 0 | |
14 | Moose::Policy::FollowPBP: 0 | |
15 | Scalar::Util: 0 | |
16 | Template: 0 | |
17 | perl: 5.8.0 | |
18 | version: 0 | |
19 | build_requires: | |
20 | File::Spec: 0 | |
21 | Test::More: 0 | |
22 | Test::NoWarnings: 0 | |
23 | recommends: | |
24 | Getopt::Long: 0 | |
25 | LaTeX::Driver: 0 | |
26 | LaTeX::Encode: 0 | |
27 | Number::Format: 0 | |
28 | Text::CSV: 0 | |
29 | provides: | |
30 | LaTeX::Table: | |
31 | file: lib/LaTeX/Table.pm | |
32 | version: 0.9.15 | |
33 | LaTeX::Table::Themes::Beamer: | |
34 | file: lib/LaTeX/Table/Themes/Beamer.pm | |
35 | version: 1298 | |
36 | LaTeX::Table::Themes::Booktabs: | |
37 | file: lib/LaTeX/Table/Themes/Booktabs.pm | |
38 | version: 1326 | |
39 | LaTeX::Table::Themes::Classic: | |
40 | file: lib/LaTeX/Table/Themes/Classic.pm | |
41 | version: 1151 | |
42 | LaTeX::Table::Themes::Modern: | |
43 | file: lib/LaTeX/Table/Themes/Modern.pm | |
44 | version: 1298 | |
45 | LaTeX::Table::Themes::ThemeI: | |
46 | file: lib/LaTeX/Table/Themes/ThemeI.pm | |
47 | version: 1312 | |
48 | LaTeX::Table::Types::Ctable: | |
49 | file: lib/LaTeX/Table/Types/Ctable.pm | |
50 | version: 1307 | |
51 | LaTeX::Table::Types::Longtable: | |
52 | file: lib/LaTeX/Table/Types/Longtable.pm | |
53 | version: 1313 | |
54 | LaTeX::Table::Types::Std: | |
55 | file: lib/LaTeX/Table/Types/Std.pm | |
56 | version: 1307 | |
57 | LaTeX::Table::Types::TypeI: | |
58 | file: lib/LaTeX/Table/Types/TypeI.pm | |
59 | version: 1612 | |
60 | LaTeX::Table::Types::Xtab: | |
61 | file: lib/LaTeX/Table/Types/Xtab.pm | |
62 | version: 1564 | |
63 | generated_by: Module::Build version 0.33 | |
64 | meta-spec: | |
65 | url: http://module-build.sourceforge.net/META-spec-v1.4.html | |
66 | version: 1.4 |
0 | use 5.008; | |
1 | ||
2 | use strict; | |
3 | use warnings; | |
4 | use ExtUtils::MakeMaker; | |
5 | ||
6 | WriteMakefile( | |
7 | NAME => 'LaTeX::Table', | |
8 | AUTHOR => 'Markus Riester <mriester@gmx.de>', | |
9 | VERSION_FROM => 'lib/LaTeX/Table.pm', | |
10 | ABSTRACT_FROM => 'lib/LaTeX/Table.pm', | |
11 | ((ExtUtils::MakeMaker->VERSION() gt '6.30') ? | |
12 | ('LICENSE' => 'perl') : ()), | |
13 | PL_FILES => {}, | |
14 | PREREQ_PM => { | |
15 | 'Test::More' => 0, | |
16 | 'Test::NoWarnings' => 0, | |
17 | 'Moose' => 0, | |
18 | 'Moose::Policy::FollowPBP' => 0, | |
19 | 'Module::Pluggable' => 0, | |
20 | 'Scalar::Util' => 0, | |
21 | 'version' => 0, | |
22 | 'Template' => 0, | |
23 | }, | |
24 | EXE_FILES => [ 'bin/csv2pdf', 'bin/ltpretty' ], | |
25 | dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', }, | |
26 | clean => { FILES => 'LaTeX-Table-*' }, | |
27 | ); |
0 | LaTeX-Table version 0.9.15 | |
1 | ||
2 | This module supports multipage tables via the xtab and the longtable package. | |
3 | For publication quality tables it utilizes the booktabs package. It also | |
4 | supports the tabularx and tabulary packages for nicer fixed-width tables. | |
5 | Furthermore, it supports the colortbl package for colored tables optimized for | |
6 | presentations. The powerful new ctable package is supported and especially | |
7 | recommended when footnotes are needed. LaTeX::Table ships with some | |
8 | predefined, good looking themes. | |
9 | ||
10 | INSTALLATION | |
11 | ||
12 | To install this module, run the following commands: | |
13 | ||
14 | perl Build.PL | |
15 | ./Build | |
16 | ./Build test | |
17 | ./Build install | |
18 | ||
19 | ||
20 | Alternatively, to install with ExtUtils::MakeMaker, you can use the following | |
21 | commands: | |
22 | ||
23 | perl Makefile.PL | |
24 | make | |
25 | make test | |
26 | make install | |
27 | ||
28 | ||
29 | Now start the script generate_examples.pl in the examples directory of this | |
30 | distibution. | |
31 | ||
32 | perl generate_examples.pl | |
33 | ||
34 | This script generates some LaTeX files with some example tables. | |
35 | Now please compile these examples with LaTeX and check if all tables look ok: | |
36 | ||
37 | latex examples.tex | |
38 | xdvi examples.dvi | |
39 | ||
40 | ||
41 | PROGRAMS | |
42 | ||
43 | This module ships with two small utilities. The first, csv2pdf is a CSV to PDF | |
44 | converter. It is only about 100 lines of code short and only meant as an | |
45 | example application, but it is already very powerful. It requires Getopt::Long, | |
46 | Text::CSV, LaTeX::Encode and LaTeX::Driver, which are not installed during the | |
47 | installation of this module. | |
48 | ||
49 | The second utility is ltpretty. It takes a lazy formatted LaTeX table from | |
50 | STDIN (typically piped from Vim or emacs) and outputs a completely formatted | |
51 | table. This makes this module not only useful for automatically generated | |
52 | reports, but also saves a lot of typing work in creating custom tables. | |
53 | ||
54 | ||
55 | DEPENDENCIES | |
56 | ||
57 | Carp | |
58 | Class::Std | |
59 | English | |
60 | Readonly | |
61 | Scalar::Util | |
62 | Text::Wrap | |
63 | ||
64 | COPYRIGHT AND LICENCE | |
65 | ||
66 | Copyright (C) 2006-2009, Markus Riester | |
67 | ||
68 | This library is free software; you can redistribute it and/or modify | |
69 | it under the same terms as Perl itself. |
0 | before 1.0 | |
1 | ||
2 | - fine tune default parameters | |
3 | - nicer examples.pdf (started) | |
4 | - make it possible to use custom templates (done, now document it) | |
5 | - remove deprecated code (release candidate 1) | |
6 | ||
7 | after 1.0 | |
8 | ||
9 | - code cleanup (use more Moose features, e.g. validation) | |
10 | - shortcut for multirows |
0 | #!/usr/bin/perl | |
1 | ||
2 | ############################################################################# | |
3 | # $Author: markus $ | |
4 | # $Date: 2009-05-29 10:38:31 +0200 (Fri, 29 May 2009) $ | |
5 | # $Revision: 1616 $ | |
6 | ############################################################################# | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use utf8; | |
12 | ||
13 | use Fatal qw(open close); | |
14 | use Getopt::Long; | |
15 | use Pod::Usage; | |
16 | use Carp; | |
17 | ||
18 | use Text::CSV; | |
19 | use File::Basename; | |
20 | use Readonly; | |
21 | ||
22 | use LaTeX::Table; | |
23 | use LaTeX::Encode; | |
24 | use LaTeX::Driver; | |
25 | ||
26 | use version; our $VERSION = $LaTeX::Table::VERSION; | |
27 | ||
28 | Readonly my $DEFAULT_XENTRYSTRETCH => -0.05; | |
29 | Readonly my $DEFAULT_THEME => 'Meyrin'; | |
30 | ||
31 | my ( $infile, $outfile, $help, $man, $version ); | |
32 | ||
33 | my $sep_char = q{,}; | |
34 | my $latex_encode = 0; | |
35 | my $landscape = 0; | |
36 | my $outputlatex = 0; | |
37 | my $theme = $DEFAULT_THEME; | |
38 | my $title = 0; | |
39 | my $coldef = 0; | |
40 | my $header = 0; | |
41 | ||
42 | my $options_ok = GetOptions( | |
43 | 'in=s' => \$infile, | |
44 | 'out=s' => \$outfile, | |
45 | 'sep_char=s' => \$sep_char, | |
46 | 'latex_encode' => \$latex_encode, | |
47 | 'landscape' => \$landscape, | |
48 | 'outputlatex' => \$outputlatex, | |
49 | 'theme=s' => \$theme, | |
50 | 'title=s' => \$title, | |
51 | 'coldef=s' => \$coldef, | |
52 | 'header=s' => \$header, | |
53 | 'help|?' => \$help, | |
54 | 'version|v' => \$version, | |
55 | 'man' => \$man, | |
56 | ) or pod2usage(2); | |
57 | ||
58 | if ($version) { | |
59 | print "$0 $VERSION\n" or croak q{Can't print to stdout.}; | |
60 | exit; | |
61 | } | |
62 | ||
63 | if ($man) { | |
64 | pod2usage( -exitstatus => 0, -verbose => 2 ); | |
65 | } | |
66 | if ( $help || !defined $infile ) { | |
67 | pod2usage(1); | |
68 | } | |
69 | if ( !defined $outfile ) { | |
70 | $outfile = q{./} . fileparse( $infile, qw(csv txt dat) ) . '.pdf'; | |
71 | } | |
72 | ||
73 | my $csv = Text::CSV->new( | |
74 | { binary => 1, | |
75 | sep_char => $sep_char, | |
76 | allow_whitespace => 1 | |
77 | } | |
78 | ); | |
79 | ||
80 | my @header; | |
81 | my @data; | |
82 | ||
83 | if ($header) { | |
84 | my $status = $csv->parse($header); | |
85 | @header = [ $csv->fields() ]; | |
86 | } | |
87 | ||
88 | my $line_number = 0; | |
89 | ||
90 | open my $IN, '<', $infile; | |
91 | while ( my $line = <$IN> ) { | |
92 | chomp $line; | |
93 | my $status = $csv->parse($line); | |
94 | if ( !$header && $line_number == 0 ) { | |
95 | @header = [ $csv->fields() ]; | |
96 | } | |
97 | else { | |
98 | push @data, [ $csv->fields() ]; | |
99 | } | |
100 | $line_number++; | |
101 | } | |
102 | close $IN; | |
103 | ||
104 | my $table = LaTeX::Table->new( | |
105 | { header => \@header, | |
106 | data => \@data, | |
107 | type => 'xtab', | |
108 | xentrystretch => $DEFAULT_XENTRYSTRETCH, | |
109 | tabletail => q{ }, | |
110 | theme => $theme, | |
111 | ||
112 | # width => '\textwidth', | |
113 | coldef => $coldef, | |
114 | callback => sub { | |
115 | my ( $row, $col, $value, $is_header ) = @_; | |
116 | if ($latex_encode) { | |
117 | return latex_encode($value); | |
118 | } | |
119 | return $value; | |
120 | }, | |
121 | } | |
122 | ); | |
123 | ||
124 | my $ls = q{}; | |
125 | my $lg = q{}; | |
126 | if ($landscape) { | |
127 | $ls = '[landscape]'; | |
128 | $lg = '\usepackage[landscape]{geometry}'; | |
129 | } | |
130 | my $tc = q{}; | |
131 | my $mtc = q{}; | |
132 | ||
133 | if ($title) { | |
134 | $tc = '\title{' . $title . '}'; | |
135 | $mtc = '\maketitle'; | |
136 | } | |
137 | my $code = '\documentclass' . $ls | |
138 | . '{article}\usepackage{xtab}' | |
139 | . $lg | |
140 | . '\usepackage{booktabs}' | |
141 | . '\usepackage{xcolor}' | |
142 | . '\usepackage{colortbl}' | |
143 | . '\usepackage{array}' | |
144 | . '\usepackage{helvet}' | |
145 | . $tc | |
146 | . '\begin{document}' | |
147 | . $mtc . "\n" | |
148 | . $table->generate_string | |
149 | . '\end{document}'; | |
150 | ||
151 | my $drv = LaTeX::Driver->new( | |
152 | source => \$code, | |
153 | output => $outfile, | |
154 | format => 'pdf', | |
155 | ); | |
156 | my $ok = $drv->run; | |
157 | ||
158 | if ($outputlatex) { | |
159 | print "$code" or croak q{Can't print to stdout.}; | |
160 | } | |
161 | ||
162 | __END__ | |
163 | ||
164 | =head1 NAME | |
165 | ||
166 | csv2pdf - A simple but yet powerful LaTeX::Table example application. | |
167 | ||
168 | =head1 SYNOPSIS | |
169 | ||
170 | csv2pdf [OPTIONS] --in in.csv [--out out.pdf] | |
171 | ||
172 | =head1 OPTIONS | |
173 | ||
174 | =over | |
175 | ||
176 | =item C<--sep_char> | |
177 | ||
178 | The separator character. Default comma ','. | |
179 | ||
180 | =item C<--latex_encode> | |
181 | ||
182 | Use L<LaTeX::Encode>. | |
183 | ||
184 | =item C<--landscape> | |
185 | ||
186 | Output the PDF in landscape orientation. | |
187 | ||
188 | =item C<--theme> | |
189 | ||
190 | The table theme. See L<LaTeX::Table>. Default I<Meyrin>. | |
191 | ||
192 | =item C<--coldef> | |
193 | ||
194 | The column definition, eg 'llp{5cm}'. If unset, guessed by L<LaTeX::Table>. | |
195 | ||
196 | =item C<--title> | |
197 | ||
198 | If set, then uses the specified string as title. | |
199 | ||
200 | =item C<--header> | |
201 | ||
202 | Instead of the first line, use the specified string as header. | |
203 | ||
204 | --header "Header A, Header B, Header C" | |
205 | ||
206 | The separator character must be the same as in the file. If unset, then the | |
207 | first line is used as header. | |
208 | ||
209 | =item C<--outputlatex> | |
210 | ||
211 | Prints the LaTeX code to STDOUT. | |
212 | ||
213 | =item C<--man> | |
214 | ||
215 | Display manpage. | |
216 | ||
217 | =item C<--version> | |
218 | ||
219 | Print version number of this software. | |
220 | ||
221 | =back | |
222 | ||
223 | =head1 DESCRIPTION | |
224 | ||
225 | Converts a CSV file to PDF. Requires LaTeX. | |
226 | ||
227 | =head1 CONFIGURATION AND ENVIRONMENT | |
228 | ||
229 | C<csv2pdf> does not support configuration files or environment variables. | |
230 | ||
231 | =head1 DEPENDENCIES | |
232 | ||
233 | LaTeX. | |
234 | ||
235 | L<Fatal>, L<File::Basename>, L<Getopt::Long>, L<LaTeX::Driver>, L<LaTeX::Encode>, L<LaTeX::Table>, | |
236 | L<Pod::Usage>, L<Readonly>, L<Text::CSV> | |
237 | ||
238 | =head1 BUGS AND LIMITATIONS | |
239 | ||
240 | No bugs have been reported. | |
241 | ||
242 | Please report any bugs or feature requests to | |
243 | C<bug-latex-table@rt.cpan.org>, or through the web interface at | |
244 | L<http://rt.cpan.org>. | |
245 | ||
246 | =head1 AUTHOR | |
247 | ||
248 | Markus Riester C<< <mriester@gmx.de> >> | |
249 | ||
250 | =head1 LICENSE AND COPYRIGHT | |
251 | ||
252 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
253 | ||
254 | This program is free software; you can redistribute it and/or | |
255 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
256 | ||
257 | =head1 DISCLAIMER OF WARRANTY | |
258 | ||
259 | BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |
260 | FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |
261 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |
262 | PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER | |
263 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
264 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE | |
265 | ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH | |
266 | YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL | |
267 | NECESSARY SERVICING, REPAIR, OR CORRECTION. | |
268 | ||
269 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
270 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |
271 | REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE | |
272 | LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, | |
273 | OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE | |
274 | THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING | |
275 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A | |
276 | FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF | |
277 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | |
278 | SUCH DAMAGES. | |
279 | ||
280 | =cut | |
281 | ||
282 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | #!/usr/bin/perl | |
1 | ||
2 | ############################################################################# | |
3 | # $Author: markus $ | |
4 | # $Date: 2009-01-03 12:59:20 +0100 (Sat, 03 Jan 2009) $ | |
5 | # $Revision: 1259 $ | |
6 | ############################################################################# | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use LaTeX::Table; | |
12 | use Carp; | |
13 | ||
14 | use version; our $VERSION = $LaTeX::Table::VERSION; | |
15 | ||
16 | my $line_id = 0; | |
17 | my @input; | |
18 | my $paramline; | |
19 | ||
20 | while (my $line = <>) { | |
21 | chomp $line; | |
22 | $line =~ s{\s+}{ }xmsg; | |
23 | $line =~ s{\A \s* | \\ | \s* \z}{}xmsg; | |
24 | if ($line_id == 0) { #first line contains the parameters | |
25 | $paramline = $line; | |
26 | } | |
27 | else { | |
28 | push @input, $line; | |
29 | } | |
30 | $line_id++; | |
31 | } | |
32 | ||
33 | # uncomment original input | |
34 | _say( join q{}, map { "\n % $_" } ($paramline, @input) ); | |
35 | ||
36 | @input = map { [ split m{ & }xms ] } @input; | |
37 | ||
38 | # store the paramline in a hash | |
39 | my %params = map { _parse_param($_) } split m{ ; }xms, $paramline; | |
40 | ||
41 | my $table = LaTeX::Table->new({ | |
42 | header => [ $input[0] ], | |
43 | data => [ @input[1 .. $#input ] ], | |
44 | %params, | |
45 | }); | |
46 | ||
47 | _say("\n" . $table->generate_string()); | |
48 | ||
49 | sub _parse_param { | |
50 | my ( $s ) = @_; | |
51 | if ( $s =~ m{ \A (.*?) = (.*) \z}xms) { | |
52 | return $1 => $2; | |
53 | } | |
54 | else { | |
55 | croak q{Invalid parameter line}; | |
56 | } | |
57 | return; | |
58 | } | |
59 | ||
60 | sub _say { | |
61 | my ( $s ) = @_; | |
62 | print "$s\n" or croak q{Can't print to stdout.}; | |
63 | return; | |
64 | } | |
65 | ||
66 | __END__ | |
67 | ||
68 | =head1 NAME | |
69 | ||
70 | ltpretty - Use LaTeX::Table from within your text editor. | |
71 | ||
72 | =head1 SYNOPSIS | |
73 | ||
74 | ltpretty < lazytable | |
75 | ||
76 | =head1 DESCRIPTION | |
77 | ||
78 | This program takes a I<lazy formatted> LaTeX table from STDIN (typically piped | |
79 | from Vim or emacs) and outputs a completely formatted table. | |
80 | ||
81 | =head1 LAZY FORMAT | |
82 | ||
83 | The first line must contain the L<LaTeX::Table> options (seperated by | |
84 | semicolons C<;>) in the format C<optionname=value>. The | |
85 | second line must contain the header, the following lines the data. | |
86 | Columns are seperated by C<&>. | |
87 | ||
88 | =head1 EXAMPLE | |
89 | ||
90 | ||
91 | theme=NYC;label=test;position=htb | |
92 | Header Col1 & Header Col2 | |
93 | Data Col1 & Data Col2 | |
94 | ||
95 | =head1 VIM | |
96 | ||
97 | =over | |
98 | ||
99 | =item 1. Select the text in C<VISUAL LINE> mode (C<shift+v>). | |
100 | ||
101 | =item 2. Type C<!ltpretty> | |
102 | ||
103 | =back | |
104 | ||
105 | =head1 EMACS | |
106 | ||
107 | =over | |
108 | ||
109 | =item 1. Select the text | |
110 | ||
111 | =item 2. Press C<alt+|> | |
112 | ||
113 | =item 3. Now "Shell command on region" should appear. Type C<ltpretty> | |
114 | ||
115 | =back | |
116 | ||
117 | =head1 CONFIGURATION AND ENVIRONMENT | |
118 | ||
119 | C<ltpretty> does not support configuration files or environment variables. | |
120 | ||
121 | =head1 DEPENDENCIES | |
122 | ||
123 | L<LaTeX::Table> | |
124 | ||
125 | =head1 BUGS AND LIMITATIONS | |
126 | ||
127 | Our I<lazy format> does not support multi-line headers. Just add the other | |
128 | header lines afterwards. More importantly, it currently does not support | |
129 | non-scalar L<LaTeX::Table> options like for example C<columns_like_header>. | |
130 | A future version may add this functionality. | |
131 | ||
132 | Please report any bugs or feature requests to | |
133 | C<bug-latex-table@rt.cpan.org>, or through the web interface at | |
134 | L<http://rt.cpan.org>. | |
135 | ||
136 | =head1 AUTHOR | |
137 | ||
138 | Markus Riester C<< <mriester@gmx.de> >> | |
139 | ||
140 | =head1 LICENSE AND COPYRIGHT | |
141 | ||
142 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
143 | ||
144 | This program is free software; you can redistribute it and/or | |
145 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
146 | ||
147 | =head1 DISCLAIMER OF WARRANTY | |
148 | ||
149 | BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |
150 | FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |
151 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |
152 | PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER | |
153 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
154 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE | |
155 | ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH | |
156 | YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL | |
157 | NECESSARY SERVICING, REPAIR, OR CORRECTION. | |
158 | ||
159 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
160 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |
161 | REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE | |
162 | LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, | |
163 | OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE | |
164 | THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING | |
165 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A | |
166 | FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF | |
167 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | |
168 | SUCH DAMAGES. | |
169 | ||
170 | =cut | |
171 | ||
172 | # vim: ft=perl sw=4 ts=4 expandtab |
Binary diff not shown
0 | #!/usr/bin/perl | |
1 | ||
2 | use strict; | |
3 | use warnings; | |
4 | ||
5 | use LaTeX::Table; | |
6 | use LaTeX::Encode; | |
7 | use Number::Format qw(:subs); | |
8 | use Data::Dumper; | |
9 | use Text::CSV; | |
10 | ||
11 | system('rm *.tex'); | |
12 | ||
13 | my $test_data = [ | |
14 | [ 'Gnat', 'per gram', '13.651' ], | |
15 | [ '', 'each', '0.012' ], | |
16 | [ 'Gnu', 'stuffed', '92.59' ], | |
17 | [ 'Emu', 'stuffed', '33.33' ], | |
18 | [ 'Armadillo', 'frozen', '8.99' ], | |
19 | ]; | |
20 | ||
21 | my $test_data_large = []; | |
22 | ||
23 | for my $i ( 1 .. 9 ) { | |
24 | $test_data_large = [ @$test_data_large, @$test_data ]; | |
25 | } | |
26 | ||
27 | my $table = LaTeX::Table->new( | |
28 | { maincaption => 'Price List', | |
29 | fontsize => 'large', | |
30 | caption => '', | |
31 | callback => sub { | |
32 | my ( $row, $col, $value, $is_header ) = @_; | |
33 | if ( $col == 2 && !$is_header ) { | |
34 | $value = format_price( $value, 2, '' ); | |
35 | } | |
36 | return $value; | |
37 | }, | |
38 | } | |
39 | ); | |
40 | ||
41 | my $themes = { | |
42 | 'Custom' => { | |
43 | 'HEADER_FONT_STYLE' => 'sc', | |
44 | 'HEADER_CENTERED' => 1, | |
45 | 'CAPTION_FONT_STYLE' => 'sc', | |
46 | 'VERTICAL_RULES' => [ 1, 2, 1 ], | |
47 | 'HORIZONTAL_RULES' => [ 1, 2, 0 ], | |
48 | }, | |
49 | }; | |
50 | ||
51 | $table->set_custom_themes($themes); | |
52 | ||
53 | foreach my $theme ( keys %{ $table->get_available_themes } ) { | |
54 | ||
55 | my $test_header | |
56 | = [ [ 'Item:2c', '' ], [ 'Animal', 'Description', 'Price' ] ]; | |
57 | ||
58 | if ( $theme eq 'Zurich' || $theme eq 'Meyrin' ) { | |
59 | $test_header = [ | |
60 | [ 'Item:2c', '' ], | |
61 | ['\cmidrule(r){1-2}'], | |
62 | [ 'Animal', 'Description', 'Price' ] | |
63 | ]; | |
64 | } | |
65 | ||
66 | $table->set_maincaption("\\texttt{theme=$theme, type=std}"); | |
67 | ||
68 | if ($theme eq 'Muenchen') { | |
69 | $table->set_fontfamily('sf'); | |
70 | } | |
71 | else { | |
72 | $table->set_fontfamily(0); | |
73 | } | |
74 | $table->set_filename("$theme.tex"); | |
75 | $table->set_position('!htb'); | |
76 | $table->set_caption_top(0); | |
77 | $table->set_theme($theme); | |
78 | $table->set_type('std'); | |
79 | $table->set_header($test_header); | |
80 | $table->set_data($test_data); | |
81 | #$table->set_width('0.9\textwidth'); | |
82 | $table->generate(); | |
83 | ||
84 | $table->set_type('ctable'); | |
85 | $table->set_maincaption("\\texttt{theme=$theme, type=ctable}"); | |
86 | ||
87 | $table->set_label("theme${theme}ctable"); | |
88 | $table->set_filename("${theme}ctable.tex"); | |
89 | $table->generate(); | |
90 | $table->set_label(0); | |
91 | ||
92 | # warn Dumper $test_data; | |
93 | $table->set_type('xtab'); | |
94 | $table->set_maincaption("\\texttt{theme=$theme, type=xtab}"); | |
95 | $table->set_position(0); | |
96 | ||
97 | # $table->set_caption_top(1); | |
98 | $table->set_filename("${theme}multipage.tex"); | |
99 | $table->set_xentrystretch(-0.1); | |
100 | $table->set_header($test_header); | |
101 | $table->set_data($test_data_large); | |
102 | $table->set_caption_top( | |
103 | '\setlength{\abovecaptionskip}{0pt}\setlength{\belowcaptionskip}{10pt}\topcaption' | |
104 | ); | |
105 | $table->generate(); | |
106 | $table->set_filename("${theme}multipage2.tex"); | |
107 | $table->set_type('longtable'); | |
108 | $table->set_maincaption("\\texttt{theme=$theme, type=longtable}"); | |
109 | $table->generate(); | |
110 | } | |
111 | ||
112 | open my $OUT, '>', 'examples.tex'; | |
113 | foreach my $line (<DATA>) { | |
114 | print $OUT $line; | |
115 | } | |
116 | ||
117 | my $code = << 'EOC' | |
118 | \subsection{Table width, tabular* environment} | |
119 | \tref{tbl:width} demonstrates a fixed-width table in the \texttt{tabular*} | |
120 | environment. Here, the space between the columns is filled with spaces. | |
121 | \begin{verbatim} | |
122 | $table = LaTeX::Table->new( | |
123 | { header => $header, | |
124 | data => $data, | |
125 | width => '0.7\textwidth', | |
126 | label => 'tbl:width', | |
127 | caption => '\texttt{width}', | |
128 | } | |
129 | ); | |
130 | \end{verbatim} | |
131 | EOC | |
132 | ; | |
133 | my $test_header = [ [ 'Animal', 'Description', 'Price' ] ]; | |
134 | $table = LaTeX::Table->new( | |
135 | { header => $test_header, | |
136 | data => $test_data, | |
137 | label => 'tbl:width', | |
138 | width => '0.7\textwidth', | |
139 | caption => '\texttt{width}', | |
140 | } | |
141 | ); | |
142 | print ${OUT} $code . $table->generate_string; | |
143 | ||
144 | $code = << 'EOC' | |
145 | \subsection{Large Columns} | |
146 | The next example is a small table with two larger columns. | |
147 | \cpanmodule{LaTeX::Table} automatically sets the column to \texttt{p\{5cm\}} when a | |
148 | cell in a column has more than 30 characters. \LaTeX~generates | |
149 | \tref{tbl:paragraph}. | |
150 | ||
151 | \begin{verbatim} | |
152 | $table = LaTeX::Table->new( | |
153 | { header => $header, | |
154 | data => $data, | |
155 | label => 'tbl:paragraph', | |
156 | caption => 'LaTeX paragraph column attribute.', | |
157 | } | |
158 | ); | |
159 | \end{verbatim} | |
160 | EOC | |
161 | ; | |
162 | ||
163 | my $header = [ [ 'Character', 'Fullname', 'Voice' ], ]; | |
164 | my $data = [ | |
165 | [ 'Homer', 'Homer Jay Simpson', 'Dan Castellaneta', ], | |
166 | [ 'Marge', 'Marjorie Simpson (née Bouvier)', 'Julie Kavner', ], | |
167 | [ 'Bart', 'Bartholomew Jojo Simpson', 'Nancy Cartwright', ], | |
168 | [ 'Lisa', 'Elizabeth Marie Simpson', 'Yeardley Smith', ], | |
169 | [ 'Maggie', | |
170 | 'Margaret Simpson', | |
171 | 'Elizabeth Taylor, Nancy Cartwright, James Earl Jones,' | |
172 | . 'Yeardley Smith, Harry Shearer', | |
173 | ], | |
174 | ]; | |
175 | $table = LaTeX::Table->new( | |
176 | { header => $header, | |
177 | data => $data, | |
178 | label => 'tbl:paragraph', | |
179 | caption => 'LaTeX paragraph column attribute.', | |
180 | } | |
181 | ); | |
182 | ||
183 | print ${OUT} $code; | |
184 | ||
185 | #$table->set_tabledef_strategy( { 'LONG_COL' => 'p{4cm}', 'IS_LONG' => 30 } ); | |
186 | print ${OUT} $table->generate_string; | |
187 | ||
188 | $code = << 'EOC' | |
189 | \subsubsection{\texttt{tabularx}} | |
190 | We can use the \ctanpackage{tabularx} package to find better column widths than the | |
191 | default 5cm. See \tref{tbl:tabularx} for the results. | |
192 | \begin{verbatim} | |
193 | $table = LaTeX::Table->new( | |
194 | { header => $header, | |
195 | data => $data, | |
196 | width => '0.9\textwidth', | |
197 | width_environment => 'tabularx', | |
198 | label => 'tbl:tabularx', | |
199 | caption => '\texttt{width\_environment=tabularx}.', | |
200 | } | |
201 | ); | |
202 | \end{verbatim} | |
203 | EOC | |
204 | ; | |
205 | $table->set_label('tbl:tabularx'); | |
206 | $table->set_caption('\texttt{width\_environment=tabularx}.'); | |
207 | ||
208 | $table->set_width('0.9\textwidth'); | |
209 | $table->set_width_environment('tabularx'); | |
210 | print ${OUT} $code . $table->generate_string; | |
211 | ||
212 | $code = << 'EOC' | |
213 | \subsubsection{\texttt{tabulary}} | |
214 | A third option is to use the \ctanpackage{tabulary} package. See \tref{tbl:tabulary}. | |
215 | \begin{verbatim} | |
216 | $table = LaTeX::Table->new( | |
217 | { header => $header, | |
218 | data => $data, | |
219 | width => '0.9\textwidth', | |
220 | width_environment => 'tabulary', | |
221 | label => 'tbl:tabulary', | |
222 | caption => '\texttt{width\_environment=tabulary}.', | |
223 | } | |
224 | ); | |
225 | \end{verbatim} | |
226 | EOC | |
227 | ; | |
228 | $table->set_label('tbl:tabulary'); | |
229 | $table->set_caption('\texttt{width\_environment=tabulary}.'); | |
230 | $table->set_width_environment('tabulary'); | |
231 | ||
232 | print ${OUT} $code . $table->generate_string; | |
233 | ||
234 | $code = << 'EOC' | |
235 | \subsection{Rotate tables} | |
236 | \tref{tbl:sideways} demonstrates the \ltoption{sideways} option. Requires the | |
237 | \ctanpackage{rotating} package. | |
238 | \begin{verbatim} | |
239 | $table = LaTeX::Table->new( | |
240 | { header => $header, | |
241 | data => $data, | |
242 | width => '0.9\textwidth', | |
243 | width_environment | |
244 | => 'tabularx', | |
245 | sideways => 1, | |
246 | label => 'tbl:sideways', | |
247 | caption => '\texttt{width\_environment=tabularx, sideways}.', | |
248 | } | |
249 | ); | |
250 | \end{verbatim} | |
251 | EOC | |
252 | ; | |
253 | ||
254 | $table->set_sideways(1); | |
255 | $table->set_caption('\texttt{width\_environment=tabularx, sideways}.'); | |
256 | $table->set_label('tbl:sideways'); | |
257 | ||
258 | print ${OUT} $code . $table->generate_string; | |
259 | ||
260 | $code = << 'EOC' | |
261 | \subsection{Resize tables} | |
262 | In Tables \ref{tbl:resizebox1} and \ref{tbl:resizebox2}, the | |
263 | \ltoption{resizebox} option was used to get the desired width (and height in | |
264 | the second example). Requires the \ctanpackage{graphicx} package. | |
265 | \begin{verbatim} | |
266 | $table = LaTeX::Table->new( | |
267 | { header => $header, | |
268 | data => $data, | |
269 | resizebox => [ '0.6\textwidth' ], | |
270 | label => 'tbl:resizebox1', | |
271 | caption => '\texttt{resizebox}, Example 1', | |
272 | } | |
273 | ); | |
274 | ||
275 | $table->set_resizebox([ '300pt', '120pt' ]); | |
276 | \end{verbatim} | |
277 | EOC | |
278 | ; | |
279 | ||
280 | $table->set_sideways(0); | |
281 | $table->set_label('tbl:resizebox1'); | |
282 | $table->set_resizebox( ['0.6\textwidth'] ); | |
283 | $table->set_caption('\texttt{resizebox}, Example 1'); | |
284 | ||
285 | print ${OUT} $code . $table->generate_string; | |
286 | ||
287 | $table->set_label('tbl:resizebox2'); | |
288 | $table->set_resizebox( [ '300pt', '120pt' ] ); | |
289 | $table->set_caption('scaled to a size of 300pt x 120pt'); | |
290 | $table->set_caption('\texttt{resizebox}, Example 2'); | |
291 | ||
292 | print ${OUT} $table->generate_string; | |
293 | ||
294 | $code = << 'EOC' | |
295 | \subsection{Callback functions} | |
296 | Callback functions are an easy way of formatting the cells. Note that the | |
297 | prices for Gnat are rounded in the following tables. | |
298 | \begin{verbatim} | |
299 | my $table = LaTeX::Table->new( | |
300 | { | |
301 | filename => 'prices.tex', | |
302 | maincaption => 'Price List', | |
303 | caption => 'Try our special offer today!', | |
304 | label => 'tbl:prices', | |
305 | header => $header, | |
306 | data => $data, | |
307 | callback => sub { | |
308 | my ($row, $col, $value, $is_header ) = @_; | |
309 | if ($col == 2 && $!is_header) { | |
310 | $value = format_price($value, 2, ''); | |
311 | } | |
312 | return $value; | |
313 | }, | |
314 | }); | |
315 | \end{verbatim} | |
316 | EOC | |
317 | ; | |
318 | ||
319 | print $OUT $code; | |
320 | ||
321 | $header = [ | |
322 | [ 'Item:2c', '' ], | |
323 | ['\cmidrule(r){1-2}'], | |
324 | [ 'Animal', 'Description', 'Price' ] | |
325 | ]; | |
326 | ||
327 | $data = [ | |
328 | [ 'Gnat', 'per gram', '13.651' ], | |
329 | [ '', 'each', '0.012' ], | |
330 | [ 'Gnu', 'stuffed', '92.59' ], | |
331 | [ 'Emu', 'stuffed', '33.33' ], | |
332 | [ 'Armadillo', 'frozen', '8.99' ], | |
333 | ]; | |
334 | ||
335 | $table = LaTeX::Table->new( | |
336 | { filename => 'prices.tex', | |
337 | caption => '\texttt{caption\_top}, Example 1', | |
338 | caption_top => 1, | |
339 | label => 'table:pricestop', | |
340 | header => $header, | |
341 | data => $data, | |
342 | callback => sub { | |
343 | my ( $row, $col, $value, $is_header ) = @_; | |
344 | if ($is_header) { | |
345 | $value = uc $value; | |
346 | } | |
347 | elsif ( $col == 2 && !$is_header ) { | |
348 | $value = format_price( $value, 2, '' ); | |
349 | } | |
350 | return $value; | |
351 | }, | |
352 | } | |
353 | ); | |
354 | ||
355 | $code = << 'EOT'; | |
356 | \subsection{Captions} | |
357 | \subsubsection{Placement} | |
358 | Tables can be placed on top of the tables with \ltoption{caption\_top => 1}. See | |
359 | \tref{table:pricestop}. Note that the standard \LaTeX~macros are optimized for | |
360 | bottom captions. Use something like | |
361 | \begin{verbatim} | |
362 | \usepackage[tableposition=top]{caption} | |
363 | \end{verbatim} | |
364 | to fix the spacing. Alternatively, you could fix the spacing by yourself by | |
365 | providing your own command(s) (\tref{table:pricestop2}): | |
366 | \begin{verbatim} | |
367 | $table->set_caption_top( | |
368 | '\setlength{\abovecaptionskip}{0pt}' . | |
369 | '\setlength{\belowcaptionskip}{10pt}' . | |
370 | \caption' | |
371 | ); | |
372 | \end{verbatim} | |
373 | EOT | |
374 | ||
375 | print $OUT $code . $table->generate_string(); | |
376 | $table->set_caption_top( | |
377 | '\setlength{\abovecaptionskip}{0pt}\setlength{\belowcaptionskip}{10pt}\caption' | |
378 | ); | |
379 | $table->set_label('table:pricestop2'); | |
380 | $table->set_caption('\texttt{caption\_top}, Example 2'); | |
381 | ||
382 | print $OUT $table->generate_string(); | |
383 | ||
384 | $code = << 'EOT'; | |
385 | \subsection{Multicolumns} | |
386 | If you want tables with vertical lines (are you sure?) you should use our | |
387 | shortcut to generate multicolumns. These shortcuts are not only much less | |
388 | typing work, but they also automatically add the vertical lines, see | |
389 | \tref{tbl:mc}. | |
390 | \begin{verbatim} | |
391 | $header = [ [ 'A:3c' ], | |
392 | [ 'A:2c', 'B' ], | |
393 | ['A', 'B', 'C' ], ]; | |
394 | ||
395 | $data = [ [ '1', 'w', 'x' ], | |
396 | [ '2', 'c:2c' ], ]; | |
397 | ||
398 | $table = LaTeX::Table->new( | |
399 | { header => $header, | |
400 | data => $data, | |
401 | theme => 'Dresden', | |
402 | label => 'tbl:mc', | |
403 | caption => 'Multicolumns.', | |
404 | } | |
405 | ); | |
406 | \end{verbatim} | |
407 | EOT | |
408 | ||
409 | $header = [ ['A:3c'], [ 'A:2c', 'B' ], [ 'A', 'B', 'C' ], ]; | |
410 | $data = [ [ '1', 'w', 'x' ], [ '2', 'c:2c' ], ]; | |
411 | ||
412 | $table = LaTeX::Table->new( | |
413 | { environment => 1, | |
414 | header => $header, | |
415 | data => $data, | |
416 | label => 'tbl:mc', | |
417 | caption => 'Multicolumns.', | |
418 | theme => 'Dresden', | |
419 | } | |
420 | ); | |
421 | ||
422 | print $OUT $code . $table->generate_string(); | |
423 | ||
424 | ||
425 | $code = << 'EOT'; | |
426 | \subsection{Headers} | |
427 | If you don't need headers, just leave them undefined (see | |
428 | \tref{tbl:noheader}). If you want that the first column looks like a header, | |
429 | you can define this with the \ltoption{columns\_like\_header} option | |
430 | (\tref{table:collikeheader} and \tref{table:collikeheader2}). You | |
431 | can also rotate the header columns by 90 degrees | |
432 | (\tref{table:headersideways}) with \ltoption{header\_sideways}. If you do | |
433 | not want to rotate all header cells, use a callback function instead | |
434 | (\tref{table:headersideways2}). | |
435 | \begin{verbatim} | |
436 | $table = LaTeX::Table->new( | |
437 | { | |
438 | data => $data, | |
439 | label => 'tbl:noheader', | |
440 | caption => 'Table without header.', | |
441 | }); | |
442 | \end{verbatim} | |
443 | EOT | |
444 | ||
445 | $data = [ | |
446 | [ 'Gnat', 'per gram', '13.651' ], | |
447 | [ '', 'each', '0.012' ], | |
448 | [ 'Gnu', 'stuffed', '92.59' ], | |
449 | [ 'Emu', 'stuffed', '33.33' ], | |
450 | [ 'Armadillo', 'frozen', '8.99' ], | |
451 | ]; | |
452 | ||
453 | $table = LaTeX::Table->new( | |
454 | { caption => 'Table without header.', | |
455 | label => 'tbl:noheader', | |
456 | data => $data, | |
457 | } | |
458 | ); | |
459 | ||
460 | ||
461 | print $OUT $code . $table->generate_string(); | |
462 | ||
463 | $table->set_theme('NYC2'); | |
464 | $table->set_columns_like_header( [0] ); | |
465 | $table->set_label('table:collikeheader'); | |
466 | $table->set_caption('\texttt{columns\_like\_header}, Example 1: A transposed table.'); | |
467 | ||
468 | print $OUT $table->generate_string(); | |
469 | ||
470 | $table->set_label('table:collikeheader2'); | |
471 | $table->set_caption('\texttt{columns\_like\_header}, Example 2.'); | |
472 | $table->set_header($header); | |
473 | ||
474 | print $OUT $table->generate_string(); | |
475 | ||
476 | $table->set_theme('NYC'); | |
477 | $header | |
478 | = [ [ 'Time', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday' ] ]; | |
479 | ||
480 | $data = [ | |
481 | [ '9.00', '', '', '', '', '', ], | |
482 | [ '10.00', '', '', '', '', '', ], | |
483 | [ '11.00', '', '', '', '', '', ], | |
484 | [ '12.00', '', '', '', '', '', ], | |
485 | ]; | |
486 | ||
487 | $table = LaTeX::Table->new( | |
488 | { header => $header, | |
489 | data => $data, | |
490 | header_sideways => 1, | |
491 | left => 1, | |
492 | theme => 'NYC', | |
493 | label => 'table:headersideways', | |
494 | caption => '\texttt{header\_sideways, left}', | |
495 | } | |
496 | ); | |
497 | ||
498 | print $OUT $table->generate_string(); | |
499 | ||
500 | $table = LaTeX::Table->new( | |
501 | { header => $header, | |
502 | data => $data, | |
503 | label => 'table:headersideways2', | |
504 | caption => '\texttt{callback, right}', | |
505 | header_sideways => 0, | |
506 | right => 1, | |
507 | callback => sub { | |
508 | my ( $row, $col, $value, $is_header ) = @_; | |
509 | if ( $col != 0 && $is_header ) { | |
510 | $value = '\begin{sideways}' . $value . '\end{sideways}'; | |
511 | } | |
512 | return $value; | |
513 | }, | |
514 | theme => 'NYC', | |
515 | } | |
516 | ); | |
517 | ||
518 | print $OUT $table->generate_string(); | |
519 | ||
520 | $code = << 'EOT'; | |
521 | \subsection{CSV Files} | |
522 | For importing CSV files, we can use the CPAN module \cpanmodule{Text::CSV}: | |
523 | \begin{verbatim} | |
524 | my $csv = Text::CSV->new( | |
525 | { binary => 1, | |
526 | sep_char => q{,}, | |
527 | allow_whitespace => 1 | |
528 | } | |
529 | ); | |
530 | ||
531 | open my $IN, '<', 'imdbtop40.dat'; | |
532 | ||
533 | my $line_number = 0; | |
534 | while ( my $line = <$IN> ) { | |
535 | chomp $line; | |
536 | my $status = $csv->parse($line); | |
537 | if ( $line_number == 0 ) { | |
538 | $header = [ [ $csv->fields() ] ]; | |
539 | } | |
540 | else { | |
541 | push @{$data}, [ $csv->fields() ]; | |
542 | } | |
543 | $line_number++; | |
544 | } | |
545 | close $IN; | |
546 | ||
547 | $table = LaTeX::Table->new( | |
548 | { header => $header, | |
549 | data => $data, | |
550 | type => 'xtab', | |
551 | sideways => 1, | |
552 | tabletail => q{}, | |
553 | label => 'tbl:xtab', | |
554 | caption => '\texttt{type=xtab}', | |
555 | caption_top => 1, | |
556 | } | |
557 | ); | |
558 | \end{verbatim} | |
559 | See \tref{tbl:xtab}, which uses the \ctanpackage{xtab} package for spanning across | |
560 | multiple pages. You can also use the \ctanpackage{longtable} package here. | |
561 | This package can be used together with the \ctanpackage{ltxtable} package to | |
562 | define a table width. Here, you have to generate a \textit{file} and then load the | |
563 | file with the \texttt{LTXtable} command. See \tref{tbl:longtable}. | |
564 | \begin{verbatim} | |
565 | $table = LaTeX::Table->new( | |
566 | { header => $header, | |
567 | data => $data, | |
568 | type => 'longtable', | |
569 | tabletail => q{}, | |
570 | label => 'tbl:longtable', | |
571 | caption => '\texttt{type=longtable}', | |
572 | caption_top => 1, | |
573 | center => 0, | |
574 | # we don't define a width here! | |
575 | width_environment => 'tabularx', | |
576 | filename => 'longtable.tex' | |
577 | } | |
578 | ); | |
579 | ||
580 | %now in LaTeX: | |
581 | \begin{center} | |
582 | \LTXtable{0.8\textwidth}{longtable} | |
583 | \end{center} | |
584 | ||
585 | \end{verbatim} | |
586 | EOT | |
587 | my $line_number = 0; | |
588 | ||
589 | my $csv = Text::CSV->new( | |
590 | { binary => 1, | |
591 | sep_char => q{,}, | |
592 | allow_whitespace => 1 | |
593 | } | |
594 | ); | |
595 | ||
596 | @{$data} = (); | |
597 | ||
598 | open my $IN, '<', 'imdbtop40.dat'; | |
599 | while ( my $line = <$IN> ) { | |
600 | chomp $line; | |
601 | my $status = $csv->parse($line); | |
602 | if ( $line_number == 0 ) { | |
603 | $header = [ [ $csv->fields() ] ]; | |
604 | } | |
605 | else { | |
606 | push @{$data}, [ $csv->fields() ]; | |
607 | } | |
608 | $line_number++; | |
609 | } | |
610 | close $IN; | |
611 | ||
612 | $table = LaTeX::Table->new( | |
613 | { header => $header, | |
614 | data => $data, | |
615 | type => 'xtab', | |
616 | sideways => 1, | |
617 | tabletail => q{ }, | |
618 | label => 'tbl:xtab', | |
619 | caption => '\texttt{type=xtab}', | |
620 | caption_top => | |
621 | '\setlength{\abovecaptionskip}{0pt}\setlength{\belowcaptionskip}{10pt}\topcaption', | |
622 | } | |
623 | ); | |
624 | print $OUT $code . $table->generate_string(); | |
625 | ||
626 | $table = LaTeX::Table->new( | |
627 | { header => $header, | |
628 | data => $data, | |
629 | type => 'longtable', | |
630 | tabletail => q{}, | |
631 | label => 'tbl:longtable', | |
632 | caption => '\texttt{type=longtable}', | |
633 | caption_top => 1, | |
634 | center => 0, | |
635 | # we don't define a width here! | |
636 | width_environment => 'tabularx', | |
637 | filename => 'longtable.tex', | |
638 | }); | |
639 | ||
640 | print $table->generate(); | |
641 | ||
642 | $code = << 'EOT'; | |
643 | \begin{center} | |
644 | \LTXtable{0.8\textwidth}{longtable} | |
645 | \end{center} | |
646 | ||
647 | \subsection{Automatic column definitions} | |
648 | We can easily provide regular expressions that define the alignment of | |
649 | columns. See \tref{tbl:coldef_strategy}. | |
650 | \begin{verbatim} | |
651 | $table = LaTeX::Table->new( | |
652 | { header => [ [ 'Website', 'URL' ] ], | |
653 | data => [ | |
654 | [ 'Slashdot', 'http://www.slashdot.org' ], | |
655 | [ 'Perlmonks', 'http://www.perlmonks.org' ], | |
656 | [ 'Google', 'http://www.google.com' ], | |
657 | ], | |
658 | coldef_strategy => { | |
659 | URL => qr{ \A \s* http }xms, | |
660 | URL_COL => '>{\ttfamily}l', | |
661 | }, | |
662 | label => 'tbl:coldef_strategy', | |
663 | caption => '\texttt{coldef\_strategy}', | |
664 | } | |
665 | ); | |
666 | \end{verbatim} | |
667 | EOT | |
668 | ||
669 | $table = LaTeX::Table->new( | |
670 | { header => [ [ 'Website', 'URL' ] ], | |
671 | data => [ | |
672 | [ 'Slashdot', 'http://www.slashdot.org' ], | |
673 | [ 'Perlmonks', ' http://www.perlmonks.org' ], | |
674 | [ 'Google', 'http://www.google.com' ], | |
675 | ], | |
676 | coldef_strategy => { | |
677 | URL => qr{ \A \s* http }xms, | |
678 | URL_COL => '>{\ttfamily}l', | |
679 | }, | |
680 | label => 'tbl:coldef_strategy', | |
681 | caption => '\texttt{coldef\_strategy}', | |
682 | } | |
683 | ); | |
684 | ||
685 | print $OUT $code . $table->generate_string(); | |
686 | ||
687 | $code = << 'EOT'; | |
688 | \subsection{Continued Tables} | |
689 | As alternative to multi-page tables, we can also split tables. The | |
690 | \ltoption{continued} option then decrements the table counter and adds the | |
691 | \ltoption{continuedmsg} (default is `(continued)') to the caption. See | |
692 | \tref{tbl:coldef_strategy}. That even works with \ltoption{xtab} tables. | |
693 | \begin{verbatim} | |
694 | $table = LaTeX::Table->new( | |
695 | { header => [ [ 'Website', 'URL' ] ], | |
696 | data => [ | |
697 | [ 'CPAN', 'http://www.cpan.org' ], | |
698 | [ 'Amazon', 'http://www.amazon.com' ], | |
699 | ], | |
700 | coldef_strategy => { | |
701 | URL => qr{ \A \s* http }xms, | |
702 | URL_COL => '>{\ttfamily}l', | |
703 | }, | |
704 | continued => 1, | |
705 | label => 'tbl:continued', | |
706 | caption => '\texttt{continued}', | |
707 | } | |
708 | ); | |
709 | \end{verbatim} | |
710 | EOT | |
711 | $table = LaTeX::Table->new( | |
712 | { header => [ [ 'Website', 'URL' ] ], | |
713 | data => [ | |
714 | [ 'CPAN', 'http://www.cpan.org' ], | |
715 | [ 'Amazon', 'http://www.amazon.com' ], | |
716 | ], | |
717 | coldef_strategy => { | |
718 | URL => qr{ \A \s* http }xms, | |
719 | URL_COL => '>{\ttfamily}l', | |
720 | }, | |
721 | continued => 1, | |
722 | label => 'tbl:continued', | |
723 | caption => '\texttt{continued}', | |
724 | } | |
725 | ); | |
726 | ||
727 | print $OUT $code . $table->generate_string(); | |
728 | ||
729 | ||
730 | $code = << 'EOT'; | |
731 | \subsection{Ctable Package} | |
732 | The \ctanpackage{ctable} package makes it easy to add footnotes. See | |
733 | \tref{tbl:websitectable}. | |
734 | \begin{verbatim} | |
735 | $table->set_type('ctable'); | |
736 | $table->set_foottable('\tnote{footnotes are placed under the table}'); | |
737 | \end{verbatim} | |
738 | EOT | |
739 | ||
740 | $table->set_label('tbl:websitectable'); | |
741 | $table->set_caption('\texttt{coldef\_strategy, type=ctable, foottable, continued}.'); | |
742 | $table->set_type('ctable'); | |
743 | $table->set_foottable('\tnote{footnotes are placed under the table}'); | |
744 | $table->set_data( | |
745 | [ | |
746 | [ 'Slashdot\tmark', 'http://www.slashdot.org' ], | |
747 | [ 'Perlmonks', 'http://www.perlmonks.org' ], | |
748 | [ 'Google', 'http://www.google.com' ], | |
749 | ]); | |
750 | ||
751 | print $OUT $code . $table->generate_string(); | |
752 | ||
753 | ||
754 | $code = << 'EOT'; | |
755 | \subsection{Multicols} | |
756 | In a twocolumn or multicols document, we use this starred version for | |
757 | \tref{table:websitectablestar}: | |
758 | ||
759 | \begin{multicols}{2} | |
760 | \begin{verbatim} | |
761 | $table->set_star(1); | |
762 | \end{verbatim} | |
763 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
764 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
765 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
766 | bla bla bla bla bla bla | |
767 | ||
768 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
769 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
770 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
771 | bla bla bla bla bla bla | |
772 | ||
773 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
774 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
775 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
776 | bla bla bla bla bla bla | |
777 | EOT | |
778 | ||
779 | $table->set_star(1); | |
780 | $table->set_continued(0); | |
781 | $table->set_position('htbp'); | |
782 | $table->set_label('table:websitectablestar'); | |
783 | $table->set_caption('\texttt{coldef\_strategy, type=ctable, foottable, star}.'); | |
784 | print $OUT $code . $table->generate_string(); | |
785 | ||
786 | $code = << 'EOT'; | |
787 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
788 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
789 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
790 | bla bla bla bla bla bla | |
791 | ||
792 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
793 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
794 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
795 | bla bla bla bla bla bla | |
796 | ||
797 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
798 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
799 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
800 | bla bla bla bla bla bla | |
801 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
802 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
803 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
804 | bla bla bla bla bla bla | |
805 | ||
806 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
807 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
808 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
809 | bla bla bla bla bla bla | |
810 | ||
811 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
812 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
813 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
814 | bla bla bla bla bla bla | |
815 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
816 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
817 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
818 | bla bla bla bla bla bla | |
819 | ||
820 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
821 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
822 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
823 | bla bla bla bla bla bla | |
824 | ||
825 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
826 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
827 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
828 | bla bla bla bla bla bla | |
829 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
830 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
831 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
832 | bla bla bla bla bla bla | |
833 | ||
834 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
835 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
836 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
837 | bla bla bla bla bla bla | |
838 | ||
839 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
840 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
841 | bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla | |
842 | bla bla bla bla bla bla | |
843 | EOT | |
844 | ||
845 | print $OUT $code . "\n\\end{multicols}\n"; | |
846 | ||
847 | $code = << 'EOT'; | |
848 | \section{Customize \cpanmodule{LaTeX::Table}} | |
849 | ||
850 | This module tries hard to produce perfect results with as less provided | |
851 | options as possible. However, typesetting tables is a complex topic and | |
852 | therefore almost everything in \cpanmodule{LaTeX::Table} is configurable. | |
853 | ||
854 | \subsection{Custom Themes}\label{sec:customthemes} | |
855 | ||
856 | \tref{table:customtheme1} displays our example table with the \textit{NYC} | |
857 | theme, which is meant for presentations (with LaTeX Beamer for example). You | |
858 | can change the theme by copying it, changing it and then storing it in | |
859 | \ltoption{custom\_themes} (\tref{table:customtheme2}). You can also add the | |
860 | theme to the predfined themes by creating a themes module. See | |
861 | \cpanmodule{LaTeX::Table::Themes::ThemeI} how to do that. | |
862 | \begin{verbatim} | |
863 | my $nyc_theme = $table->get_available_themes->{'NYC'}; | |
864 | $nyc_theme->{'DEFINE_COLORS'} = | |
865 | '\definecolor{latextablegreen}{RGB}{93,127,114}'; | |
866 | $nyc_theme->{'HEADER_BG_COLOR'} = 'latextablegreen'; | |
867 | $nyc_theme->{'DATA_BG_COLOR_ODD'} = 'latextablegreen!25'; | |
868 | $nyc_theme->{'DATA_BG_COLOR_EVEN'} = 'latextablegreen!10'; | |
869 | ||
870 | $table->set_custom_themes({ CENTRALPARK => $nyc_theme }); | |
871 | $table->set_theme('CENTRALPARK'); | |
872 | \end{verbatim} | |
873 | EOT | |
874 | ||
875 | $header = [ [ 'Item:2c', '' ], [ 'Animal', 'Description', 'Price' ] ]; | |
876 | ||
877 | $data = [ | |
878 | [ 'Gnat', 'per gram', '13.651' ], | |
879 | [ '', 'each', '0.012' ], | |
880 | [ 'Gnu', 'stuffed', '92.59' ], | |
881 | [ 'Emu', 'stuffed', '33.33' ], | |
882 | [ 'Armadillo', 'frozen', '8.99' ], | |
883 | ]; | |
884 | ||
885 | $table = LaTeX::Table->new( | |
886 | { filename => 'prices.tex', | |
887 | caption => '\texttt{custom\_themes}, Example 1', | |
888 | label => 'table:customtheme1', | |
889 | header => $header, | |
890 | data => $data, | |
891 | theme => 'NYC', | |
892 | callback => sub { | |
893 | my ( $row, $col, $value, $is_header ) = @_; | |
894 | if ( $col == 2 && !$is_header ) { | |
895 | $value = format_price( $value, 2, '' ); | |
896 | } | |
897 | return $value; | |
898 | }, | |
899 | } | |
900 | ); | |
901 | ||
902 | print $OUT $code . $table->generate_string(); | |
903 | ||
904 | my $nyc_theme = $table->get_available_themes->{'NYC'}; | |
905 | $nyc_theme->{'DEFINE_COLORS'} | |
906 | = '\definecolor{latextablegreen}{RGB}{93,127,114}'; | |
907 | $nyc_theme->{'HEADER_BG_COLOR'} = 'latextablegreen'; | |
908 | $nyc_theme->{'DATA_BG_COLOR_ODD'} = 'latextablegreen!25'; | |
909 | $nyc_theme->{'DATA_BG_COLOR_EVEN'} = 'latextablegreen!10'; | |
910 | $nyc_theme->{'EXTRA_ROW_HEIGHT'} = '1pt'; | |
911 | ||
912 | $table->set_custom_themes( { CENTRALPARK => $nyc_theme } ); | |
913 | $table->set_theme('CENTRALPARK'); | |
914 | $table->set_label('table:customtheme2'); | |
915 | $table->set_caption('\texttt{custom\_themes}, Example 2'); | |
916 | ||
917 | print $OUT $table->generate_string(); | |
918 | ||
919 | $code = << 'EOT'; | |
920 | \subsection{Custom Templates}\label{sec:customtemplates} | |
921 | ||
922 | \cpanmodule{LaTeX::Table} ships with some very flexible and powerful | |
923 | templates. Templates are a convenient way of generating the LaTeX code out of | |
924 | the user options and data. Internally, the \cpanmodule{Template} Toolkit | |
925 | available from CPAN is used. It is possible to change the standard templates | |
926 | (each table \ltoption{type} has its own template) with the | |
927 | \ltoption{custom\_template} option. For example, the \LaTeX~styles of some | |
928 | scientific journals provide their own table commands, here the one from the | |
929 | Bioinformatics journal: | |
930 | ||
931 | \begin{verbatim} | |
932 | \begin{table}[!t] | |
933 | \processtable{This is table caption\label{Tab:01}} | |
934 | {\begin{tabular}{llll} | |
935 | \toprule | |
936 | head1 & head2 & head3 & head4 \\ | |
937 | \midrule | |
938 | row1 & row1 & row1 & row1 \\ | |
939 | row2 & row2 & row2 & row2 \\ | |
940 | row3 & row3 & row3 & row3 \\ | |
941 | row4 & row4 & row4 & row4 \\ | |
942 | \botrule | |
943 | \end{tabular}}{This is a footnote} | |
944 | \end{table} | |
945 | \end{verbatim} | |
946 | A very basic template for this would be: | |
947 | {\footnotesize | |
948 | \begin{verbatim} | |
949 | [% IF ENVIRONMENT %] | |
950 | \begin{[% ENVIRONMENT %][% IF STAR %]*[% END %]}[% IF POSITION %][[% POSITION %]] | |
951 | [% END %][% END %] | |
952 | \processtable{[% IF CAPTION %][% CAPTION %][% END %][% IF LABEL %]\label{[% LABEL %]}[% END %]} | |
953 | {\begin{[% TABULAR_ENVIRONMENT %]}{[% COLDEF %]} | |
954 | [% HEADER_CODE %][% DATA_CODE %]\end{[% TABULAR_ENVIRONMENT %]}}{[% FOOTTABLE %]} | |
955 | [% IF ENVIRONMENT %]\end{table}[% END %] | |
956 | \end{verbatim}} | |
957 | \noindent Now we have to define a the theme that is responsible for the rules (see | |
958 | \ref{sec:customthemes}): | |
959 | \begin{verbatim} | |
960 | 'Oxford' => { | |
961 | 'STUB_ALIGN' => q{l}, | |
962 | 'VERTICAL_RULES' => [ 0, 0, 0 ], | |
963 | 'HORIZONTAL_RULES' => [ 1, 1, 0 ], | |
964 | 'RULES_CMD' => [ '\toprule', '\midrule', '\midrule', '\botrule' ], | |
965 | } | |
966 | \end{verbatim} | |
967 | Finally we can typeset tables for the Bioinformatics journal: | |
968 | \begin{verbatim} | |
969 | $table = LaTeX::Table->new( | |
970 | { | |
971 | caption => 'This is table caption', | |
972 | label => 'Tab:01', | |
973 | foottable => 'This is a footnote', | |
974 | position => '!t', | |
975 | header => $test_header, | |
976 | data => $test_data, | |
977 | theme => 'Oxford', | |
978 | custom_template => $custom_template, | |
979 | } | |
980 | ); | |
981 | \end{verbatim} | |
982 | If you think your custom template might be useful for others, please | |
983 | contribute it! | |
984 | EOT | |
985 | ; | |
986 | ||
987 | print ${OUT} | |
988 | "$code\\section{Version}\\small{Generated with LaTeX::Table Version $LaTeX::Table::VERSION}\n"; | |
989 | ||
990 | $code = << 'EOT'; | |
991 | \clearpage\begin{appendix} | |
992 | \section{Header/Data} | |
993 | \subsection{Simpsons Table} | |
994 | \begin{verbatim} | |
995 | my $header = [ [ 'Character', 'Fullname', 'Voice' ], ]; | |
996 | my $data = [ | |
997 | [ 'Homer', 'Homer Jay Simpson', 'Dan Castellaneta' ], | |
998 | [ 'Marge', 'Marjorie Simpson', 'Julie Kavner' ], | |
999 | [ 'Bart', 'Bartholomew Jojo Simpson', 'Nancy Cartwright' ], | |
1000 | [ 'Lisa', 'Elizabeth Marie Simpson', 'Yeardley Smith' ], | |
1001 | [ 'Maggie', 'Margaret Simpson', | |
1002 | 'Elizabeth Taylor, Nancy Cartwright, James Earl Jones,' | |
1003 | . 'Yeardley Smith, Harry Shearer' ], | |
1004 | ]; | |
1005 | \end{verbatim} | |
1006 | ||
1007 | \subsection{Animal Table} | |
1008 | ||
1009 | \begin{verbatim} | |
1010 | my $header = [ | |
1011 | [ 'Item:2c', '' ], | |
1012 | [ '\cmidrule(r){1-2}'], | |
1013 | [ 'Animal', 'Description', 'Price' ] | |
1014 | ]; | |
1015 | ||
1016 | my $data = [ | |
1017 | [ 'Gnat', 'per gram', '13.651' ], | |
1018 | [ '', 'each', '0.012' ], | |
1019 | [ 'Gnu', 'stuffed', '92.59' ], | |
1020 | [ 'Emu', 'stuffed', '33.33' ], | |
1021 | [ 'Armadillo', 'frozen', '8.99' ], | |
1022 | ]; | |
1023 | \end{verbatim} | |
1024 | ||
1025 | \section{Themes} | |
1026 | EOT | |
1027 | ; | |
1028 | print $OUT $code; | |
1029 | ||
1030 | $table = LaTeX::Table->new(); | |
1031 | ||
1032 | my %section = ( std => '', | |
1033 | ctable => 'ctable', | |
1034 | longtable => 'multipage2', | |
1035 | xtab => 'multipage',); | |
1036 | ||
1037 | for my $sect (qw(std ctable xtab longtable)) { | |
1038 | ||
1039 | print $OUT "\\subsection{Type $sect}\n"; | |
1040 | for my $theme ( sort keys %{ $table->get_available_themes } ) { | |
1041 | print $OUT "\\input{$theme$section{$sect}.tex}\n"; | |
1042 | if ($sect eq "xtab") { | |
1043 | print $OUT "\\clearpage \n"; | |
1044 | } | |
1045 | } | |
1046 | print $OUT "\\clearpage \n"; | |
1047 | } | |
1048 | print $OUT '\end{appendix}\end{document}' . "\n"; | |
1049 | close $OUT; | |
1050 | ||
1051 | __DATA__ | |
1052 | \documentclass[11pt]{article} | |
1053 | \usepackage{layouts} | |
1054 | ||
1055 | \setlength{\textheight}{8.0in} | |
1056 | \setlength{\textwidth}{6.0in} | |
1057 | \setlength{\oddsidemargin}{0.25in} | |
1058 | \setlength{\evensidemargin}{0.25in} | |
1059 | \setlength{\marginparwidth}{0.6in} | |
1060 | \setlength{\parskip}{5pt} | |
1061 | \setcounter{secnumdepth}{4} | |
1062 | \setcounter{tocdepth}{4} | |
1063 | ||
1064 | \setlength{\columnsep}{30pt} | |
1065 | ||
1066 | \setcounter{topnumber}{2} | |
1067 | \setcounter{bottomnumber}{2} | |
1068 | \setcounter{totalnumber}{4} | |
1069 | \renewcommand{\topfraction}{0.9} | |
1070 | \renewcommand{\bottomfraction}{0.6} | |
1071 | \renewcommand{\textfraction}{0.1} | |
1072 | ||
1073 | ||
1074 | %\newlength{\figrulesep} | |
1075 | %\setlength{\figrulesep}{0.5\textfloatsep} | |
1076 | % | |
1077 | %\newcommand{\topfigrule}{\vspace*{-1pt}% | |
1078 | % \noindent\rule[-\figrulesep]{\columnwidth}{1pt}} | |
1079 | % | |
1080 | %\newcommand{\botfigrule}{\vspace*{-2pt}% | |
1081 | % \noindent\rule[\figrulesep]{\columnwidth}{2pt}} | |
1082 | ||
1083 | \makeatletter | |
1084 | ||
1085 | \renewcommand{\subsubsection}{\@startsection% | |
1086 | {subsubsection}% | |
1087 | {3}% | |
1088 | {0mm}% | |
1089 | {-\baselineskip}% | |
1090 | {0.5\baselineskip}% | |
1091 | {\large\itshape}} | |
1092 | ||
1093 | ||
1094 | \newcommand{\fref}[1]{Figure~\ref{#1}} | |
1095 | \newcommand{\tref}[1]{Table~\ref{#1}} | |
1096 | \newcommand{\T}{\texttt{true}} | |
1097 | \newcommand{\F}{\texttt{false}} | |
1098 | \newcommand{\TF}{\textit{true/false}} | |
1099 | ||
1100 | ||
1101 | %%%% the \meta command | |
1102 | \begingroup | |
1103 | \obeyspaces% | |
1104 | \catcode`\^^M\active% | |
1105 | \gdef\meta{\begingroup\obeyspaces\catcode`\^^M\active% | |
1106 | \let^^M\do@space\let \do@space% | |
1107 | \def\-{\egroup\discretionary{-}{}{}\hbox\bgroup\it}% | |
1108 | \m@ta}% | |
1109 | \endgroup | |
1110 | \def\m@ta#1{\leavevmode\hbox\bgroup$\langle$\it#1\/$\rangle$\egroup | |
1111 | \endgroup} | |
1112 | \def\do@space{\egroup\space | |
1113 | \hbox\bgroup\it\futurelet\next\sp@ce} | |
1114 | \def\sp@ce{\ifx\next\do@space\expandafter\sp@@ce\fi} | |
1115 | \def\sp@@ce#1{\futurelet\next\sp@ce} | |
1116 | ||
1117 | \newcommand{\marg}[1]{\texttt{\{}\meta{#1}\texttt{\}}} | |
1118 | ||
1119 | \newcommand{\file}[1]{\textsf{#1}} | |
1120 | \newcommand{\ltoption}[1]{\texttt{#1}} | |
1121 | \newcommand{\ctanpackage}[1]{\file{#1}} | |
1122 | \newcommand{\cpanmodule}[1]{\file{#1}} | |
1123 | ||
1124 | \providecommand{\indexfill}{} | |
1125 | \providecommand{\sindexfill}{} | |
1126 | \providecommand{\ssindexfill}{} | |
1127 | \providecommand{\otherindexspace}[1]{} | |
1128 | \providecommand{\alphaindexspace}[1]{\indexspace{\bfseries #1}} | |
1129 | ||
1130 | %%% \setlength{\parindent}{-4em} | |
1131 | \makeatother | |
1132 | \usepackage{url} | |
1133 | \usepackage{ctable} | |
1134 | \usepackage{graphics, graphicx} | |
1135 | \usepackage{xtab} | |
1136 | \usepackage{lscape} | |
1137 | \usepackage{booktabs} | |
1138 | \usepackage{rotating} | |
1139 | \usepackage{tabularx} | |
1140 | \usepackage{tabulary} | |
1141 | \usepackage{listings} | |
1142 | \usepackage{longtable} | |
1143 | %\usepackage{color} | |
1144 | \usepackage{colortbl} | |
1145 | \usepackage{xcolor} | |
1146 | \usepackage{graphicx} | |
1147 | \usepackage{ltxtable} | |
1148 | \usepackage{multicol} | |
1149 | \usepackage{array}% in the preamble | |
1150 | %\usepackage[tableposition=top]{caption} | |
1151 | \title{LaTeX::Table} | |
1152 | \date{\today} | |
1153 | \author{Markus Riester} | |
1154 | \makeindex | |
1155 | \begin{document} | |
1156 | \bibliographystyle{alpha} | |
1157 | \pagenumbering{roman} | |
1158 | \maketitle | |
1159 | \begin{abstract} | |
1160 | ||
1161 | \file{LaTeX::Table} is a Perl module that provides functionality for an | |
1162 | intuitive and easy generation of LaTeX tables. It ships with some predefined | |
1163 | good looking table styles. This module supports multipage tables via the | |
1164 | \texttt{xtab} and the \texttt{longtable} package and publication quality | |
1165 | tables with the \texttt{booktabs} package. It also supports the | |
1166 | \texttt{tabularx} and \texttt{tabulary} packages for nicer fixed-width tables. | |
1167 | Furthermore, it supports the \texttt{colortbl} package for colored tables | |
1168 | optimized for presentations. | |
1169 | ||
1170 | \end{abstract} | |
1171 | \tableofcontents | |
1172 | \listoftables | |
1173 | \clearpage | |
1174 | \pagenumbering{arabic} | |
1175 | ||
1176 | \section{Installation} | |
1177 | You can install this software with the \texttt{cpan} command. | |
1178 | ||
1179 | \begin{verbatim} | |
1180 | $ cpan LaTeX::Table | |
1181 | \end{verbatim} | |
1182 | Alternatively, download \cpanmodule{LaTeX::Table} directly from | |
1183 | \url{http://search.cpan.org/dist/LaTeX-Table/} and install in manually: | |
1184 | \begin{verbatim} | |
1185 | $ tar xvfz LaTeX-Table-VERSION.tar.gz | |
1186 | $ perl Build.PL | |
1187 | $ ./Build test | |
1188 | $ ./Build install | |
1189 | \end{verbatim} | |
1190 | ||
1191 | \section{Examples} | |
1192 |
0 | Rank,Rating,Title,Year,Votes | |
1 | 1. ,9.1,"The Shawshank Redemption",1994,403610 | |
2 | 2. ,9.1,"The Godfather",1972,338496 | |
3 | 3. ,9.0,"The Godfather: Part II",1974,195253 | |
4 | 4. ,8.9,"Buono, il brutto, il cattivo., Il",1966,117494 | |
5 | 5. ,8.9,"The Dark Knight",2008,340243 | |
6 | 6. ,8.9,"Pulp Fiction",1994,333085 | |
7 | 7. ,8.8,"Schindler's List",1993,220503 | |
8 | 8. ,8.8,"One Flew Over the Cuckoo's Nest",1975,168842 | |
9 | 9. ,8.8,"12 Angry Men",1957,84726 | |
10 | 10.,8.8,"Star Wars: Episode V - The Empire Strikes Back",1980,229894 | |
11 | 11.,8.8,"Casablanca",1942,139763 | |
12 | 12.,8.8,"Star Wars",1977,271586 | |
13 | 13.,8.8,"Shichinin no samurai",1954,79374 | |
14 | 14.,8.8,"The Lord of the Rings: The Return of the King",2003,294259 | |
15 | 15.,8.7,"Goodfellas",1990,182825 | |
16 | 16.,8.7,"Rear Window",1954,95538 | |
17 | 17.,8.7,"Cidade de Deus",2002,124546 | |
18 | 18.,8.7,"Raiders of the Lost Ark",1981,205298 | |
19 | 19.,8.7,"C'era una volta il West",1968,56185 | |
20 | 20.,8.7,"The Lord of the Rings: The Fellowship of the Ring",2001,322699 | |
21 | 21.,8.7,"The Usual Suspects",1994,221641 | |
22 | 22.,8.7,"Fight Club",1999,301078 | |
23 | 23.,8.7,"Psycho",1960,115936 | |
24 | 24.,8.6,"The Silence of the Lambs",1991,198677 | |
25 | 25.,8.6,"Sunset Blvd.",1950,42280 | |
26 | 26.,8.6,"Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb",1964,131289 | |
27 | 27.,8.6,"Memento",2000,217339 | |
28 | 28.,8.6,"North by Northwest",1959,76221 | |
29 | 29.,8.6,"Citizen Kane",1941,117600 | |
30 | 30.,8.6,"The Matrix",1999,310491 | |
31 | 31.,8.6,"It's a Wonderful Life",1946,84643 | |
32 | 32.,8.6,"The Lord of the Rings: The Two Towers",2002, 269196 | |
33 | 33.,8.6,"Se7en",1995,220400 | |
34 | 34.,8.6,"Slumdog Millionaire",2008, 50475 | |
35 | 35.,8.5,"Leon",1994,154149 | |
36 | 36.,8.5,"Apocalypse Now",1979,142659 | |
37 | 37.,8.5,"American Beauty",1999,241532 | |
38 | 38.,8.5,"Taxi Driver",1976,122785 | |
39 | 39.,8.5,"WALL-E",2008,114271 | |
40 | 40.,8.5,"Lawrence of Arabia",1962,66188 |
0 | ############################################################################# | |
1 | # $Author: markus $ | |
2 | # $Date: 2009-02-03 17:09:45 +0100 (Tue, 03 Feb 2009) $ | |
3 | # $Revision: 1298 $ | |
4 | ############################################################################# | |
5 | ||
6 | package LaTeX::Table::Themes::Beamer; | |
7 | use Moose; | |
8 | ||
9 | with 'LaTeX::Table::Themes::ThemeI'; | |
10 | ||
11 | use version; | |
12 | our ($VERSION) = '$Revision: 1298 $' =~ m{ \$Revision: \s+ (\S+) }xms; | |
13 | ||
14 | sub _definition { | |
15 | my $themes = { | |
16 | NYC => { | |
17 | 'HEADER_FONT_STYLE' => 'bf', | |
18 | 'HEADER_FONT_COLOR' => 'white', | |
19 | 'HEADER_BG_COLOR' => 'latextbl', | |
20 | 'DATA_BG_COLOR_ODD' => 'latextbl!25', | |
21 | 'DATA_BG_COLOR_EVEN' => 'latextbl!10', | |
22 | 'DEFINE_COLORS' => '\definecolor{latextbl}{RGB}{78,130,190}', | |
23 | 'HEADER_CENTERED' => 1, | |
24 | 'VERTICAL_RULES' => [ 1, 0, 0 ], | |
25 | 'HORIZONTAL_RULES' => [ 1, 1, 0 ], | |
26 | 'BOOKTABS' => 0, | |
27 | 'EXTRA_ROW_HEIGHT' => '1pt', | |
28 | }, | |
29 | NYC2 => { | |
30 | 'HEADER_FONT_STYLE' => 'bf', | |
31 | 'HEADER_FONT_COLOR' => 'white', | |
32 | 'HEADER_BG_COLOR' => 'latextbl', | |
33 | 'DATA_BG_COLOR_ODD' => 'latextbl!25', | |
34 | 'DATA_BG_COLOR_EVEN' => 'latextbl!10', | |
35 | 'DEFINE_COLORS' => '\definecolor{latextbl}{RGB}{78,130,190}', | |
36 | 'HEADER_CENTERED' => 1, | |
37 | 'VERTICAL_RULES' => [ 1, 0, 0 ], | |
38 | 'HORIZONTAL_RULES' => [ 1, 0, 0 ], | |
39 | 'BOOKTABS' => 0, | |
40 | 'EXTRA_ROW_HEIGHT' => '1pt', | |
41 | }, | |
42 | NYC3 => { | |
43 | 'HEADER_FONT_STYLE' => 'bf', | |
44 | 'HEADER_FONT_COLOR' => 'white', | |
45 | 'HEADER_BG_COLOR' => 'latextbl', | |
46 | 'DATA_BG_COLOR_ODD' => 'latextbl!25', | |
47 | 'DATA_BG_COLOR_EVEN' => 'latextbl!10', | |
48 | 'DEFINE_COLORS' => '\definecolor{latextbl}{RGB}{78,130,190}', | |
49 | 'HEADER_CENTERED' => 1, | |
50 | 'VERTICAL_RULES' => [ 1, 1, 1 ], | |
51 | 'HORIZONTAL_RULES' => [ 1, 2, 1 ], | |
52 | 'BOOKTABS' => 0, | |
53 | 'EXTRA_ROW_HEIGHT' => '1pt', | |
54 | 'RULES_COLOR_GLOBAL' => | |
55 | '\arrayrulecolor{white}\doublerulesepcolor{black}', | |
56 | 'RULES_WIDTH_GLOBAL' => | |
57 | '\setlength\arrayrulewidth{1pt}\setlength\doublerulesep{0pt}', | |
58 | }, | |
59 | NYC4 => { | |
60 | 'HEADER_FONT_STYLE' => 'bf', | |
61 | 'HEADER_FONT_COLOR' => 'white', | |
62 | 'HEADER_BG_COLOR' => 'latextbl', | |
63 | 'DATA_BG_COLOR_ODD' => 'latextbl!25', | |
64 | 'DATA_BG_COLOR_EVEN' => 'latextbl!10', | |
65 | 'DEFINE_COLORS' => '\definecolor{latextbl}{RGB}{78,130,190}', | |
66 | 'HEADER_CENTERED' => 1, | |
67 | 'VERTICAL_RULES' => [ 0, 0, 0 ], | |
68 | 'HORIZONTAL_RULES' => [ 1, 1, 0 ], | |
69 | 'BOOKTABS' => 0, | |
70 | 'EXTRA_ROW_HEIGHT' => '1pt', | |
71 | 'RULES_COLOR_GLOBAL' => | |
72 | '\arrayrulecolor{black}\doublerulesepcolor{black}', | |
73 | 'RULES_WIDTH_GLOBAL' => | |
74 | '\setlength\arrayrulewidth{1pt}\setlength\doublerulesep{0pt}', | |
75 | }, | |
76 | Redmond => { | |
77 | 'HEADER_FONT_STYLE' => 'bf', | |
78 | 'HEADER_FONT_COLOR' => 'white', | |
79 | 'HEADER_BG_COLOR' => 'black', | |
80 | 'DATA_BG_COLOR_ODD' => 'latextbl!25', | |
81 | 'DATA_BG_COLOR_EVEN' => 'latextbl!10', | |
82 | 'DEFINE_COLORS' => '\definecolor{latextbl}{RGB}{78,130,190}', | |
83 | 'STUB_ALIGN' => 'l', | |
84 | 'VERTICAL_RULES' => [ 0, 0, 0 ], | |
85 | 'HORIZONTAL_RULES' => [ 0, 2, 1 ], | |
86 | 'BOOKTABS' => 0, | |
87 | 'RULES_COLOR_GLOBAL' => | |
88 | '\arrayrulecolor{white}\doublerulesepcolor{black}', | |
89 | 'RULES_WIDTH_GLOBAL' => | |
90 | '\setlength\arrayrulewidth{1pt}\setlength\doublerulesep{0pt}', | |
91 | 'EXTRA_ROW_HEIGHT' => '1pt', | |
92 | }, | |
93 | Redmond2 => { | |
94 | 'HEADER_FONT_STYLE' => 'bf', | |
95 | 'HEADER_FONT_COLOR' => 'white', | |
96 | 'HEADER_BG_COLOR' => 'black', | |
97 | 'DATA_BG_COLOR_ODD' => 'latextbl!25', | |
98 | 'DATA_BG_COLOR_EVEN' => 'latextbl!10', | |
99 | 'DEFINE_COLORS' => '\definecolor{latextbl}{RGB}{78,130,190}', | |
100 | 'STUB_ALIGN' => 'l', | |
101 | 'VERTICAL_RULES' => [ 0, 0, 0 ], | |
102 | 'HORIZONTAL_RULES' => [ 0, 2, 0 ], | |
103 | 'BOOKTABS' => 0, | |
104 | 'RULES_COLOR_GLOBAL' => | |
105 | '\arrayrulecolor{white}\doublerulesepcolor{black}', | |
106 | 'RULES_WIDTH_GLOBAL' => | |
107 | '\setlength\arrayrulewidth{1pt}\setlength\doublerulesep{0pt}', | |
108 | 'EXTRA_ROW_HEIGHT' => '1pt', | |
109 | }, | |
110 | }; | |
111 | return $themes; | |
112 | } | |
113 | ||
114 | 1; | |
115 | __END__ | |
116 | ||
117 | =head1 NAME | |
118 | ||
119 | LaTeX::Table::Themes::Beamer - Colorful LaTeX table themes optimized for presentations. | |
120 | ||
121 | =head1 PROVIDES | |
122 | ||
123 | This module provides following themes: | |
124 | ||
125 | NYC | |
126 | NYC2 # same, but without midline after header | |
127 | NYC3 # with a white grid | |
128 | NYC3 # with black horizontal lines | |
129 | Redmond | |
130 | Redmond2 # same, but without horizontal lines | |
131 | ||
132 | =head1 REQUIRES | |
133 | ||
134 | The themes defined in this module require following LaTeX packages: | |
135 | ||
136 | \usepackage{array} | |
137 | \usepackage{colortbl} | |
138 | \usepackage{xcolor} | |
139 | ||
140 | =head1 SEE ALSO | |
141 | ||
142 | L<LaTeX::Table>, L<LaTeX::Table::Themes::ThemeI> | |
143 | ||
144 | =head1 AUTHOR | |
145 | ||
146 | Markus Riester C<< <mriester@gmx.de> >> | |
147 | ||
148 | =head1 LICENSE AND COPYRIGHT | |
149 | ||
150 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
151 | ||
152 | This module is free software; you can redistribute it and/or | |
153 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
154 | ||
155 | =cut | |
156 | ||
157 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | ############################################################################# | |
1 | # $Author: markus $ | |
2 | # $Date: 2009-02-24 10:30:34 +0100 (Tue, 24 Feb 2009) $ | |
3 | # $Revision: 1326 $ | |
4 | ############################################################################# | |
5 | ||
6 | package LaTeX::Table::Themes::Booktabs; | |
7 | use Moose; | |
8 | ||
9 | with 'LaTeX::Table::Themes::ThemeI'; | |
10 | ||
11 | use version; | |
12 | our ($VERSION) = '$Revision: 1326 $' =~ m{ \$Revision: \s+ (\S+) }xms; | |
13 | ||
14 | sub _definition { | |
15 | my $themes = { | |
16 | 'Zurich' => { | |
17 | 'HEADER_FONT_STYLE' => 'bf', | |
18 | 'HEADER_CENTERED' => 1, | |
19 | 'STUB_ALIGN' => 'l', | |
20 | 'VERTICAL_RULES' => [ 0, 0, 0 ], | |
21 | 'HORIZONTAL_RULES' => [ 1, 1, 0 ], | |
22 | 'BOOKTABS' => 1, | |
23 | }, | |
24 | 'Meyrin' => { | |
25 | 'STUB_ALIGN' => 'l', | |
26 | 'VERTICAL_RULES' => [ 0, 0, 0 ], | |
27 | 'HORIZONTAL_RULES' => [ 1, 1, 0 ], | |
28 | 'BOOKTABS' => 1, | |
29 | }, | |
30 | }; | |
31 | return $themes; | |
32 | } | |
33 | ||
34 | 1; | |
35 | __END__ | |
36 | ||
37 | =head1 NAME | |
38 | ||
39 | LaTeX::Table::Themes::Booktabs - Publication quality LaTeX table themes. | |
40 | ||
41 | =head1 PROVIDES | |
42 | ||
43 | This module provides following themes: | |
44 | ||
45 | Meyrin # as described in the booktabs documentation | |
46 | Zurich # header centered and in bold font | |
47 | ||
48 | =head1 REQUIRES | |
49 | ||
50 | The themes defined in this module require following LaTeX packages: | |
51 | ||
52 | \usepackage{booktabs} | |
53 | ||
54 | =head1 SEE ALSO | |
55 | ||
56 | L<LaTeX::Table>, L<LaTeX::Table::Themes::ThemeI> | |
57 | ||
58 | =head1 AUTHOR | |
59 | ||
60 | Markus Riester C<< <mriester@gmx.de> >> | |
61 | ||
62 | =head1 LICENSE AND COPYRIGHT | |
63 | ||
64 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
65 | ||
66 | This module is free software; you can redistribute it and/or | |
67 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
68 | ||
69 | =cut | |
70 | ||
71 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | ############################################################################# | |
1 | # $Author: markus $ | |
2 | # $Date: 2008-11-04 22:44:22 +0100 (Tue, 04 Nov 2008) $ | |
3 | # $Revision: 1151 $ | |
4 | ############################################################################# | |
5 | ||
6 | package LaTeX::Table::Themes::Classic; | |
7 | use Moose; | |
8 | ||
9 | with 'LaTeX::Table::Themes::ThemeI'; | |
10 | ||
11 | use version; | |
12 | our ($VERSION) = '$Revision: 1151 $' =~ m{ \$Revision: \s+ (\S+) }xms; | |
13 | ||
14 | sub _definition { | |
15 | my $themes = { | |
16 | 'Dresden' => { | |
17 | 'HEADER_FONT_STYLE' => 'bf', | |
18 | 'HEADER_CENTERED' => 1, | |
19 | 'CAPTION_FONT_STYLE' => 'bf', | |
20 | 'VERTICAL_RULES' => [ 1, 2, 1 ], | |
21 | 'HORIZONTAL_RULES' => [ 1, 2, 0 ], | |
22 | 'BOOKTABS' => 0, | |
23 | }, | |
24 | 'Houston' => { | |
25 | 'HEADER_FONT_STYLE' => 'bf', | |
26 | 'HEADER_CENTERED' => 1, | |
27 | 'CAPTION_FONT_STYLE' => 'bf', | |
28 | 'VERTICAL_RULES' => [ 1, 2, 1 ], | |
29 | 'HORIZONTAL_RULES' => [ 1, 2, 1 ], | |
30 | 'EXTRA_ROW_HEIGHT' => '1pt', | |
31 | 'BOOKTABS' => 0, | |
32 | }, | |
33 | 'Berlin' => { | |
34 | 'HEADER_FONT_STYLE' => 'bf', | |
35 | 'HEADER_CENTERED' => 1, | |
36 | 'CAPTION_FONT_STYLE' => 'bf', | |
37 | 'VERTICAL_RULES' => [ 1, 1, 1 ], | |
38 | 'HORIZONTAL_RULES' => [ 1, 2, 0 ], | |
39 | 'BOOKTABS' => 0, | |
40 | }, | |
41 | 'Miami' => { | |
42 | 'HEADER_FONT_STYLE' => 'bf', | |
43 | 'HEADER_CENTERED' => 1, | |
44 | 'CAPTION_FONT_STYLE' => 'bf', | |
45 | 'STUB_ALIGN' => 'l', | |
46 | 'VERTICAL_RULES' => [ 0, 0, 0 ], | |
47 | 'HORIZONTAL_RULES' => [ 0, 1, 0 ], | |
48 | 'BOOKTABS' => 0, | |
49 | }, | |
50 | 'plain' => { | |
51 | 'STUB_ALIGN' => 'l', | |
52 | 'VERTICAL_RULES' => [ 0, 0, 0 ], | |
53 | 'HORIZONTAL_RULES' => [ 0, 0, 0 ], | |
54 | 'BOOKTABS' => 0, | |
55 | }, | |
56 | }; | |
57 | return $themes; | |
58 | } | |
59 | ||
60 | 1; | |
61 | __END__ | |
62 | ||
63 | =head1 NAME | |
64 | ||
65 | LaTeX::Table::Themes::Classic - Classic LaTeX table themes. | |
66 | ||
67 | =head1 PROVIDES | |
68 | ||
69 | This module provides following themes: | |
70 | ||
71 | Berlin | |
72 | Dresden | |
73 | Houston | |
74 | Miami | |
75 | plain | |
76 | ||
77 | =head1 REQUIRES | |
78 | ||
79 | The themes defined in this module require no additional LaTeX packages. | |
80 | ||
81 | =head1 SEE ALSO | |
82 | ||
83 | L<LaTeX::Table>, L<LaTeX::Table::Themes::ThemeI> | |
84 | ||
85 | =head1 AUTHOR | |
86 | ||
87 | Markus Riester C<< <mriester@gmx.de> >> | |
88 | ||
89 | =head1 LICENSE AND COPYRIGHT | |
90 | ||
91 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
92 | ||
93 | This module is free software; you can redistribute it and/or | |
94 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
95 | ||
96 | =cut | |
97 | ||
98 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | ############################################################################# | |
1 | # $Author: markus $ | |
2 | # $Date: 2009-02-03 17:09:45 +0100 (Tue, 03 Feb 2009) $ | |
3 | # $Revision: 1298 $ | |
4 | ############################################################################# | |
5 | ||
6 | package LaTeX::Table::Themes::Modern; | |
7 | use Moose; | |
8 | ||
9 | with 'LaTeX::Table::Themes::ThemeI'; | |
10 | ||
11 | use version; | |
12 | our ($VERSION) = '$Revision: 1298 $' =~ m{ \$Revision: \s+ (\S+) }xms; | |
13 | ||
14 | sub _definition { | |
15 | my $themes = { | |
16 | 'Paris' => { | |
17 | 'HEADER_FONT_STYLE' => 'bf', | |
18 | 'HEADER_CENTERED' => 1, | |
19 | 'HEADER_BG_COLOR' => 'latextblgray', | |
20 | 'DEFINE_COLORS' => | |
21 | '\definecolor{latextblgray}{gray}{0.7}', | |
22 | 'CAPTION_FONT_STYLE' => 'bf', | |
23 | 'VERTICAL_RULES' => [ 1, 1, 1 ], | |
24 | 'HORIZONTAL_RULES' => [ 1, 1, 0 ], | |
25 | 'BOOKTABS' => 0, | |
26 | }, | |
27 | 'Muenchen' => { | |
28 | 'HEADER_FONT_STYLE' => 'bf', | |
29 | 'STUB_ALIGN' => 'l', | |
30 | 'DEFINE_COLORS' => | |
31 | '\definecolor{latexttbl}{RGB}{78,130,190}', | |
32 | 'CAPTION_FONT_STYLE' => 'bf', | |
33 | 'DATA_BG_COLOR_EVEN' => 'latextbl!20', | |
34 | 'VERTICAL_RULES' => [ 0, 0, 0 ], | |
35 | 'HORIZONTAL_RULES' => [ 0, 0, 0 ], | |
36 | 'BOOKTABS' => 1, | |
37 | 'EXTRA_ROW_HEIGHT' => '1pt', | |
38 | }, | |
39 | }; | |
40 | return $themes; | |
41 | } | |
42 | ||
43 | 1; | |
44 | __END__ | |
45 | ||
46 | =head1 NAME | |
47 | ||
48 | LaTeX::Table::Themes::Modern - Modern LaTeX table themes. | |
49 | ||
50 | =head1 PROVIDES | |
51 | ||
52 | This module provides following themes: | |
53 | ||
54 | Paris | |
55 | Muenchen | |
56 | ||
57 | =head1 REQUIRES | |
58 | ||
59 | The themes defined in this module requires following LaTeX packages: | |
60 | ||
61 | \usepackage{xcolor} | |
62 | ||
63 | =head1 NOTES | |
64 | ||
65 | You probably want to use a Sans-serif font: | |
66 | ||
67 | $tbl->set_fontfamily('sf'); | |
68 | ||
69 | =head1 SEE ALSO | |
70 | ||
71 | L<LaTeX::Table>, L<LaTeX::Table::Themes::ThemeI> | |
72 | ||
73 | =head1 AUTHOR | |
74 | ||
75 | Markus Riester C<< <mriester@gmx.de> >> | |
76 | ||
77 | =head1 LICENSE AND COPYRIGHT | |
78 | ||
79 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
80 | ||
81 | This module is free software; you can redistribute it and/or | |
82 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
83 | ||
84 | =cut | |
85 | ||
86 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | ############################################################################# | |
1 | # $Author: markus $ | |
2 | # $Date: 2009-02-04 16:33:40 +0100 (Wed, 04 Feb 2009) $ | |
3 | # $Revision: 1312 $ | |
4 | ############################################################################# | |
5 | ||
6 | package LaTeX::Table::Themes::ThemeI; | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Moose::Role; | |
12 | ||
13 | use version; | |
14 | our ($VERSION) = '$Revision: 1312 $' =~ m{ \$Revision: \s+ (\S+) }xms; | |
15 | ||
16 | requires '_definition'; | |
17 | ||
18 | around '_definition' => sub { | |
19 | my $orig = shift; | |
20 | my $self = shift; | |
21 | my $ret = $orig->($self, @_); | |
22 | for my $theme (keys %{$ret}) { | |
23 | if (defined $ret->{$theme}->{BOOKTABS} && $ret->{$theme}->{BOOKTABS}) { | |
24 | $ret->{$theme}->{RULES_CMD} = | |
25 | [ '\toprule', '\midrule', '\midrule', '\bottomrule' ]; | |
26 | } | |
27 | } | |
28 | return $ret; | |
29 | }; | |
30 | ||
31 | 1; | |
32 | ||
33 | __END__ | |
34 | ||
35 | =head1 NAME | |
36 | ||
37 | LaTeX::Table::Themes::ThemeI - Interface for LaTeX table themes. | |
38 | ||
39 | =head1 SYNOPSIS | |
40 | ||
41 | package MyThemes::Custom; | |
42 | use Moose; | |
43 | ||
44 | with 'LaTeX::Table::Themes::ThemeI'; | |
45 | ||
46 | sub _definition { | |
47 | return { CENTRALPARK => | |
48 | { | |
49 | 'HEADER_FONT_STYLE' => 'bf', | |
50 | 'HEADER_FONT_COLOR' => 'white', | |
51 | 'HEADER_BG_COLOR' => 'latextbl', | |
52 | 'DATA_BG_COLOR_ODD' => 'latextbl!25', | |
53 | 'DATA_BG_COLOR_EVEN' => 'latextbl!10', | |
54 | 'DEFINE_COLORS' => '\definecolor{latextbl}{RGB}{93,127,114}', | |
55 | 'HEADER_CENTERED' => 1, | |
56 | 'VERTICAL_RULES' => [ 1, 0, 0 ], | |
57 | 'HORIZONTAL_RULES' => [ 1, 1, 0 ], | |
58 | 'BOOKTABS' => 0, | |
59 | 'EXTRA_ROW_HEIGHT' => '1pt', | |
60 | }}; | |
61 | } | |
62 | ||
63 | 1; | |
64 | ||
65 | .. | |
66 | $table->search_path( add => 'MyThemes'); | |
67 | ||
68 | =head1 DESCRIPTION | |
69 | ||
70 | This is the theme interface (or L<Moose> role), that all theme objects must use. | |
71 | ||
72 | =head1 CREATING THEMES | |
73 | ||
74 | A theme is defined as an hash reference containing all options: | |
75 | ||
76 | # a very ugly theme... | |
77 | my $theme = { | |
78 | 'Duisburg' => { | |
79 | 'HEADER_FONT_STYLE' => 'sc', | |
80 | 'HEADER_FONT_COLOR' => 'white', | |
81 | 'HEADER_BG_COLOR' => 'blue', | |
82 | 'HEADER_CENTERED' => 1, | |
83 | 'DATA_BG_COLOR_ODD' => 'blue!30', | |
84 | 'DATA_BG_COLOR_EVEN' => 'blue!10', | |
85 | 'CAPTION_FONT_STYLE' => 'sc', | |
86 | 'VERTICAL_RULES' => [ 1, 2, 1 ], | |
87 | 'HORIZONTAL_RULES' => [ 1, 2, 0 ], | |
88 | 'EXTRA_ROW_HEIGHT' => '2pt', | |
89 | 'BOOKTABS' => 0, | |
90 | }, | |
91 | }; | |
92 | ||
93 | ||
94 | =over | |
95 | ||
96 | =item Fonts | |
97 | ||
98 | C<HEADER_FONT_STYLE>, C<CAPTION_FONT_STYLE>. Valid values are I<bf> (bold), | |
99 | I<it> (italics), I<sc> (caps) and I<tt> (typewriter). When this option is | |
100 | undef, then header (or caption, respectively) is written in normal font. | |
101 | ||
102 | =item Colors | |
103 | ||
104 | C<HEADER_FONT_COLOR> can be used to specify a different font color for the | |
105 | header. Requires the C<xcolor> LaTeX package. | |
106 | ||
107 | Set C<HEADER_BG_COLOR> to use a background color in the header, | |
108 | C<DATA_BG_COLOR_EVEN> and C<DATA_BG_COLOR_ODD> for even and odd data rows. | |
109 | Requires the C<colortbl> and the C<xcolor> LaTeX package. | |
110 | ||
111 | You can define colors with C<DEFINE_COLORS>, for example: | |
112 | ||
113 | 'DEFINE_COLORS' => '\definecolor{latextbl}{RGB}{78,130,190}', | |
114 | ||
115 | =item Rules | |
116 | ||
117 | =over | |
118 | ||
119 | =item C<VERTICAL_RULES>, C<HORIZONTAL_RULES> | |
120 | ||
121 | A reference to an array with three integers, e.g. C<[ 1, 2, 0 ]>. The first | |
122 | integer defines the number of outer rules. The second the number of rules | |
123 | after the header and after the first column. The third is the number of inner | |
124 | rules. For example I<Dresden> is defined as: | |
125 | ||
126 | 'Dresden' => { | |
127 | ... | |
128 | 'VERTICAL_RULES' => [ 1, 2, 1 ], | |
129 | 'HORIZONTAL_RULES' => [ 1, 2, 0 ], | |
130 | } | |
131 | ||
132 | The first integers define one outer rule - vertical and horizontal. So a box | |
133 | is drawn around the table. The second integers define two rules between header | |
134 | and table and two vertical rules between first and second column. And finally | |
135 | the third integers define that columns are separated by a single vertical | |
136 | rule whereas rows are not separated by horizontal lines. | |
137 | ||
138 | =item C<RULES_COLOR_GLOBAL> | |
139 | ||
140 | If your theme uses the C<colortbl> LaTeX package, this command should handle | |
141 | the coloring of the rules. See the C<colortbl> documentation. | |
142 | ||
143 | 'RULES_COLOR_GLOBAL' => | |
144 | '\arrayrulecolor{white}\doublerulesepcolor{black}', | |
145 | ||
146 | =item C<RULES_WIDTH_GLOBAL> | |
147 | ||
148 | Code that controls the width of the rules. See for example the C<colortbl> | |
149 | documentation. | |
150 | ||
151 | 'RULES_WIDTH_GLOBAL' => | |
152 | '\setlength\arrayrulewidth{1pt}\setlength\doublerulesep{0pt}', | |
153 | ||
154 | =item C<RULES_CMD> | |
155 | ||
156 | A reference to an array with four LaTeX commands for the top, mid (between header and | |
157 | data), inner and bottom rules. | |
158 | ||
159 | RULES_CMD => [ '\toprule', '\midrule', '\midrule', '\bottomrule' ]; | |
160 | ||
161 | =item C<BOOKTABS> | |
162 | ||
163 | Use the C<booktabs> LaTeX package for "Publication quality tables". Instead of | |
164 | C<\hline>, C<LaTeX::Table> then uses C<\toprule>, C<\midrule> and | |
165 | C<\bottomrule>. 0 (don't use this package) or 1 (use it). A shortcut for | |
166 | ||
167 | RULES_CMD => [ '\toprule', '\midrule', '\midrule', '\bottomrule' ]; | |
168 | ||
169 | =back | |
170 | ||
171 | =item Misc | |
172 | ||
173 | =over | |
174 | ||
175 | =item C<EXTRA_ROW_HEIGHT> | |
176 | ||
177 | Will set C<\extrarowheight> in the floating environment. Requires the C<array> | |
178 | LaTeX package. | |
179 | ||
180 | =item C<STUB_ALIGN> | |
181 | ||
182 | Defines how the left-hand column, the stub, is aligned. Default is 'l' (left | |
183 | aligned). | |
184 | ||
185 | =item C<HEADER_CENTERED> | |
186 | ||
187 | This controls the alignment of the header columns, excluding the stub when | |
188 | C<STUB_ALIGN> is defined. Valid values are 0 (not centered) or 1 (centered). | |
189 | Typically, it is recommended to center headers, but sometimes this does not | |
190 | look right. In this case, (left) align the header manually. | |
191 | ||
192 | =back | |
193 | ||
194 | =back | |
195 | ||
196 | You can either quickly add themes after initiation of an L<LaTeX::Table>: | |
197 | ||
198 | $table->set_custom_themes($theme); | |
199 | ||
200 | Or, you can build a L<"THEME MODULE"> and extend the list of predefined themes. | |
201 | ||
202 | =head1 THEME MODULE | |
203 | ||
204 | Now, to build a theme that you can easily load, take the L<"SYNOPSIS"> | |
205 | template, change it and then make it accessible in C<LaTeX::Table> by saving | |
206 | it under the C<LaTeX::Table::Themes::*> namespace. Alternatively, you can use | |
207 | the search_path() method to add custom paths. See L<"SYNOPSIS">. If your theme | |
208 | looks nice, please contribute it. | |
209 | ||
210 | =head1 SEE ALSO | |
211 | ||
212 | L<LaTeX::Table> | |
213 | ||
214 | =head1 AUTHOR | |
215 | ||
216 | Markus Riester C<< <mriester@gmx.de> >> | |
217 | ||
218 | =head1 LICENSE AND COPYRIGHT | |
219 | ||
220 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
221 | ||
222 | This module is free software; you can redistribute it and/or | |
223 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
224 | ||
225 | =cut | |
226 | ||
227 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | ############################################################################# | |
1 | # $Author: markus $ | |
2 | # $Date: 2009-02-04 12:25:08 +0100 (Wed, 04 Feb 2009) $ | |
3 | # $Revision: 1307 $ | |
4 | ############################################################################# | |
5 | ||
6 | package LaTeX::Table::Types::Ctable; | |
7 | use Moose; | |
8 | ||
9 | with 'LaTeX::Table::Types::TypeI'; | |
10 | ||
11 | use version; | |
12 | our ($VERSION) = '$Revision: 1307 $' =~ m{ \$Revision: \s+ (\S+) }xms; | |
13 | ||
14 | my $template =<<'EOT' | |
15 | {[% DEFINE_COLORS_CODE %][% FONTSIZE_CODE %][% FONTFAMILY_CODE %][% | |
16 | EXTRA_ROW_HEIGHT %][% RULES_WIDTH_GLOBAL %][% RESIZEBOX_BEGIN_CODE %] | |
17 | \ctable[[% IF CAPTION %]caption = {[% CAPTION %]}, | |
18 | [% IF SHORTCAPTION %]cap = {[% SHORTCAPTION %]}, | |
19 | [% END %][% UNLESS CAPTION_TOP %]botcap, | |
20 | [% END %][% END %][% IF POSITION %]pos = [% POSITION %], | |
21 | [% END %][% IF LABEL %]label = {[% LABEL %]}, | |
22 | [% END %][% IF MAXWIDTH %]maxwidth = {[% MAXWIDTH %]}, | |
23 | [% END %][% IF WIDTH %]width = {[% WIDTH %]}, | |
24 | [% END %][% IF CENTER %]center, | |
25 | [% END %][% IF LEFT %]left, | |
26 | [% END %][% IF RIGHT %]right, | |
27 | [% END %][% IF SIDEWAYS %]sideways, | |
28 | [% END %][% IF STAR %]star, | |
29 | [% END %][% IF CONTINUED %]continued = {[% CONTINUEDMSG %]}, | |
30 | [% END %]]{[% COLDEF %]}{[% FOOTTABLE %]}{ | |
31 | [% RULES_COLOR_GLOBAL %][% HEADER_CODE %][% DATA_CODE %]} | |
32 | [% RESIZEBOX_END_CODE %]} | |
33 | EOT | |
34 | ; | |
35 | ||
36 | has '+_tabular_environment' => (default => 'tabular'); | |
37 | has '+_template' => (default => $template); | |
38 | ||
39 | 1; | |
40 | ||
41 | __END__ | |
42 | ||
43 | =head1 NAME | |
44 | ||
45 | LaTeX::Table::Types::Ctable - Create LaTeX tables with the ctable package. | |
46 | ||
47 | =head1 INTERFACE | |
48 | ||
49 | =over | |
50 | ||
51 | =item C<generate_latex_code> | |
52 | ||
53 | =back | |
54 | ||
55 | =head1 SEE ALSO | |
56 | ||
57 | L<LaTeX::Table>, L<LaTeX::Table::Types::TypeI> | |
58 | ||
59 | =head1 AUTHOR | |
60 | ||
61 | Markus Riester C<< <mriester@gmx.de> >> | |
62 | ||
63 | =head1 LICENSE AND COPYRIGHT | |
64 | ||
65 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
66 | ||
67 | This module is free software; you can redistribute it and/or | |
68 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
69 | ||
70 | =cut | |
71 | ||
72 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | ############################################################################# | |
1 | # $Author: markus $ | |
2 | # $Date: 2009-02-23 20:05:36 +0100 (Mon, 23 Feb 2009) $ | |
3 | # $Revision$ | |
4 | ############################################################################# | |
5 | ||
6 | package LaTeX::Table::Types::Longtable; | |
7 | use Moose; | |
8 | ||
9 | with 'LaTeX::Table::Types::TypeI'; | |
10 | ||
11 | use version; | |
12 | our ($VERSION) = '$Revision: 1313 $' =~ m{ \$Revision: \s+ (\S+) }xms; | |
13 | ||
14 | my $template =<<'EOT' | |
15 | { | |
16 | [% IF CONTINUED %]\addtocounter{table}{-1}[% END | |
17 | %][% DEFINE_COLORS_CODE %][% EXTRA_ROW_HEIGHT %][% RULES_WIDTH_GLOBAL | |
18 | %][% RULES_COLOR_GLOBAL %][% FONTSIZE_CODE %][% FONTFAMILY_CODE | |
19 | %][%IF SIDEWAYS %]\begin{landscape}[% END | |
20 | %][% IF CENTER %]\begin{center} | |
21 | [% END %][% IF LEFT %]\begin{flushleft} | |
22 | [% END %][% IF RIGHT %]\begin{flushright} | |
23 | [% END %][% RESIZEBOX_BEGIN_CODE %]\begin{[% TABULAR_ENVIRONMENT %][% IF STAR %]*[% END %]}[% IF WIDTH %]{[%WIDTH %]}[% END %]{[% COLDEF %]} | |
24 | [% IF CAPTION %][%IF CAPTION_TOP %]\caption[%IF SHORTCAPTION %][[% | |
25 | SHORTCAPTION %]][% END %]{[% CAPTION %][% IF CONTINUED %] [% CONTINUEDMSG %][% | |
26 | END %][% IF LABEL %]\label{[% LABEL %]}[% END %]}\\ | |
27 | [% END %][% END %][% HEADER_CODE %]\endfirsthead | |
28 | [% IF CAPTION %][% IF CAPTION_TOP %][% IF TABLEHEADMSG %]\caption[]{[% TABLEHEADMSG %]}\\ | |
29 | [% END %][% END %][% END %] | |
30 | [% HEADER_CODE %]\endhead | |
31 | [% TABLETAIL %]\endfoot | |
32 | [% TABLETAIL_LAST %] | |
33 | [% IF CAPTION %][% UNLESS CAPTION_TOP %]\caption[%IF SHORTCAPTION %][[% | |
34 | SHORTCAPTION %]][% END %]{[% CAPTION %][% IF CONTINUED %] [% CONTINUEDMSG %][% | |
35 | END %][% IF LABEL %]\label{[% LABEL %]}[% END %]}\\ | |
36 | [% END %][% END %]\endlastfoot | |
37 | [% DATA_CODE %]\end{[% TABULAR_ENVIRONMENT %][% IF STAR %]*[% END %]} | |
38 | [% RESIZEBOX_END_CODE %][% IF CENTER %]\end{center}[% END %][% IF LEFT | |
39 | %]\end{flushleft}[% END %][% IF RIGHT %]\end{flushright}[% END %][% IF | |
40 | SIDEWAYS %]\end{landscape}[% END %] | |
41 | } | |
42 | EOT | |
43 | ; | |
44 | ||
45 | has '+_tabular_environment' => (default => 'longtable'); | |
46 | has '+_template' => (default => $template); | |
47 | ||
48 | ########################################################################### | |
49 | # Usage : $self->_get_tabletail_code(\@data, $final_tabletail); | |
50 | # Purpose : generates the LaTeX code of the xtab tabletail | |
51 | # Returns : LaTeX code | |
52 | # Parameters : the data columns and a flag indicating whether it is the | |
53 | # code for the final tail (1). | |
54 | ||
55 | sub _get_tabletail_code { | |
56 | my ( $self, $data, $final_tabletail ) = @_; | |
57 | ||
58 | my $tbl = $self->_table_obj; | |
59 | my $code; | |
60 | my $hlines = $tbl->get_theme_settings->{'HORIZONTAL_RULES'}; | |
61 | my $vlines = $tbl->get_theme_settings->{'VERTICAL_RULES'}; | |
62 | my $linecode1 = $self->_get_hline_code($self->_RULE_MID_ID); | |
63 | my $linecode2 = $self->_get_hline_code($self->_RULE_BOTTOM_ID); | |
64 | ||
65 | # if custom table tail is defined, then return it | |
66 | if ( $tbl->get_tabletail ) { | |
67 | $code = $tbl->get_tabletail; | |
68 | } | |
69 | elsif ( !$final_tabletail ) { | |
70 | my @cols = $tbl->_get_data_summary(); | |
71 | my $nu_cols = scalar @cols; | |
72 | ||
73 | my $v0 = q{|} x $vlines->[0]; | |
74 | $code = "$linecode1\\multicolumn{$nu_cols}{${v0}r$v0}{{" | |
75 | . $tbl->get_tabletailmsg | |
76 | . "}} \\\\\n"; | |
77 | } | |
78 | if ($final_tabletail) { | |
79 | return q{}; | |
80 | } | |
81 | return "$code$linecode2"; | |
82 | } | |
83 | ||
84 | ||
85 | 1; | |
86 | __END__ | |
87 | ||
88 | =head1 NAME | |
89 | ||
90 | LaTeX::Table::Types::Longtable - Create multi-page LaTeX tables with the longtable package. | |
91 | ||
92 | =head1 INTERFACE | |
93 | ||
94 | =over | |
95 | ||
96 | =item C<generate_latex_code> | |
97 | ||
98 | =back | |
99 | ||
100 | =head1 SEE ALSO | |
101 | ||
102 | L<LaTeX::Table>, L<LaTeX::Table::Types::TypeI> | |
103 | ||
104 | =head1 AUTHOR | |
105 | ||
106 | Markus Riester C<< <mriester@gmx.de> >> | |
107 | ||
108 | =head1 LICENSE AND COPYRIGHT | |
109 | ||
110 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
111 | ||
112 | This module is free software; you can redistribute it and/or | |
113 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
114 | ||
115 | =cut | |
116 | ||
117 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | ############################################################################# | |
1 | # $Author: markus $ | |
2 | # $Date: 2009-02-04 12:25:08 +0100 (Wed, 04 Feb 2009) $ | |
3 | # $Revision: 1307 $ | |
4 | ############################################################################# | |
5 | ||
6 | package LaTeX::Table::Types::Std; | |
7 | use Moose; | |
8 | ||
9 | with 'LaTeX::Table::Types::TypeI'; | |
10 | ||
11 | use version; | |
12 | our ($VERSION) = '$Revision: 1307 $' =~ m{ \$Revision: \s+ (\S+) }xms; | |
13 | ||
14 | my $template =<<'EOT' | |
15 | [%IF CONTINUED %]\addtocounter{table}{-1}[% END %][% DEFINE_COLORS_CODE %][% IF ENVIRONMENT %]\begin{[% IF SIDEWAYS %]sidewaystable[% ELSE %][% ENVIRONMENT %][% END %][% IF STAR %]*[% END %]}[% IF POSITION %][[% POSITION %]][% END %] | |
16 | [% FONTSIZE_CODE %][% FONTFAMILY_CODE %][% RULES_WIDTH_GLOBAL %][% IF CENTER %]\centering | |
17 | [% END %][% IF LEFT %]\raggedright | |
18 | [% END %][% IF RIGHT %]\raggedleft | |
19 | [% END %][% IF CAPTION_TOP %][% IF CAPTION %]\[% CAPTION_CMD %][% IF SHORTCAPTION %][[% SHORTCAPTION %]][% END %]{[% CAPTION %][% IF CONTINUED %] [% CONTINUEDMSG %][% END %]} | |
20 | [% END %][% END %][% END %][% EXTRA_ROW_HEIGHT %][% RESIZEBOX_BEGIN_CODE %]\begin{[% TABULAR_ENVIRONMENT %]}[% IF WIDTH %]{[% WIDTH %]}[% END %]{[% COLDEF %]} | |
21 | [% RULES_COLOR_GLOBAL %][% HEADER_CODE %][% DATA_CODE %]\end{[% | |
22 | TABULAR_ENVIRONMENT %]}[% RESIZEBOX_END_CODE %][% IF ENVIRONMENT %][% UNLESS CAPTION_TOP %][% IF CAPTION %] | |
23 | \[% CAPTION_CMD %][% IF SHORTCAPTION %][[% SHORTCAPTION %]][% END %]{[% CAPTION %][% IF CONTINUED %] [% CONTINUEDMSG %][% END %]}[% END %][% END %][%IF LABEL %] | |
24 | \label{[% LABEL %]}[% END %] | |
25 | \end{[% IF SIDEWAYS %]sidewaystable[% ELSE %][% ENVIRONMENT %][% END %][% IF STAR %]*[% END %]}[% END %] | |
26 | EOT | |
27 | ; | |
28 | ||
29 | has '+_tabular_environment' => (default => 'tabular'); | |
30 | has '+_template' => (default => $template); | |
31 | ||
32 | 1; | |
33 | ||
34 | __END__ | |
35 | ||
36 | =head1 NAME | |
37 | ||
38 | LaTeX::Table::Types::Std - Create standard LaTeX tables. | |
39 | ||
40 | =head1 INTERFACE | |
41 | ||
42 | =over | |
43 | ||
44 | =item C<generate_latex_code> | |
45 | ||
46 | =back | |
47 | ||
48 | =head1 SEE ALSO | |
49 | ||
50 | L<LaTeX::Table>, L<LaTeX::Table::Types::TypeI> | |
51 | ||
52 | =head1 AUTHOR | |
53 | ||
54 | Markus Riester C<< <mriester@gmx.de> >> | |
55 | ||
56 | =head1 LICENSE AND COPYRIGHT | |
57 | ||
58 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
59 | ||
60 | This module is free software; you can redistribute it and/or | |
61 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
62 | ||
63 | =cut | |
64 | ||
65 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | ############################################################################# | |
1 | # $Author: markus $ | |
2 | # $Date: 2009-05-28 18:46:45 +0200 (Thu, 28 May 2009) $ | |
3 | # $Revision: 1612 $ | |
4 | ############################################################################# | |
5 | ||
6 | package LaTeX::Table::Types::TypeI; | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Moose::Role; | |
12 | use Template; | |
13 | ||
14 | use version; | |
15 | our ($VERSION) = '$Revision: 1612 $' =~ m{ \$Revision: \s+ (\S+) }xms; | |
16 | ||
17 | use Scalar::Util qw(reftype); | |
18 | ||
19 | use Carp; | |
20 | ||
21 | has '_table_obj' => ( is => 'rw', isa => 'LaTeX::Table', required => 1 ); | |
22 | has '_tabular_environment' => ( is => 'ro', required => 1 ); | |
23 | has '_template' => ( is => 'ro', required => 1 ); | |
24 | ||
25 | has '_RULE_TOP_ID' => ( is => 'ro', default => 0 ); | |
26 | has '_RULE_MID_ID' => ( is => 'ro', default => 1 ); | |
27 | has '_RULE_INNER_ID' => ( is => 'ro', default => 2 ); | |
28 | ## no critic (ValuesAndExpressions::ProhibitMagicNumbers) | |
29 | has '_RULE_BOTTOM_ID' => ( is => 'ro', default => 3 ); | |
30 | ## use critic | |
31 | ||
32 | 1; | |
33 | ||
34 | ########################################################################### | |
35 | # Usage : $self->_header(\@header,\@data); | |
36 | # Purpose : create the LaTeX header | |
37 | # Returns : LaTeX code | |
38 | # Parameters : header and data columns | |
39 | # Throws : | |
40 | # Comments : n/a | |
41 | # See also : _footer | |
42 | ||
43 | sub generate_latex_code { | |
44 | my ( $self, $header, $data ) = @_; | |
45 | ||
46 | my $tbl = $self->_table_obj; | |
47 | ||
48 | # if specified, use coldef, otherwise guess a good definition | |
49 | my $table_def; | |
50 | if ( $tbl->get_coldef ) { | |
51 | $table_def = $tbl->get_coldef; | |
52 | } | |
53 | else { | |
54 | $table_def = $tbl->_get_coldef_code($data); | |
55 | } | |
56 | ||
57 | my $center = $tbl->get_center; | |
58 | ||
59 | if ( $tbl->get__default_align ) { | |
60 | $center = 1; | |
61 | } | |
62 | my $header_code = $self->_get_header_columns_code($header); | |
63 | ||
64 | my $template_vars = { | |
65 | 'CENTER' => $center, | |
66 | 'LEFT' => $tbl->get_left(), | |
67 | 'RIGHT' => $tbl->get_right(), | |
68 | 'ENVIRONMENT' => $tbl->get_environment, | |
69 | 'FONTFAMILY' => $tbl->get_fontfamily(), | |
70 | 'FONTFAMILY_CODE' => $self->_get_fontfamily_code(), | |
71 | 'FONTSIZE' => $tbl->get_fontsize(), | |
72 | 'FONTSIZE_CODE' => $self->_get_fontsize_code(), | |
73 | 'FOOTTABLE' => $tbl->get_foottable(), | |
74 | 'POSITION' => $tbl->get_position(), | |
75 | 'CAPTION_TOP' => $tbl->get_caption_top(), | |
76 | 'CAPTION' => $self->_get_caption(), | |
77 | 'CAPTION_CMD' => $self->_get_caption_command(), | |
78 | 'CONTINUED' => $tbl->get_continued(), | |
79 | 'CONTINUEDMSG' => $tbl->get_continuedmsg(), | |
80 | 'SHORTCAPTION' => $self->_get_shortcaption(), | |
81 | 'SIDEWAYS' => $tbl->get_sideways(), | |
82 | 'STAR' => $tbl->get_star(), | |
83 | 'EXTRA_ROW_HEIGHT' => $self->_get_extra_row_height_code(), | |
84 | 'RULES_COLOR_GLOBAL' => $self->_get_rules_color_global_code(), | |
85 | 'RULES_WIDTH_GLOBAL' => $self->_get_rules_width_global_code(), | |
86 | 'RESIZEBOX_BEGIN_CODE' => $self->_get_begin_resizebox_code(), | |
87 | 'RESIZEBOX_END_CODE' => $self->_get_end_resizebox_code(), | |
88 | 'WIDTH' => $tbl->get_width(), | |
89 | 'MAXWIDTH' => $tbl->get_maxwidth(), | |
90 | 'COLDEF' => $table_def, | |
91 | 'LABEL' => $tbl->get_label(), | |
92 | 'HEADER_CODE' => $header_code, | |
93 | 'TABLEHEADMSG' => $tbl->get_tableheadmsg(), | |
94 | 'TABLEHEAD' => $self->_get_tablehead_code( $header_code ), | |
95 | 'TABLETAIL' => $self->_get_tabletail_code( $data, 0 ), | |
96 | 'TABLETAIL_LAST' => $self->_get_tabletail_code( $data, 1 ), | |
97 | 'XENTRYSTRETCH_CODE' => $self->_get_xentrystretch_code(), | |
98 | 'DATA_CODE' => $self->_get_data_code(), | |
99 | 'TABULAR_ENVIRONMENT' => $self->_get_tabular_environment(), | |
100 | 'DEFINE_COLORS_CODE' => $self->_get_colordef_code, | |
101 | }; | |
102 | ||
103 | my $template_obj = Template->new(); | |
104 | my $template = $self->_template; | |
105 | ||
106 | if ($tbl->get_custom_template) { | |
107 | $template = $tbl->get_custom_template; | |
108 | } | |
109 | ||
110 | my $template_output; | |
111 | ||
112 | $template_obj->process( \$template, $template_vars, \$template_output ) | |
113 | or croak $template_obj->error(); | |
114 | return $template_output; | |
115 | } | |
116 | ||
117 | sub _get_data_code { | |
118 | my ($self) = @_; | |
119 | my $code = q{}; | |
120 | my $tbl = $self->_table_obj; | |
121 | ||
122 | my $theme = $tbl->get_theme_settings; | |
123 | my $i = 0; | |
124 | my $row_id = 0; | |
125 | ||
126 | # check the data and apply callback function | |
127 | my @data = $tbl->_examine_data; | |
128 | my @code; | |
129 | ROW: | |
130 | for my $row (@data) { | |
131 | $i++; | |
132 | ||
133 | # empty rows produce a horizontal line | |
134 | if ( !@{$row} ) { | |
135 | push @code, $self->_get_hline_code( $self->_RULE_INNER_ID, 1); | |
136 | next ROW; | |
137 | } | |
138 | else { | |
139 | ||
140 | # single column rows that start with a backslash are just | |
141 | # printed out | |
142 | if ( $tbl->_row_is_latex_command($row) ) { | |
143 | push @code, $row->[0] . "\n"; | |
144 | next ROW; | |
145 | } | |
146 | ||
147 | $row_id++; | |
148 | ||
149 | # now print the row LaTeX code | |
150 | my $bgcolor = $theme->{'DATA_BG_COLOR_EVEN'}; | |
151 | if ( ( $row_id % 2 ) == 1 ) { | |
152 | $bgcolor = $theme->{'DATA_BG_COLOR_ODD'}; | |
153 | } | |
154 | push @code, $tbl->_get_row_array( $row, $bgcolor, 0 ); | |
155 | ||
156 | # do we have to draw a horizontal line? | |
157 | if ( $i == scalar @data ) { | |
158 | push @code, $self->_get_hline_code( $self->_RULE_BOTTOM_ID ); | |
159 | } | |
160 | else { | |
161 | push @code, $self->_get_hline_code( $self->_RULE_INNER_ID ); | |
162 | } | |
163 | } | |
164 | } | |
165 | ||
166 | return $self->_align_code(\@code); | |
167 | } | |
168 | ||
169 | sub _align_code { | |
170 | my ( $self, $code_ref ) = @_; | |
171 | my %max; | |
172 | for my $row (@{$code_ref}) { | |
173 | next if (!defined reftype $row); | |
174 | for my $i ( 0 .. scalar( @{$row} ) - 1 ) { | |
175 | $row->[$i] =~ s{^\s+|\s+$}{}gxms; | |
176 | my $l = length $row->[$i]; | |
177 | if (!defined $max{$i} || $max{$i} < $l) { | |
178 | $max{$i} = $l; | |
179 | } | |
180 | } | |
181 | } | |
182 | ||
183 | my $code = q{}; | |
184 | ROW: | |
185 | for my $row (@{$code_ref}) { | |
186 | if (!defined reftype $row) { | |
187 | $code .= $row; | |
188 | next ROW; | |
189 | } | |
190 | for my $i ( 0 .. scalar( @{$row} ) - 1 ) { | |
191 | $row->[$i] = sprintf '%-*s', $max{$i}, $row->[$i]; | |
192 | } | |
193 | $code .= join( ' & ', @{$row} ) . " \\\\\n"; | |
194 | } | |
195 | return $code; | |
196 | } | |
197 | ||
198 | sub _get_caption_command { | |
199 | my ($self) = @_; | |
200 | my $tbl = $self->_table_obj; | |
201 | my $c_caption = 'caption'; | |
202 | if ( $tbl->get_caption_top ) { | |
203 | $c_caption = $tbl->get_caption_top; | |
204 | $c_caption =~ s{ \A \\ }{}xms; | |
205 | if ( $c_caption eq '1' ) { | |
206 | $c_caption = 'caption'; | |
207 | } | |
208 | } | |
209 | return $c_caption; | |
210 | } | |
211 | ||
212 | sub _get_colordef_code { | |
213 | my ($self) = @_; | |
214 | my $tbl = $self->_table_obj; | |
215 | my $colordef = q{}; | |
216 | if ( defined $tbl->get_theme_settings->{DEFINE_COLORS} ) { | |
217 | $colordef = $tbl->get_theme_settings->{DEFINE_COLORS} . "\n"; | |
218 | } | |
219 | return $colordef; | |
220 | } | |
221 | ||
222 | sub _get_begin_resizebox_code { | |
223 | my ($self) = @_; | |
224 | if ( $self->_table_obj->get_resizebox ) { | |
225 | my $rb_width = $self->_table_obj->get_resizebox->[0]; | |
226 | my $rb_height = q{!}; | |
227 | if ( defined $self->_table_obj->get_resizebox->[1] ) { | |
228 | $rb_height = $self->_table_obj->get_resizebox->[1]; | |
229 | } | |
230 | return "\\resizebox{$rb_width}{$rb_height}{\n"; | |
231 | } | |
232 | return q{}; | |
233 | } | |
234 | ||
235 | sub _get_end_resizebox_code { | |
236 | my ($self) = @_; | |
237 | my $end_resizebox = q{}; | |
238 | if ( $self->_table_obj->get_resizebox ) { | |
239 | $end_resizebox = "}\n"; | |
240 | } | |
241 | return $end_resizebox; | |
242 | } | |
243 | ||
244 | ########################################################################### | |
245 | # Usage : $self->_get_caption_code($header); | |
246 | # Purpose : generates the LaTeX code of the caption | |
247 | # Returns : LaTeX code | |
248 | # Parameters : called from _header? | |
249 | # Comments : header specifies whether this function has been called in | |
250 | # the header or footer. ignored for xtab, because there it | |
251 | # is always placed on top | |
252 | ||
253 | sub _get_caption { | |
254 | my ( $self, $header ) = @_; | |
255 | my $caption = q{}; | |
256 | my $s_caption = q{}; | |
257 | my $tbl = $self->_table_obj; | |
258 | ||
259 | if ( !$tbl->get_caption) { | |
260 | if (!$tbl->get_maincaption) { | |
261 | return 0; | |
262 | } | |
263 | } | |
264 | else { | |
265 | $caption = $tbl->get_caption; | |
266 | } | |
267 | ||
268 | my $theme = $tbl->get_theme_settings; | |
269 | ||
270 | my $tmp = q{}; | |
271 | if ( $tbl->get_maincaption ) { | |
272 | $tmp = $tbl->get_maincaption . '. '; | |
273 | if ( defined $theme->{CAPTION_FONT_STYLE} ) { | |
274 | $tmp = $tbl->_add_font_family( $tmp, | |
275 | $theme->{CAPTION_FONT_STYLE} ); | |
276 | } | |
277 | } | |
278 | ||
279 | return $tmp . $caption; | |
280 | } | |
281 | ||
282 | sub _get_shortcaption { | |
283 | my ($self) = @_; | |
284 | my $tbl = $self->_table_obj; | |
285 | if ( $tbl->get_maincaption ) { | |
286 | return $tbl->get_maincaption; | |
287 | } | |
288 | if ( $tbl->get_shortcaption ) { | |
289 | return $tbl->get_shortcaption; | |
290 | } | |
291 | return 0; | |
292 | } | |
293 | ||
294 | sub _get_extra_row_height_code { | |
295 | my ($self) = @_; | |
296 | if ( defined $self->_table_obj->get_theme_settings->{EXTRA_ROW_HEIGHT} ) { | |
297 | return '\setlength{\extrarowheight}{' | |
298 | . $self->_table_obj->get_theme_settings->{EXTRA_ROW_HEIGHT} | |
299 | . "}\n"; | |
300 | } | |
301 | return q{}; | |
302 | } | |
303 | ||
304 | sub _get_rules_color_global_code { | |
305 | my ($self) = @_; | |
306 | if ( defined $self->_table_obj->get_theme_settings->{RULES_COLOR_GLOBAL} ) { | |
307 | return $self->_table_obj->get_theme_settings->{RULES_COLOR_GLOBAL} | |
308 | . "\n"; | |
309 | } | |
310 | return q{}; | |
311 | } | |
312 | ||
313 | sub _get_rules_width_global_code { | |
314 | my ($self) = @_; | |
315 | if ( defined $self->_table_obj->get_theme_settings->{RULES_WIDTH_GLOBAL} ) { | |
316 | return $self->_table_obj->get_theme_settings->{RULES_WIDTH_GLOBAL} | |
317 | . "\n"; | |
318 | } | |
319 | return q{}; | |
320 | } | |
321 | ||
322 | sub _get_hline_code { | |
323 | my ( $self, $id, $single ) = @_; | |
324 | my $tbl = $self->_table_obj; | |
325 | my $theme = $tbl->get_theme_settings; | |
326 | my $hlines = $theme->{'HORIZONTAL_RULES'}; | |
327 | my $line = '\hline'; | |
328 | if ( defined $theme->{RULES_CMD} && reftype $theme->{RULES_CMD} eq 'ARRAY') { | |
329 | $line = $theme->{RULES_CMD}->[$id]; | |
330 | } | |
331 | if ( $id == $self->_RULE_BOTTOM_ID ) { | |
332 | $id = 0; | |
333 | } | |
334 | # just one line? | |
335 | if (defined $single && $single) { | |
336 | return "$line\n"; | |
337 | } | |
338 | return "$line\n" x $hlines->[$id]; | |
339 | } | |
340 | ||
341 | ########################################################################### | |
342 | # Usage : $self->_get_fontsize_code(); | |
343 | # Purpose : generates the LaTeX code of the fontsize (e.g. \small, \large) | |
344 | # Returns : LaTeX code | |
345 | # Parameters : none | |
346 | # Throws : exception if fontsize is not valid | |
347 | ||
348 | sub _get_fontsize_code { | |
349 | my ($self) = @_; | |
350 | my %valid = ( | |
351 | 'tiny' => 1, | |
352 | 'scriptsize' => 1, | |
353 | 'footnotesize' => 1, | |
354 | 'small' => 1, | |
355 | 'normal' => 1, | |
356 | 'large' => 1, | |
357 | 'Large' => 1, | |
358 | 'LARGE' => 1, | |
359 | 'huge' => 1, | |
360 | 'Huge' => 1, | |
361 | ); | |
362 | my $size = $self->_table_obj->get_fontsize; | |
363 | return q{} if !$size; | |
364 | ||
365 | if ( !defined $valid{$size} ) { | |
366 | $self->_table_obj->invalid_option_usage( | |
367 | 'custom_themes', | |
368 | "Size not known: $size. Valid sizes are: " . join ', ', | |
369 | sort keys %valid | |
370 | ); | |
371 | } | |
372 | return "\\$size\n"; | |
373 | } | |
374 | ||
375 | ||
376 | sub _get_fontfamily_code { | |
377 | my ($self) = @_; | |
378 | my %valid = ( | |
379 | 'rm' => 1, | |
380 | 'sf' => 1, | |
381 | 'tt' => 1, | |
382 | ); | |
383 | my $family = $self->_table_obj->get_fontfamily; | |
384 | return q{} if !$family; | |
385 | ||
386 | if ( !defined $valid{$family} ) { | |
387 | $self->_table_obj->invalid_option_usage( | |
388 | 'fontfamily', | |
389 | "Family not known: $family. Valid families are: " . join ', ', | |
390 | sort keys %valid | |
391 | ); | |
392 | } | |
393 | return "\\${family}family\n"; | |
394 | } | |
395 | ||
396 | sub _get_tabular_environment { | |
397 | my ($self) = @_; | |
398 | my $res; | |
399 | my $tbl = $self->_table_obj; | |
400 | ||
401 | if ( $tbl->get_custom_tabular_environment ) { | |
402 | $res = $tbl->get_custom_tabular_environment; | |
403 | } | |
404 | else { | |
405 | $res = $self->_tabular_environment; | |
406 | } | |
407 | if ( $tbl->get_width ) { | |
408 | if ( !$tbl->get_width_environment ) { | |
409 | $res .= q{*}; | |
410 | } | |
411 | elsif ( $tbl->get_type ne 'longtable') { #want the ltxtable package? | |
412 | $res = $tbl->get_width_environment; | |
413 | } | |
414 | } | |
415 | return $res; | |
416 | } | |
417 | ||
418 | ########################################################################### | |
419 | # Usage : $self->_get_header_columns_code(\@header); | |
420 | # Purpose : generate the header LaTeX code | |
421 | # Returns : LaTeX code | |
422 | # Parameters : header columns | |
423 | # Throws : | |
424 | # Comments : n/a | |
425 | # See also : _get_row_code | |
426 | ||
427 | sub _get_header_columns_code { | |
428 | my ( $self, $header ) = @_; | |
429 | my $tbl = $self->_table_obj; | |
430 | my $code = q{}; | |
431 | my $theme = $tbl->get_theme_settings; | |
432 | ||
433 | my $i = 0; | |
434 | ||
435 | my @code = ( $self->_get_hline_code( $self->_RULE_TOP_ID ) ); | |
436 | ||
437 | CENTER_ROW: | |
438 | for my $row ( @{$header} ) { | |
439 | my @cols = @{$row}; | |
440 | if ( scalar @cols == 0 ) { | |
441 | push @code, $self->_get_hline_code( $self->_RULE_INNER_ID, 1); | |
442 | next CENTER_ROW; | |
443 | } | |
444 | if ( $tbl->_row_is_latex_command($row) ) { | |
445 | push @code, $cols[0] . "\n"; | |
446 | next CENTER_ROW; | |
447 | } | |
448 | ||
449 | my $j = 0; | |
450 | ||
451 | for my $col (@cols) { | |
452 | if ( $tbl->get_header_sideways() ) { | |
453 | my $col_def = $tbl->_get_mc_def($col); | |
454 | $col_def->{value} | |
455 | = '\begin{sideways}' . $col_def->{value} . '\end{sideways}'; | |
456 | $col = $tbl->_get_mc_value($col_def); | |
457 | } | |
458 | #next if $col =~ m{\A \\ }xms; | |
459 | if ( $tbl->get_callback ) { | |
460 | $col = $tbl->_apply_callback( $i, $j, $col, 1 ); | |
461 | } | |
462 | $col = $tbl->_apply_header_formatting( $col, (!defined | |
463 | $theme->{STUB_ALIGN} || $j > 0) ); | |
464 | $j += $tbl->_extract_number_columns($col); | |
465 | } | |
466 | ||
467 | push @code, $tbl->_get_row_array( \@cols, $theme->{'HEADER_BG_COLOR'}, 1 ); | |
468 | $i++; | |
469 | } | |
470 | ||
471 | # without header, just draw the topline, not this midline | |
472 | if ($i) { | |
473 | push @code, $self->_get_hline_code( $self->_RULE_MID_ID ); | |
474 | } | |
475 | return $self->_align_code(\@code); | |
476 | } | |
477 | ||
478 | sub _get_tabletail_code { return q{}; } | |
479 | sub _get_xentrystretch_code { return q{}; } | |
480 | sub _get_tablehead_code { return q{}; } | |
481 | ||
482 | 1; | |
483 | __END__ | |
484 | ||
485 | =head1 NAME | |
486 | ||
487 | LaTeX::Table::Types::TypeI - Interface for LaTeX table types. | |
488 | ||
489 | =head1 SYNOPSIS | |
490 | ||
491 | =head1 DESCRIPTION | |
492 | ||
493 | This is the type interface (or L<Moose> role), that all type objects must use. | |
494 | L<LaTeX::Table> delegates the boring work of building the LaTeX code to type | |
495 | objects. It stores all information we have in easy to use L<"TEMPLATE | |
496 | VARIABLES">. L<LaTeX::Table> ships with very flexible templates, but you can | |
497 | also use the template variables defined here to build custom templates. | |
498 | ||
499 | =head1 INTERFACE | |
500 | ||
501 | =over | |
502 | ||
503 | =item C<generate_latex_code> | |
504 | ||
505 | =back | |
506 | ||
507 | =head1 TEMPLATE VARIABLES | |
508 | ||
509 | CAUTION: This API is not stable. If you build custom templates, they might not | |
510 | work in future versions! | |
511 | ||
512 | Most options are accessable here: | |
513 | ||
514 | =over | |
515 | ||
516 | =item C<CENTER, LEFT, RIGHT> | |
517 | ||
518 | Example: | |
519 | ||
520 | [% IF CENTER %]\centering | |
521 | [% END %] | |
522 | ||
523 | =item C<ENVIRONMENT, STAR, POSITION, SIDEWAYS> | |
524 | ||
525 | These options for floating environments are typically used like: | |
526 | ||
527 | [% IF ENVIRONMENT %]\begin{[% ENVIRONMENT %][% IF STAR %]*[% END %]}[% IF POSITION %][[% POSITION %]][% END %] | |
528 | ... | |
529 | [% END %] | |
530 | # the tabular environment here | |
531 | ... | |
532 | [% IF ENVIRONMENT %] ... | |
533 | \end{[% ENVIRONMENT %][% IF STAR %]*[% END %]}[% END %] | |
534 | ||
535 | =item C<CAPTION_TOP, CAPTION_CMD, SHORTCAPTION, CAPTION, CONTINUED, CONTINUEDMSG> | |
536 | ||
537 | The variables to build the caption command. Note that there is NO template for | |
538 | the C<maincaption> option. C<CAPTION> already includes this maincaption if | |
539 | specified. | |
540 | ||
541 | =item C<LABEL> | |
542 | ||
543 | The label: | |
544 | ||
545 | [% IF LABEL %]\label{[% LABEL %]}[% END %] | |
546 | ||
547 | =item C<TABULAR_ENVIRONMENT, WIDTH, COLDEF> | |
548 | ||
549 | These three options define the tabular environment: | |
550 | ||
551 | \begin{[% TABULAR_ENVIRONMENT %]}[% IF WIDTH %]{[% WIDTH %]}[% END %]{[% COLDEF %]} | |
552 | ||
553 | =back | |
554 | ||
555 | In addition, some variables already contain formatted LaTeX code: | |
556 | ||
557 | =over | |
558 | ||
559 | =item C<HEADER_CODE> | |
560 | ||
561 | The formatted header: | |
562 | ||
563 | \toprule | |
564 | \multicolumn{2}{c}{Item} & \\ | |
565 | \cmidrule(r){1-2} | |
566 | Animal & Description & Price \\ | |
567 | \midrule | |
568 | ||
569 | =item C<DATA_CODE> | |
570 | ||
571 | The formatted data: | |
572 | ||
573 | Gnat & per gram & 13.65 \\ | |
574 | & each & 0.01 \\ | |
575 | Gnu & stuffed & 92.59 \\ | |
576 | Emu & stuffed & 33.33 \\ | |
577 | Armadillo & frozen & 8.99 \\ | |
578 | \bottomrule | |
579 | ||
580 | =item C<FONTFAMILY_CODE, FONTSIZE_CODE> | |
581 | ||
582 | =item C<RESIZEBOX_BEGIN_CODE, RESIZEBOX_END_CODE> | |
583 | ||
584 | Everything between these two template variables is resized according the | |
585 | C<resizebox> option. | |
586 | ||
587 | =back | |
588 | ||
589 | =head1 SEE ALSO | |
590 | ||
591 | L<LaTeX::Table> | |
592 | ||
593 | The predefined templates: L<LaTeX::Table::Types::Std>, | |
594 | L<LaTeX::Table::Types::Ctable>, L<LaTeX::Table::Types::Xtab> | |
595 | ||
596 | =head1 AUTHOR | |
597 | ||
598 | Markus Riester C<< <mriester@gmx.de> >> | |
599 | ||
600 | =head1 LICENSE AND COPYRIGHT | |
601 | ||
602 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
603 | ||
604 | This module is free software; you can redistribute it and/or | |
605 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
606 | ||
607 | =cut | |
608 | ||
609 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | ############################################################################# | |
1 | # $Author: markus $ | |
2 | # $Date: 2009-05-20 21:07:28 +0200 (Wed, 20 May 2009) $ | |
3 | # $Revision: 1564 $ | |
4 | ############################################################################# | |
5 | ||
6 | package LaTeX::Table::Types::Xtab; | |
7 | use Moose; | |
8 | ||
9 | with 'LaTeX::Table::Types::TypeI'; | |
10 | ||
11 | use version; | |
12 | our ($VERSION) = '$Revision: 1564 $' =~ m{ \$Revision: \s+ (\S+) }xms; | |
13 | ||
14 | my $template =<<'EOT' | |
15 | { | |
16 | [%IF CONTINUED %]\addtocounter{table}{-1}[% END %][% DEFINE_COLORS_CODE %][% | |
17 | EXTRA_ROW_HEIGHT %][% RULES_WIDTH_GLOBAL %][% RULES_COLOR_GLOBAL %][% | |
18 | FONTSIZE_CODE %][% FONTFAMILY_CODE %][%IF SIDEWAYS %]\begin{landscape}[% END %][% IF CAPTION %][%IF CAPTION_TOP | |
19 | %]\topcaption[% ELSE %]\bottomcaption[% END %][%IF SHORTCAPTION %][[% SHORTCAPTION %]][% END %]{[% CAPTION %][% IF CONTINUED %] [% CONTINUEDMSG %][% END %]} | |
20 | [% END %][% XENTRYSTRETCH %][% IF LABEL %]\label{[% LABEL %]} | |
21 | [% END %] | |
22 | [% TABLEHEAD %] | |
23 | [% TABLETAIL %] | |
24 | [% TABLETAIL_LAST %] | |
25 | [% IF CENTER %]\begin{center} | |
26 | [% END %][% IF LEFT %]\begin{flushleft} | |
27 | [% END %][% IF RIGHT %]\begin{flushright} | |
28 | [% END %][% RESIZEBOX_BEGIN_CODE %]\begin{[% TABULAR_ENVIRONMENT %][% IF STAR %]*[% END %]}[% IF WIDTH %]{[%WIDTH %]}[% END %]{[% COLDEF %]} | |
29 | [% DATA_CODE %]\end{[% TABULAR_ENVIRONMENT %][% IF STAR %]*[% END %]} | |
30 | [% RESIZEBOX_END_CODE %][% IF CENTER %]\end{center}[% END %][% IF LEFT | |
31 | %]\end{flushleft}[% END %][% IF RIGHT %]\end{flushright}[% END %][% IF | |
32 | SIDEWAYS %]\end{landscape}[% END %] | |
33 | } | |
34 | EOT | |
35 | ; | |
36 | ||
37 | has '+_tabular_environment' => (default => 'xtabular'); | |
38 | has '+_template' => (default => $template); | |
39 | ||
40 | sub _get_tablehead_code { | |
41 | my ($self, $code) =@_; | |
42 | my $tbl = $self->_table_obj; | |
43 | ||
44 | my $tablehead = q{}; | |
45 | my @summary = $tbl->_get_data_summary(); | |
46 | ||
47 | if ( $tbl->get_caption_top && $tbl->get_tableheadmsg ) { | |
48 | my $continued_caption = '\\multicolumn{' | |
49 | . scalar(@summary) | |
50 | . '}{c}{{ \normalsize \tablename\ \thetable: ' | |
51 | . $tbl->get_tableheadmsg | |
52 | . "}}\\\\[\\abovecaptionskip]\n"; | |
53 | $tablehead | |
54 | = "\\tablefirsthead{$code}\n\\tablehead{$continued_caption$code}\n"; | |
55 | ||
56 | # $tablehead = "\\tablehead{$code}"; | |
57 | } | |
58 | else { | |
59 | $tablehead = "\\tablehead{$code}"; | |
60 | } | |
61 | return $tablehead; | |
62 | } | |
63 | ||
64 | ########################################################################### | |
65 | # Usage : $self->_get_tabletail_code(\@data, $final_tabletail); | |
66 | # Purpose : generates the LaTeX code of the xtab tabletail | |
67 | # Returns : LaTeX code | |
68 | # Parameters : the data columns and a flag indicating whether it is the | |
69 | # code for the final tail (1). | |
70 | ||
71 | sub _get_tabletail_code { | |
72 | my ( $self, $data, $final_tabletail ) = @_; | |
73 | ||
74 | my $tbl = $self->_table_obj; | |
75 | my $code; | |
76 | my $hlines = $tbl->get_theme_settings->{'HORIZONTAL_RULES'}; | |
77 | my $vlines = $tbl->get_theme_settings->{'VERTICAL_RULES'}; | |
78 | my $linecode1 = $self->_get_hline_code($self->_RULE_MID_ID); | |
79 | my $linecode2 = $self->_get_hline_code($self->_RULE_BOTTOM_ID); | |
80 | ||
81 | # if custom table tail is defined, then return it | |
82 | if ( $tbl->get_tabletail ) { | |
83 | $code = $tbl->get_tabletail; | |
84 | } | |
85 | elsif ( !$final_tabletail ) { | |
86 | my @cols = $tbl->_get_data_summary(); | |
87 | my $nu_cols = scalar @cols; | |
88 | ||
89 | my $v0 = q{|} x $vlines->[0]; | |
90 | $code = "$linecode1\\multicolumn{$nu_cols}{${v0}r$v0}{{" | |
91 | . $tbl->get_tabletailmsg | |
92 | . "}} \\\\\n"; | |
93 | } | |
94 | if ($final_tabletail) { | |
95 | return '\tablelasttail{}'; | |
96 | } | |
97 | return "\\tabletail{$code$linecode2}"; | |
98 | } | |
99 | ||
100 | sub _get_xentrystretch_code { | |
101 | my ($self) = @_; | |
102 | my $tbl = $self->_table_obj; | |
103 | if ( $tbl->get_xentrystretch ) { | |
104 | my $xs = $tbl->get_xentrystretch(); | |
105 | if ( $xs !~ /\A-?(?:\d+(?:\.\d*)?|\.\d+)\z/xms ) { | |
106 | $tbl->invalid_option_usage( 'xentrystretch', | |
107 | 'Not a number: ' . $tbl->get_xentrystretch ); | |
108 | } | |
109 | return "\\xentrystretch{$xs}\n"; | |
110 | } | |
111 | return q{}; | |
112 | } | |
113 | ||
114 | ||
115 | 1; | |
116 | __END__ | |
117 | ||
118 | =head1 NAME | |
119 | ||
120 | LaTeX::Table::Types::Xtab - Create multi-page LaTeX tables with the xtabular package. | |
121 | ||
122 | =head1 INTERFACE | |
123 | ||
124 | =over | |
125 | ||
126 | =item C<generate_latex_code> | |
127 | ||
128 | =back | |
129 | ||
130 | =head1 SEE ALSO | |
131 | ||
132 | L<LaTeX::Table>, L<LaTeX::Table::Types::TypeI> | |
133 | ||
134 | =head1 AUTHOR | |
135 | ||
136 | Markus Riester C<< <mriester@gmx.de> >> | |
137 | ||
138 | =head1 LICENSE AND COPYRIGHT | |
139 | ||
140 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
141 | ||
142 | This module is free software; you can redistribute it and/or | |
143 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
144 | ||
145 | =cut | |
146 | ||
147 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | ############################################################################# | |
1 | # $Author: markus $ | |
2 | # $Date: 2009-05-29 10:13:11 +0200 (Fri, 29 May 2009) $ | |
3 | # $Revision: 1615 $ | |
4 | ############################################################################# | |
5 | ||
6 | package LaTeX::Table; | |
7 | ||
8 | use strict; | |
9 | use warnings; | |
10 | ||
11 | use Moose::Policy 'Moose::Policy::FollowPBP'; | |
12 | use Moose; | |
13 | ||
14 | use version; our $VERSION = qv('0.9.15'); | |
15 | ||
16 | use LaTeX::Table::Types::Std; | |
17 | use LaTeX::Table::Types::Xtab; | |
18 | use LaTeX::Table::Types::Ctable; | |
19 | use LaTeX::Table::Types::Longtable; | |
20 | ||
21 | use Carp; | |
22 | use Scalar::Util qw(reftype); | |
23 | use English qw( -no_match_vars ); | |
24 | ||
25 | use Module::Pluggable | |
26 | search_path => 'LaTeX::Table::Themes', | |
27 | sub_name => 'themes', | |
28 | except => 'LaTeX::Table::Themes::ThemeI', | |
29 | instantiate => 'new'; | |
30 | ||
31 | for my $attr ( | |
32 | qw(label maincaption shortcaption caption caption_top coldef coldef_strategy | |
33 | columns_like_header continued text_wrap header_sideways width maxwidth width_environment | |
34 | custom_tabular_environment position fontsize fontfamily callback tabletail xentrystretch | |
35 | resizebox sideways star _data_summary) | |
36 | ) | |
37 | { | |
38 | has $attr => ( is => 'rw', default => 0 ); | |
39 | } | |
40 | ||
41 | has 'custom_template' => ( is => 'rw', isa => 'Str', default => 0 ); | |
42 | has 'filename' => ( is => 'rw', isa => 'Str', default => 'latextable.tex' ); | |
43 | has 'foottable' => ( is => 'rw', isa => 'Str', default => q{} ); | |
44 | has 'type' => ( is => 'rw', default => 'std' ); | |
45 | has '_type_obj' => ( is => 'rw' ); | |
46 | has 'header' => ( is => 'rw', default => sub { [] } ); | |
47 | has 'data' => ( is => 'rw', default => sub { [] } ); | |
48 | has 'environment' => ( is => 'rw', default => 1 ); | |
49 | has 'theme' => ( is => 'rw', default => 'Meyrin' ); | |
50 | has 'predef_themes' => ( is => 'rw', default => sub { {} } ); | |
51 | has 'custom_themes' => ( is => 'rw', default => sub { {} } ); | |
52 | ||
53 | for my $attr (qw(center left right _default_align)) { | |
54 | has $attr => ( is => 'rw', isa => 'Bool', predicate => "has_$attr" ); | |
55 | } | |
56 | ||
57 | has 'continuedmsg' => ( is => 'rw', default => '(continued)' ); | |
58 | has 'tabletailmsg' => ( is => 'rw', default => 'Continued on next page' ); | |
59 | has 'tableheadmsg' => | |
60 | ( is => 'rw', default => 'Continued from previous page' ); | |
61 | ||
62 | # deprecated | |
63 | has 'table_environment' => ( is => 'rw', default => 'deprecated' ); | |
64 | has 'tabledef' => ( is => 'rw', default => 'deprecated' ); | |
65 | has 'tabledef_strategy' => ( is => 'rw', default => 'deprecated' ); | |
66 | has 'tablepos' => ( is => 'rw', default => 'deprecated' ); | |
67 | has 'size' => ( is => 'rw', default => 'deprecated' ); | |
68 | ||
69 | __PACKAGE__->meta->make_immutable; | |
70 | ||
71 | ########################################################################### | |
72 | # Usage : $table->generate_string(); | |
73 | # Purpose : generates LaTex data | |
74 | # Returns : code | |
75 | # Parameters : node | |
76 | # Throws : | |
77 | # Comments : n/a | |
78 | # See also : | |
79 | ||
80 | sub generate_string { | |
81 | my ( $self, @args ) = @_; | |
82 | ||
83 | # support for < 0.9.3 API | |
84 | $self->_compatibility_layer(@args); | |
85 | ||
86 | # are the user provided options ok? | |
87 | $self->_check_options(); | |
88 | ||
89 | # analyze the data | |
90 | $self->_calc_data_summary( $self->get_data ); | |
91 | ||
92 | if ( $self->get_type eq 'xtab' ) { | |
93 | $self->set__type_obj( | |
94 | LaTeX::Table::Types::Xtab->new( _table_obj => $self ) ); | |
95 | } | |
96 | elsif ( $self->get_type eq 'longtable' ) { | |
97 | $self->set__type_obj( | |
98 | LaTeX::Table::Types::Longtable->new( _table_obj => $self ) ); | |
99 | } | |
100 | elsif ( $self->get_type eq 'ctable' ) { | |
101 | $self->set__type_obj( | |
102 | LaTeX::Table::Types::Ctable->new( _table_obj => $self ) ); | |
103 | } | |
104 | else { | |
105 | $self->set__type_obj( | |
106 | LaTeX::Table::Types::Std->new( _table_obj => $self ) ); | |
107 | } | |
108 | ||
109 | my $code = $self->get__type_obj->generate_latex_code( $self->get_header, | |
110 | $self->get_data ); | |
111 | ||
112 | return $code; | |
113 | } | |
114 | ||
115 | sub _load_themes { | |
116 | my ($self) = @_; | |
117 | my %defs; | |
118 | ||
119 | for my $theme_obj ( $self->themes ) { | |
120 | %defs = ( %defs, %{ $theme_obj->_definition } ); | |
121 | } | |
122 | $self->set_predef_themes( \%defs ); | |
123 | return; | |
124 | } | |
125 | ||
126 | sub _compatibility_layer { | |
127 | my ( $self, @args ) = @_; | |
128 | if ( $self->get_tablepos ne 'deprecated' ) { | |
129 | carp('DEPRECATED: Use position instead of tablepos.'); | |
130 | $self->set_position( $self->get_tablepos ); | |
131 | } | |
132 | if ( $self->get_table_environment ne 'deprecated' ) { | |
133 | carp('DEPRECATED: Use environment instead of table_environment.'); | |
134 | $self->set_environment( $self->get_table_environment ); | |
135 | } | |
136 | if ( $self->get_tabledef ne 'deprecated' ) { | |
137 | carp('DEPRECATED: Use coldef instead of tabledef.'); | |
138 | $self->set_coldef( $self->get_tabledef ); | |
139 | } | |
140 | if ( $self->get_tabledef_strategy ne 'deprecated' ) { | |
141 | carp('DEPRECATED: Use coldef_strategy instead of tabledef_strategy.'); | |
142 | $self->set_coldef_strategy( $self->get_tabledef_strategy ); | |
143 | } | |
144 | if ( $self->get_size ne 'deprecated' ) { | |
145 | carp('DEPRECATED: size was renamed to fontsize.'); | |
146 | $self->set_fontsize( $self->get_size ); | |
147 | } | |
148 | my $cs = $self->get_coldef_strategy(); | |
149 | ||
150 | if ( $cs && defined reftype $cs && reftype $cs eq 'HASH' ) { | |
151 | if ( defined $cs->{'DEFAULT'} ) { | |
152 | carp( 'DEPRECATED: DEFAULT in coldef_strategy was renamed to ' | |
153 | . 'DEFAULT_COL.' ); | |
154 | $cs->{'DEFAULT_COL'} = $cs->{'DEFAULT'}; | |
155 | delete $cs->{'DEFAULT'}; | |
156 | } | |
157 | if ( defined $cs->{'DEFAULT_X'} ) { | |
158 | carp( 'DEPRECATED: DEFAULT_X in coldef_strategy was renamed to ' | |
159 | . 'DEFAULT_COL_X.' ); | |
160 | $cs->{'DEFAULT_COL_X'} = $cs->{'DEFAULT_X'}; | |
161 | delete $cs->{'DEFAULT_X'}; | |
162 | } | |
163 | if ( defined $cs->{'IS_A_NUMBER'} ) { | |
164 | carp( 'DEPRECATED: IS_A_NUMBER in coldef_strategy was renamed to ' | |
165 | . 'NUMBER.' ); | |
166 | $cs->{'NUMBER'} = $cs->{'IS_A_NUMBER'}; | |
167 | delete $cs->{'IS_A_NUMBER'}; | |
168 | } | |
169 | if ( defined $cs->{'IS_LONG'} ) { | |
170 | carp( 'DEPRECATED: IS_LONG in coldef_strategy was renamed to ' | |
171 | . 'LONG and is now a regex. Converting it.' ); | |
172 | $cs->{'LONG'} = qr{\A \s* .{$cs->{'IS_LONG'},}? \s* \z}xms; | |
173 | delete $cs->{'IS_LONG'}; | |
174 | } | |
175 | $self->set_coldef_strategy($cs); | |
176 | } | |
177 | return if !defined $args[0]; | |
178 | if ( reftype $args[0] eq 'ARRAY' ) { | |
179 | carp('DEPRECATED. Use options header and data instead.'); | |
180 | $self->set_header( $args[0] ); | |
181 | if ( reftype $args[1] eq 'ARRAY' ) { | |
182 | $self->set_data( $args[1] ); | |
183 | } | |
184 | } | |
185 | return; | |
186 | } | |
187 | ||
188 | sub _row_is_latex_command { | |
189 | my ( $self, $row ) = @_; | |
190 | if ( scalar( @{$row} ) == 1 && $row->[0] =~ m{\A \s* \\ }xms ) { | |
191 | return 1; | |
192 | } | |
193 | return 0; | |
194 | } | |
195 | ||
196 | sub invalid_option_usage { | |
197 | my ( $self, $option, $msg ) = @_; | |
198 | croak "Invalid usage of option $option: $msg."; | |
199 | } | |
200 | ||
201 | sub _check_options { | |
202 | my ($self) = @_; | |
203 | ||
204 | # default floating enviromnent is table | |
205 | if ( $self->get_environment eq '1' ) { | |
206 | $self->set_environment('table'); | |
207 | } | |
208 | ||
209 | # check header and data | |
210 | $self->_check_2d_array( $self->get_header, 'header' ); | |
211 | $self->_check_2d_array( $self->get_data, 'data' ); | |
212 | ||
213 | if ( $self->get_callback && reftype $self->get_callback ne 'CODE' ) { | |
214 | $self->invalid_option_usage( 'callback', 'Not a code reference' ); | |
215 | } | |
216 | if ( $self->get_columns_like_header ) { | |
217 | $self->_check_1d_array( $self->get_columns_like_header, | |
218 | q{}, 'columns_like_header' ); | |
219 | } | |
220 | if ( $self->get_resizebox ) { | |
221 | $self->_check_1d_array( $self->get_resizebox, q{}, 'resizebox' ); | |
222 | } | |
223 | if ( $self->get_type eq 'xtab' && !$self->get_environment ) { | |
224 | $self->invalid_option_usage( 'environment', | |
225 | 'xtab requires an environment' ); | |
226 | } | |
227 | if ( $self->get_type eq 'xtab' && $self->get_position ) { | |
228 | $self->invalid_option_usage( 'position', | |
229 | 'xtab does not support position' ); | |
230 | } | |
231 | ||
232 | # handle default values by ourselves | |
233 | if ( $self->get_width_environment eq 'tabular*' ) { | |
234 | $self->set_width_environment(0); | |
235 | } | |
236 | ||
237 | $self->_check_align; | |
238 | ||
239 | if ( $self->get_maincaption && $self->get_shortcaption ) { | |
240 | $self->invalid_option_usage( 'maincaption, shortcaption', | |
241 | 'only one allowed.' ); | |
242 | } | |
243 | if ( !$self->get_width && $self->get_type ne 'longtable' && $self->get_width_environment eq 'tabularx' ) { | |
244 | $self->invalid_option_usage( 'width_environment', | |
245 | 'Is tabularx and width is unset' ); | |
246 | } | |
247 | if ( !$self->get_width && $self->get_width_environment eq 'tabulary' ) { | |
248 | $self->invalid_option_usage( 'width_environment', | |
249 | 'Is tabulary and width is unset' ); | |
250 | } | |
251 | return; | |
252 | } | |
253 | ||
254 | sub _check_align { | |
255 | my ($self) = @_; | |
256 | my $cnt_def_alignments = 0; | |
257 | my $cnt_true_alignments = 0; | |
258 | ||
259 | if ( $self->has_center ) { | |
260 | $cnt_def_alignments++; | |
261 | } | |
262 | if ( $self->has_right ) { | |
263 | $cnt_def_alignments++; | |
264 | } | |
265 | if ( $self->has_left ) { | |
266 | $cnt_def_alignments++; | |
267 | } | |
268 | if ( $self->get_center ) { | |
269 | $cnt_true_alignments++; | |
270 | } | |
271 | if ( $self->get_right ) { | |
272 | $cnt_true_alignments++; | |
273 | } | |
274 | if ( $self->get_left ) { | |
275 | $cnt_true_alignments++; | |
276 | } | |
277 | ||
278 | if ( $cnt_true_alignments > 1 ) { | |
279 | $self->invalid_option_usage( 'center, left, right', | |
280 | 'only one allowed.' ); | |
281 | } | |
282 | if ( $cnt_def_alignments == 0 ) { | |
283 | $self->set__default_align(1); | |
284 | } | |
285 | else { | |
286 | $self->set__default_align(0); | |
287 | } | |
288 | return; | |
289 | } | |
290 | ||
291 | sub _apply_callback { | |
292 | my ( $self, $i, $j, $value, $is_header ) = @_; | |
293 | my $col_cb = $self->_get_mc_def($value); | |
294 | $col_cb->{value} | |
295 | = &{ $self->get_callback }( $i, $j, $col_cb->{value}, $is_header ); | |
296 | return $self->_get_mc_value($col_cb); | |
297 | } | |
298 | ||
299 | sub _examine_data { | |
300 | my ($self) = @_; | |
301 | my $text_wrap = $self->get_text_wrap; | |
302 | my @data = @{ $self->get_data }; | |
303 | if ( $self->get_callback ) { | |
304 | for my $i ( 0 .. $#data ) { | |
305 | my @row = @{ $data[$i] }; | |
306 | my $k = 0; | |
307 | for my $j ( 0 .. ( scalar @{ $data[$i] } - 1 ) ) { | |
308 | $row[$j] = $self->_apply_callback( $i, $k, $data[$i][$j], 0 ); | |
309 | $k += $self->_extract_number_columns( $data[$i][$j] ); | |
310 | } | |
311 | $data[$i] = \@row; | |
312 | } | |
313 | } | |
314 | return @data | |
315 | } | |
316 | ||
317 | sub _ioerror { | |
318 | my ( $self, $function, $error ) = @_; | |
319 | croak "IO error: Can't $function '" . $self->get_filename . "': $error"; | |
320 | } | |
321 | ||
322 | sub generate { | |
323 | my ( $self, $header, $data ) = @_; | |
324 | my $code = $self->generate_string( $header, $data ); | |
325 | open my $LATEX, '>', $self->get_filename | |
326 | or $self->_ioerror( 'open', $OS_ERROR ); | |
327 | print {$LATEX} $code | |
328 | or $self->_ioerror( 'write', $OS_ERROR ); | |
329 | close $LATEX | |
330 | or $self->_ioerror( 'close', $OS_ERROR ); | |
331 | return 1; | |
332 | } | |
333 | ||
334 | sub _default_coldef_strategy { | |
335 | my ($self) = @_; | |
336 | my $STRATEGY = { | |
337 | MISSING_VALUE => qr{\A \s* \z}xms, | |
338 | NUMBER => | |
339 | qr{\A\s*([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?\s*\z}xms, | |
340 | NUMBER_MUST_MATCH_ALL => 1, | |
341 | LONG => qr{\A \s* (?=\w+\s+\w+).{29,}? \S}xms, | |
342 | LONG_MUST_MATCH_ALL => 0, | |
343 | NUMBER_COL => 'r', | |
344 | NUMBER_COL_X => 'r', | |
345 | LONG_COL => 'p{5cm}', | |
346 | LONG_COL_X => 'X', | |
347 | LONG_COL_Y => 'L', | |
348 | DEFAULT_COL => 'l', | |
349 | DEFAULT_COL_X => 'l', | |
350 | }; | |
351 | $self->set_coldef_strategy($STRATEGY); | |
352 | return $STRATEGY; | |
353 | } | |
354 | ||
355 | sub _check_coldef_strategy { | |
356 | my ( $self, $strategy ) = @_; | |
357 | my $rt_strategy = reftype $strategy; | |
358 | if ( !defined $rt_strategy || $rt_strategy ne 'HASH' ) { | |
359 | $self->invalid_option_usage( 'coldef_strategy', | |
360 | 'Not a hash reference' ); | |
361 | } | |
362 | my $default = $self->_default_coldef_strategy; | |
363 | for my $key ( keys %{$default} ) { | |
364 | if ( !defined $strategy->{$key} ) { | |
365 | $strategy->{$key} = $default->{$key}; | |
366 | } | |
367 | } | |
368 | ||
369 | $self->set_coldef_strategy($strategy); | |
370 | ||
371 | my @coltypes = $self->_get_coldef_types(); | |
372 | for my $type (@coltypes) { | |
373 | if ( !defined $strategy->{"${type}_COL"} ) { | |
374 | $self->invalid_option_usage( 'coldef_strategy', | |
375 | "Missing column attribute ${type}_COL for $type" ); | |
376 | } | |
377 | if ( !defined $strategy->{"${type}_MUST_MATCH_ALL"} ) { | |
378 | $strategy->{"${type}_MUST_MATCH_ALL"} = 1; | |
379 | } | |
380 | } | |
381 | return; | |
382 | } | |
383 | ||
384 | sub _extract_number_columns { | |
385 | my ( $self, $col ) = @_; | |
386 | my $def = $self->_get_mc_def($col); | |
387 | if ( defined $def->{cols} ) { | |
388 | return $def->{cols}; | |
389 | } | |
390 | else { | |
391 | return 1; | |
392 | } | |
393 | } | |
394 | ||
395 | sub _get_coldef_types { | |
396 | my ($self) = @_; | |
397 | ||
398 | # everything that does not contain an underscore is a coltype | |
399 | my @coltypes = | |
400 | sort grep {m{ \A [^_]+ \z }xms} keys %{ $self->get_coldef_strategy }; | |
401 | ||
402 | return @coltypes; | |
403 | } | |
404 | ||
405 | sub _get_data_summary { | |
406 | my ($self) = @_; | |
407 | return @{ $self->get__data_summary() }; | |
408 | } | |
409 | ||
410 | ########################################################################### | |
411 | # Usage : $self->_get_data_summary(\@data); | |
412 | # Purpose : find out how many columns we need and if column consists of | |
413 | # numbers only | |
414 | # Returns : an array with one entry for every column. Entry is either 1 | |
415 | # (column is numerical) or 0. | |
416 | # Parameters : data columns | |
417 | # Throws : | |
418 | # Comments : n/a | |
419 | # See also : | |
420 | ||
421 | sub _calc_data_summary { | |
422 | my ( $self, $data ) = @_; | |
423 | my $max_col_number = 0; | |
424 | my $strategy = $self->get_coldef_strategy; | |
425 | if ( !$strategy ) { | |
426 | $strategy = $self->_default_coldef_strategy; | |
427 | } | |
428 | else { | |
429 | $self->_check_coldef_strategy($strategy); | |
430 | } | |
431 | my %matches; | |
432 | my %cells; | |
433 | ||
434 | my @coltypes = $self->_get_coldef_types(); | |
435 | ||
436 | ROW: | |
437 | for my $row ( @{$data} ) { | |
438 | if ( scalar @{$row} == 0 || $self->_row_is_latex_command($row) ) { | |
439 | next ROW; | |
440 | } | |
441 | if ( scalar @{$row} > $max_col_number ) { | |
442 | $max_col_number = scalar @{$row}; | |
443 | } | |
444 | my $i = 0; | |
445 | COL: | |
446 | for my $col ( @{$row} ) { | |
447 | next COL if $col =~ $strategy->{MISSING_VALUE}; | |
448 | ||
449 | for my $coltype (@coltypes) { | |
450 | if ( $col =~ $strategy->{$coltype} ) { | |
451 | $matches{$i}{$coltype}++; | |
452 | } | |
453 | } | |
454 | $cells{$i}++; | |
455 | $i += $self->_extract_number_columns($col); | |
456 | } | |
457 | } | |
458 | my @summary; | |
459 | for my $i ( 0 .. $max_col_number - 1 ) { | |
460 | my $type_of_this_col = 'DEFAULT'; | |
461 | for my $coltype (@coltypes) { | |
462 | if (defined $matches{$i}{$coltype} | |
463 | && ( !$strategy->{"${coltype}_MUST_MATCH_ALL"} | |
464 | || $cells{$i} == $matches{$i}{$coltype} ) | |
465 | ) | |
466 | { | |
467 | $type_of_this_col = $coltype; | |
468 | } | |
469 | } | |
470 | push @summary, $type_of_this_col; | |
471 | } | |
472 | $self->set__data_summary( \@summary ); | |
473 | return; | |
474 | } | |
475 | ||
476 | sub _apply_header_formatting { | |
477 | my ( $self, $col, $aligning ) = @_; | |
478 | my $theme = $self->get_theme_settings; | |
479 | if ( $aligning | |
480 | && defined $theme->{'HEADER_CENTERED'} | |
481 | && $theme->{'HEADER_CENTERED'} ) | |
482 | { | |
483 | $col = $self->_add_mc_def( | |
484 | { value => $col, align => 'c', cols => '1' } ); | |
485 | } | |
486 | if ( length $col ) { | |
487 | if ( defined $theme->{'HEADER_FONT_STYLE'} ) { | |
488 | $col = $self->_add_font_family( $col, | |
489 | $theme->{'HEADER_FONT_STYLE'} ); | |
490 | } | |
491 | if ( defined $theme->{'HEADER_FONT_COLOR'} ) { | |
492 | $col = $self->_add_font_color( $col, | |
493 | $theme->{'HEADER_FONT_COLOR'} ); | |
494 | } | |
495 | } | |
496 | return $col; | |
497 | } | |
498 | ||
499 | sub _get_cell_bg_color { | |
500 | my ( $self, $row_bg_color, $col_id ) = @_; | |
501 | my $cell_bg_color = $row_bg_color; | |
502 | if ( $self->get_columns_like_header ) { | |
503 | HEADER_COLUMN: | |
504 | for my $i ( @{ $self->get_columns_like_header } ) { | |
505 | if ( $i == $col_id ) { | |
506 | $cell_bg_color | |
507 | = $self->get_theme_settings->{'HEADER_BG_COLOR'}; | |
508 | last HEADER_COLUMN; | |
509 | } | |
510 | } | |
511 | } | |
512 | return $cell_bg_color; | |
513 | } | |
514 | ||
515 | ########################################################################### | |
516 | # Usage : $self->_get_row_code($cols_ref); | |
517 | # Purpose : generate the LaTeX code of a row | |
518 | # Returns : LaTeX code | |
519 | # Parameters : the columns | |
520 | # Throws : | |
521 | # Comments : n/a | |
522 | # See also : | |
523 | ||
524 | sub _get_row_array { | |
525 | my ( $self, $cols_ref, $bgcolor, $is_header ) = @_; | |
526 | my @cols_defs = map { $self->_get_mc_def($_) } @{$cols_ref}; | |
527 | my @cols = (); | |
528 | my $theme = $self->get_theme_settings; | |
529 | my $vlines = $theme->{'VERTICAL_RULES'}; | |
530 | my $v0 = q{|} x $vlines->[0]; | |
531 | my $v1 = q{|} x $vlines->[1]; | |
532 | my $v2 = q{|} x $vlines->[2]; | |
533 | my $j = 0; | |
534 | my $col_id = 0; | |
535 | for my $col_def (@cols_defs) { | |
536 | if ( !$is_header && $self->get_columns_like_header ) { | |
537 | HEADER_COLUMN: | |
538 | for my $i ( @{ $self->get_columns_like_header } ) { | |
539 | next HEADER_COLUMN if $i != $col_id; | |
540 | $col_def = $self->_get_mc_def( | |
541 | $self->_apply_header_formatting( | |
542 | $self->_get_mc_value($col_def), 0 | |
543 | ) | |
544 | ); | |
545 | if ( !defined $col_def->{cols} ) { | |
546 | my @summary = $self->_get_data_summary(); | |
547 | $col_def->{cols} = 1; | |
548 | $col_def->{align} | |
549 | = $self->get_coldef_strategy->{ $summary[$col_id] | |
550 | . $self->_get_coldef_type_col_suffix }; | |
551 | } | |
552 | } | |
553 | } | |
554 | if ( defined $col_def->{cols} ) { | |
555 | my $vl_pre = q{}; | |
556 | my $vl_post = q{}; | |
557 | ||
558 | if ( $j == 0 ) { | |
559 | $vl_pre = $v0; | |
560 | } | |
561 | ||
562 | if ( $j == ( scalar(@cols_defs) - 1 ) ) { | |
563 | $vl_post = $v0; | |
564 | } | |
565 | elsif ( $j == 0 && $col_def->{cols} == 1 ) { | |
566 | $vl_post = $v1; | |
567 | } | |
568 | else { | |
569 | $vl_post = $v2; | |
570 | } | |
571 | ||
572 | my $color_code = q{}; | |
573 | ||
574 | my $cell_bg_color | |
575 | = $self->_get_cell_bg_color( $bgcolor, $col_id ); | |
576 | if ( defined $cell_bg_color ) { | |
577 | $color_code = '>{\columncolor{' . $cell_bg_color . '}}'; | |
578 | } | |
579 | ||
580 | push @cols, | |
581 | '\\multicolumn{' | |
582 | . $col_def->{cols} . '}{' | |
583 | . $vl_pre | |
584 | . $color_code | |
585 | . $col_def->{align} | |
586 | . $vl_post . '}{' | |
587 | . $col_def->{value} . '}'; | |
588 | ||
589 | $col_id += $col_def->{cols}; | |
590 | } | |
591 | else { | |
592 | push @cols, $col_def->{value}; | |
593 | $col_id++; | |
594 | } | |
595 | $j++; | |
596 | } | |
597 | if ( defined $bgcolor ) { | |
598 | ||
599 | # @cols has always at least one element, otherwise we draw a line | |
600 | $cols[0] = "\\rowcolor{$bgcolor}" . $cols[0]; | |
601 | } | |
602 | return \@cols; | |
603 | } | |
604 | ||
605 | sub _get_row_code { | |
606 | my ( $self, $cols_ref, $bgcolor, $is_header ) = @_; | |
607 | my $cols = $self->_get_row_array( $cols_ref, $bgcolor, $is_header ); | |
608 | return join( ' & ', @{$cols} ) . "\\\\\n"; | |
609 | } | |
610 | ||
611 | sub _add_mc_def { | |
612 | my ( $self, $arg_ref ) = @_; | |
613 | my $def = $self->_get_mc_def( $arg_ref->{value} ); | |
614 | if ( defined $def->{cols} ) { | |
615 | return $arg_ref->{value}; | |
616 | } | |
617 | else { | |
618 | return $self->_get_mc_value($arg_ref); | |
619 | } | |
620 | } | |
621 | ||
622 | sub _get_mc_value { | |
623 | my ( $self, $def ) = @_; | |
624 | if ( defined $def->{cols} ) { | |
625 | return $def->{value} . q{:} . $def->{cols} . $def->{align}; | |
626 | } | |
627 | else { | |
628 | return $def->{value}; | |
629 | } | |
630 | } | |
631 | ||
632 | sub _get_mc_def { | |
633 | my ( $self, $value ) = @_; | |
634 | if ( $value =~ m{ \A (.*)\:(\d)([clr]) \z }xms ) { | |
635 | return { value => $1, cols => $2, align => $3 }; | |
636 | } | |
637 | else { | |
638 | return { value => $value }; | |
639 | } | |
640 | } | |
641 | ||
642 | ############################################################################### | |
643 | # Usage : $self->_add_font_family($col, 'bf'); | |
644 | # Purpose : add font family to column value | |
645 | # Returns : new column value | |
646 | # Parameters : column value and family (tt, bf, it, sc) | |
647 | # Throws : exception when family is not known | |
648 | ||
649 | sub _add_font_family { | |
650 | my ( $self, $col, $family ) = @_; | |
651 | my %know_families = ( tt => 1, bf => 1, it => 1, sc => 1 ); | |
652 | if ( !defined $know_families{$family} ) { | |
653 | $self->invalid_option_usage( | |
654 | 'custom_themes', | |
655 | "Family not known: $family. Valid families are: " . join ', ', | |
656 | sort keys %know_families | |
657 | ); | |
658 | } | |
659 | my $col_def = $self->_get_mc_def($col); | |
660 | $col_def->{value} = "\\text$family" . '{' . $col_def->{value} . '}'; | |
661 | return $self->_get_mc_value($col_def); | |
662 | } | |
663 | ||
664 | ############################################################################### | |
665 | # Usage : $self->_add_font_color($col, $color); | |
666 | # Purpose : add font color to column value | |
667 | # Returns : new column value | |
668 | # Parameters : column value and color | |
669 | ||
670 | sub _add_font_color { | |
671 | my ( $self, $col, $color ) = @_; | |
672 | my $col_def = $self->_get_mc_def($col); | |
673 | $col_def->{value} = "\\color{$color}" . $col_def->{value}; | |
674 | return $self->_get_mc_value($col_def); | |
675 | } | |
676 | ||
677 | sub _get_coldef_type_col_suffix { | |
678 | my ($self) = @_; | |
679 | if ( $self->get_width_environment eq 'tabularx' | |
680 | || $self->get_type eq 'ctable' ) | |
681 | { | |
682 | return '_COL_X'; | |
683 | } | |
684 | if ( $self->get_width_environment eq 'tabulary' ) { | |
685 | return '_COL_Y'; | |
686 | } | |
687 | return '_COL'; | |
688 | } | |
689 | ||
690 | ########################################################################### | |
691 | # Usage : $self->_get_coldef_code(\@data); | |
692 | # Purpose : generate the LaTeX code of the column definitions (e.g. | |
693 | # |l|r|r|r|) | |
694 | # Returns : LaTeX code | |
695 | # Parameters : the data columns | |
696 | # Comments : Tries to be intelligent. Hope it is ;) | |
697 | ||
698 | sub _get_coldef_code { | |
699 | my ( $self, $data ) = @_; | |
700 | my @cols = $self->_get_data_summary(); | |
701 | my $vlines = $self->get_theme_settings->{'VERTICAL_RULES'}; | |
702 | ||
703 | my $v0 = q{|} x $vlines->[0]; | |
704 | my $v1 = q{|} x $vlines->[1]; | |
705 | my $v2 = q{|} x $vlines->[2]; | |
706 | ||
707 | my $table_def = q{}; | |
708 | my $i = 0; | |
709 | my $strategy = $self->get_coldef_strategy(); | |
710 | my $typesuffix = $self->_get_coldef_type_col_suffix(); | |
711 | ||
712 | my @attributes = grep {m{ _COL }xms} keys %{$strategy}; | |
713 | ||
714 | for my $col (@cols) { | |
715 | ||
716 | # align text right, numbers left, first col always left | |
717 | my $align; | |
718 | ||
719 | for my $attribute ( sort @attributes ) { | |
720 | if ( $attribute =~ m{ \A $col $typesuffix \z }xms ) { | |
721 | $align = $strategy->{$attribute}; | |
722 | ||
723 | # for _X and _Y, use default if no special defs are found | |
724 | } | |
725 | elsif ( ( $typesuffix eq '_COL_X' || $typesuffix eq '_COL_Y' ) | |
726 | && $attribute =~ m{ \A $col _COL \z }xms ) | |
727 | { | |
728 | $align = $strategy->{$attribute}; | |
729 | } | |
730 | } | |
731 | ||
732 | if ( $i == 0 ) { | |
733 | if ( defined $self->get_theme_settings->{'STUB_ALIGN'} ) { | |
734 | $align = $self->get_theme_settings->{'STUB_ALIGN'}; | |
735 | } | |
736 | $table_def .= $v0 . $align . $v1; | |
737 | } | |
738 | elsif ( $i == ( scalar(@cols) - 1 ) ) { | |
739 | $table_def .= $align . $v0; | |
740 | } | |
741 | else { | |
742 | $table_def .= $align . $v2; | |
743 | } | |
744 | $i++; | |
745 | if ( $i == 1 | |
746 | && $self->get_width | |
747 | && !$self->get_width_environment | |
748 | && $self->get_type ne 'ctable' ) | |
749 | { | |
750 | $table_def .= '@{\extracolsep{\fill}}'; | |
751 | } | |
752 | } | |
753 | return $table_def; | |
754 | } | |
755 | ||
756 | ########################################################################### | |
757 | # Usage : $self->get_theme_settings(); | |
758 | # Purpose : return an hash reference with all settings of the current | |
759 | # theme | |
760 | # Returns : see purpose | |
761 | # Parameters : none | |
762 | # Throws : exception if theme is unknown | |
763 | # See also : get_available_themes(); | |
764 | ||
765 | sub get_theme_settings { | |
766 | my ($self) = @_; | |
767 | ||
768 | my $themes = $self->get_available_themes(); | |
769 | if ( defined $themes->{ $self->get_theme } ) { | |
770 | return $themes->{ $self->get_theme }; | |
771 | } | |
772 | $self->invalid_option_usage( 'theme', 'Not known: ' . $self->get_theme ); | |
773 | return; | |
774 | } | |
775 | ||
776 | sub _check_1d_array { | |
777 | my ( $self, $arr_ref_1d, $desc, $option ) = @_; | |
778 | if ( !defined reftype $arr_ref_1d || reftype $arr_ref_1d ne 'ARRAY' ) { | |
779 | $self->invalid_option_usage( $option, | |
780 | "${desc}Not an array reference" ); | |
781 | } | |
782 | return; | |
783 | } | |
784 | ||
785 | sub _check_2d_array { | |
786 | my ( $self, $arr_ref_2d, $desc ) = @_; | |
787 | $self->_check_1d_array( $arr_ref_2d, q{}, $desc ); | |
788 | my $i = 0; | |
789 | for my $arr_ref ( @{$arr_ref_2d} ) { | |
790 | $self->_check_1d_array( $arr_ref, "$desc\[$i\] ", $desc ); | |
791 | my $j = 0; | |
792 | for my $scalar ( @{$arr_ref} ) { | |
793 | my $rt_scalar = reftype $scalar; | |
794 | if ( defined $rt_scalar ) { | |
795 | $self->invalid_option_usage( $desc, | |
796 | "$desc\[$i\]\[$j\] not a scalar" ); | |
797 | } | |
798 | if ( !defined $scalar ) { | |
799 | $self->invalid_option_usage( $desc, | |
800 | "Undefined value in $desc\[$i\]\[$j\]" ); | |
801 | } | |
802 | $j++; | |
803 | } | |
804 | $i++; | |
805 | } | |
806 | return; | |
807 | } | |
808 | ||
809 | ########################################################################### | |
810 | # Usage : $self->get_available_themes(); | |
811 | # Purpose : return an hash reference with all available themes | |
812 | # (predefined and custom) | |
813 | # Returns : see purpose | |
814 | # Parameters : none | |
815 | # Throws : no exceptions | |
816 | # See also : get_theme_settings() | |
817 | ||
818 | sub get_available_themes { | |
819 | my ($self) = @_; | |
820 | $self->_load_themes(); | |
821 | return { | |
822 | ( %{ $self->get_predef_themes }, %{ $self->get_custom_themes } ) }; | |
823 | } | |
824 | ||
825 | no Moose; | |
826 | 1; # Magic true value required at end of module | |
827 | __END__ | |
828 | ||
829 | =head1 NAME | |
830 | ||
831 | LaTeX::Table - Perl extension for the automatic generation of LaTeX tables. | |
832 | ||
833 | =head1 VERSION | |
834 | ||
835 | This document describes LaTeX::Table version 0.9.15 | |
836 | ||
837 | =head1 SYNOPSIS | |
838 | ||
839 | use LaTeX::Table; | |
840 | use Number::Format qw(:subs); # use mighty CPAN to format values | |
841 | ||
842 | my $header = [ | |
843 | [ 'Item:2c', '' ], | |
844 | [ '\cmidrule(r){1-2}' ], | |
845 | [ 'Animal', 'Description', 'Price' ], | |
846 | ]; | |
847 | ||
848 | my $data = [ | |
849 | [ 'Gnat', 'per gram', '13.65' ], | |
850 | [ '', 'each', '0.0173' ], | |
851 | [ 'Gnu', 'stuffed', '92.59' ], | |
852 | [ 'Emu', 'stuffed', '33.33' ], | |
853 | [ 'Armadillo', 'frozen', '8.99' ], | |
854 | ]; | |
855 | ||
856 | my $table = LaTeX::Table->new( | |
857 | { | |
858 | filename => 'prices.tex', | |
859 | maincaption => 'Price List', | |
860 | caption => 'Try our special offer today!', | |
861 | label => 'table:prices', | |
862 | position => 'htb', | |
863 | header => $header, | |
864 | data => $data, | |
865 | } | |
866 | ); | |
867 | ||
868 | # write LaTeX code in prices.tex | |
869 | $table->generate(); | |
870 | ||
871 | # callback functions help you to format values easily (as | |
872 | # a great alternative to LaTeX packages like rccol) | |
873 | # | |
874 | # Here, the first colum and the header is printed in upper | |
875 | # case and the third colum is formatted with format_price() | |
876 | $table->set_callback(sub { | |
877 | my ($row, $col, $value, $is_header ) = @_; | |
878 | if ($col == 0 || $is_header) { | |
879 | $value = uc $value; | |
880 | } | |
881 | elsif ($col == 2 && !$is_header) { | |
882 | $value = format_price($value, 2, ''); | |
883 | } | |
884 | return $value; | |
885 | }); | |
886 | ||
887 | print $table->generate_string(); | |
888 | ||
889 | Now in your LaTeX document: | |
890 | ||
891 | \documentclass{article} | |
892 | ||
893 | % for multipage tables (xtab or longtable) | |
894 | \usepackage{xtab} | |
895 | %\usepackage{longtable} | |
896 | ||
897 | % for publication quality tables (Meyrin theme, the default) | |
898 | \usepackage{booktabs} | |
899 | % for the NYC theme | |
900 | \usepackage{array} | |
901 | \usepackage{colortbl} | |
902 | \usepackage{xcolor} | |
903 | ||
904 | \begin{document} | |
905 | \input{prices} | |
906 | \end{document} | |
907 | ||
908 | =head1 DESCRIPTION | |
909 | ||
910 | LaTeX makes professional typesetting easy. Unfortunately, this is not entirely | |
911 | true for tables and the standard LaTeX table macros have a rather limited | |
912 | functionality. This module supports many CTAN packages and hides the | |
913 | complexity of using them behind an easy and intuitive API. | |
914 | ||
915 | =head1 FEATURES | |
916 | ||
917 | This module supports multipage tables via the C<xtab> or the C<longtable> | |
918 | package. For publication quality tables, it uses the C<booktabs> package. It | |
919 | also supports the C<tabularx> and C<tabulary> packages for nicer fixed-width | |
920 | tables. Furthermore, it supports the C<colortbl> package for colored tables | |
921 | optimized for presentations. The powerful new C<ctable> package is supported | |
922 | and especially recommended when footnotes are needed. C<LaTeX::Table> ships | |
923 | with some predefined, good looking L<"THEMES">. The program I<ltpretty> makes | |
924 | it possible to use this module from within a text editor. | |
925 | ||
926 | =head1 INTERFACE | |
927 | ||
928 | =over | |
929 | ||
930 | =item C<my $table = LaTeX::Table-E<gt>new($arg_ref)> | |
931 | ||
932 | Constructs a C<LaTeX::Table> object. The parameter is an hash reference with | |
933 | options (see below). | |
934 | ||
935 | =item C<$table-E<gt>generate()> | |
936 | ||
937 | Generates the LaTeX table code. The generated LaTeX table can be included in | |
938 | a LaTeX document with the C<\input> command: | |
939 | ||
940 | % include prices.tex, generated by LaTeX::Table | |
941 | \input{prices} | |
942 | ||
943 | =item C<$table-E<gt>generate_string()> | |
944 | ||
945 | Same as generate() but instead of creating a LaTeX file, this returns the LaTeX code | |
946 | as string. | |
947 | ||
948 | my $latexcode = $table->generate_string(); | |
949 | ||
950 | =item C<$table-E<gt>get_available_themes()> | |
951 | ||
952 | Returns an hash reference to all available themes. See L<"THEMES"> for | |
953 | details. | |
954 | ||
955 | for my $theme ( keys %{ $table->get_available_themes } ) { | |
956 | ... | |
957 | } | |
958 | ||
959 | =item C<$table-E<gt>search_path( add =E<gt> "MyThemes" );> | |
960 | ||
961 | C<LaTeX::Table> will search under the C<LaTeX::Table::Themes::> namespace for | |
962 | themes. You can add here an additional search path. Inherited from | |
963 | L<Module::Pluggable>. | |
964 | ||
965 | =back | |
966 | ||
967 | =head1 OPTIONS | |
968 | ||
969 | Options can be defined in the constructor hash reference or with the setter | |
970 | C<set_optionname>. Additionally, getters of the form C<get_optionname> are | |
971 | created. | |
972 | ||
973 | =head2 BASIC OPTIONS | |
974 | ||
975 | =over | |
976 | ||
977 | =item C<filename> | |
978 | ||
979 | The name of the LaTeX output file. Default is 'latextable.tex'. | |
980 | ||
981 | =item C<type> | |
982 | ||
983 | Can be 'std' for standard LaTeX tables, 'ctable' for tables using the | |
984 | C<ctable> package or 'xtab' and 'longtable' for multipage tables | |
985 | (requires the C<xtab> and C<longtable> LaTeX | |
986 | packages, respectively). | |
987 | ||
988 | =item C<header> | |
989 | ||
990 | The header. It is a reference to an array (the rows) of array references (the | |
991 | columns). | |
992 | ||
993 | $table->set_header([ [ 'Animal', 'Price' ] ]); | |
994 | ||
995 | will produce following header: | |
996 | ||
997 | +--------+-------+ | |
998 | | Animal | Price | | |
999 | +--------+-------+ | |
1000 | ||
1001 | Here an example for a multirow header: | |
1002 | ||
1003 | $table->set_header([ [ 'Animal', 'Price' ], ['', '(roughly)' ] ]); | |
1004 | ||
1005 | This code will produce this header: | |
1006 | ||
1007 | +--------+-----------+ | |
1008 | | Animal | Price | | |
1009 | | | (roughly) | | |
1010 | +--------+-----------+ | |
1011 | ||
1012 | Single column rows that start with a backslash are treated as LaTeX commands | |
1013 | and are not further formatted. So, | |
1014 | ||
1015 | my $header = [ | |
1016 | [ 'Item:2c', '' ], | |
1017 | ['\cmidrule{1-2}'], | |
1018 | [ 'Animal', 'Description', 'Price' ] | |
1019 | ]; | |
1020 | ||
1021 | will produce following LaTeX code in the Zurich theme: | |
1022 | ||
1023 | \multicolumn{2}{c}{\textbf{Item}} & \\ | |
1024 | \cmidrule{1-2} | |
1025 | \textbf{Animal} & \multicolumn{1}{c}{\textbf{Description}} & \multicolumn{1}{c}{\textbf{Price}}\\ | |
1026 | ||
1027 | Note that there is no C<\multicolumn>, C<\textbf> or C<\\> added to the second row. | |
1028 | ||
1029 | =item C<data> | |
1030 | ||
1031 | The data. Once again a reference to an array (rows) of array references | |
1032 | (columns). | |
1033 | ||
1034 | $table->set_data([ [ 'Gnu', '92.59' ], [ 'Emu', '33.33' ] ]); | |
1035 | ||
1036 | And you will get a table like this: | |
1037 | ||
1038 | +-------+---------+ | |
1039 | | Gnu | 92.59 | | |
1040 | | Emu | 33.33 | | |
1041 | +-------+---------+ | |
1042 | ||
1043 | An empty column array will produce a horizontal rule (line): | |
1044 | ||
1045 | $table->set_data([ [ 'Gnu', '92.59' ], [], [ 'Emu', '33.33' ] ]); | |
1046 | ||
1047 | Now you will get such a table: | |
1048 | ||
1049 | +-------+---------+ | |
1050 | | Gnu | 92.59 | | |
1051 | +-------+---------+ | |
1052 | | Emu | 33.33 | | |
1053 | +-------+---------+ | |
1054 | ||
1055 | This works also in C<header>. | |
1056 | ||
1057 | Single column rows starting with a backslash are again printed without any | |
1058 | formatting. So, | |
1059 | ||
1060 | $table->set_data([ [ 'Gnu', '92.59' ], ['\hline'], [ 'Emu', '33.33' ] ]); | |
1061 | ||
1062 | is equivalent to the example above (except that there always the correct rule | |
1063 | command is used, i.e. C<\midrule> vs. C<\hline>). | |
1064 | ||
1065 | =item C<custom_template> | |
1066 | ||
1067 | The table types listed above use the L<Template> toolkit internally. These | |
1068 | type tempates are very flexible and powerful, but you can also provide a | |
1069 | custom template: | |
1070 | ||
1071 | # Returns the header and data formatted in LaTeX code. Nothing else. | |
1072 | $table->set_custom_template('[% HEADER_CODE %][% DATA_CODE %]'); | |
1073 | ||
1074 | See L<LaTeX::Table::Types::TypeI>. | |
1075 | ||
1076 | =back | |
1077 | ||
1078 | =head2 FLOATING TABLES | |
1079 | ||
1080 | =over | |
1081 | ||
1082 | =item C<environment> | |
1083 | ||
1084 | If get_environment() returns a true value, then a floating environment will be | |
1085 | generated. For I<std> tables, the default environment is 'table'. A true value different | |
1086 | from '1' will be used as environment name. Default is 1 (use a 'table' | |
1087 | environment). | |
1088 | ||
1089 | The non-floating I<xtab> environment is mandatory (get_environment() must | |
1090 | return a true value here) and supports all options in this section except | |
1091 | for C<position>. | |
1092 | ||
1093 | The I<ctable> type automatically adds an environment when any of the | |
1094 | following options are set. | |
1095 | ||
1096 | =item C<caption> | |
1097 | ||
1098 | The caption of the table. Only generated if get_caption() returns a true value. | |
1099 | Default is 0. Requires C<environment>. | |
1100 | ||
1101 | =item C<caption_top> | |
1102 | ||
1103 | If get_caption_top() returns a true value, then the caption is placed above the | |
1104 | table. To use the standard caption command (C<\caption> in I<std> and | |
1105 | I<longtable>, C<\topcaption> in I<xtab>) , use | |
1106 | ||
1107 | ... | |
1108 | caption_top => 1, | |
1109 | ... | |
1110 | ||
1111 | You can specify an alternative command here: | |
1112 | ||
1113 | ... | |
1114 | caption_top => 'topcaption', # would require the topcapt package | |
1115 | ||
1116 | Or even multiple commands: | |
1117 | ||
1118 | caption_top => | |
1119 | '\setlength{\abovecaptionskip}{0pt}\setlength{\belowcaptionskip}{10pt}\caption', | |
1120 | ... | |
1121 | ||
1122 | Default 0 (caption below the table) because the spacing in the standard LaTeX | |
1123 | macros is optimized for bottom captions. At least for multipage tables, | |
1124 | however, top captions are highly recommended. You can use the C<caption> | |
1125 | LaTeX package to fix the spacing: | |
1126 | ||
1127 | \usepackage[tableposition=top]{caption} | |
1128 | ||
1129 | =item C<maincaption> | |
1130 | ||
1131 | If get_maincaption() returns a true value, then this value will be displayed | |
1132 | in the table listing (C<\listoftables>) and before the C<caption>. For example, | |
1133 | ||
1134 | maincaption => 'Price List', | |
1135 | caption => 'Try our special offer today!', | |
1136 | ||
1137 | will generate | |
1138 | ||
1139 | \caption[Price List]{Price List. Try our special offer today!} | |
1140 | ||
1141 | Themes can set the font family of the maincaption. | |
1142 | ||
1143 | Default 0. Requires C<environment>. | |
1144 | ||
1145 | =item C<shortcaption> | |
1146 | ||
1147 | Same as C<maincaption>, but does not appear in the caption, only in the table | |
1148 | listing. Default 0. Requires C<environment>. | |
1149 | ||
1150 | =item C<continued> | |
1151 | ||
1152 | If true, then the table counter will be decremented by one and the | |
1153 | C<continuedmsg> is appended to the caption. Useful for splitting tables. Default 0. | |
1154 | ||
1155 | $table->set_continued(1); | |
1156 | ||
1157 | =item C<continuedmsg> | |
1158 | ||
1159 | If get_continued() returns a true value, then this text is appended to the | |
1160 | caption. Default '(continued)'. | |
1161 | ||
1162 | =item C<center>, C<right>, C<left> | |
1163 | ||
1164 | Defines how the table is aligned in the available textwidth. Default is centered. Requires | |
1165 | C<environment>. Only one of these options may return a true value. | |
1166 | ||
1167 | # don't generate any aligning code | |
1168 | $table->set_center(0); | |
1169 | ||
1170 | =item C<label> | |
1171 | ||
1172 | The label of the table. Only generated if get_label() returns a true value. | |
1173 | Default is 0. Requires C<environment>. | |
1174 | ||
1175 | $table->set_label('tbl:prices'); | |
1176 | ||
1177 | =item C<position> | |
1178 | ||
1179 | The position of the environment, e.g. 'htb'. Only generated if get_position() | |
1180 | returns a true value. Default 0. Requires C<environment> and tables of C<type> | |
1181 | I<std>. | |
1182 | ||
1183 | =item C<sideways> | |
1184 | ||
1185 | Rotates the environment by 90 degrees. Default 0. For tables of C<type> I<std> | |
1186 | and I<ctable>, this requires the C<rotating> LaTeX package, for I<xtab> or | |
1187 | I<longtable> tables the C<lscape> package. | |
1188 | ||
1189 | $table->set_sideways(1); | |
1190 | ||
1191 | =item C<star> | |
1192 | ||
1193 | Use the starred versions of the environments, which place the float over two | |
1194 | columns when the C<twocolumn> option or the C<\twocolumn> command is active. | |
1195 | Default 0. | |
1196 | ||
1197 | $table->set_star(1); | |
1198 | ||
1199 | =item C<fontfamily> | |
1200 | ||
1201 | Valid values are 'rm' (Roman, serif), 'sf' (Sans-serif), 'tt' (Monospace or | |
1202 | typewriter) and 0. Default is 0 (does not define a font family). Requires | |
1203 | C<environment>. | |
1204 | ||
1205 | =item C<fontsize> | |
1206 | ||
1207 | Valid values are 'tiny', 'scriptsize', 'footnotesize', 'small', 'normal', | |
1208 | 'large', 'Large', 'LARGE', 'huge', 'Huge' and 0. Default is 0 (does not define | |
1209 | a font size). Requires C<environment>. | |
1210 | ||
1211 | =back | |
1212 | ||
1213 | =head2 TABULAR ENVIRONMENT | |
1214 | ||
1215 | =over | |
1216 | ||
1217 | =item C<custom_tabular_environment> | |
1218 | ||
1219 | If get_custom_tabular_environment() returns a true value, then this specified | |
1220 | environment is used instead of the standard environments 'tabular' (I<std>) | |
1221 | 'longtable' (I<longtable>) or 'xtabular' (I<xtab>). For I<xtab> tables, you | |
1222 | can also use the 'mpxtabular' environment here if you need footnotes. See the | |
1223 | documentation of the C<xtab> package. | |
1224 | ||
1225 | See also the documentation of C<width> below for cases when a width is | |
1226 | specified. | |
1227 | ||
1228 | =item C<coldef> | |
1229 | ||
1230 | The table column definition, e.g. 'lrcr' which would result in: | |
1231 | ||
1232 | \begin{tabular}{lrcr} | |
1233 | .. | |
1234 | ||
1235 | If unset, C<LaTeX::Table> tries to guess a good definition. Columns containing | |
1236 | only numbers are right-justified, others left-justified. Columns with cells | |
1237 | longer than 30 characters are I<p> (paragraph) columns of size '5cm' (I<X> | |
1238 | columns when the C<tabularx>, I<L> when the C<tabulary> package is selected). | |
1239 | These rules can be changed with set_coldef_strategy(). Default is 0 (guess | |
1240 | good definition). The left-hand column, the stub, is normally exculded here | |
1241 | and is always left aligned. See L<LaTeX::Table::Themes::ThemeI>. | |
1242 | ||
1243 | =item C<coldef_strategy> | |
1244 | ||
1245 | Controls the behaviour of the C<coldef> calculation when get_coldef() | |
1246 | does not return a true value. It is a reference to a hash that contains | |
1247 | regular expressions that define the I<types> of the columns. For example, | |
1248 | the standard types I<NUMBER> and I<LONG> are defined as: | |
1249 | ||
1250 | { | |
1251 | NUMBER => | |
1252 | qr{\A\s*([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?\s*\z}xms, | |
1253 | NUMBER_MUST_MATCH_ALL => 1, | |
1254 | NUMBER_COL => 'r', | |
1255 | LONG => qr{\A\s*(?=\w+\s+\w+).{29,}?\S}xms, | |
1256 | LONG_MUST_MATCH_ALL => 0, | |
1257 | LONG_COL => 'p{5cm}', | |
1258 | LONG_COL_X => 'X', | |
1259 | LONG_COL_Y => 'L', | |
1260 | }; | |
1261 | ||
1262 | =over | |
1263 | ||
1264 | =item C<TYPE =E<gt> $regex> | |
1265 | ||
1266 | New types are defined with the regular expression C<$regex>. All B<cells> that | |
1267 | match this regular expression have type I<TYPE>. A cell can have multiple | |
1268 | types. The name of a type is not allowed to contain underscores (C<_>). | |
1269 | ||
1270 | =item C<TYPE_MUST_MATCH_ALL> | |
1271 | ||
1272 | This defines if whether a B<column> has type I<TYPE> when all B<cells> | |
1273 | are of type I<TYPE> or at least one. Default is C<1> (C<$regex> must match | |
1274 | all). | |
1275 | ||
1276 | Note that columns can have only one type. Types are applied alphabetically, | |
1277 | so for example a I<LONG> I<NUMBER> column has as final type I<NUMBER>. | |
1278 | ||
1279 | =item C<TYPE_COL> | |
1280 | ||
1281 | The C<coldef> attribute for I<TYPE> columns. Required (no default value). | |
1282 | ||
1283 | =item C<TYPE_COL_X>, C<TYPE_COL_Y> | |
1284 | ||
1285 | Same as C<TYPE_COL> but for C<tabularx> or C<tabulary> tables. If undefined, | |
1286 | the attribute defined in C<TYPE_COL> is used. | |
1287 | ||
1288 | =item C<DEFAULT_COL>, C<DEFAULT_COL_X>, C<DEFAULT_COL_Y> | |
1289 | ||
1290 | The C<coldef> attribute for columns that do not match any specified type. | |
1291 | Default 'l' (left-justified). | |
1292 | ||
1293 | =item C<MISSING_VALUE> | |
1294 | ||
1295 | Column values that match the specified regular expression are omitted in the | |
1296 | C<coldef> calculation. Default is C<qr{\A \s* \z}xms>. | |
1297 | ||
1298 | =back | |
1299 | ||
1300 | Examples: | |
1301 | ||
1302 | # change standard types | |
1303 | $table->set_coldef_strategy({ | |
1304 | NUMBER => qr{\A \s* \d+ \s* \z}xms, # integers only | |
1305 | LONG_COL => '>{\raggedright\arraybackslash}p{7cm}', # non-justified | |
1306 | }); | |
1307 | ||
1308 | # add new types (here: columns that contain only URLs) | |
1309 | $table->set_coldef_strategy({ | |
1310 | URL => qr{\A \s* http }xms, | |
1311 | URL_COL => '>{\ttfamily}l', | |
1312 | }); | |
1313 | ||
1314 | ||
1315 | ||
1316 | =item C<width> | |
1317 | ||
1318 | If get_width() returns a true value, then C<LaTeX::Table> will use the starred | |
1319 | version of the environment (e.g. C<tabular*> or C<xtabular*>) and will add the | |
1320 | specified width as second parameter. It will also add | |
1321 | C<@{\extracolsep{\fill}}> to the table column definition: | |
1322 | ||
1323 | # use 75% of textwidth | |
1324 | $table->set_width('0.75\textwidth'); | |
1325 | ||
1326 | This will produce following LaTeX code: | |
1327 | ||
1328 | \begin{tabular*}{0.75\textwidth}{l@{\extracolsep{\fill} ... } | |
1329 | ||
1330 | For tables of C<type> I<std>, it is also possible to use the C<tabularx> and | |
1331 | C<tabulary> LaTeX packages (see C<width_environment> below). The tables of type I<ctable> | |
1332 | automatically use the C<tabularx> package. | |
1333 | ||
1334 | =item C<width_environment> | |
1335 | ||
1336 | If get_width() (see above) returns a true value and table is of C<type> I<std>, | |
1337 | then this option provides the possibility to add a custom tabular environment | |
1338 | that supports a table width: | |
1339 | ||
1340 | \begin{environment}{width}{def} | |
1341 | ||
1342 | To use for example the one provided by the C<tabularx> LaTeX package, write: | |
1343 | ||
1344 | # use the tabularx package (for a std table) | |
1345 | $table->set_width('300pt'); | |
1346 | $table->set_width_environment('tabularx'); | |
1347 | ||
1348 | Note this will not add C<@{\extracolsep{\fill}}> and that this overwrites | |
1349 | a C<custom_tabular_environment>. | |
1350 | ||
1351 | It is possible to use C<tabularx> together with tables of type I<longtable>. | |
1352 | In this case, you have to generate a I<file> and then load the table with the | |
1353 | C<LTXtable> command (C<ltxtable> package): | |
1354 | ||
1355 | $table = LaTeX::Table->new( | |
1356 | { header => $header, | |
1357 | data => $data, | |
1358 | filename => 'mylongtable.tex' | |
1359 | type => 'longtable', | |
1360 | ... | |
1361 | center => 0, | |
1362 | width_environment => 'tabularx', | |
1363 | } | |
1364 | ); | |
1365 | ||
1366 | Then in LaTeX: | |
1367 | ||
1368 | \begin{center} | |
1369 | \LTXtable{0.8\textwidth}{mylongtable} | |
1370 | \end{center} | |
1371 | ||
1372 | Note that we have to do the centering and specification of the width in LaTeX. | |
1373 | ||
1374 | Default is 0 (see C<width>). | |
1375 | ||
1376 | =item C<maxwidth> | |
1377 | ||
1378 | Only supported by tables of type I<ctable>. | |
1379 | ||
1380 | =item C<callback> | |
1381 | ||
1382 | If get_callback() returns a true value and the return value is a code reference, | |
1383 | then this callback function will be called for every column in C<header> | |
1384 | and C<data>. The return value of this function is then printed instead of the | |
1385 | column value. | |
1386 | ||
1387 | The passed arguments are C<$row>, C<$col> (both starting with 0), C<$value> and | |
1388 | C<$is_header>. | |
1389 | ||
1390 | use LaTeX::Encode; | |
1391 | use Number::Format qw(:subs); | |
1392 | ... | |
1393 | ||
1394 | # use LaTeX::Encode to encode LaTeX special characters, | |
1395 | # format the third column with Format::Number (only the data) | |
1396 | my $table = LaTeX::Table->new( | |
1397 | { header => $header, | |
1398 | data => $data, | |
1399 | callback => sub { | |
1400 | my ( $row, $col, $value, $is_header ) = @_; | |
1401 | if ( $col == 2 && !$is_header ) { | |
1402 | $value = format_price($value, 2, ''); | |
1403 | } | |
1404 | else { | |
1405 | $value = latex_encode($value); | |
1406 | } | |
1407 | return $value; | |
1408 | }, | |
1409 | } | |
1410 | ); | |
1411 | ||
1412 | =item C<foottable> | |
1413 | ||
1414 | Only supported by tables of type C<ctable>. The footnote C<\tnote> commands. | |
1415 | See the documentation of the C<ctable> LaTeX package. | |
1416 | ||
1417 | $table->set_foottable('\tnote{footnotes are placed under the table}'); | |
1418 | ||
1419 | =item C<resizebox> | |
1420 | ||
1421 | If get_resizebox() returns a true value, then the resizebox command is used to | |
1422 | resize the table. Takes as argument a reference to an array. The first element | |
1423 | is the desired width. If a second element is not given, then the hight is set to | |
1424 | a value so that the aspect ratio is still the same. Requires the C<graphicx> | |
1425 | LaTeX package. Default 0. | |
1426 | ||
1427 | $table->set_resizebox([ '0.6\textwidth' ]); | |
1428 | ||
1429 | $table->set_resizebox([ '300pt', '200pt' ]); | |
1430 | ||
1431 | ||
1432 | =back | |
1433 | ||
1434 | =head2 MULTIPAGE TABLES | |
1435 | ||
1436 | =over | |
1437 | ||
1438 | =item C<tableheadmsg> | |
1439 | ||
1440 | When get_caption_top() and get_tableheadmsg() both return true values, then | |
1441 | additional captions are printed on the continued pages. Default caption text | |
1442 | is 'Continued from previous page'. | |
1443 | ||
1444 | =item C<tabletailmsg> | |
1445 | ||
1446 | Message at the end of a multipage table. Default is 'Continued on next page'. | |
1447 | When using C<caption_top>, this is in most cases unnecessary and it is | |
1448 | recommended to omit the tabletail (see below). | |
1449 | ||
1450 | =item C<tabletail> | |
1451 | ||
1452 | Custom table tail. Default is multicolumn with the tabletailmsg (see above) | |
1453 | right-justified. | |
1454 | ||
1455 | # don't add any tabletail code: | |
1456 | $table->set_tabletail(q{}); | |
1457 | ||
1458 | =item C<xentrystretch> | |
1459 | ||
1460 | Option for xtab. Play with this option if the number of rows per page is not | |
1461 | optimal. Requires a number as parameter. Default is 0 (does not use this option). | |
1462 | ||
1463 | $table->set_xentrystretch(-0.1); | |
1464 | ||
1465 | =back | |
1466 | ||
1467 | =head2 THEMES | |
1468 | ||
1469 | =over | |
1470 | ||
1471 | =item C<theme> | |
1472 | ||
1473 | The name of the theme. Default is I<Meyrin> (requires C<booktabs> LaTeX | |
1474 | package). | |
1475 | ||
1476 | See L<LaTeX::Table::Themes::ThemeI> how to define custom themes. | |
1477 | ||
1478 | The themes are defined in L<LaTeX::Table::Themes::Beamer>, | |
1479 | L<LaTeX::Table::Themes::Booktabs>, L<LaTeX::Table::Themes::Classic>, | |
1480 | L<LaTeX::Table::Themes::Modern>. | |
1481 | ||
1482 | $table->set_theme('Zurich'); | |
1483 | ||
1484 | =item C<predef_themes> | |
1485 | ||
1486 | All predefined themes. Getter only. | |
1487 | ||
1488 | =item C<custom_themes> | |
1489 | ||
1490 | All custom themes. See L<LaTeX::Table::Themes::ThemeI>. | |
1491 | ||
1492 | =item C<columns_like_header> | |
1493 | ||
1494 | Takes as argument a reference to an array with column ids (again, starting | |
1495 | with 0). These columns are formatted like header columns. | |
1496 | ||
1497 | # a "transposed" table ... | |
1498 | my $table = LaTeX::Table->new( | |
1499 | { data => $data, | |
1500 | columns_like_header => [ 0 ], } | |
1501 | ); | |
1502 | ||
1503 | =item C<header_sideways> | |
1504 | ||
1505 | If get_header_sideways() returns a true value, then the header columns will | |
1506 | be rotated by 90 degrees. Requires the C<rotating> LaTeX package. Does not | |
1507 | affect data columns specified in columns_like_header(). If you do not want to | |
1508 | rotate all headers, use a callback function B<instead>: | |
1509 | ||
1510 | ... | |
1511 | header_sideways => 0, | |
1512 | callback => sub { | |
1513 | my ( $row, $col, $value, $is_header ) = @_; | |
1514 | if ( $col != 0 && $is_header ) { | |
1515 | $value = '\begin{sideways}' . $value . '\end{sideways}'; | |
1516 | } | |
1517 | return $value; | |
1518 | } | |
1519 | ... | |
1520 | ||
1521 | =back | |
1522 | ||
1523 | =head1 MULTICOLUMNS | |
1524 | ||
1525 | Multicolumns are defined in LaTeX with | |
1526 | C<\multicolumn{$cols}{$alignment}{$text}>. This module supports a simple | |
1527 | shortcut of the format C<$text:$cols$alignment>. For example, C<Item:2c> is | |
1528 | equivalent to C<\multicolumn{2}{c}{Item}>. Note that vertical rules (C<|>) are | |
1529 | automatically added here according the rules settings in the theme. See | |
1530 | L<LaTeX::Table::Themes::ThemeI>. C<LaTeX::Table> also uses this shortcut to | |
1531 | determine the column ids. So in this example, | |
1532 | ||
1533 | my $data = [ [' \multicolumn{2}{c}{A}', 'B' ], [ 'C:2c', 'D' ] ]; | |
1534 | ||
1535 | 'B' would have an column id of 1 and 'D' 2 ('A' and 'C' both 0). This is important | |
1536 | for callback functions and for the coldef calculation. | |
1537 | See L<"TABULAR ENVIRONMENT">. | |
1538 | ||
1539 | =head1 EXAMPLES | |
1540 | ||
1541 | See I<examples/examples.pdf> in this distribution for a short tutorial that | |
1542 | covers the main features of this module. See also the example application | |
1543 | I<csv2pdf> for an example of the common task of converting a CSV (or Excel) | |
1544 | file to LaTeX or even PDF. | |
1545 | ||
1546 | =head1 DIAGNOSTICS | |
1547 | ||
1548 | If you get a LaTeX error message, please check whether you have included all | |
1549 | required packages. The packages we use are C<array>, C<booktabs>, C<colortbl>, | |
1550 | C<ctable>, C<graphicx>, C<longtable>, C<lscape>, C<rotating>, C<tabularx>, | |
1551 | C<tabulary>, C<xcolor> and C<xtab>. | |
1552 | ||
1553 | C<LaTeX::Table> may throw one of these errors and warnings: | |
1554 | ||
1555 | =over | |
1556 | ||
1557 | =item C<IO error: Can't ...> | |
1558 | ||
1559 | In method generate(), it was not possible to write the LaTeX code to | |
1560 | C<filename>. | |
1561 | ||
1562 | =item C<Invalid usage of option ...> | |
1563 | ||
1564 | See the examples in this document and in I<examples/examples.pdf> for the | |
1565 | correct usage of this option. | |
1566 | ||
1567 | =item C<DEPRECATED. ...> | |
1568 | ||
1569 | There were some minor API changes in C<LaTeX::Table> 0.1.0, 0.8.0, 0.9.0, | |
1570 | 0.9.3 and 0.9.12. Just apply the changes to the script or contact its author. | |
1571 | ||
1572 | B<Important Note:> 0.9.15 will be the last version that includes deprecated | |
1573 | code. | |
1574 | ||
1575 | =back | |
1576 | ||
1577 | =head1 CONFIGURATION AND ENVIRONMENT | |
1578 | ||
1579 | C<LaTeX::Table> requires no configuration files or environment variables. | |
1580 | ||
1581 | =head1 DEPENDENCIES | |
1582 | ||
1583 | L<Carp>, L<Module::Pluggable>, L<Moose>, L<English>, L<Scalar::Util>, | |
1584 | L<Template>, L<Text::Wrap> | |
1585 | ||
1586 | =head1 BUGS AND LIMITATIONS | |
1587 | ||
1588 | The width option causes problems with themes using the C<colortbl> package. | |
1589 | You may have to specify here the overhang arguments of the C<\columcolor> | |
1590 | commands manually. Patches are of course welcome. | |
1591 | ||
1592 | Please report any bugs or feature requests to | |
1593 | C<bug-latex-table@rt.cpan.org>, or through the web interface at | |
1594 | L<http://rt.cpan.org>. | |
1595 | ||
1596 | =head1 SEE ALSO | |
1597 | ||
1598 | L<Data::Table>, L<LaTeX::Encode> | |
1599 | ||
1600 | =head1 CREDITS | |
1601 | ||
1602 | =over | |
1603 | ||
1604 | =item David Carlisle for the C<colortbl>, C<longtable>, <ltxtable>, | |
1605 | C<tabularx> and C<tabulary> LaTeX packages. | |
1606 | ||
1607 | =item Wybo Dekker for the C<ctable> LaTeX package. | |
1608 | ||
1609 | =item Simon Fear for the C<booktabs> LaTeX package. The L<"SYNOPSIS"> table is | |
1610 | the example in his documentation. | |
1611 | ||
1612 | =item Andrew Ford (ANDREWF) for many great suggestions. He also wrote | |
1613 | L<LaTeX::Driver> and L<LaTeX::Encode> which are used by I<csv2pdf>. | |
1614 | ||
1615 | =item Lapo Filippo Mori for the excellent tutorial I<Tables in LaTeX2e: | |
1616 | Packages and Methods>. | |
1617 | ||
1618 | =item Peter Wilson for the C<xtab> LaTeX package. | |
1619 | ||
1620 | =back | |
1621 | ||
1622 | =head1 AUTHOR | |
1623 | ||
1624 | Markus Riester C<< <mriester@gmx.de> >> | |
1625 | ||
1626 | =head1 LICENSE AND COPYRIGHT | |
1627 | ||
1628 | Copyright (c) 2006-2009, Markus Riester C<< <mriester@gmx.de> >>. | |
1629 | ||
1630 | This module is free software; you can redistribute it and/or | |
1631 | modify it under the same terms as Perl itself. See L<perlartistic>. | |
1632 | ||
1633 | =head1 DISCLAIMER OF WARRANTY | |
1634 | ||
1635 | BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |
1636 | FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |
1637 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |
1638 | PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER | |
1639 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
1640 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE | |
1641 | ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH | |
1642 | YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL | |
1643 | NECESSARY SERVICING, REPAIR, OR CORRECTION. | |
1644 | ||
1645 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |
1646 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |
1647 | REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE | |
1648 | LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, | |
1649 | OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE | |
1650 | THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING | |
1651 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A | |
1652 | FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF | |
1653 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | |
1654 | SUCH DAMAGES. | |
1655 | ||
1656 | =cut | |
1657 | ||
1658 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | use Test::More tests => 11; | |
1 | use Test::NoWarnings; | |
2 | ||
3 | BEGIN { | |
4 | use_ok( 'LaTeX::Table' ); | |
5 | use_ok( 'LaTeX::Table::Themes::ThemeI' ); | |
6 | use_ok( 'LaTeX::Table::Themes::Beamer' ); | |
7 | use_ok( 'LaTeX::Table::Themes::Classic' ); | |
8 | use_ok( 'LaTeX::Table::Themes::Modern' ); | |
9 | use_ok( 'LaTeX::Table::Types::TypeI' ); | |
10 | use_ok( 'LaTeX::Table::Types::Ctable' ); | |
11 | use_ok( 'LaTeX::Table::Types::Longtable' ); | |
12 | use_ok( 'LaTeX::Table::Types::Xtab' ); | |
13 | use_ok( 'LaTeX::Table::Types::Std' ); | |
14 | } | |
15 | ||
16 | diag( "Testing LaTeX::Table $LaTeX::Table::VERSION" ); |
0 | use Test::More tests => 7; | |
1 | use Test::NoWarnings; | |
2 | ||
3 | use LaTeX::Table; | |
4 | ||
5 | my $test_header = [ ['Name','Beers:2c'], ['','before 4pm', 'after 4pm'] ]; | |
6 | my $test_data = [ | |
7 | ['Lisa\tmark','0','0'], | |
8 | [ 'Marge','0','1'], | |
9 | [ 'Wiggum','0','5'], | |
10 | [ 'Otto','1','3'], | |
11 | [ 'Homer','2','6'], | |
12 | [ 'Barney','8','16'], | |
13 | ]; | |
14 | ||
15 | my $table = LaTeX::Table->new({ filename => 'out.tex', | |
16 | label => 'beercounter', | |
17 | maincaption => 'Beer Counter', | |
18 | caption => 'Number of beers before and after 4pm.', | |
19 | header => $test_header, | |
20 | data => $test_data, | |
21 | type => 'ctable', | |
22 | theme => 'Zurich', | |
23 | }); | |
24 | ||
25 | $table->set_foottable('\tnote{footnotes are placed under the table}'); | |
26 | ||
27 | my $expected_output =<<'EOT' | |
28 | { | |
29 | \ctable[caption = {Beer Counter. Number of beers before and after 4pm.}, | |
30 | cap = {Beer Counter}, | |
31 | botcap, | |
32 | label = {beercounter}, | |
33 | center, | |
34 | ]{lrr}{\tnote{footnotes are placed under the table}}{ | |
35 | \toprule | |
36 | \textbf{Name} & \multicolumn{2}{c}{\textbf{Beers}} \\ | |
37 | & \multicolumn{1}{c}{\textbf{before 4pm}} & \multicolumn{1}{c}{\textbf{after 4pm}} \\ | |
38 | \midrule | |
39 | Lisa\tmark & 0 & 0 \\ | |
40 | Marge & 0 & 1 \\ | |
41 | Wiggum & 0 & 5 \\ | |
42 | Otto & 1 & 3 \\ | |
43 | Homer & 2 & 6 \\ | |
44 | Barney & 8 & 16 \\ | |
45 | \bottomrule | |
46 | } | |
47 | } | |
48 | EOT | |
49 | ; | |
50 | ||
51 | my $output = $table->generate_string(); | |
52 | #warn $output; | |
53 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], 'without table environment'); | |
54 | ||
55 | ||
56 | $table->set_maincaption(0); | |
57 | $table->set_shortcaption('Beer Counter'); | |
58 | ||
59 | $expected_output =<<'EOT' | |
60 | { | |
61 | \ctable[caption = {Number of beers before and after 4pm.}, | |
62 | cap = {Beer Counter}, | |
63 | botcap, | |
64 | label = {beercounter}, | |
65 | center, | |
66 | ]{lrr}{\tnote{footnotes are placed under the table}}{ | |
67 | \toprule | |
68 | \textbf{Name} & \multicolumn{2}{c}{\textbf{Beers}} \\ | |
69 | & \multicolumn{1}{c}{\textbf{before 4pm}} & \multicolumn{1}{c}{\textbf{after 4pm}} \\ | |
70 | \midrule | |
71 | Lisa\tmark & 0 & 0 \\ | |
72 | Marge & 0 & 1 \\ | |
73 | Wiggum & 0 & 5 \\ | |
74 | Otto & 1 & 3 \\ | |
75 | Homer & 2 & 6 \\ | |
76 | Barney & 8 & 16 \\ | |
77 | \bottomrule | |
78 | } | |
79 | } | |
80 | EOT | |
81 | ; | |
82 | ||
83 | $output = $table->generate_string(); | |
84 | #warn $output; | |
85 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], 'without table environment'); | |
86 | ||
87 | $table->set_right(1); | |
88 | $table->set_shortcaption(0); | |
89 | $table->set_caption_top(1); | |
90 | ||
91 | $expected_output =<<'EOT' | |
92 | { | |
93 | \ctable[caption = {Number of beers before and after 4pm.}, | |
94 | label = {beercounter}, | |
95 | right, | |
96 | ]{lrr}{\tnote{footnotes are placed under the table}}{ | |
97 | \toprule | |
98 | \textbf{Name} & \multicolumn{2}{c}{\textbf{Beers}} \\ | |
99 | & \multicolumn{1}{c}{\textbf{before 4pm}} & \multicolumn{1}{c}{\textbf{after 4pm}} \\ | |
100 | \midrule | |
101 | Lisa\tmark & 0 & 0 \\ | |
102 | Marge & 0 & 1 \\ | |
103 | Wiggum & 0 & 5 \\ | |
104 | Otto & 1 & 3 \\ | |
105 | Homer & 2 & 6 \\ | |
106 | Barney & 8 & 16 \\ | |
107 | \bottomrule | |
108 | } | |
109 | } | |
110 | EOT | |
111 | ; | |
112 | ||
113 | $output = $table->generate_string(); | |
114 | #warn $output; | |
115 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], 'without table environment'); | |
116 | ||
117 | $test_data = [ | |
118 | ['Lisa\tmark','0','0'], | |
119 | [ 'Marge','0','1'], | |
120 | [ 'Wiggum','0','5'], | |
121 | [ 'Otto','1','3'], | |
122 | [ 'Homer','This is a looooooooooooooooong longgg linee, my friedn','6'], | |
123 | [ 'Barney','8','16'], | |
124 | ]; | |
125 | ||
126 | $table->set_data($test_data); | |
127 | $table->set_maxwidth('0.9\textwidth'); | |
128 | ||
129 | $expected_output =<<'EOT' | |
130 | { | |
131 | \ctable[caption = {Number of beers before and after 4pm.}, | |
132 | label = {beercounter}, | |
133 | maxwidth = {0.9\textwidth}, | |
134 | right, | |
135 | ]{lXr}{\tnote{footnotes are placed under the table}}{ | |
136 | \toprule | |
137 | \textbf{Name} & \multicolumn{2}{c}{\textbf{Beers}} \\ | |
138 | & \multicolumn{1}{c}{\textbf{before 4pm}} & \multicolumn{1}{c}{\textbf{after 4pm}} \\ | |
139 | \midrule | |
140 | Lisa\tmark & 0 & 0 \\ | |
141 | Marge & 0 & 1 \\ | |
142 | Wiggum & 0 & 5 \\ | |
143 | Otto & 1 & 3 \\ | |
144 | Homer & This is a looooooooooooooooong longgg linee, my friedn & 6 \\ | |
145 | Barney & 8 & 16 \\ | |
146 | \bottomrule | |
147 | } | |
148 | } | |
149 | EOT | |
150 | ; | |
151 | ||
152 | $output = $table->generate_string(); | |
153 | #warn $output; | |
154 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], | |
155 | 'uses xtabular?'); | |
156 | ||
157 | ||
158 | $table = LaTeX::Table->new( | |
159 | { | |
160 | type => 'ctable', | |
161 | header => [ [ 'Website', 'URL' ] ], | |
162 | data => [ | |
163 | [ 'Slashdot', 'http://www.slashdot.org' ], | |
164 | [ 'Perlmonks', ' http://www.perlmonks.org' ], | |
165 | [ 'Google', 'http://www.google.com' ], | |
166 | ], | |
167 | coldef_strategy => { | |
168 | URL => qr{ \A \s* http }xms, | |
169 | URL_COL => '>{\ttfamily}l', | |
170 | }, | |
171 | theme => 'Zurich', | |
172 | } | |
173 | ); | |
174 | ||
175 | $expected_output =<<'EOT' | |
176 | { | |
177 | \ctable[center, | |
178 | ]{l>{\ttfamily}l}{}{ | |
179 | \toprule | |
180 | \textbf{Website} & \multicolumn{1}{c}{\textbf{URL}} \\ | |
181 | \midrule | |
182 | Slashdot & http://www.slashdot.org \\ | |
183 | Perlmonks & http://www.perlmonks.org \\ | |
184 | Google & http://www.google.com \\ | |
185 | \bottomrule | |
186 | } | |
187 | } | |
188 | EOT | |
189 | ; | |
190 | ||
191 | $output = $table->generate_string(); | |
192 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], | |
193 | 'uses _COL_X not specified'); | |
194 | ||
195 | $table->set_continued(1); | |
196 | ||
197 | $expected_output =<<'EOT' | |
198 | { | |
199 | \ctable[center, | |
200 | continued = {(continued)}, | |
201 | ]{l>{\ttfamily}l}{}{ | |
202 | \toprule | |
203 | \textbf{Website} & \multicolumn{1}{c}{\textbf{URL}} \\ | |
204 | \midrule | |
205 | Slashdot & http://www.slashdot.org \\ | |
206 | Perlmonks & http://www.perlmonks.org \\ | |
207 | Google & http://www.google.com \\ | |
208 | \bottomrule | |
209 | } | |
210 | } | |
211 | EOT | |
212 | ; | |
213 | ||
214 | $output = $table->generate_string(); | |
215 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], | |
216 | 'continued'); | |
217 |
0 | use Test::More tests => 3; | |
1 | use Test::NoWarnings; | |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
6 | use LaTeX::Table; | |
7 | ||
8 | ||
9 | my $header = [ | |
10 | [ 'Item:2c', '' ], | |
11 | ['\cmidrule(r){1-2}'], | |
12 | [ 'Animal', 'Description', 'Price' ] | |
13 | ]; | |
14 | ||
15 | my $data = [ | |
16 | [ 'Gnat', 'per gram', '13.65' ], | |
17 | [ '', 'each', '0.01' ], | |
18 | [ 'Gnu', 'stuffed', '92.59' ], | |
19 | [ 'Emu', 'stuffed', '33.33' ], | |
20 | [ 'Armadillo', 'frozen', '8.99' ], | |
21 | ]; | |
22 | ||
23 | ||
24 | my $table = LaTeX::Table->new( | |
25 | { | |
26 | filename => 'prices.tex', | |
27 | maincaption => 'Price List', | |
28 | caption => 'Try our special offer today!', | |
29 | label => 'table:prices', | |
30 | position => 'htb', | |
31 | header => $header, | |
32 | data => $data, | |
33 | theme => 'Meyrin', | |
34 | custom_template => '[% DATA_CODE %]', | |
35 | } | |
36 | ); | |
37 | ||
38 | my $expected_output =<<'EOT' | |
39 | Gnat & per gram & 13.65 \\ | |
40 | & each & 0.01 \\ | |
41 | Gnu & stuffed & 92.59 \\ | |
42 | Emu & stuffed & 33.33 \\ | |
43 | Armadillo & frozen & 8.99 \\ | |
44 | \bottomrule | |
45 | EOT | |
46 | ; | |
47 | ||
48 | my $output = $table->generate_string(); | |
49 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], | |
50 | 'BODY_CODE'); | |
51 | ||
52 | $table->set_custom_template('[% HEADER_CODE %]'); | |
53 | ||
54 | $expected_output =<<'EOT' | |
55 | \toprule | |
56 | \multicolumn{2}{c}{Item} & \\ | |
57 | \cmidrule(r){1-2} | |
58 | Animal & Description & Price \\ | |
59 | \midrule | |
60 | EOT | |
61 | ; | |
62 | ||
63 | $output = $table->generate_string(); | |
64 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], | |
65 | 'HEADER_CODE'); |
0 | use Test::More tests => 21; | |
1 | use Test::NoWarnings; | |
2 | ||
3 | use LaTeX::Table; | |
4 | ||
5 | my $test_header | |
6 | = [ [ 'Name', 'Beers:2c' ], [ '', 'before 4pm', 'after 4pm' ] ]; | |
7 | my $test_data = [ | |
8 | [ 'Lisa', '0', '0' ], | |
9 | [ 'Marge', '0', '1' ], | |
10 | [ 'Wiggum', '0', '5' ], | |
11 | [ 'Otto', '1', '3' ], | |
12 | [ 'Homer', '2', '6' ], | |
13 | [ 'Barney', '8', '16' ], | |
14 | ]; | |
15 | ||
16 | my $table = LaTeX::Table->new( | |
17 | { filename => 't/tmp/out.tex', | |
18 | label => 'beercounter', | |
19 | maincaption => 'Beer Counter', | |
20 | caption => 'Number of beers before and after 4pm.', | |
21 | environment => 0, | |
22 | theme => 'Dresden', | |
23 | header => $test_header, | |
24 | data => $test_data, | |
25 | } | |
26 | ); | |
27 | ||
28 | my $expected_output = <<'EOT' | |
29 | \begin{tabular}{|l||r|r|} | |
30 | \hline | |
31 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
32 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
33 | \hline | |
34 | \hline | |
35 | Lisa & 0 & 0 \\ | |
36 | Marge & 0 & 1 \\ | |
37 | Wiggum & 0 & 5 \\ | |
38 | Otto & 1 & 3 \\ | |
39 | Homer & 2 & 6 \\ | |
40 | Barney & 8 & 16 \\ | |
41 | \hline | |
42 | \end{tabular} | |
43 | EOT | |
44 | ; | |
45 | ||
46 | my $output = $table->generate_string(); | |
47 | my @expected_output = split "\n", $expected_output; | |
48 | ||
49 | is_deeply( | |
50 | [ split( "\n", $output ) ], | |
51 | \@expected_output, | |
52 | 'without table environment' | |
53 | ); | |
54 | ||
55 | mkdir 't/tmp'; | |
56 | $table->generate(); | |
57 | ||
58 | open my $FH, '<', 't/tmp/out.tex'; | |
59 | my @filecontent = <$FH>; | |
60 | chomp @filecontent; | |
61 | close $FH; | |
62 | ||
63 | is_deeply( \@filecontent, [@expected_output], | |
64 | 'without table environment, generate()' ) | |
65 | or die; | |
66 | ||
67 | unlink 't/tmp/out.tex'; | |
68 | rmdir 't/tmp'; | |
69 | ## with table environment | |
70 | $table->set_environment(1); | |
71 | ||
72 | $expected_output = <<'EOT' | |
73 | \begin{table} | |
74 | \centering | |
75 | \begin{tabular}{|l||r|r|} | |
76 | \hline | |
77 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
78 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
79 | \hline | |
80 | \hline | |
81 | Lisa & 0 & 0 \\ | |
82 | Marge & 0 & 1 \\ | |
83 | Wiggum & 0 & 5 \\ | |
84 | Otto & 1 & 3 \\ | |
85 | Homer & 2 & 6 \\ | |
86 | Barney & 8 & 16 \\ | |
87 | \hline | |
88 | \end{tabular} | |
89 | \caption[Beer Counter]{\textbf{Beer Counter. }Number of beers before and after 4pm.} | |
90 | \label{beercounter} | |
91 | \end{table} | |
92 | EOT | |
93 | ; | |
94 | $output = $table->generate_string(); | |
95 | is_deeply( | |
96 | [ split( "\n", $output ) ], | |
97 | [ split( "\n", $expected_output ) ], | |
98 | 'with table environment' | |
99 | ); | |
100 | ||
101 | $table->set_continued(1); | |
102 | $expected_output = <<'EOT' | |
103 | \addtocounter{table}{-1}\begin{table} | |
104 | \centering | |
105 | \begin{tabular}{|l||r|r|} | |
106 | \hline | |
107 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
108 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
109 | \hline | |
110 | \hline | |
111 | Lisa & 0 & 0 \\ | |
112 | Marge & 0 & 1 \\ | |
113 | Wiggum & 0 & 5 \\ | |
114 | Otto & 1 & 3 \\ | |
115 | Homer & 2 & 6 \\ | |
116 | Barney & 8 & 16 \\ | |
117 | \hline | |
118 | \end{tabular} | |
119 | \caption[Beer Counter]{\textbf{Beer Counter. }Number of beers before and after 4pm. (continued)} | |
120 | \label{beercounter} | |
121 | \end{table} | |
122 | EOT | |
123 | ; | |
124 | $output = $table->generate_string(); | |
125 | is_deeply( | |
126 | [ split( "\n", $output ) ], | |
127 | [ split( "\n", $expected_output ) ], | |
128 | 'with table environment' | |
129 | ); | |
130 | ||
131 | $table->set_continued(0); | |
132 | # without label and maincaption | |
133 | $table->set_environment(1); | |
134 | $table->set_label(''); | |
135 | $table->set_maincaption(''); | |
136 | ||
137 | $expected_output = <<'EOT' | |
138 | \begin{table} | |
139 | \centering | |
140 | \begin{tabular}{|l||r|r|} | |
141 | \hline | |
142 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
143 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
144 | \hline | |
145 | \hline | |
146 | Lisa & 0 & 0 \\ | |
147 | Marge & 0 & 1 \\ | |
148 | Wiggum & 0 & 5 \\ | |
149 | Otto & 1 & 3 \\ | |
150 | Homer & 2 & 6 \\ | |
151 | Barney & 8 & 16 \\ | |
152 | \hline | |
153 | \end{tabular} | |
154 | \caption{Number of beers before and after 4pm.} | |
155 | \end{table} | |
156 | EOT | |
157 | ; | |
158 | ||
159 | $output = $table->generate_string(); | |
160 | is_deeply( | |
161 | [ split( "\n", $output ) ], | |
162 | [ split( "\n", $expected_output ) ], | |
163 | 'with table environment, without maincaption and label' | |
164 | ); | |
165 | ||
166 | ## without center | |
167 | ||
168 | $table = LaTeX::Table->new( | |
169 | { environment => 1, | |
170 | center => 0, | |
171 | theme => 'Dresden', | |
172 | header => $test_header, | |
173 | data => $test_data, | |
174 | } | |
175 | ); | |
176 | $expected_output = <<'EOT' | |
177 | \begin{table} | |
178 | \begin{tabular}{|l||r|r|} | |
179 | \hline | |
180 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
181 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
182 | \hline | |
183 | \hline | |
184 | Lisa & 0 & 0 \\ | |
185 | Marge & 0 & 1 \\ | |
186 | Wiggum & 0 & 5 \\ | |
187 | Otto & 1 & 3 \\ | |
188 | Homer & 2 & 6 \\ | |
189 | Barney & 8 & 16 \\ | |
190 | \hline | |
191 | \end{tabular} | |
192 | \end{table} | |
193 | EOT | |
194 | ; | |
195 | ||
196 | $output = $table->generate_string(); | |
197 | is_deeply( | |
198 | [ split( "\n", $output ) ], | |
199 | [ split( "\n", $expected_output ) ], | |
200 | 'with table environment, without maincaption, center and label' | |
201 | ); | |
202 | ||
203 | $table = LaTeX::Table->new( | |
204 | { environment => 1, | |
205 | center => 0, | |
206 | caption_top => 1, | |
207 | caption => 'test caption', | |
208 | header => $test_header, | |
209 | data => $test_data, | |
210 | theme => 'Zurich', | |
211 | } | |
212 | ); | |
213 | ||
214 | $output = $table->generate_string(); | |
215 | ||
216 | $expected_output = <<'EOT' | |
217 | \begin{table} | |
218 | \caption{test caption} | |
219 | \begin{tabular}{lrr} | |
220 | \toprule | |
221 | \textbf{Name} & \multicolumn{2}{c}{\textbf{Beers}} \\ | |
222 | & \multicolumn{1}{c}{\textbf{before 4pm}} & \multicolumn{1}{c}{\textbf{after 4pm}} \\ | |
223 | \midrule | |
224 | Lisa & 0 & 0 \\ | |
225 | Marge & 0 & 1 \\ | |
226 | Wiggum & 0 & 5 \\ | |
227 | Otto & 1 & 3 \\ | |
228 | Homer & 2 & 6 \\ | |
229 | Barney & 8 & 16 \\ | |
230 | \bottomrule | |
231 | \end{tabular} | |
232 | \end{table} | |
233 | EOT | |
234 | ; | |
235 | ||
236 | is_deeply( | |
237 | [ split( "\n", $output ) ], | |
238 | [ split( "\n", $expected_output ) ], | |
239 | 'with table environment, without maincaption, center and label' | |
240 | ); | |
241 | ||
242 | $table->set_caption_top('topcaption'); | |
243 | $output = $table->generate_string(); | |
244 | ||
245 | $expected_output = <<'EOT' | |
246 | \begin{table} | |
247 | \topcaption{test caption} | |
248 | \begin{tabular}{lrr} | |
249 | \toprule | |
250 | \textbf{Name} & \multicolumn{2}{c}{\textbf{Beers}} \\ | |
251 | & \multicolumn{1}{c}{\textbf{before 4pm}} & \multicolumn{1}{c}{\textbf{after 4pm}} \\ | |
252 | \midrule | |
253 | Lisa & 0 & 0 \\ | |
254 | Marge & 0 & 1 \\ | |
255 | Wiggum & 0 & 5 \\ | |
256 | Otto & 1 & 3 \\ | |
257 | Homer & 2 & 6 \\ | |
258 | Barney & 8 & 16 \\ | |
259 | \bottomrule | |
260 | \end{tabular} | |
261 | \end{table} | |
262 | EOT | |
263 | ; | |
264 | ||
265 | is_deeply( | |
266 | [ split( "\n", $output ) ], | |
267 | [ split( "\n", $expected_output ) ], | |
268 | 'with table environment, without maincaption, center and label' | |
269 | ); | |
270 | ||
271 | ## with coldef | |
272 | $table = LaTeX::Table->new( | |
273 | { environment => 0, | |
274 | coldef => "|l||l|l|", | |
275 | header => $test_header, | |
276 | data => $test_data, | |
277 | theme => 'Dresden', | |
278 | } | |
279 | ); | |
280 | $expected_output = <<'EOT' | |
281 | \begin{tabular}{|l||l|l|} | |
282 | \hline | |
283 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
284 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
285 | \hline | |
286 | \hline | |
287 | Lisa & 0 & 0 \\ | |
288 | Marge & 0 & 1 \\ | |
289 | Wiggum & 0 & 5 \\ | |
290 | Otto & 1 & 3 \\ | |
291 | Homer & 2 & 6 \\ | |
292 | Barney & 8 & 16 \\ | |
293 | \hline | |
294 | \end{tabular} | |
295 | EOT | |
296 | ; | |
297 | ||
298 | $output = $table->generate_string(); | |
299 | is_deeply( | |
300 | [ split( "\n", $output ) ], | |
301 | [ split( "\n", $expected_output ) ], | |
302 | 'with coldef' | |
303 | ); | |
304 | ||
305 | $test_data = [ | |
306 | [ 'Lisa', '0', '0' ], | |
307 | [ 'Marge', '0', '1' ], | |
308 | [ 'Wiggum', '0', '' ], | |
309 | [ 'Otto', ' ', '' ], | |
310 | [ 'Homer', '2', '6' ], | |
311 | [ 'Barney', '8', '16' ], | |
312 | ]; | |
313 | ||
314 | $table = LaTeX::Table->new( | |
315 | { environment => 0, | |
316 | header => $test_header, | |
317 | data => $test_data, | |
318 | } | |
319 | ); | |
320 | ||
321 | $expected_output = <<'EOT' | |
322 | \begin{tabular}{lrr} | |
323 | \toprule | |
324 | Name & \multicolumn{2}{c}{Beers} \\ | |
325 | & before 4pm & after 4pm \\ | |
326 | \midrule | |
327 | Lisa & 0 & 0 \\ | |
328 | Marge & 0 & 1 \\ | |
329 | Wiggum & 0 & \\ | |
330 | Otto & & \\ | |
331 | Homer & 2 & 6 \\ | |
332 | Barney & 8 & 16 \\ | |
333 | \bottomrule | |
334 | \end{tabular} | |
335 | EOT | |
336 | ; | |
337 | ||
338 | $output = $table->generate_string(); | |
339 | is_deeply( | |
340 | [ split( "\n", $output ) ], | |
341 | [ split( "\n", $expected_output ) ], | |
342 | 'missing values' | |
343 | ) || diag $output; | |
344 | ||
345 | my $header = [ [ 'Character', 'Fullname', 'Voice' ], ]; | |
346 | my $data = [ | |
347 | [ 'Homer', 'Homer Jay Simpson', 'Dan Castellaneta', ], | |
348 | [], | |
349 | [ 'Marge', 'Marjorie Simpson (nee Bouvier)', 'Julie Kavner', ], | |
350 | [ 'Bart', 'Bartholomew Jojo Simpson', 'Nancy Cartwright', ], | |
351 | [ 'Lisa', 'Elizabeth Marie Simpson', 'Yeardley Smith', ], | |
352 | [ 'Maggie', | |
353 | 'Margaret Simpson', | |
354 | 'Elizabeth Taylor, Nancy Cartwright, James Earl Jones,' | |
355 | . 'Yeardley Smith, Harry Shearer', | |
356 | ], | |
357 | ]; | |
358 | ||
359 | #no header test | |
360 | $table = LaTeX::Table->new( | |
361 | { data => $data, | |
362 | width => '0.9\textwidth', | |
363 | width_environment => 'tabularx', | |
364 | position => 'ht', | |
365 | theme => 'Zurich', | |
366 | } | |
367 | ); | |
368 | $expected_output = <<'EOT' | |
369 | \begin{table}[ht] | |
370 | \centering | |
371 | \begin{tabularx}{0.9\textwidth}{lXX} | |
372 | \toprule | |
373 | Homer & Homer Jay Simpson & Dan Castellaneta \\ | |
374 | \midrule | |
375 | Marge & Marjorie Simpson (nee Bouvier) & Julie Kavner \\ | |
376 | Bart & Bartholomew Jojo Simpson & Nancy Cartwright \\ | |
377 | Lisa & Elizabeth Marie Simpson & Yeardley Smith \\ | |
378 | Maggie & Margaret Simpson & Elizabeth Taylor, Nancy Cartwright, James Earl Jones,Yeardley Smith, Harry Shearer \\ | |
379 | \bottomrule | |
380 | \end{tabularx} | |
381 | \end{table} | |
382 | EOT | |
383 | ; | |
384 | ||
385 | $output = $table->generate_string(); | |
386 | is_deeply( | |
387 | [ split( "\n", $output ) ], | |
388 | [ split( "\n", $expected_output ) ], | |
389 | 'no header' | |
390 | ); | |
391 | ||
392 | $table->set_width_environment('tabulary'); | |
393 | $expected_output = <<'EOT' | |
394 | \begin{table}[ht] | |
395 | \centering | |
396 | \begin{tabulary}{0.9\textwidth}{lLL} | |
397 | \toprule | |
398 | Homer & Homer Jay Simpson & Dan Castellaneta \\ | |
399 | \midrule | |
400 | Marge & Marjorie Simpson (nee Bouvier) & Julie Kavner \\ | |
401 | Bart & Bartholomew Jojo Simpson & Nancy Cartwright \\ | |
402 | Lisa & Elizabeth Marie Simpson & Yeardley Smith \\ | |
403 | Maggie & Margaret Simpson & Elizabeth Taylor, Nancy Cartwright, James Earl Jones,Yeardley Smith, Harry Shearer \\ | |
404 | \bottomrule | |
405 | \end{tabulary} | |
406 | \end{table} | |
407 | EOT | |
408 | ; | |
409 | ||
410 | $output = $table->generate_string(); | |
411 | is_deeply( | |
412 | [ split( "\n", $output ) ], | |
413 | [ split( "\n", $expected_output ) ], | |
414 | 'tabulary' | |
415 | ); | |
416 | ||
417 | ||
418 | ## tabularx test | |
419 | $table = LaTeX::Table->new( | |
420 | { header => $header, | |
421 | data => $data, | |
422 | width => '0.9\textwidth', | |
423 | width_environment => 'tabularx', | |
424 | position => 'ht', | |
425 | theme => 'Zurich', | |
426 | } | |
427 | ); | |
428 | ||
429 | $expected_output = <<'EOT' | |
430 | \begin{table}[ht] | |
431 | \centering | |
432 | \begin{tabularx}{0.9\textwidth}{lXX} | |
433 | \toprule | |
434 | \textbf{Character} & \multicolumn{1}{c}{\textbf{Fullname}} & \multicolumn{1}{c}{\textbf{Voice}} \\ | |
435 | \midrule | |
436 | Homer & Homer Jay Simpson & Dan Castellaneta \\ | |
437 | \midrule | |
438 | Marge & Marjorie Simpson (nee Bouvier) & Julie Kavner \\ | |
439 | Bart & Bartholomew Jojo Simpson & Nancy Cartwright \\ | |
440 | Lisa & Elizabeth Marie Simpson & Yeardley Smith \\ | |
441 | Maggie & Margaret Simpson & Elizabeth Taylor, Nancy Cartwright, James Earl Jones,Yeardley Smith, Harry Shearer \\ | |
442 | \bottomrule | |
443 | \end{tabularx} | |
444 | \end{table} | |
445 | EOT | |
446 | ; | |
447 | ||
448 | $output = $table->generate_string(); | |
449 | is_deeply( | |
450 | [ split( "\n", $output ) ], | |
451 | [ split( "\n", $expected_output ) ], | |
452 | 'with coldef' | |
453 | ); | |
454 | ||
455 | $table->set_width_environment('tabular*'); | |
456 | ||
457 | $expected_output = <<'EOT' | |
458 | \begin{table}[ht] | |
459 | \centering | |
460 | \begin{tabular*}{0.9\textwidth}{l@{\extracolsep{\fill}}p{5cm}p{5cm}} | |
461 | \toprule | |
462 | \textbf{Character} & \multicolumn{1}{c}{\textbf{Fullname}} & \multicolumn{1}{c}{\textbf{Voice}} \\ | |
463 | \midrule | |
464 | Homer & Homer Jay Simpson & Dan Castellaneta \\ | |
465 | \midrule | |
466 | Marge & Marjorie Simpson (nee Bouvier) & Julie Kavner \\ | |
467 | Bart & Bartholomew Jojo Simpson & Nancy Cartwright \\ | |
468 | Lisa & Elizabeth Marie Simpson & Yeardley Smith \\ | |
469 | Maggie & Margaret Simpson & Elizabeth Taylor, Nancy Cartwright, James Earl Jones,Yeardley Smith, Harry Shearer \\ | |
470 | \bottomrule | |
471 | \end{tabular*} | |
472 | \end{table} | |
473 | EOT | |
474 | ; | |
475 | ||
476 | $output = $table->generate_string(); | |
477 | is_deeply( | |
478 | [ split( "\n", $output ) ], | |
479 | [ split( "\n", $expected_output ) ], | |
480 | 'with coldef' | |
481 | ); | |
482 | ||
483 | $test_header = [ [ 'A:3c' ] , [ 'A:2c', 'B' ], ['A', 'B', 'C' ], ]; | |
484 | $test_data = [ [ '1', 'w', 'x' ], [ '2', 'c:2c' ], ]; | |
485 | ||
486 | $table = LaTeX::Table->new( | |
487 | { environment => 0, | |
488 | header => $test_header, | |
489 | data => $test_data, | |
490 | theme => 'Dresden', | |
491 | } | |
492 | ); | |
493 | ||
494 | $output = $table->generate_string(); | |
495 | ||
496 | $expected_output = <<'EOT' | |
497 | \begin{tabular}{|r||l|l|} | |
498 | \hline | |
499 | \multicolumn{3}{|c|}{\textbf{A}} \\ | |
500 | \multicolumn{2}{|c|}{\textbf{A}} & \multicolumn{1}{c|}{\textbf{B}} \\ | |
501 | \multicolumn{1}{|c||}{\textbf{A}} & \multicolumn{1}{c|}{\textbf{B}} & \multicolumn{1}{c|}{\textbf{C}} \\ | |
502 | \hline | |
503 | \hline | |
504 | 1 & w & x \\ | |
505 | 2 & \multicolumn{2}{c|}{c} \\ | |
506 | \hline | |
507 | \end{tabular} | |
508 | EOT | |
509 | ; | |
510 | ||
511 | ||
512 | $output = $table->generate_string(); | |
513 | is_deeply( | |
514 | [ split( "\n", $output ) ], | |
515 | [ split( "\n", $expected_output ) ], | |
516 | 'with very complicated multicolum shortcuts' | |
517 | ); | |
518 | ||
519 | $table->set_theme('NYC'); | |
520 | ||
521 | $expected_output = <<'EOT' | |
522 | \definecolor{latextbl}{RGB}{78,130,190} | |
523 | \setlength{\extrarowheight}{1pt} | |
524 | \begin{tabular}{|rll|} | |
525 | \hline | |
526 | \rowcolor{latextbl}\multicolumn{3}{|>{\columncolor{latextbl}}c|}{\color{white}\textbf{A}} \\ | |
527 | \rowcolor{latextbl}\multicolumn{2}{|>{\columncolor{latextbl}}c}{\color{white}\textbf{A}} & \multicolumn{1}{>{\columncolor{latextbl}}c|}{\color{white}\textbf{B}} \\ | |
528 | \rowcolor{latextbl}\multicolumn{1}{|>{\columncolor{latextbl}}c}{\color{white}\textbf{A}} & \multicolumn{1}{>{\columncolor{latextbl}}c}{\color{white}\textbf{B}} & \multicolumn{1}{>{\columncolor{latextbl}}c|}{\color{white}\textbf{C}} \\ | |
529 | \hline | |
530 | \rowcolor{latextbl!25}1 & w & x \\ | |
531 | \rowcolor{latextbl!10}2 & \multicolumn{2}{>{\columncolor{latextbl!10}}c|}{c} \\ | |
532 | \hline | |
533 | \end{tabular} | |
534 | EOT | |
535 | ; | |
536 | ||
537 | $output = $table->generate_string(); | |
538 | is_deeply( | |
539 | [ split( "\n", $output ) ], | |
540 | [ split( "\n", $expected_output ) ], | |
541 | 'theme with colordef' | |
542 | ); | |
543 | ||
544 | $table->set_resizebox(['0.6\textwidth']); | |
545 | ||
546 | ||
547 | $expected_output = <<'EOT' | |
548 | \definecolor{latextbl}{RGB}{78,130,190} | |
549 | \setlength{\extrarowheight}{1pt} | |
550 | \resizebox{0.6\textwidth}{!}{ | |
551 | \begin{tabular}{|rll|} | |
552 | \hline | |
553 | \rowcolor{latextbl}\multicolumn{3}{|>{\columncolor{latextbl}}c|}{\color{white}\textbf{A}} \\ | |
554 | \rowcolor{latextbl}\multicolumn{2}{|>{\columncolor{latextbl}}c}{\color{white}\textbf{A}} & \multicolumn{1}{>{\columncolor{latextbl}}c|}{\color{white}\textbf{B}} \\ | |
555 | \rowcolor{latextbl}\multicolumn{1}{|>{\columncolor{latextbl}}c}{\color{white}\textbf{A}} & \multicolumn{1}{>{\columncolor{latextbl}}c}{\color{white}\textbf{B}} & \multicolumn{1}{>{\columncolor{latextbl}}c|}{\color{white}\textbf{C}} \\ | |
556 | \hline | |
557 | \rowcolor{latextbl!25}1 & w & x \\ | |
558 | \rowcolor{latextbl!10}2 & \multicolumn{2}{>{\columncolor{latextbl!10}}c|}{c} \\ | |
559 | \hline | |
560 | \end{tabular}} | |
561 | EOT | |
562 | ; | |
563 | ||
564 | $output = $table->generate_string(); | |
565 | is_deeply( | |
566 | [ split( "\n", $output ) ], | |
567 | [ split( "\n", $expected_output ) ], | |
568 | 'theme with colordef and resizebox' | |
569 | ); | |
570 | ||
571 | $table->set_resizebox(['300pt', '200pt']); | |
572 | $expected_output = <<'EOT' | |
573 | \definecolor{latextbl}{RGB}{78,130,190} | |
574 | \setlength{\extrarowheight}{1pt} | |
575 | \resizebox{300pt}{200pt}{ | |
576 | \begin{tabular}{|rll|} | |
577 | \hline | |
578 | \rowcolor{latextbl}\multicolumn{3}{|>{\columncolor{latextbl}}c|}{\color{white}\textbf{A}} \\ | |
579 | \rowcolor{latextbl}\multicolumn{2}{|>{\columncolor{latextbl}}c}{\color{white}\textbf{A}} & \multicolumn{1}{>{\columncolor{latextbl}}c|}{\color{white}\textbf{B}} \\ | |
580 | \rowcolor{latextbl}\multicolumn{1}{|>{\columncolor{latextbl}}c}{\color{white}\textbf{A}} & \multicolumn{1}{>{\columncolor{latextbl}}c}{\color{white}\textbf{B}} & \multicolumn{1}{>{\columncolor{latextbl}}c|}{\color{white}\textbf{C}} \\ | |
581 | \hline | |
582 | \rowcolor{latextbl!25}1 & w & x \\ | |
583 | \rowcolor{latextbl!10}2 & \multicolumn{2}{>{\columncolor{latextbl!10}}c|}{c} \\ | |
584 | \hline | |
585 | \end{tabular}} | |
586 | EOT | |
587 | ; | |
588 | ||
589 | $output = $table->generate_string(); | |
590 | is_deeply( | |
591 | [ split( "\n", $output ) ], | |
592 | [ split( "\n", $expected_output ) ], | |
593 | 'theme with colordef and resizebox' | |
594 | ); | |
595 | ||
596 | $test_data = [ [ '1', 'w', 'x' ],['\hline' ], [ '2', 'c:2c' ], ]; | |
597 | ||
598 | $table = LaTeX::Table->new( | |
599 | { | |
600 | data => $test_data, | |
601 | theme => 'NYC', | |
602 | columns_like_header => [ 0 ], | |
603 | } | |
604 | ); | |
605 | ||
606 | $expected_output = <<'EOT' | |
607 | \definecolor{latextbl}{RGB}{78,130,190} | |
608 | \begin{table} | |
609 | \centering | |
610 | \setlength{\extrarowheight}{1pt} | |
611 | \begin{tabular}{|rll|} | |
612 | \hline | |
613 | \rowcolor{latextbl!25}\multicolumn{1}{|>{\columncolor{latextbl}}r}{\color{white}\textbf{1}} & w & x \\ | |
614 | \hline | |
615 | \rowcolor{latextbl!10}\multicolumn{1}{|>{\columncolor{latextbl}}r}{\color{white}\textbf{2}} & \multicolumn{2}{>{\columncolor{latextbl!10}}c|}{c} \\ | |
616 | \hline | |
617 | \end{tabular} | |
618 | \end{table} | |
619 | EOT | |
620 | ; | |
621 | ||
622 | ||
623 | $output = $table->generate_string(); | |
624 | ||
625 | is_deeply( | |
626 | [ split( "\n", $output ) ], | |
627 | [ split( "\n", $expected_output ) ], | |
628 | 'theme with colordef and resizebox' | |
629 | ) || diag $output; | |
630 | ||
631 | $header = [ ['Time', 'Weekdays:5c'], [], [ '', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday' ] ]; | |
632 | ||
633 | $data = [ | |
634 | [ '9.00', '','', '', '', '', ], | |
635 | [ '12.00', '','', '', '', '', ], | |
636 | ]; | |
637 | ||
638 | $table = LaTeX::Table->new( | |
639 | { | |
640 | header => $header, | |
641 | data => $data, | |
642 | header_sideways => 1, | |
643 | sideways => 1, | |
644 | theme => 'NYC', | |
645 | } | |
646 | ); | |
647 | ||
648 | $expected_output = <<'EOT' | |
649 | \definecolor{latextbl}{RGB}{78,130,190} | |
650 | \begin{sidewaystable} | |
651 | \centering | |
652 | \setlength{\extrarowheight}{1pt} | |
653 | \begin{tabular}{|rlllll|} | |
654 | \hline | |
655 | \rowcolor{latextbl}\multicolumn{1}{|>{\columncolor{latextbl}}c}{\color{white}\textbf{\begin{sideways}Time\end{sideways}}} & \multicolumn{5}{>{\columncolor{latextbl}}c|}{\color{white}\textbf{\begin{sideways}Weekdays\end{sideways}}} \\ | |
656 | \hline | |
657 | \rowcolor{latextbl}\multicolumn{1}{|>{\columncolor{latextbl}}c}{\color{white}\textbf{\begin{sideways}\end{sideways}}} & \multicolumn{1}{>{\columncolor{latextbl}}c}{\color{white}\textbf{\begin{sideways}Monday\end{sideways}}} & \multicolumn{1}{>{\columncolor{latextbl}}c}{\color{white}\textbf{\begin{sideways}Tuesday\end{sideways}}} & \multicolumn{1}{>{\columncolor{latextbl}}c}{\color{white}\textbf{\begin{sideways}Wednesday\end{sideways}}} & \multicolumn{1}{>{\columncolor{latextbl}}c}{\color{white}\textbf{\begin{sideways}Thursday\end{sideways}}} & \multicolumn{1}{>{\columncolor{latextbl}}c|}{\color{white}\textbf{\begin{sideways}Friday\end{sideways}}} \\ | |
658 | \hline | |
659 | \rowcolor{latextbl!25}9.00 & & & & & \\ | |
660 | \rowcolor{latextbl!10}12.00 & & & & & \\ | |
661 | \hline | |
662 | \end{tabular} | |
663 | \end{sidewaystable} | |
664 | EOT | |
665 | ; | |
666 | ||
667 | ||
668 | $output = $table->generate_string(); | |
669 | ||
670 | is_deeply( | |
671 | [ split( "\n", $output ) ], | |
672 | [ split( "\n", $expected_output ) ], | |
673 | 'NYC header sideways' | |
674 | ) || diag $output; | |
675 | ||
676 |
0 | use Test::More tests => 6; | |
1 | use Test::NoWarnings; | |
2 | ||
3 | use LaTeX::Table; | |
4 | ||
5 | my $test_header = [ ['Name','Beers:2c'], ['','before 4pm', 'after 4pm'] ]; | |
6 | my $test_data = [ | |
7 | ['Lisa','0','0'], | |
8 | [ 'Marge','0','1'], | |
9 | [ 'Wiggum','0','5'], | |
10 | [ 'Otto','1','3'], | |
11 | [ 'Homer','2','6'], | |
12 | [ 'Barney','8','16'], | |
13 | ]; | |
14 | ||
15 | my $table = LaTeX::Table->new({ filename => 'out.tex', | |
16 | label => 'beercounter', | |
17 | maincaption => 'Beer Counter', | |
18 | caption => 'Number of beers before and after 4pm.', | |
19 | header => $test_header, | |
20 | data => $test_data, | |
21 | type => 'xtab', | |
22 | theme => 'Dresden', | |
23 | }); | |
24 | ||
25 | my $expected_output =<<'EOT' | |
26 | { | |
27 | \bottomcaption[Beer Counter]{\textbf{Beer Counter. }Number of beers before and after 4pm.} | |
28 | \label{beercounter} | |
29 | ||
30 | \tablehead{\hline | |
31 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
32 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
33 | \hline | |
34 | \hline | |
35 | } | |
36 | \tabletail{\hline | |
37 | \hline | |
38 | \multicolumn{3}{|r|}{{Continued on next page}} \\ | |
39 | \hline | |
40 | } | |
41 | \tablelasttail{} | |
42 | \begin{center} | |
43 | \begin{xtabular}{|l||r|r|} | |
44 | Lisa & 0 & 0 \\ | |
45 | Marge & 0 & 1 \\ | |
46 | Wiggum & 0 & 5 \\ | |
47 | Otto & 1 & 3 \\ | |
48 | Homer & 2 & 6 \\ | |
49 | Barney & 8 & 16 \\ | |
50 | \hline | |
51 | \end{xtabular} | |
52 | \end{center} | |
53 | } | |
54 | EOT | |
55 | ; | |
56 | ||
57 | my $output = $table->generate_string(); | |
58 | #warn $output; | |
59 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], 'without table environment'); | |
60 | ||
61 | $table->set_tabletail(q{ }); | |
62 | ||
63 | $expected_output =<<'EOT' | |
64 | { | |
65 | \bottomcaption[Beer Counter]{\textbf{Beer Counter. }Number of beers before and after 4pm.} | |
66 | \label{beercounter} | |
67 | ||
68 | \tablehead{\hline | |
69 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
70 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
71 | \hline | |
72 | \hline | |
73 | } | |
74 | \tabletail{ \hline | |
75 | } | |
76 | \tablelasttail{} | |
77 | \begin{center} | |
78 | \begin{xtabular}{|l||r|r|} | |
79 | Lisa & 0 & 0 \\ | |
80 | Marge & 0 & 1 \\ | |
81 | Wiggum & 0 & 5 \\ | |
82 | Otto & 1 & 3 \\ | |
83 | Homer & 2 & 6 \\ | |
84 | Barney & 8 & 16 \\ | |
85 | \hline | |
86 | \end{xtabular} | |
87 | \end{center} | |
88 | } | |
89 | EOT | |
90 | ; | |
91 | ||
92 | $output = $table->generate_string(); | |
93 | ||
94 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], | |
95 | 'without table environment, custom tabletail') || diag $output; | |
96 | ||
97 | $table->set_caption_top(1); | |
98 | $table->set_center(0); | |
99 | ||
100 | $expected_output =<<'EOT' | |
101 | { | |
102 | \topcaption[Beer Counter]{\textbf{Beer Counter. }Number of beers before and after 4pm.} | |
103 | \label{beercounter} | |
104 | ||
105 | \tablefirsthead{\hline | |
106 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
107 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
108 | \hline | |
109 | \hline | |
110 | } | |
111 | \tablehead{\multicolumn{3}{c}{{ \normalsize \tablename\ \thetable: Continued from previous page}}\\[\abovecaptionskip] | |
112 | \hline | |
113 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
114 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
115 | \hline | |
116 | \hline | |
117 | } | |
118 | ||
119 | \tabletail{ \hline | |
120 | } | |
121 | \tablelasttail{} | |
122 | \begin{xtabular}{|l||r|r|} | |
123 | Lisa & 0 & 0 \\ | |
124 | Marge & 0 & 1 \\ | |
125 | Wiggum & 0 & 5 \\ | |
126 | Otto & 1 & 3 \\ | |
127 | Homer & 2 & 6 \\ | |
128 | Barney & 8 & 16 \\ | |
129 | \hline | |
130 | \end{xtabular} | |
131 | ||
132 | } | |
133 | EOT | |
134 | ; | |
135 | ||
136 | $output = $table->generate_string(); | |
137 | ||
138 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], | |
139 | 'without table environment, topcaption custom tabletail'); | |
140 | ||
141 | $table->set_caption_top('topcaption'); | |
142 | ||
143 | $expected_output =<<'EOT' | |
144 | { | |
145 | \topcaption[Beer Counter]{\textbf{Beer Counter. }Number of beers before and after 4pm.} | |
146 | \label{beercounter} | |
147 | ||
148 | \tablefirsthead{\hline | |
149 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
150 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
151 | \hline | |
152 | \hline | |
153 | } | |
154 | \tablehead{\multicolumn{3}{c}{{ \normalsize \tablename\ \thetable: Continued from previous page}}\\[\abovecaptionskip] | |
155 | \hline | |
156 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
157 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
158 | \hline | |
159 | \hline | |
160 | } | |
161 | ||
162 | \tabletail{ \hline | |
163 | } | |
164 | \tablelasttail{} | |
165 | \begin{xtabular}{|l||r|r|} | |
166 | Lisa & 0 & 0 \\ | |
167 | Marge & 0 & 1 \\ | |
168 | Wiggum & 0 & 5 \\ | |
169 | Otto & 1 & 3 \\ | |
170 | Homer & 2 & 6 \\ | |
171 | Barney & 8 & 16 \\ | |
172 | \hline | |
173 | \end{xtabular} | |
174 | ||
175 | } | |
176 | EOT | |
177 | ; | |
178 | ||
179 | $output = $table->generate_string(); | |
180 | ||
181 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], | |
182 | 'without table environment, topcaption custom tabletail'); | |
183 | ||
184 | ||
185 | $table->set_tableheadmsg(0); | |
186 | $table->set_custom_tabular_environment('mpxtabular'); | |
187 | ||
188 | $expected_output =<<'EOT' | |
189 | { | |
190 | \topcaption[Beer Counter]{\textbf{Beer Counter. }Number of beers before and after 4pm.} | |
191 | \label{beercounter} | |
192 | ||
193 | \tablehead{\hline | |
194 | \multicolumn{1}{|c||}{\textbf{Name}} & \multicolumn{2}{c|}{\textbf{Beers}} \\ | |
195 | \multicolumn{1}{|c||}{\textbf{}} & \multicolumn{1}{c|}{\textbf{before 4pm}} & \multicolumn{1}{c|}{\textbf{after 4pm}} \\ | |
196 | \hline | |
197 | \hline | |
198 | } | |
199 | \tabletail{ \hline | |
200 | } | |
201 | \tablelasttail{} | |
202 | \begin{mpxtabular}{|l||r|r|} | |
203 | Lisa & 0 & 0 \\ | |
204 | Marge & 0 & 1 \\ | |
205 | Wiggum & 0 & 5 \\ | |
206 | Otto & 1 & 3 \\ | |
207 | Homer & 2 & 6 \\ | |
208 | Barney & 8 & 16 \\ | |
209 | \hline | |
210 | \end{mpxtabular} | |
211 | ||
212 | } | |
213 | EOT | |
214 | ; | |
215 | ||
216 | $output = $table->generate_string(); | |
217 | ||
218 | is_deeply([ split("\n",$output) ], [split("\n",$expected_output)], | |
219 | 'without table environment, topcaption custom tabletail'); | |
220 |
0 | use Test::More tests => 9; | |
1 | use Test::NoWarnings; | |
2 | ||
3 | use LaTeX::Table; | |
4 | ||
5 | my $table = LaTeX::Table->new({ filename => 'out.tex', | |
6 | label => 'beercounter', | |
7 | maincaption => 'Beer Counter', | |
8 | caption => 'Number of beers before and after 4pm.', | |
9 | theme => 'Zurich', | |
10 | }); | |
11 | ||
12 | my $test_def = 'test:1c'; | |
13 | ||
14 | is($table->_add_mc_def({ value => $test_def, align => 'r', cols => 2}), $test_def, 'no adding if already has a def'); | |
15 | is($table->_add_mc_def({ value => 'test', align => 'r', cols => 2}), 'test:2r', 'no adding if already has a def'); | |
16 | is_deeply($table->_get_mc_def('test'), { value => 'test' }, 'get without def'); | |
17 | is_deeply($table->_get_mc_def('test:2c'), { value => 'test', align => 'c', cols => 2 }, 'get with def'); | |
18 | ||
19 | is_deeply($table->_add_font_family('test:2r', 'bf'), '\\textbf{test}:2r', 'add bold fonts'); | |
20 | is($table->_extract_number_columns('test:2c'), 2, 'columwidth correct'); | |
21 | is($table->_extract_number_columns('test:2'), 1, 'columwidth correct'); | |
22 | ||
23 | ||
24 | my $header = [ [ 'A:3c'], ['A:2c', 'B'], ['A', 'B', 'C'], ]; | |
25 | my $data = [ [ 'D:3c'], ['D:2c', '1.2'], ['D', 'E', '1.3'], ]; | |
26 | ||
27 | $table = LaTeX::Table->new( | |
28 | { header => $header, | |
29 | data => $data, | |
30 | theme => 'Zurich', | |
31 | } | |
32 | ); | |
33 | ||
34 | $expected_output = <<'EOT' | |
35 | \begin{table} | |
36 | \centering | |
37 | \begin{tabular}{llr} | |
38 | \toprule | |
39 | \multicolumn{3}{c}{\textbf{A}} \\ | |
40 | \multicolumn{2}{c}{\textbf{A}} & \multicolumn{1}{c}{\textbf{B}} \\ | |
41 | \textbf{A} & \multicolumn{1}{c}{\textbf{B}} & \multicolumn{1}{c}{\textbf{C}} \\ | |
42 | \midrule | |
43 | \multicolumn{3}{c}{D} \\ | |
44 | \multicolumn{2}{c}{D} & 1.2 \\ | |
45 | D & E & 1.3 \\ | |
46 | \bottomrule | |
47 | \end{tabular} | |
48 | \end{table} | |
49 | ||
50 | EOT | |
51 | ; | |
52 | ||
53 | my $output = $table->generate_string; | |
54 | ||
55 | is_deeply( | |
56 | [ split( "\n", $output ) ], | |
57 | [ split( "\n", $expected_output ) ], | |
58 | 'is_number works with complicated shortcutted headers and data', | |
59 | ); |
0 | use Test::More tests => 32; | |
1 | use Test::NoWarnings; | |
2 | ||
3 | use LaTeX::Table; | |
4 | use English qw( -no_match_vars ); | |
5 | ||
6 | my $table = LaTeX::Table->new(); | |
7 | # font family test 1 | |
8 | eval { $table->_add_font_family( { value => 'test' }, 'test' ) }; | |
9 | ok( $EVAL_ERROR, 'unknown font family' ); | |
10 | ||
11 | #font family test 2 | |
12 | eval { $table->_add_font_family( { value => 'test' }, 'bf' ) }; | |
13 | ok( !$EVAL_ERROR, 'known font family' ); | |
14 | ||
15 | # callback test 1 | |
16 | my $header = [ [ 'a', 'b' ] ]; | |
17 | my $data = [ [ '1', '2' ] ]; | |
18 | ||
19 | $table = LaTeX::Table->new( | |
20 | { header => $header, | |
21 | data => $data, | |
22 | callback => [], | |
23 | } | |
24 | ); | |
25 | ||
26 | eval { $table->generate_string; }; | |
27 | like( | |
28 | $EVAL_ERROR, | |
29 | qr{Invalid usage of option callback: Not a code reference\.}, | |
30 | 'callback not a code reference' | |
31 | ) || diag $EVAL_ERROR; | |
32 | ||
33 | # callback test 2 | |
34 | $table->set_callback( sub { return 'a'; } ); | |
35 | ||
36 | eval { $table->generate_string; }; | |
37 | ok( !$EVAL_ERROR, 'no error with valid callback' ) || diag $EVAL_ERROR; | |
38 | ||
39 | ||
40 | # xentrystretch test 1 | |
41 | $table = LaTeX::Table->new( | |
42 | { header => $header, | |
43 | data => $data, | |
44 | type => 'xtab', | |
45 | xentrystretch => 'a', | |
46 | } | |
47 | ); | |
48 | ||
49 | eval { $table->generate_string; }; | |
50 | like( | |
51 | $EVAL_ERROR, | |
52 | qr{Invalid usage of option xentrystretch: Not a number: a\.}, | |
53 | 'xentrystretch not a number' | |
54 | ) || diag $EVAL_ERROR; | |
55 | ||
56 | # xentrystretch test 2 | |
57 | $table->set_xentrystretch(0.8); | |
58 | eval { $table->generate_string; }; | |
59 | ok( !$EVAL_ERROR, 'no error with valid xentrystretch' ) || diag $EVAL_ERROR; | |
60 | ||
61 | # theme test 1 | |
62 | # xentrystretch test 1 | |
63 | $table = LaTeX::Table->new( | |
64 | { header => $header, | |
65 | data => $data, | |
66 | theme => 'Leipzig', | |
67 | } | |
68 | ); | |
69 | ||
70 | eval { $table->generate_string; }; | |
71 | like( | |
72 | $EVAL_ERROR, | |
73 | qr{Invalid usage of option theme: Not known: Leipzig\.}, | |
74 | 'unknown theme' | |
75 | ) || diag $EVAL_ERROR; | |
76 | ||
77 | $table->set_theme('Dresden'); | |
78 | eval { $table->generate_string; }; | |
79 | ok( !$EVAL_ERROR, 'no error with valid theme' ) || diag $EVAL_ERROR; | |
80 | ||
81 | # size tests | |
82 | ||
83 | $table = LaTeX::Table->new( | |
84 | { header => $header, | |
85 | data => $data, | |
86 | fontsize => 'HUGE', | |
87 | } | |
88 | ); | |
89 | ||
90 | eval { $table->generate_string; }; | |
91 | like( | |
92 | $EVAL_ERROR, | |
93 | qr{^Invalid usage of option custom_themes: Size not known: HUGE. Valid sizes}, | |
94 | 'unknown size' | |
95 | ) || diag $EVAL_ERROR; | |
96 | $table->set_fontsize('Huge'); | |
97 | ||
98 | eval { $table->generate_string; }; | |
99 | ok( !$EVAL_ERROR, 'no error with valid size' ) || diag $EVAL_ERROR; | |
100 | ||
101 | # header tests | |
102 | $table = LaTeX::Table->new( | |
103 | { header => 'A, B', | |
104 | data => $data, | |
105 | } | |
106 | ); | |
107 | ||
108 | eval { $table->generate_string; }; | |
109 | like( | |
110 | $EVAL_ERROR, | |
111 | qr{Invalid usage of option header: Not an array reference\.}, | |
112 | 'header is not an array reference' | |
113 | ) || diag $EVAL_ERROR; | |
114 | $table->set_header([ 'A', 'B' ]); | |
115 | eval { $table->generate_string; }; | |
116 | like( | |
117 | $EVAL_ERROR, | |
118 | qr{\QInvalid usage of option header: header[0] Not an array reference.}, | |
119 | 'header[0] is not an array reference' | |
120 | ) || diag $EVAL_ERROR; | |
121 | ||
122 | $table->set_header([ [ 'A', ['B'] ] ]); | |
123 | eval { $table->generate_string; }; | |
124 | like( | |
125 | $EVAL_ERROR, | |
126 | qr{\QInvalid usage of option header: header[0][1] not a scalar.}, | |
127 | 'header[0][1] is not a scalar' | |
128 | ) || diag $EVAL_ERROR; | |
129 | ||
130 | # data tests | |
131 | $table = LaTeX::Table->new( | |
132 | { header => $header, | |
133 | data => { 'A' => 1, 'B' => 1 }, | |
134 | } | |
135 | ); | |
136 | ||
137 | eval { $table->generate_string; }; | |
138 | like( | |
139 | $EVAL_ERROR, | |
140 | qr{Invalid usage of option data: Not an array reference\.}, | |
141 | 'data is not an array reference' | |
142 | ) || diag $EVAL_ERROR; | |
143 | ||
144 | $table->set_data([ [ 'A', 'B'], { 'A' => 1, 'B' => 1 } ]); | |
145 | eval { $table->generate_string; }; | |
146 | like( | |
147 | $EVAL_ERROR, | |
148 | qr{\QInvalid usage of option data: data[1] Not an array reference.}, | |
149 | 'data[1] is not an array reference' | |
150 | ) || diag $EVAL_ERROR; | |
151 | ||
152 | $table->set_data([ [ 'A', 'B'], [ 'A', undef ] ]); | |
153 | eval { $table->generate_string; }; | |
154 | like( | |
155 | $EVAL_ERROR, | |
156 | qr{Undefined value in data\[1\]\[1\].}, | |
157 | 'undef value' | |
158 | ) || diag $EVAL_ERROR; | |
159 | ||
160 | $table->set_data($data); | |
161 | $table->set_coldef_strategy(1); | |
162 | ||
163 | eval { $table->generate_string; }; | |
164 | like( | |
165 | $EVAL_ERROR, | |
166 | qr{Invalid usage of option coldef_strategy: Not a hash reference\.}, | |
167 | 'coldef_strategy not a hash' | |
168 | ) || diag $EVAL_ERROR; | |
169 | ||
170 | $table->set_coldef_strategy(['a', 'b']); | |
171 | ||
172 | eval { $table->generate_string; }; | |
173 | like( | |
174 | $EVAL_ERROR, | |
175 | qr{Invalid usage of option coldef_strategy: Not a hash reference\.}, | |
176 | 'coldef_strategy not a hash' | |
177 | ) || diag $EVAL_ERROR; | |
178 | ||
179 | $table->set_coldef_strategy({ | |
180 | URL => qr{ \A \s* http }xms, | |
181 | }); | |
182 | ||
183 | eval { $table->generate_string; }; | |
184 | like( | |
185 | $EVAL_ERROR, | |
186 | qr{^Invalid usage of option coldef_strategy: Missing column attribute URL_COL for URL\.}, | |
187 | 'Missing column attribute URL_COL for URL.' | |
188 | ) || diag $EVAL_ERROR; | |
189 | ||
190 | $table = LaTeX::Table->new( | |
191 | { header => $header, | |
192 | data => $data, | |
193 | width_environment => 'tabularx', | |
194 | } | |
195 | ); | |
196 | ||
197 | eval { $table->generate_string; }; | |
198 | like( | |
199 | $EVAL_ERROR, | |
200 | qr{Invalid usage of option width_environment: Is tabularx and width is unset\. }, | |
201 | 'unknown width environment' | |
202 | ) || diag $EVAL_ERROR; | |
203 | ||
204 | $table = LaTeX::Table->new( | |
205 | { header => $header, | |
206 | data => $data, | |
207 | width_environment => 'tabulary', | |
208 | } | |
209 | ); | |
210 | ||
211 | eval { $table->generate_string; }; | |
212 | like( | |
213 | $EVAL_ERROR, | |
214 | qr{Invalid usage of option width_environment: Is tabulary and width is unset\. }, | |
215 | 'unknown width environment' | |
216 | ) || diag $EVAL_ERROR; | |
217 | ||
218 | $table = LaTeX::Table->new( | |
219 | { header => $header, | |
220 | data => $data, | |
221 | columns_like_header => 2, | |
222 | } | |
223 | ); | |
224 | ||
225 | eval { $table->generate_string; }; | |
226 | like( | |
227 | $EVAL_ERROR, | |
228 | qr{^Invalid usage of option columns_like_header: Not an array reference\.}, | |
229 | 'columns_like_header not an array reference' | |
230 | ) || diag $EVAL_ERROR; | |
231 | ||
232 | $table = LaTeX::Table->new( | |
233 | { header => $header, | |
234 | data => $data, | |
235 | columns_like_header => { 1 => 2 }, | |
236 | } | |
237 | ); | |
238 | ||
239 | eval { $table->generate_string; }; | |
240 | like( | |
241 | $EVAL_ERROR, | |
242 | qr{Invalid usage of option columns_like_header: Not an array reference\.}, | |
243 | 'columns_like_header not an array reference' | |
244 | ) || diag $EVAL_ERROR; | |
245 | ||
246 | $table = LaTeX::Table->new( | |
247 | { header => $header, | |
248 | data => $data, | |
249 | columns_like_header => 0, | |
250 | } | |
251 | ); | |
252 | ||
253 | eval { $table->generate_string; }; | |
254 | ok( | |
255 | !$EVAL_ERROR, | |
256 | 'columns_like_header 0 is ok' | |
257 | ) || diag $EVAL_ERROR; | |
258 | ||
259 | ## resizebox | |
260 | ||
261 | $table = LaTeX::Table->new( | |
262 | { header => $header, | |
263 | data => $data, | |
264 | resizebox => 2, | |
265 | } | |
266 | ); | |
267 | eval { $table->generate_string; }; | |
268 | like( | |
269 | $EVAL_ERROR, | |
270 | qr{Invalid usage of option resizebox: Not an array reference\.}, | |
271 | 'resizebox not an array reference' | |
272 | ) || diag $EVAL_ERROR; | |
273 | ||
274 | $table = LaTeX::Table->new( | |
275 | { header => $header, | |
276 | data => $data, | |
277 | resizebox => { 1 => 2 }, | |
278 | } | |
279 | ); | |
280 | ||
281 | eval { $table->generate_string; }; | |
282 | like( | |
283 | $EVAL_ERROR, | |
284 | qr{Invalid usage of option resizebox: Not an array reference\.}, | |
285 | 'resizebox not an array reference' | |
286 | ) || diag $EVAL_ERROR; | |
287 | ||
288 | $table = LaTeX::Table->new( | |
289 | { header => $header, | |
290 | data => $data, | |
291 | resizebox => 0, | |
292 | } | |
293 | ); | |
294 | ||
295 | eval { $table->generate_string; }; | |
296 | ok( | |
297 | !$EVAL_ERROR, | |
298 | 'resizebox 0 is ok' | |
299 | ) || diag $EVAL_ERROR; | |
300 | ||
301 | $table = LaTeX::Table->new( | |
302 | { header => $header, | |
303 | data => $data, | |
304 | environment => 0, | |
305 | type => 'xtab', | |
306 | } | |
307 | ); | |
308 | ||
309 | ||
310 | eval { $table->generate_string; }; | |
311 | ||
312 | like( | |
313 | $EVAL_ERROR, | |
314 | qr{Invalid usage of option environment: xtab requires an environment\.}, | |
315 | 'xtab requires environment' | |
316 | ) || diag $EVAL_ERROR; | |
317 | ||
318 | $table = LaTeX::Table->new( | |
319 | { header => $header, | |
320 | data => $data, | |
321 | position => 'htb', | |
322 | type => 'xtab', | |
323 | } | |
324 | ); | |
325 | ||
326 | ||
327 | eval { $table->generate_string; }; | |
328 | ||
329 | like( | |
330 | $EVAL_ERROR, | |
331 | qr{Invalid usage of option position: xtab does not support position\.}, | |
332 | 'xtab does not support position' | |
333 | ) || diag $EVAL_ERROR; | |
334 | ||
335 | $table = LaTeX::Table->new( | |
336 | { header => $header, | |
337 | data => $data, | |
338 | left => 1, | |
339 | center => 1, | |
340 | } | |
341 | ); | |
342 | ||
343 | eval { $table->generate_string; }; | |
344 | ||
345 | like( | |
346 | $EVAL_ERROR, | |
347 | qr{Invalid usage of option center, left, right}, | |
348 | 'only one allowed' | |
349 | ) || diag $EVAL_ERROR; | |
350 | ||
351 | $table = LaTeX::Table->new( | |
352 | { header => $header, | |
353 | data => $data, | |
354 | shortcaption => 'short', | |
355 | maincaption => 'main', | |
356 | } | |
357 | ); | |
358 | ||
359 | eval { $table->generate_string; }; | |
360 | ||
361 | like( | |
362 | $EVAL_ERROR, | |
363 | qr{Invalid usage of option maincaption, shortcaption}, | |
364 | 'only one allowed' | |
365 | ) || diag $EVAL_ERROR; |
0 | use Test::More tests => 4; | |
1 | use Test::NoWarnings; | |
2 | ||
3 | use LaTeX::Table; | |
4 | use English qw( -no_match_vars ) ; | |
5 | ||
6 | my $table = LaTeX::Table->new({ filename => 'out.tex', | |
7 | label => 'beercounter', | |
8 | maincaption => 'Beer Counter', | |
9 | caption => 'Number of beers before and after 4pm.', | |
10 | }); | |
11 | ||
12 | my $test_data = [ [ 1, 2, 4], [ 2, 3 ] ]; | |
13 | $table->_calc_data_summary($test_data); | |
14 | my @summary = $table->_get_data_summary(); | |
15 | is_deeply(\@summary, ['NUMBER','NUMBER','NUMBER'], 'all integers'); | |
16 | ||
17 | $test_data = [ [ 'a', 2, 4], [ 'b', 3 ] ]; | |
18 | $table->_calc_data_summary($test_data); | |
19 | @summary = $table->_get_data_summary(); | |
20 | is_deeply(\@summary, ['DEFAULT','NUMBER','NUMBER'], 'not all integers'); | |
21 | ||
22 | $test_data = [ [ 'a', 2, ], [ '1', 3 ] ]; | |
23 | $table->_calc_data_summary($test_data); | |
24 | @summary = $table->_get_data_summary(); | |
25 | is_deeply(\@summary, ['DEFAULT','NUMBER'], 'not all integers'); |
0 | use Test::More tests => 2; | |
1 | use Test::NoWarnings; | |
2 | use English qw( -no_match_vars ) ; | |
3 | ||
4 | my $SYNOPSIS = <<'EOT' | |
5 | ||
6 | use LaTeX::Table; | |
7 | #use Number::Format qw(:subs); # use mighty CPAN to format values | |
8 | ||
9 | my $header = [ | |
10 | [ 'Item:2c', '' ], | |
11 | ['\cmidrule(r){1-2}'], | |
12 | [ 'Animal', 'Description', 'Price' ] | |
13 | ]; | |
14 | ||
15 | my $data = [ | |
16 | [ 'Gnat', 'per gram', '13.65' ], | |
17 | [ '', 'each', '0.0173' ], | |
18 | [ 'Gnu', 'stuffed', '92.59' ], | |
19 | [ 'Emu', 'stuffed', '33.33' ], | |
20 | [ 'Armadillo', 'frozen', '8.99' ], | |
21 | ]; | |
22 | ||
23 | ||
24 | my $table = LaTeX::Table->new( | |
25 | { | |
26 | filename => 'prices.tex', | |
27 | maincaption => 'Price List', | |
28 | caption => 'Try our special offer today!', | |
29 | label => 'table:prices', | |
30 | position => 'htb', | |
31 | header => $header, | |
32 | data => $data, | |
33 | } | |
34 | ); | |
35 | ||
36 | # write LaTeX code in prices.tex | |
37 | $table->generate_string(); | |
38 | ||
39 | # callback functions help you to format values easily (as | |
40 | # a great alternative to LaTeX packages like rccol) | |
41 | # | |
42 | # Here, the first colum and the header is printed in upper | |
43 | # case and the third colum is formatted with format_price() | |
44 | $table->set_callback(sub { | |
45 | my ($row, $col, $value, $is_header ) = @_; | |
46 | if ($col == 0 || $is_header) { | |
47 | $value = uc $value; | |
48 | } | |
49 | elsif ($col == 2 && !$is_header) { | |
50 | # $value = format_price($value, 2, ''); | |
51 | } | |
52 | return $value; | |
53 | }); | |
54 | ||
55 | print $table->generate_string(); | |
56 | ||
57 | EOT | |
58 | ; | |
59 | ||
60 | eval $SYNOPSIS; | |
61 | ok(!$EVAL_ERROR,"Test Synopsis") || diag $EVAL_ERROR; | |
62 |
0 | use Test::More tests => 7; | |
1 | use Test::NoWarnings; | |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
6 | use LaTeX::Table; | |
7 | use English qw( -no_match_vars ); | |
8 | ||
9 | my $header = [ [ 'A', 'B', 'C', ], ]; | |
10 | my $data = [ | |
11 | [ '123.45678', ' 12345678901234567890', '12345', ], | |
12 | [ '123.45', ' A ', '12345', ], | |
13 | ]; | |
14 | ||
15 | my $table = LaTeX::Table->new( | |
16 | { header => $header, | |
17 | data => $data, | |
18 | } | |
19 | ); | |
20 | ||
21 | my $output = $table->generate_string(); | |
22 | ||
23 | my $expected_output = <<'EOT'; | |
24 | \begin{table} | |
25 | \centering | |
26 | \begin{tabular}{llr} | |
27 | \toprule | |
28 | A & B & C \\ | |
29 | \midrule | |
30 | 123.45678 & 12345678901234567890 & 12345 \\ | |
31 | 123.45 & A & 12345 \\ | |
32 | \bottomrule | |
33 | \end{tabular} | |
34 | \end{table} | |
35 | EOT | |
36 | ||
37 | is_deeply( | |
38 | [ split( "\n", $output ) ], | |
39 | [ split( "\n", $expected_output ) ], | |
40 | 'three number columns' | |
41 | ); | |
42 | ||
43 | $table->set_coldef_strategy({ | |
44 | NUMBER => qr{\A \s* \d+ \s* \z}xms, # integers only | |
45 | LONG_COL => '>{\raggedright\arraybackslash}p{7cm}', # non-justified | |
46 | }); | |
47 | ||
48 | $output = $table->generate_string(); | |
49 | ||
50 | $expected_output = <<'EOT'; | |
51 | \begin{table} | |
52 | \centering | |
53 | \begin{tabular}{llr} | |
54 | \toprule | |
55 | A & B & C \\ | |
56 | \midrule | |
57 | 123.45678 & 12345678901234567890 & 12345 \\ | |
58 | 123.45 & A & 12345 \\ | |
59 | \bottomrule | |
60 | \end{tabular} | |
61 | \end{table} | |
62 | EOT | |
63 | ||
64 | is_deeply( | |
65 | [ split( "\n", $output ) ], | |
66 | [ split( "\n", $expected_output ) ], | |
67 | 'three number columns' | |
68 | ); | |
69 | ||
70 | $table->set_coldef_strategy({ | |
71 | NUMBER => qr{\A \s* \d+ \s* \z}xms, # integers only | |
72 | NUMBER_MUST_MATCH_ALL => 0, | |
73 | LONG_COL => '>{\raggedright\arraybackslash}p{7cm}', # non-justified | |
74 | }); | |
75 | ||
76 | ||
77 | $output = $table->generate_string(); | |
78 | ||
79 | $expected_output = <<'EOT'; | |
80 | \begin{table} | |
81 | \centering | |
82 | \begin{tabular}{lrr} | |
83 | \toprule | |
84 | A & B & C \\ | |
85 | \midrule | |
86 | 123.45678 & 12345678901234567890 & 12345 \\ | |
87 | 123.45 & A & 12345 \\ | |
88 | \bottomrule | |
89 | \end{tabular} | |
90 | \end{table} | |
91 | EOT | |
92 | ||
93 | is_deeply( | |
94 | [ split( "\n", $output ) ], | |
95 | [ split( "\n", $expected_output ) ], | |
96 | 'three number columns' | |
97 | ); | |
98 | ||
99 | $data = [ | |
100 | [ '123.45678', ' 12345678901123456789011234567890 ', '12345', ], | |
101 | [ '123.45', ' 1234567898 ', '12345', ], | |
102 | ]; | |
103 | $table = LaTeX::Table->new( | |
104 | { header => $header, | |
105 | data => $data, | |
106 | } | |
107 | ); | |
108 | ||
109 | $table->set_coldef_strategy({ | |
110 | NUMBER => qr{\A \s* \d+ \s* \z}xms, # integers only | |
111 | LONG_COL => '>{\raggedright\arraybackslash}p{7cm}', # non-justified | |
112 | }); | |
113 | ||
114 | ||
115 | $output = $table->generate_string(); | |
116 | ||
117 | $expected_output = <<'EOT'; | |
118 | \begin{table} | |
119 | \centering | |
120 | \begin{tabular}{lrr} | |
121 | \toprule | |
122 | A & B & C \\ | |
123 | \midrule | |
124 | 123.45678 & 12345678901123456789011234567890 & 12345 \\ | |
125 | 123.45 & 1234567898 & 12345 \\ | |
126 | \bottomrule | |
127 | \end{tabular} | |
128 | \end{table} | |
129 | EOT | |
130 | ||
131 | is_deeply( | |
132 | [ split( "\n", $output ) ], | |
133 | [ split( "\n", $expected_output ) ], | |
134 | 'LONG NUMBER Is NUMBER' | |
135 | ); | |
136 | ||
137 | # not a number anymore | |
138 | $table->set_data([ | |
139 | [ '123.45678', ' 1234567890 1234567890 1234567890', '12345', ], | |
140 | [ '123.45', ' 1234567898.122 ', '12345', ], | |
141 | ]); | |
142 | ||
143 | $output = $table->generate_string(); | |
144 | ||
145 | $expected_output = <<'EOT'; | |
146 | \begin{table} | |
147 | \centering | |
148 | \begin{tabular}{l>{\raggedright\arraybackslash}p{7cm}r} | |
149 | \toprule | |
150 | A & B & C \\ | |
151 | \midrule | |
152 | 123.45678 & 1234567890 1234567890 1234567890 & 12345 \\ | |
153 | 123.45 & 1234567898.122 & 12345 \\ | |
154 | \bottomrule | |
155 | \end{tabular} | |
156 | \end{table} | |
157 | EOT | |
158 | ||
159 | is_deeply( | |
160 | [ split( "\n", $output ) ], | |
161 | [ split( "\n", $expected_output ) ], | |
162 | 'LONG Is LONG' | |
163 | ); | |
164 | ||
165 | $table->set_coldef_strategy({ | |
166 | URL => qr{\A \s* http }xms, | |
167 | URL_COL => 'U', # centered | |
168 | }); | |
169 | ||
170 | $table->set_data([ | |
171 | [ '123.45678', ' http://www.google.com', '12345', ], | |
172 | [ '123.45', ' http://www.slashdot.org ', '12345', ], | |
173 | ]); | |
174 | ||
175 | $output = $table->generate_string(); | |
176 | ||
177 | $expected_output = <<'EOT'; | |
178 | \begin{table} | |
179 | \centering | |
180 | \begin{tabular}{lUr} | |
181 | \toprule | |
182 | A & B & C \\ | |
183 | \midrule | |
184 | 123.45678 & http://www.google.com & 12345 \\ | |
185 | 123.45 & http://www.slashdot.org & 12345 \\ | |
186 | \bottomrule | |
187 | \end{tabular} | |
188 | \end{table} | |
189 | EOT | |
190 | ||
191 | is_deeply( | |
192 | [ split( "\n", $output ) ], | |
193 | [ split( "\n", $expected_output ) ], | |
194 | 'new column type' | |
195 | ); | |
196 |
0 | use Test::More tests => 4; | |
1 | use Test::NoWarnings; | |
2 | ||
3 | use LaTeX::Table; | |
4 | ||
5 | my $header = [ [ 'A', 'B', 'C' ], [ 'a', 'b', 'c' ] ]; | |
6 | my $data = [ | |
7 | [ 'Marge', 'Homer', 'Bart' ], | |
8 | [ 'Marge', 'Homer', 'Bart' ], | |
9 | [ 'Marge', 'Homer', 'Bart' ], | |
10 | ]; | |
11 | ||
12 | my $table = LaTeX::Table->new( | |
13 | { header => $header, | |
14 | data => $data, | |
15 | theme => 'Dresden', | |
16 | callback => sub { | |
17 | my ( $row, $col, $value, $is_header ) = @_; | |
18 | if ( $row == 1 && !$is_header ) { | |
19 | return lc $value; | |
20 | } | |
21 | if ( $row == 0 && $is_header ) { | |
22 | return lc $value; | |
23 | } | |
24 | if ( ( $row + $col ) % 2 == 0 ) { | |
25 | return uc $value; | |
26 | } | |
27 | return 'foo'; | |
28 | }, | |
29 | } | |
30 | ); | |
31 | my $expected_output = <<'EOT' | |
32 | \begin{table} | |
33 | \centering | |
34 | \begin{tabular}{|l||l|l|} | |
35 | \hline | |
36 | \multicolumn{1}{|c||}{\textbf{a}} & \multicolumn{1}{c|}{\textbf{b}} & \multicolumn{1}{c|}{\textbf{c}} \\ | |
37 | \multicolumn{1}{|c||}{\textbf{foo}} & \multicolumn{1}{c|}{\textbf{B}} & \multicolumn{1}{c|}{\textbf{foo}} \\ | |
38 | \hline | |
39 | \hline | |
40 | MARGE & foo & BART \\ | |
41 | marge & homer & bart \\ | |
42 | MARGE & foo & BART \\ | |
43 | \hline | |
44 | \end{tabular} | |
45 | \end{table} | |
46 | EOT | |
47 | ; | |
48 | my $output = $table->generate_string; | |
49 | ||
50 | is_deeply( | |
51 | [ split( "\n", $output ) ], | |
52 | [ split( "\n", $expected_output ) ], | |
53 | 'callback seems to work with words', | |
54 | ); | |
55 | ||
56 | $header = [ [ 'A:2c', 'C' ], [ 'a', 'b', 'c' ] ]; | |
57 | $table = LaTeX::Table->new( | |
58 | { header => $header, | |
59 | data => $data, | |
60 | callback => sub { | |
61 | my ( $row, $col, $value, $is_header ) = @_; | |
62 | if ( $is_header ) { | |
63 | return uc $value; | |
64 | } | |
65 | }, | |
66 | theme => 'Zurich', | |
67 | } | |
68 | ); | |
69 | ||
70 | $expected_output = <<'EOT' | |
71 | \begin{table} | |
72 | \centering | |
73 | \begin{tabular}{lll} | |
74 | \toprule | |
75 | \multicolumn{2}{c}{\textbf{A}} & \multicolumn{1}{c}{\textbf{C}} \\ | |
76 | \textbf{A} & \multicolumn{1}{c}{\textbf{B}} & \multicolumn{1}{c}{\textbf{C}} \\ | |
77 | \midrule | |
78 | 0 & 0 & 0 \\ | |
79 | 0 & 0 & 0 \\ | |
80 | 0 & 0 & 0 \\ | |
81 | \bottomrule | |
82 | \end{tabular} | |
83 | \end{table} | |
84 | ||
85 | EOT | |
86 | ; | |
87 | $output = $table->generate_string; | |
88 | ||
89 | is_deeply( | |
90 | [ split( "\n", $output ) ], | |
91 | [ split( "\n", $expected_output ) ], | |
92 | 'callback seems to work with uc headers and shortcuts', | |
93 | ); | |
94 | ||
95 | ||
96 | $header = [ [ 'A:3c'], ['A:2c', 'B'], ['A', 'B', 'C'], ]; | |
97 | $data = [ [ 'D:3c'], ['D:2c', 'E'], ['D', 'E', 'F'], ]; | |
98 | ||
99 | $table = LaTeX::Table->new( | |
100 | { header => $header, | |
101 | data => $data, | |
102 | callback => sub { | |
103 | my ( $row, $col, $value, $is_header ) = @_; | |
104 | if ( $col == 0) { | |
105 | return 'X' . $value; | |
106 | } | |
107 | elsif ( $col == 1) { | |
108 | return 'Y' . $value; | |
109 | } | |
110 | else { | |
111 | return 'Z' . $value; | |
112 | } | |
113 | }, | |
114 | theme => 'Zurich', | |
115 | } | |
116 | ); | |
117 | ||
118 | $output = $table->generate_string; | |
119 | ||
120 | $expected_output = <<'EOT' | |
121 | \begin{table} | |
122 | \centering | |
123 | \begin{tabular}{lll} | |
124 | \toprule | |
125 | \multicolumn{3}{c}{\textbf{XA}} \\ | |
126 | \multicolumn{2}{c}{\textbf{XA}} & \multicolumn{1}{c}{\textbf{ZB}} \\ | |
127 | \textbf{XA} & \multicolumn{1}{c}{\textbf{YB}} & \multicolumn{1}{c}{\textbf{ZC}} \\ | |
128 | \midrule | |
129 | \multicolumn{3}{c}{XD} \\ | |
130 | \multicolumn{2}{c}{XD} & ZE \\ | |
131 | XD & YE & ZF \\ | |
132 | \bottomrule | |
133 | \end{tabular} | |
134 | \end{table} | |
135 | ||
136 | EOT | |
137 | ; | |
138 | ||
139 | $output = $table->generate_string; | |
140 | ||
141 | is_deeply( | |
142 | [ split( "\n", $output ) ], | |
143 | [ split( "\n", $expected_output ) ], | |
144 | 'callback works with complicated shortcutted headers and data', | |
145 | ); |
0 | use Test::More tests => 9; | |
1 | use Test::NoWarnings; | |
2 | ||
3 | use lib 't/lib'; | |
4 | use LaTeX::Table; | |
5 | ||
6 | my $themes = { | |
7 | 'Leipzig' => { | |
8 | 'HEADER_FONT_STYLE' => 'sc', | |
9 | 'HEADER_CENTERED' => 1, | |
10 | 'VERTICAL_RULES' => [ 1, 2, 1 ], | |
11 | 'HORIZONTAL_RULES' => [ 1, 2, 0 ], | |
12 | }, | |
13 | 'Leipzig2' => { | |
14 | 'HEADER_CENTERED' => 1, | |
15 | 'VERTICAL_RULES' => [ 1, 2, 1 ], | |
16 | 'HORIZONTAL_RULES' => [ 1, 2, 0 ], | |
17 | }, | |
18 | 'Leipzig3' => { | |
19 | 'VERTICAL_RULES' => [ 1, 2, 1 ], | |
20 | 'HORIZONTAL_RULES' => [ 1, 2, 0 ], | |
21 | }, | |
22 | 'Leipzig3b' => { | |
23 | 'HEADER_CENTERED' => 0, | |
24 | 'VERTICAL_RULES' => [ 1, 2, 1 ], | |
25 | 'HORIZONTAL_RULES' => [ 1, 2, 0 ], | |
26 | 'BOOKTABS' => 0, | |
27 | }, | |
28 | }; | |
29 | ||
30 | my $test_header = [ [ 'A', 'B', 'C' ], ]; | |
31 | my $test_data = [ [ '1', 'w', 'x' ], [], [ '2', 'y', 'z' ], ]; | |
32 | ||
33 | my $table = LaTeX::Table->new( | |
34 | { environment => 'sidewaystable', | |
35 | caption => 'Test Caption', | |
36 | maincaption => 'Test', | |
37 | header => $test_header, | |
38 | data => $test_data, | |
39 | custom_themes => $themes, | |
40 | theme => 'Leipzig', | |
41 | } | |
42 | ); | |
43 | ||
44 | my $expected_output = <<'EOT' | |
45 | \begin{sidewaystable} | |
46 | \centering | |
47 | \begin{tabular}{|r||l|l|} | |
48 | \hline | |
49 | \multicolumn{1}{|c||}{\textsc{A}} & \multicolumn{1}{c|}{\textsc{B}} & \multicolumn{1}{c|}{\textsc{C}} \\ | |
50 | \hline | |
51 | \hline | |
52 | 1 & w & x \\ | |
53 | \hline | |
54 | 2 & y & z \\ | |
55 | \hline | |
56 | \end{tabular} | |
57 | \caption[Test]{Test. Test Caption} | |
58 | \end{sidewaystable} | |
59 | EOT | |
60 | ; | |
61 | ||
62 | my $output = $table->generate_string(); | |
63 | my @expected_output = split "\n", $expected_output; | |
64 | ||
65 | is_deeply( | |
66 | [ split( "\n", $output ) ], | |
67 | \@expected_output, | |
68 | 'without table environment' | |
69 | ); | |
70 | ||
71 | $table->set_theme('Leipzig2'); | |
72 | $table->set_environment('table'); | |
73 | $output = $table->generate_string(); | |
74 | ||
75 | $expected_output = <<'EOT' | |
76 | \begin{table} | |
77 | \centering | |
78 | \begin{tabular}{|r||l|l|} | |
79 | \hline | |
80 | \multicolumn{1}{|c||}{A} & \multicolumn{1}{c|}{B} & \multicolumn{1}{c|}{C} \\ | |
81 | \hline | |
82 | \hline | |
83 | 1 & w & x \\ | |
84 | \hline | |
85 | 2 & y & z \\ | |
86 | \hline | |
87 | \end{tabular} | |
88 | \caption[Test]{Test. Test Caption} | |
89 | \end{table} | |
90 | EOT | |
91 | ; | |
92 | ||
93 | @expected_output = split "\n", $expected_output; | |
94 | ||
95 | is_deeply( | |
96 | [ split( "\n", $output ) ], | |
97 | \@expected_output, | |
98 | 'without header font' | |
99 | ); | |
100 | ||
101 | $table->set_theme('Leipzig3'); | |
102 | $output = $table->generate_string(); | |
103 | ||
104 | $expected_output = <<'EOT' | |
105 | \begin{table} | |
106 | \centering | |
107 | \begin{tabular}{|r||l|l|} | |
108 | \hline | |
109 | A & B & C \\ | |
110 | \hline | |
111 | \hline | |
112 | 1 & w & x \\ | |
113 | \hline | |
114 | 2 & y & z \\ | |
115 | \hline | |
116 | \end{tabular} | |
117 | \caption[Test]{Test. Test Caption} | |
118 | \end{table} | |
119 | EOT | |
120 | ; | |
121 | @expected_output = split "\n", $expected_output; | |
122 | ||
123 | is_deeply( | |
124 | [ split( "\n", $output ) ], | |
125 | \@expected_output, | |
126 | 'theme, without header centered' | |
127 | ); | |
128 | ||
129 | $table->set_theme('Leipzig3b'); | |
130 | $output = $table->generate_string(); | |
131 | is_deeply( | |
132 | [ split( "\n", $output ) ], | |
133 | \@expected_output, | |
134 | 'theme, without header centered' | |
135 | ); | |
136 | ||
137 | $table->set_theme('Zurich'); | |
138 | $output = $table->generate_string(); | |
139 | ||
140 | $expected_output = <<'EOT' | |
141 | \begin{table} | |
142 | \centering | |
143 | \begin{tabular}{lll} | |
144 | \toprule | |
145 | \textbf{A} & \multicolumn{1}{c}{\textbf{B}} & \multicolumn{1}{c}{\textbf{C}} \\ | |
146 | \midrule | |
147 | 1 & w & x \\ | |
148 | \midrule | |
149 | 2 & y & z \\ | |
150 | \bottomrule | |
151 | \end{tabular} | |
152 | \caption[Test]{Test. Test Caption} | |
153 | \end{table} | |
154 | EOT | |
155 | ; | |
156 | @expected_output = split "\n", $expected_output; | |
157 | ||
158 | is_deeply( | |
159 | [ split( "\n", $output ) ], | |
160 | \@expected_output, | |
161 | 'standard theme' | |
162 | ); | |
163 | ||
164 | $table->search_path( add => 'MyThemes' ); | |
165 | $table->set_theme('Erfurt'); | |
166 | ||
167 | $output = $table->generate_string(); | |
168 | ||
169 | $expected_output = <<'EOT' | |
170 | \begin{table} | |
171 | \centering | |
172 | \begin{tabular}{lll} | |
173 | \toprule | |
174 | \textsc{A} & \multicolumn{1}{c}{\textsc{B}} & \multicolumn{1}{c}{\textsc{C}} \\ | |
175 | \midrule | |
176 | 1 & w & x \\ | |
177 | \midrule | |
178 | 2 & y & z \\ | |
179 | \bottomrule | |
180 | \end{tabular} | |
181 | \caption[Test]{Test. Test Caption} | |
182 | \end{table} | |
183 | EOT | |
184 | ; | |
185 | @expected_output = split "\n", $expected_output; | |
186 | ||
187 | is_deeply( | |
188 | [ split( "\n", $output ) ], | |
189 | \@expected_output, | |
190 | 'custom search path' | |
191 | ); | |
192 | ||
193 | is_deeply($table->get_available_themes->{Erfurt}->{RULES_CMD},[ '\toprule', | |
194 | '\midrule', '\midrule', '\bottomrule' ], 'BOOKTABS shortcut' ); | |
195 | ||
196 | ||
197 | $test_header = [ [ 'head1', 'head2', 'head3', 'head4' ], ]; | |
198 | $test_data = [ | |
199 | [ 'row1', 'row1', 'row1', 'row1' ], | |
200 | [ 'row2', 'row2', 'row2', 'row2' ], | |
201 | [ 'row3', 'row3', 'row3', 'row3' ], | |
202 | [ 'row4', 'row4', 'row4', 'row4' ], | |
203 | ]; | |
204 | ||
205 | my $custom_template = << 'EOT' | |
206 | [%IF CONTINUED %]\addtocounter{table}{-1}[% END %][% COLORDEF_CODE %][% IF | |
207 | ENVIRONMENT %]\begin{[% ENVIRONMENT %][% IF STAR %]*[% END %]}[% IF POSITION %][[% POSITION %]][% END %][% END %] | |
208 | \processtable{[% IF CAPTION %][% CAPTION %][% END %][% IF CONTINUED %] [% CONTINUEDMSG %][% END %][% IF LABEL %]\label{[% LABEL %]}[% END %]} | |
209 | {\begin{[% TABULAR_ENVIRONMENT %]}{[% COLDEF %]} | |
210 | [% HEADER_CODE %][% DATA_CODE %]\end{[% TABULAR_ENVIRONMENT %]}}{[% FOOTTABLE %]} | |
211 | [% IF ENVIRONMENT %]\end{table}[% END %] | |
212 | EOT | |
213 | ; | |
214 | ||
215 | $table = LaTeX::Table->new( | |
216 | { | |
217 | caption => 'This is table caption', | |
218 | label => 'Tab:01', | |
219 | foottable => 'This is a footnote', | |
220 | position => '!t', | |
221 | header => $test_header, | |
222 | data => $test_data, | |
223 | custom_themes => $themes, | |
224 | theme => 'Oxford', | |
225 | custom_template => $custom_template, | |
226 | } | |
227 | ); | |
228 | ||
229 | $expected_output = <<'EOT' | |
230 | \begin{table}[!t] | |
231 | \processtable{This is table caption\label{Tab:01}} | |
232 | {\begin{tabular}{llll} | |
233 | \toprule | |
234 | head1 & head2 & head3 & head4 \\ | |
235 | \midrule | |
236 | row1 & row1 & row1 & row1 \\ | |
237 | row2 & row2 & row2 & row2 \\ | |
238 | row3 & row3 & row3 & row3 \\ | |
239 | row4 & row4 & row4 & row4 \\ | |
240 | \botrule | |
241 | \end{tabular}}{This is a footnote} | |
242 | \end{table} | |
243 | EOT | |
244 | ; | |
245 | ||
246 | @expected_output = split "\n", $expected_output; | |
247 | $output = $table->generate_string(); | |
248 | ||
249 | is_deeply( | |
250 | [ split( "\n", $output ) ], | |
251 | \@expected_output, | |
252 | 'custom search path' | |
253 | ); |
0 | BEGIN { our $WARNMSG; $SIG{'__WARN__'} = sub { $WARNMSG = $_[0]; } }; | |
1 | ||
2 | use Test::More tests => 4; | |
3 | ||
4 | use LaTeX::Table; | |
5 | ||
6 | ||
7 | my $test_header = [ [ 'A', 'B', 'C' ], ]; | |
8 | my $test_data = [ [ '1', 'w', 'x' ], [], [ '2', 'y', 'z' ], ]; | |
9 | ||
10 | my $table = LaTeX::Table->new({ tablepos => 'ht', | |
11 | table_environment => 'sidewaystable', | |
12 | tabledef => 'lcc', | |
13 | theme => 'Zurich', | |
14 | }); | |
15 | ||
16 | $table->generate_string($test_header, $test_data); | |
17 | like($WARNMSG, qr{DEPRECATED. Use options header and data instead}, | |
18 | 'DEPRECATED warning'); | |
19 | ||
20 | my $expected_output = <<'EOT' | |
21 | \begin{sidewaystable}[ht] | |
22 | \centering | |
23 | \begin{tabular}{lcc} | |
24 | \toprule | |
25 | \textbf{A} & \multicolumn{1}{c}{\textbf{B}} & \multicolumn{1}{c}{\textbf{C}} \\ | |
26 | \midrule | |
27 | 1 & w & x \\ | |
28 | \midrule | |
29 | 2 & y & z \\ | |
30 | \bottomrule | |
31 | \end{tabular} | |
32 | \end{sidewaystable} | |
33 | EOT | |
34 | ; | |
35 | ||
36 | my $output = $table->generate_string(); | |
37 | my @expected_output = split "\n", $expected_output; | |
38 | ||
39 | is_deeply( | |
40 | [ split( "\n", $output ) ], | |
41 | \@expected_output, | |
42 | 'with < 0.1.0 API' | |
43 | ); | |
44 | ||
45 | $table = LaTeX::Table->new({ tablepos => 'ht', | |
46 | header => $test_header, | |
47 | data => [ [ '1', 'w', 'x' ], [], [ '2.1', | |
48 | 'y12345', 'z' ], ], | |
49 | theme => 'Zurich', | |
50 | }); | |
51 | ||
52 | $table->set_tabledef_strategy({ | |
53 | IS_A_NUMBER => qr{\A \d+ \z}xms, | |
54 | IS_LONG => 5, | |
55 | LONG_COL => 'p{5cm}', | |
56 | DEFAULT_X => 'c', | |
57 | DEFAULT => 'r', | |
58 | }); | |
59 | ||
60 | $expected_output = <<'EOT' | |
61 | \begin{table}[ht] | |
62 | \centering | |
63 | \begin{tabular}{lp{5cm}r} | |
64 | \toprule | |
65 | \textbf{A} & \multicolumn{1}{c}{\textbf{B}} & \multicolumn{1}{c}{\textbf{C}} \\ | |
66 | \midrule | |
67 | 1 & w & x \\ | |
68 | \midrule | |
69 | 2.1 & y12345 & z \\ | |
70 | \bottomrule | |
71 | \end{tabular} | |
72 | \end{table} | |
73 | EOT | |
74 | ; | |
75 | ||
76 | $output = $table->generate_string(); | |
77 | ||
78 | is_deeply( | |
79 | [ split( "\n", $output ) ], | |
80 | [ split( "\n", $expected_output ) ], | |
81 | 'three number columns' | |
82 | ); | |
83 | ||
84 | $table->set_width('300pt'); | |
85 | $table->set_width_environment('tabularx'); | |
86 | ||
87 | $expected_output = <<'EOT' | |
88 | \begin{table}[ht] | |
89 | \centering | |
90 | \begin{tabularx}{300pt}{lXc} | |
91 | \toprule | |
92 | \textbf{A} & \multicolumn{1}{c}{\textbf{B}} & \multicolumn{1}{c}{\textbf{C}} \\ | |
93 | \midrule | |
94 | 1 & w & x \\ | |
95 | \midrule | |
96 | 2.1 & y12345 & z \\ | |
97 | \bottomrule | |
98 | \end{tabularx} | |
99 | \end{table} | |
100 | EOT | |
101 | ; | |
102 | ||
103 | $output = $table->generate_string(); | |
104 | ||
105 | is_deeply( | |
106 | [ split( "\n", $output ) ], | |
107 | [ split( "\n", $expected_output ) ], | |
108 | 'three number columns' | |
109 | ); |
0 | package MyThemes::Custom; | |
1 | use Moose; | |
2 | ||
3 | with 'LaTeX::Table::Themes::ThemeI'; | |
4 | ||
5 | sub _definition { | |
6 | return { | |
7 | 'Erfurt' => { | |
8 | 'HEADER_FONT_STYLE' => 'sc', | |
9 | 'HEADER_CENTERED' => 1, | |
10 | 'STUB_ALIGN' => q{l}, | |
11 | 'VERTICAL_RULES' => [ 0, 0, 0 ], | |
12 | 'HORIZONTAL_RULES' => [ 1, 1, 0 ], | |
13 | 'BOOKTABS' => 1, | |
14 | }, | |
15 | 'Oxford' => { | |
16 | 'STUB_ALIGN' => q{l}, | |
17 | 'VERTICAL_RULES' => [ 0, 0, 0 ], | |
18 | 'HORIZONTAL_RULES' => [ 1, 1, 0 ], | |
19 | 'RULES_CMD' => [ '\toprule', '\midrule', '\midrule', '\botrule' ], | |
20 | } | |
21 | }; | |
22 | } | |
23 | ||
24 | 1; | |
25 | ||
26 | # vim: ft=perl sw=4 ts=4 expandtab |
0 | #!perl | |
1 | ||
2 | use strict; | |
3 | use warnings; | |
4 | use File::Spec; | |
5 | use Test::More; | |
6 | use English qw(-no_match_vars); | |
7 | ||
8 | if ( not $ENV{TEST_AUTHOR} ) { | |
9 | my $msg = 'Author test. Set $ENV{TEST_AUTHOR} to a true value to run.'; | |
10 | plan( skip_all => $msg ); | |
11 | } | |
12 | ||
13 | eval { require Test::Perl::Critic; }; | |
14 | ||
15 | if ( $EVAL_ERROR ) { | |
16 | my $msg = 'Test::Perl::Critic required to criticise code'; | |
17 | plan( skip_all => $msg ); | |
18 | } | |
19 | ||
20 | my $rcfile = File::Spec->catfile( 't', 'perlcriticrc' ); | |
21 | Test::Perl::Critic->import( -profile => $rcfile ); | |
22 | all_critic_ok(); |
0 | severity=1 | |
1 | verbose=11 | |
2 | ||
3 | [-Documentation::RequirePodSections] | |
4 | ||
5 | [Miscellanea::RequireRcsKeywords] | |
6 | keywords = Date Author Revision | |
7 | ||
8 | [-ValuesAndExpressions::RequireInterpolationOfMetachars] | |
9 | ||
10 | [InputOutput::RequireBriefOpen] | |
11 | lines = 15 |
0 | #!perl -T | |
1 | ||
2 | use Test::More; | |
3 | eval "use Test::Pod::Coverage 1.04"; | |
4 | plan skip_all => "Test::Pod::Coverage 1.04 required for testing POD coverage" if $@; | |
5 | my $trustme = { trustme => | |
6 | [qr/^(close|open|BUILD|START|meta|invalid_option_usage)$|^set_|^get_|^has_/] }; | |
7 | all_pod_coverage_ok($trustme); |