latex 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/LICENSE.txt +58 -0
  2. data/README +57 -0
  3. data/examples/test-latex.rb +40 -0
  4. data/lib/latex.rb +516 -0
  5. metadata +39 -0
@@ -0,0 +1,58 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.co.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the GPL
3
+ (see COPYING.txt file), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a) place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b) use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c) rename any non-standard executables so the names do not conflict
21
+ with standard executables, which must also be provided.
22
+
23
+ d) make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or executable
26
+ form, provided that you do at least ONE of the following:
27
+
28
+ a) distribute the executables and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b) accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c) give non-standard executables non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d) make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under this terms.
43
+
44
+ They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
45
+ files under the ./missing directory. See each file for the copying
46
+ condition.
47
+
48
+ 5. The scripts and library files supplied as input to or produced as
49
+ output from the software do not automatically fall under the
50
+ copyright of the software, but belong to whomever generated them,
51
+ and may be sold commercially, and may be aggregated with this
52
+ software.
53
+
54
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
55
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
56
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
57
+ PURPOSE.
58
+
data/README ADDED
@@ -0,0 +1,57 @@
1
+ Latex README
2
+ ============
3
+
4
+ Latex is a ruby library and contains LaTeX text generation support for Ruby.
5
+ Its main class LatexFile contains:
6
+ - support for the subfigure environment => LatexFile.figures
7
+ - complex tables with nested headers and subheaders => LatexFile.table
8
+ - the method LatexFile.puts indents the given lines according to begin...end
9
+ blocks.
10
+
11
+ The directory examples/ contains a demonstration of the table generating
12
+ features.
13
+
14
+
15
+ Requirements
16
+ ------------
17
+
18
+ * Ruby 1.8
19
+
20
+
21
+ Install
22
+ -------
23
+
24
+ De-compress archive and enter its top directory.
25
+ Then type:
26
+
27
+ ($ su)
28
+ # ruby setup.rb
29
+
30
+ This simple step installs this program under the default
31
+ location of Ruby libraries. You can also install files into
32
+ your favorite directory by supplying setup.rb some options.
33
+ Try "ruby setup.rb --help".
34
+
35
+
36
+ Alternatively you can use the remote installer RubyGems
37
+ [http://rubygems.rubyforge.org/] for installation. Having RubyGems installed
38
+ on your system, just type:
39
+
40
+ ($ su)
41
+ # gem install latex --remote
42
+
43
+
44
+ Usage
45
+ -----
46
+
47
+ In order to get an overview of the features you can generate
48
+ the RDoc documentation and hava a look at the examples/ directory.
49
+
50
+
51
+ License
52
+ -------
53
+
54
+ Ruby License
55
+
56
+
57
+ Christian Bang, cbang AT web.de
@@ -0,0 +1,40 @@
1
+ require 'latex'
2
+
3
+ tex=LatexFile.new("latextest.tex")
4
+ rows = {}
5
+ rows["row1"] = {"col1" => "r1c1", "col2"=>"r1c2", "col3"=>["r1c3","3"]}
6
+ rows["row2"] = {"col1" => "r2c1", "col2"=>"r2c2", "Col3"=>["r2c3","1.4","2"]}
7
+ tex.table(rows,"common table")
8
+
9
+ File.open("saved_table.dat","w") do |f|
10
+ Marshal::dump(rows, f)
11
+ end
12
+
13
+ rows = {}
14
+ rows["A1"] = {'B'=>
15
+ {'A'=> ['5',6],
16
+ 'C'=> {'F'=>'1','G'=>'2'},
17
+ 'D'=> {'H'=>'3','I'=>'4'}
18
+ },
19
+ 'X'=>[1,3,55.55]}
20
+ rows["A2"] = {'B'=>
21
+ {'C'=> {'F'=>'11','G2'=>'22'},
22
+ 'D'=> {'H'=>'33','I2'=>{'a'=>'44','b'=>'66'}},
23
+ 'E'=> '55'},
24
+ 'X'=>[2.3,5.111,1,4]}
25
+ tex.table(rows,"hierarchical headers", "Rows")
26
+
27
+ File.open("saved_table.dat","r") do |f|
28
+ old_rows = Marshal::load(f)
29
+ rows.merge!(old_rows)
30
+ end
31
+ tex.table(rows,"both tables",:rowTitle=>"Instance") do |x,y|
32
+ order = %w{X B C D E G F H col1 col2 col3 Col3}
33
+ if order.index(x) && order.index(y)
34
+ order.index(x) <=> order.index(y)
35
+ else
36
+ x <=> y
37
+ end
38
+ end
39
+ tex.close
40
+
@@ -0,0 +1,516 @@
1
+ # Copyright (c) 2004 Christian Bang <cbang AT web.de> and Frank Hutter
2
+ #
3
+ # Version 0.1.1
4
+ #
5
+ # All rights reserved. You can redistribute and/or modify it under the same terms as Ruby.
6
+ #
7
+ # This file provides a LatexFile class for Ruby.
8
+
9
+ class String
10
+ #Escapes underscores. Use this if you have a string that contains
11
+ #such but you don't mean the latex semantic of underscore.
12
+ def escape_
13
+ gsub(/_/,"\\_")
14
+ end
15
+ end
16
+
17
+ #examples: Figure.new("9cm", "image.eps", "Test image")
18
+ # Figure.new("angle=-90,width=9.5cm", "rotatedimage.eps", "Rotated image", "link01")
19
+ Figure = Struct.new(:format, :filename, :title, :label)
20
+
21
+ class FormatError < StandardError
22
+ end
23
+
24
+ # +LatexFile+ is a +File+ with special functions for easy generation of
25
+ # LaTeX code.
26
+ # Current mayor features are +table+ and +figures+ generation.
27
+ #
28
+ # You may want to quote underscores ('_') in some Latex code you create. For this use String.escape_ which
29
+ # is available with this file.
30
+ class LatexFile < File
31
+ Header = Struct.new(:name, :children)
32
+
33
+ # the default table font size, default is nil which means the Latex default. See #table for possible values
34
+ attr_accessor :defaultTableFontSize
35
+
36
+ @@defaultUsePackages = %w([latin1]{inputenc} [final]{graphics} [pdftex]{graphicx} [dvips]{color}
37
+ {amsfonts} {subfigure} {lscape} {hyperref})
38
+ @@default_extras = {:fontsize => "10pt" }
39
+ attr_reader :extras
40
+
41
+ # Open a new latex-file for writing.
42
+ # +extras+ is an optional hash that may contain the following flags
43
+ # <tt>:landscape</tt>:: turns all pages 90�
44
+ # <tt>:twocolumn</tt>:: the whole document has two columns
45
+ # <tt>extras[:fontsize]</tt>:: string containing the font size like "10pt"
46
+ # === Example:
47
+ # f = LatexFile.new("test.tex", {:twocolumn => true, :fontsize => "11pt"})
48
+ def initialize(filename, extras = nil)
49
+ super(filename,"w") # open a file for write access
50
+ @extras = extras || Hash.new
51
+ #use defaults for unused entries:
52
+ @extras.each_key{|key| @extras[key] |= @@default_extras[key] }
53
+ @indent = 0 # indent lines in blocks
54
+
55
+ @usePackages = @extras[:usePackages] || @@defaultUsePackages
56
+
57
+ writeDocumentHeader
58
+ @lastWasPrint = false
59
+ end
60
+
61
+ def writeDocumentHeader
62
+ twocolumn = @extras[:twocolumn] ? ",twocolumn" : ""
63
+ landscape = @extras[:landscape] ? "\\special{landscape}" : ""
64
+ puts "\\documentclass[#{@extras[:fontsize]}#{twocolumn}]{article}"
65
+ @usePackages.each{|package| puts "\\usepackage#{package}"}
66
+ puts "\\addtolength{\\oddsidemargin}{-3.5cm}"
67
+ puts "\\addtolength{\\textwidth}{7cm}"
68
+ puts "\\addtolength{\\topmargin}{-3cm}"
69
+ puts "\\addtolength{\\textheight}{5cm}"
70
+ puts "\\newcommand{\\hide}[1]{}"
71
+ puts "#{landscape}"
72
+ puts "\\begin{document}"
73
+ puts "\\DeclareGraphicsExtensions{.jpg,.pdf,.mps,.png}"
74
+ end
75
+
76
+ #Write the latex-file footer and closes the file.
77
+ def close
78
+ puts "\\end{document}"
79
+ super
80
+ end
81
+
82
+ #Prints a string to the latex file and indents each line with respect to the
83
+ #current indentation level that depends on nested blocks.
84
+ def puts(string)
85
+ lines = string.split("\n")
86
+ for line in lines
87
+ @indent -= 2 if line[0,5]=='\\end{' && @indent >= 2
88
+ if @lastWasPrint
89
+ super(line)
90
+ @lastWasPrint = false
91
+ else
92
+ super(" " * @indent + line)
93
+ end
94
+ @indent += 2 if line[0,7]=='\\begin{'
95
+ end
96
+ end
97
+
98
+ #Insert spaces up to the current indentation level
99
+ def indent
100
+ print " "*@indent
101
+ end
102
+
103
+ #Other than puts, print does NOT indent the text. If you want to do so
104
+ #call +indent+ before.
105
+ def print(string)
106
+ @lastWasPrint = true
107
+ @indent -= 2 if string[/\\end/]
108
+ @indent += 2 if string[/\\begin/]
109
+ super(string)
110
+ end
111
+
112
+ # Easy creation of environments.
113
+ # +name+:: the name of the environment.
114
+ # +args+:: an optional list of arguments that will be added after the environment definition.
115
+ # === Example:
116
+ # tex.env("table","[ht]") do
117
+ # tex.puts "<table body>"
118
+ # end
119
+ def env(name, *args)
120
+ puts "\\begin{#{name}}#{args}"
121
+ yield if block_given?
122
+ puts "\\end{#{name}}"
123
+ end
124
+
125
+ ########### Figure generation #################################################
126
+
127
+ #Inserts one (ore more) figure block(s) with given figures as subfigures.
128
+ #+figures+::
129
+ # is an array consisting of +Figure+ instances.
130
+ # <tt>Figure = Struct.new(:format, :filename, :title)</tt>
131
+ # If +format+ begins with a number, it is assumed to be the width of the image.
132
+ # But you can also set e.g. <tt>"height=10.5cm,angle=-90"</tt>.
133
+ # For more info see the documentation to <tt>\includegraphics </tt> in the
134
+ # +graphicx+ package of _LaTeX_.
135
+ #+caption+:: is placed on each figure block that is created.
136
+ #+newPageThreshold+::
137
+ # is maximum the number of figures in a block.
138
+ # If more figures are given then a new block is created with the same
139
+ # caption.
140
+ #+placement+:: an optional placement for the figure blocks.
141
+ #+label+:: an optional label of the figures block ('fig:' is added)
142
+ # You can also use label="\\hypertarget{...}" if you like.
143
+ # Otherwise a \label{fig:...} is generated.
144
+ #=== Example:
145
+ # Experiment = Struct.new(:caption, :figures)
146
+ # thisExperiment = Experiment.new
147
+ # thisExperiment.caption = "Instance: #{instance}_1.dat".escape_
148
+ # thisExperiment.figures = [
149
+ # Figure.new("6.5cm", epsDirectory, "#{instance}-a.eps"),
150
+ # Figure.new("6.5cm", epsDirectory, "#{instance}-b.eps"),
151
+ # Figure.new("14cm", epsDirectory, "#{instance}-c.eps", "Title for image c)")
152
+ # ]
153
+ # tex.figures(thisExperiment.caption, thisExperiment.figures, 3)
154
+ def figures(caption, figures, newPageThreshold, placement = "htbp", label = nil)
155
+ lastimagepath = ""
156
+ figures.each_with_index do |figure,i|
157
+ figure.title = "[{#{figure.title}}]" unless figure.title == "" or figure.title == nil
158
+ if i % newPageThreshold == 0
159
+ puts "\\begin{figure}[#{placement}]"
160
+ puts "\\caption{#{caption}}"
161
+ if label
162
+ if label[0,1]=='\\' #you can use \hypertarget here
163
+ puts label
164
+ else
165
+ puts "\\label{fig:#{label}}"
166
+ end
167
+ end
168
+ puts "\\centering"
169
+ end
170
+ imagepath = File.dirname(figure.filename)
171
+ puts "\\graphicspath{{#{imagepath}}}" if imagepath != "" and imagepath != "." and lastimagepath != imagepath
172
+ lastimagepath = imagepath
173
+ figure.format = "width="+figure.format if figure.format =~ /^[0-9\.]/
174
+ if figure.label
175
+ if figure.label[0,1]=='\\'
176
+ puts figure.label
177
+ else
178
+ puts "\\label{#{figure.label}}"
179
+ end
180
+ end
181
+ puts "\\subfigure#{figure.title}{\\includegraphics[#{figure.format}]{#{File.basename(figure.filename)}}}"
182
+ if i % newPageThreshold == newPageThreshold-1 or figure == figures[-1]
183
+ puts "\\end{figure}"
184
+ puts "\\clearpage"
185
+ end
186
+ end
187
+ end
188
+
189
+ ########### Table Generation functions #################################################
190
+
191
+ #This is a helper function for table generation.
192
+ #It computes the number of columns that are leaves of the tree with root +header_node+.
193
+ #You can also say, it computes the number of leaves of the given tree.
194
+ #+header+:: is of type +Header+: (name, children)
195
+ def getNumColsOfHeader(header)
196
+ header.children.inject(0) do |numChildren, child|
197
+ numChildren + ((child.class == Header) ? getNumColsOfHeader(child) : 1)
198
+ end
199
+ end
200
+ private :getNumColsOfHeader
201
+
202
+ #+hash+:: must contain hashes as values for all keys.
203
+ #These child hashes will be joined/merged to one big hash.
204
+ #The actual leafes will be ignored so that only the header remain.
205
+ def getHeaderMergedHash(list)
206
+ merged = {}
207
+ toMerge = Hash.new {|h,k| h[k] = [] }
208
+ nothingToMerge = true
209
+ for entry in list
210
+ if entry.class == Hash
211
+ entry.each_pair do |key,value|
212
+ toMerge[key] << value
213
+ end
214
+ nothingToMerge = false
215
+ end
216
+ end
217
+ #return list if nothingToMerge
218
+ return nil if nothingToMerge #return only header tree without any data
219
+ toMerge.each_pair do |key,value|
220
+ merged[key] = getHeaderMergedHash(value)
221
+ end
222
+ return merged
223
+ end
224
+ private :getHeaderMergedHash
225
+
226
+ @@default_sort = Proc.new { |x,y| x <=> y }
227
+
228
+ #Given a list of hashes, initially a hash-list of each row it
229
+ #returns a sorted tree representation - a headerList.
230
+ #+sort_block+:: a block that compares header names
231
+ def hash2HeaderList(hash, sort_block = @@default_sort)
232
+ headerList = []
233
+ entries = hash.to_a
234
+ entries.sort! {|x,y| sort_block.call(x[0],y[0])}
235
+ for key,value in entries
236
+ if value.class == Hash
237
+ subtree = hash2HeaderList(value, sort_block)
238
+ headerList << Header.new(key,subtree)
239
+ else
240
+ headerList << key
241
+ end
242
+ end
243
+ return headerList
244
+ end
245
+ private :hash2HeaderList
246
+
247
+ #Performes a breath first traversal of the given tree
248
+ #+headerList+:: a list of header nodes of class +Header+.
249
+ #Returns a list of headers (together with the number of columns they use) for each header line needed.
250
+ #example: <tt>[['B',['C',['F','G']], ['D',['H','I']],['E']]]</tt> =>
251
+ #<tt>[['B'], ['C','D','E'], ['F','G','H','I']]</tt> and with their column width information
252
+ #if the (sub)header covers more than one column =>
253
+ #<tt>[[['B',5]], [['C',2],['D',2],'E'], ['F','G','H','I']]</tt>
254
+ #The length of the returned list is the number of rows needed for the headers.
255
+ def getHeaderLines(headerList) #:nodoc:
256
+ line = []
257
+ nextLevel = [] # collects the children nodes of all nodes processed (BFS)
258
+ hasChildrenInNextLevel = false
259
+ for header in headerList
260
+ if header.class != Header
261
+ line << header #leaf node will not be put in an array with column width info
262
+ nextLevel += ["~"] # insert this for lines below this
263
+ else
264
+ line << [header.name, getNumColsOfHeader(header)]
265
+ nextLevel += header.children
266
+ hasChildrenInNextLevel = true
267
+ end
268
+ end
269
+ return hasChildrenInNextLevel ? [line] + getHeaderLines(nextLevel) : [line]
270
+ end
271
+ private :getHeaderLines
272
+
273
+ #Returns a list of paths to all leaf nodes of the given header-tree list. The Leaf nodes are the final
274
+ #columns. In order to compute the table value at (row,col) we want to access only the leaf cols and not
275
+ #the header columns.
276
+ #Example: let <tt>[['B',['C',['F','G']], ['D',['H','I']],['E']]]</tt> be our
277
+ #header tree. The real columns are F,G,H,I,E. In order to access e.g. 'I' we need to know the path [B,D,I].
278
+ #<tt> => [["B", "C", "F"], ["B", "C", "G"], ["B", "D", "H"], ["B", "D", "I"], ["B", "E"]]</tt>
279
+ def getLeafColumns(headerList, path_prefix = nil) #:nodoc:
280
+ paths = []
281
+ path_prefix = path_prefix || []
282
+ for header in headerList
283
+ if header.class == Header
284
+ paths += getLeafColumns(header.children, path_prefix + [header.name])
285
+ else #header is not of class Header but a leaf header (string)
286
+ paths << path_prefix + [header]
287
+ end
288
+ end
289
+ return paths
290
+ end
291
+ private :getLeafColumns
292
+
293
+ #Pretty print output of table entries. If an entry is an array then
294
+ #+prettyPrintCell+ will be called for every table item. You can override this
295
+ #function if you like a special behaviour.
296
+ def prettyPrintCell(x)
297
+ if x.kind_of?(Integer)
298
+ x = "%d" % x
299
+ elsif x.kind_of?(Float)
300
+ x = "%.2f" % x
301
+ else
302
+ x = x.to_s
303
+ end
304
+ raise(FormatError, "Invalid format: #{x.inspect} contains % that is not sufficiently quoted for latex.", caller) if x =~ /[^\\]%|^%/
305
+ x.gsub(/1.#J|Infinity|1.#INF0/, "$\\infty$")
306
+ end
307
+
308
+
309
+ # Generates a table with the specified entries.
310
+ # +entries+::
311
+ # the row-hash where the keys are the row names which are printed in the first column.
312
+ # The <tt>entries[row]</tt> is a column-hash. Its keys are the column names.
313
+ # A column-hash value can be either
314
+ # - an object (with a <tt>to_s</tt> method) that are printed
315
+ # - an array containing objects. In this case a new row is added for each array entry
316
+ # - a hash in which case the keys of this hash are subheaders.
317
+ # +caption+:: the caption of the table.
318
+ # +args+::
319
+ # is either a hash or further arguments
320
+ # Case 1::
321
+ # The hash is indexed by one of the argument symbols below, the values correspond to the
322
+ # argument values you want to set to the corresponding argument.
323
+ # Instead of symbols you can also use strings, e.g. <tt>:label</tt> or <tt>"label"<</tt>
324
+ # Case 2::
325
+ # args are some more arguments. Then they will be interpreted as the following arguments
326
+ # in the same order. You need not use all of them.
327
+ # <tt>:rowTitle</tt>:: the title of the first column that contains the row names.
328
+ # <tt>:label</tt>:: the label of the table. The "tab:" prefix is added automatically .
329
+ # <tt>:newTableThreshold</tt>::
330
+ # maximum number of lines per table. If reached then a new table will be created.
331
+ # Zero means no restriction. An empty row (entries[name] == nil) also toggles a new table.
332
+ # <tt>:placement</tt>:: the LaTeX placement for the table. See the LaTeX documentation for details.
333
+ # <tt>:empty</tt>:: a string that will be put in those fields that have no value.
334
+ # <tt>:sort</tt>::
335
+ # is used to sort the rows and columns. Default is alphabetical ordering.
336
+ # See the example below to get an idea on how to implement customized ordering.
337
+ # <tt>:landscape</tt>:: if true, it will turn the page by 90 degree.
338
+ # <tt>:fontSize</tt>::
339
+ # A latex fontsize modifier like tiny, scriptsize, footnotesize, small,
340
+ # normalsize (default), large, Large, LARGE, huge, Huge.
341
+ # <tt>:header_hlines</tt>::
342
+ # If +true+, then horizontal lines between headers of different depths are drawn.
343
+ # Default is +false+ (no horizontal header lines).
344
+ #
345
+ # === Example:
346
+ # require 'latex'
347
+ # tex = LatexFile.new("table.tex")
348
+ # rows["row1"] = {'Main Header'=>
349
+ # {'A'=> '5',
350
+ # 'B'=> {'D'=>'1','E'=>'2'},
351
+ # 'C'=> {'F'=>'3','G'=>'4'}},
352
+ # 'X'=> [1,3,55.55]}
353
+ # tex.table(rows,"table with hierarchical headers",:rowTitle=>"Instance")
354
+ # tableSort = Proc.new do |x,y|
355
+ # order = %w{A X B C D E}
356
+ # (order.index(x) && order.index(y)) ? order.index(x) <=> order.index(y) : x <=> y
357
+ # end
358
+ # tex.table(rows,"special ordering", :rowTitle=>"Instance", :sort => tableSort)
359
+ def table(entries, caption, *args)
360
+ tableValidArgs = [:rowTitle, :label, :newTableThreshold, :placement, :empty, :sort, :landscape, :fontSize, :grouping, :header_hlines]
361
+ # raise(ArgumentError,"Too many arguments Latex.table", caller) unless args.length <= 1
362
+ hash = {}
363
+ args = if args[0].kind_of?(Hash)
364
+ args[0].each_pair{|key,value| hash[key.to_sym]= value}; hash # allow string keys also
365
+ else
366
+ args.each_with_index{|arg,i| hash[tableValidArgs[i].to_sym] = arg}; hash
367
+ end
368
+ args.each_key{|key| raise(ArgumentError,"Invalid argument: #{key} for Latex.table", caller) unless tableValidArgs.include?(key)}
369
+ @tableCaption = caption
370
+ rowTitle = args[:rowTitle] || ""
371
+ @tableLabel = args[:label] || ""
372
+ newTableThreshold = args[:newTableThreshold] || (args[:landscape] ? 38 : 60)
373
+ placement = args[:placement] || "htbp"
374
+ empty = args[:empty] ||"-"
375
+ sort_block = args[:sort] ||@@default_sort
376
+ grouping = args[:grouping] || [entries.keys]
377
+ @tableLandscape = args[:landscape]
378
+ @tableFontSize = args[:fontSize] || @defaultTableFontSize
379
+ @header_hlines = args[:header_hlines]
380
+
381
+ #access an element in the table which is located in row _rowName_ and in a column
382
+ #that is defined by a _path_ through the headers that can be obtained with
383
+ #the function +getLeafColumns+.
384
+ def accessElement(entries, rowName, path) #:nodoc:
385
+ entry = entries[rowName]
386
+ for key in path
387
+ entry = entry[key]
388
+ return [] unless entry
389
+ end
390
+ return entry.is_a?(Array) ? entry : [entry]
391
+ end
392
+
393
+ def printTableHeader(placement, headerLines, leafColumns, rowTitle) #:nodoc:
394
+ puts "\\begin{landscape}" if @tableLandscape
395
+ puts "\n\\begin{table}[#{placement}]\n\\begin{center}"
396
+ puts "\\#{@tableFontSize}" if @tableFontSize
397
+ print " "*@indent + "\\begin{tabular}{|"
398
+ print "c|" * (leafColumns.length+1)
399
+ puts "}"
400
+ currentHeaderRowNumber = 0
401
+ puts "\\hline"
402
+ for headerLine in headerLines
403
+ print " "*@indent
404
+ if headerLine == headerLines[-1]
405
+ print "#{rowTitle} & " # row name title comes in the last header line
406
+ else
407
+ print "~ & "
408
+ end
409
+ currentColumn = 2
410
+ cline = ""
411
+ print headerLine.map {|headerName, columns|
412
+ raise(FormatError, "Invalid format: #{headerName.inspect} contains % that is not sufficiently quoted for latex.", caller) if headerName =~ /[^\\]%|^%/
413
+ if columns
414
+ cline += "\\cline{#{currentColumn}-#{(currentColumn+=columns)-1}}" if @header_hlines
415
+ "\\multicolumn{#{columns}}{c|}{#{headerName}}"
416
+ else
417
+ currentColumn += 1
418
+ if currentHeaderRowNumber == headerLines.length-1 || headerName == "~"
419
+ headerName
420
+ else
421
+ delta = "%.1f" % ((headerLines.length-currentHeaderRowNumber-1).to_f)
422
+ "\\raisebox{-#{delta}\\totalheight}[1ex][1ex]{#{headerName}}"
423
+ end
424
+ end
425
+ }.join(" & ")
426
+ puts "\\\\"+cline
427
+ currentHeaderRowNumber += 1
428
+ end
429
+ puts "\\hline\\hline"
430
+ end
431
+
432
+ def printTableFooter #:nodoc:
433
+ puts "\\end{tabular}"
434
+ puts "\\caption{#{@tableCaption}}\n\\label{tab:#@tableLabel}"
435
+ puts "\\end{center}\n\\end{table}\n"
436
+ puts "\\end{landscape}" if @tableLandscape
437
+ end
438
+
439
+ #====== Generate header
440
+ headerList = hash2HeaderList(getHeaderMergedHash(entries.values), sort_block)
441
+ headerLines = getHeaderLines(headerList)
442
+ leafColumns = getLeafColumns(headerList)
443
+ printTableHeader(placement, headerLines, leafColumns, rowTitle)
444
+
445
+ currentRow = 0
446
+ for row_names in grouping
447
+ #======= Compute table break for multiple groupings.
448
+ new_lines = 0
449
+ for row_name in row_names
450
+ max_lines_per_entry = 1
451
+ for col_header in leafColumns
452
+ max_lines_per_entry = [max_lines_per_entry, accessElement(entries,row_name,col_header).length].max
453
+ end
454
+ new_lines += max_lines_per_entry
455
+ end
456
+
457
+ if (currentRow > 0 and currentRow + new_lines >= newTableThreshold)
458
+ currentRow = 0
459
+ printTableFooter # close last table
460
+ printTableHeader(placement, headerLines, leafColumns, rowTitle) # open new table
461
+ else
462
+ unless currentRow == 0
463
+ puts "\\hline" unless row_names == []
464
+ currentRow += 0.5
465
+ end
466
+ end
467
+
468
+ row_names.sort! &sort_block
469
+ #====== Generate entries.
470
+ for row_name in row_names
471
+ if (newTableThreshold > 0 and currentRow >= newTableThreshold)
472
+ currentRow = 0
473
+ printTableFooter # close last table
474
+ printTableHeader(placement, headerLines, leafColumns, rowTitle) # open new table
475
+ end
476
+ max_lines_per_entry = 1
477
+ for col_header in leafColumns
478
+ max_lines_per_entry = [max_lines_per_entry, accessElement(entries,row_name,col_header).length].max
479
+ end
480
+
481
+ for i in 0...max_lines_per_entry
482
+ #print row-name
483
+ print " "*@indent
484
+ output = (i==0 ? row_name.to_s.gsub(/_/,"\\_") : "~")
485
+ delta = "%.1f" % ((max_lines_per_entry-1).to_f)
486
+ output = "\\raisebox{-#{delta}\\totalheight}[1ex][1ex]{#{output}}" if max_lines_per_entry > 1
487
+ print output
488
+
489
+ #print the other columns
490
+ for col_header in leafColumns
491
+ entry = accessElement(entries,row_name,col_header)
492
+ if entry[i]
493
+ output = prettyPrintCell(entry[i])
494
+ delta = "%.1f" % (max_lines_per_entry-entry.length).to_f
495
+ else
496
+ output = (i==0 ? empty : "~")
497
+ delta = max_lines_per_entry
498
+ end
499
+ #Center the entries vertically in the cell. Out-comment this if you don't like that.
500
+ if entry.length != max_lines_per_entry# && entry.length > 0
501
+ output = "\\raisebox{-#{delta}\\totalheight}[1ex][1ex]{#{output}}" unless output == "~"
502
+ end
503
+ print " & " + output
504
+ end
505
+ puts "\\\\"
506
+ end
507
+ puts "\\hline"
508
+ currentRow += max_lines_per_entry
509
+ end
510
+ end
511
+ #====== Generate footer.
512
+ printTableFooter
513
+ end
514
+ end
515
+
516
+
metadata ADDED
@@ -0,0 +1,39 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.1
3
+ specification_version: 1
4
+ name: latex
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.1
7
+ date: 2004-09-30
8
+ summary: Latex is a LaTeX text generation library for Ruby.
9
+ require_paths:
10
+ - lib
11
+ author: Christian Bang
12
+ email: cbang AT web.de
13
+ homepage: http://latex.rubyforge.org
14
+ rubyforge_project: latex
15
+ description:
16
+ autorequire: latex/latex
17
+ default_executable:
18
+ bindir: bin
19
+ has_rdoc: true
20
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
21
+ requirements:
22
+ -
23
+ - ">"
24
+ - !ruby/object:Gem::Version
25
+ version: 0.0.0
26
+ version:
27
+ platform: ruby
28
+ files:
29
+ - lib/latex.rb
30
+ - README
31
+ - LICENSE.txt
32
+ - examples/test-latex.rb
33
+ test_files: []
34
+ rdoc_options: []
35
+ extra_rdoc_files: []
36
+ executables: []
37
+ extensions: []
38
+ requirements: []
39
+ dependencies: []