docgenerator 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/docgenerator.rb +137 -0
- data/docgenerator_attribute.rb +142 -0
- data/docgenerator_characters.rb +171 -0
- data/docgenerator_css.rb +207 -0
- data/docgenerator_document.rb +374 -0
- data/docgenerator_element.rb +570 -0
- data/docgenerator_elements.rb +554 -0
- data/docgenerator_environments.rb +73 -0
- data/docgenerator_footnote.rb +106 -0
- data/docgenerator_lists.rb +163 -0
- data/docgenerator_sections.rb +88 -0
- data/docgenerator_tabular.rb +376 -0
- data/docgenerator_template.rb +103 -0
- data/examples/docgenerator_example.rb +185 -0
- data/packages/docgenerator_attachfile.rb +71 -0
- data/packages/docgenerator_beamer.rb +250 -0
- data/packages/docgenerator_caption.rb +43 -0
- data/packages/docgenerator_hyperref.rb +109 -0
- data/packages/docgenerator_listings.rb +100 -0
- data/packages/docgenerator_pdfpages.rb +18 -0
- data/packages/docgenerator_scrlettr2.rb +128 -0
- data/packages/docgenerator_scrpage2.rb +172 -0
- data/packages/docgenerator_url.rb +84 -0
- metadata +68 -0
@@ -0,0 +1,374 @@
|
|
1
|
+
#
|
2
|
+
#Container for a document.
|
3
|
+
#
|
4
|
+
#Each document contains a header and a body. Both are special Element classes.
|
5
|
+
#
|
6
|
+
class Document
|
7
|
+
#Create a new document.
|
8
|
+
#There are different document templates supported.
|
9
|
+
#The templates refer to the corresponding TeX-classes.
|
10
|
+
#- article
|
11
|
+
#- report
|
12
|
+
#- book
|
13
|
+
def initialize( template = nil )
|
14
|
+
#Set template defaults
|
15
|
+
@template = {
|
16
|
+
:html => DocumentTemplate[:html],
|
17
|
+
:latex => DocumentTemplate[:article],
|
18
|
+
:text => DocumentTemplate[:text],
|
19
|
+
:wiki => DocumentTemplate[:wiki],
|
20
|
+
}
|
21
|
+
self.set_template( template ) if template
|
22
|
+
@body = element( :body )
|
23
|
+
@head = element( :head )
|
24
|
+
#~ @body.part_of << self
|
25
|
+
#~ @head.part_of << self
|
26
|
+
@body.part_of_doc << self
|
27
|
+
@head.part_of_doc << self
|
28
|
+
@language = 'ngerman'
|
29
|
+
@options = []
|
30
|
+
@meta = {} #some meta-Tags for HTML
|
31
|
+
#Flag to avoid double definition of docinfo()
|
32
|
+
@docinfo_called = false
|
33
|
+
@creator = nil
|
34
|
+
end
|
35
|
+
#
|
36
|
+
#Set Template to Generate a target.
|
37
|
+
#
|
38
|
+
#Compatibility for old version:
|
39
|
+
#-If template is an array, each entry is used as a key for DocumentTemplate.
|
40
|
+
#
|
41
|
+
def set_template( template, target = :latex )
|
42
|
+
template = [ template ] if template.kind_of?( Symbol )
|
43
|
+
#Compatibility for older version: Template can be given direct
|
44
|
+
if template.kind_of?(String )
|
45
|
+
#~ puts "Set Template with string"
|
46
|
+
@template[target] = template
|
47
|
+
return
|
48
|
+
elsif template.kind_of?(Array )
|
49
|
+
template.each{|templ|
|
50
|
+
if SUPPORTED_LaTeX_TEMPLATES.include?( templ )
|
51
|
+
target = :latex
|
52
|
+
elsif SUPPORTED_HTML_TEMPLATES.include?( templ )
|
53
|
+
target = :html
|
54
|
+
elsif /text/ =~ templ.to_s or /txt/ =~ templ.to_s
|
55
|
+
target = :txt
|
56
|
+
else
|
57
|
+
puts "Unknown template conversion for #{templ}"
|
58
|
+
target = :latex
|
59
|
+
end
|
60
|
+
@template[target] = DocumentTemplate[templ]
|
61
|
+
if ! @template[target]
|
62
|
+
puts "Unknown template #{templ}, valid:\n\t#{DocumentTemplate.keys.join("\n\t")}" #fixme raise
|
63
|
+
elsif ! @template[target].kind_of?(String )
|
64
|
+
puts "Template no string #{@template.inspect}"
|
65
|
+
@template[target] = @template[target].to_s
|
66
|
+
end
|
67
|
+
}
|
68
|
+
else
|
69
|
+
raise "Should set template, but don't know how #{template.inspect}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
#body and head are lists, containing elements.
|
73
|
+
attr_reader :body, :head
|
74
|
+
attr_reader :template
|
75
|
+
#Document title
|
76
|
+
attr_accessor :title
|
77
|
+
#Set document description
|
78
|
+
attr_writer :author, :date, :keywords, :description, :creator
|
79
|
+
attr_writer :language
|
80
|
+
#Flag, if tex should be started immediate after document creation.
|
81
|
+
attr_writer :runtex
|
82
|
+
#Add more keywords
|
83
|
+
def keyword_add( keyword )
|
84
|
+
@keywords << ", #{keyword}"
|
85
|
+
end
|
86
|
+
|
87
|
+
#Constant to detect the generated header
|
88
|
+
PREFIX_ENDFLAG = 'Generation-Info-End'
|
89
|
+
#
|
90
|
+
#Define, if there should be a message in case of:
|
91
|
+
#-:change Document changed
|
92
|
+
#-:nochange Document existed, but is unchanged
|
93
|
+
#Give an array with the wanted values.
|
94
|
+
def Document.givemessage=( value = [:change, :nochange] )
|
95
|
+
@@givemessage = value
|
96
|
+
end
|
97
|
+
@@givemessage = [:change, :nochange]
|
98
|
+
def Document.givemessage(); @@givemessage; end
|
99
|
+
#Add a meta-tag-information for the HTML-Output.
|
100
|
+
def meta( key, content )
|
101
|
+
key = key.to_s
|
102
|
+
if @meta[key]
|
103
|
+
puts "Double definition meta-tag #{key} (old: #{@meta[key]}, new: #{content})"
|
104
|
+
end
|
105
|
+
@meta[key] = content
|
106
|
+
end
|
107
|
+
#Prepare the docinfo.
|
108
|
+
#May be called only once.
|
109
|
+
#
|
110
|
+
#If the title should change (e.g. when you save the document twice in different versions)
|
111
|
+
#you can do it via the parameter.
|
112
|
+
def docinfo()
|
113
|
+
#If this method is called twice (e.g. with save to tex and html),
|
114
|
+
#then the title is doubled in the second output.
|
115
|
+
#(Elements are added to @head)
|
116
|
+
return nil if @docinfo_called
|
117
|
+
@docinfo_called = true
|
118
|
+
|
119
|
+
#Build docinfo.
|
120
|
+
result = []
|
121
|
+
result << element( :title, {:short => @meta["shorttitle"] }, @title).CR if @title
|
122
|
+
result << element( :author, {}, @author).cr if @author
|
123
|
+
result << element( :date, {}, @date).cr if @date
|
124
|
+
result << element( :keywords, {}, @keywords).cr if @keywords
|
125
|
+
result << element( :metadescription, {}, @description).cr if @description
|
126
|
+
result << element( :creator, {}, @creator).cr if @creator
|
127
|
+
@meta.each{ |key, content|
|
128
|
+
result << element( :meta, { :name => key, :content => content } ).cr
|
129
|
+
}
|
130
|
+
return result
|
131
|
+
end
|
132
|
+
def add_option( option)
|
133
|
+
@options << option
|
134
|
+
end
|
135
|
+
#Prepare a table of content.
|
136
|
+
#More or less a test.
|
137
|
+
#Use it for element :tableofcontents?
|
138
|
+
def toc()
|
139
|
+
toc = []
|
140
|
+
toccnt = 0
|
141
|
+
#~ toc = element(:ul).cR
|
142
|
+
toc_ids = [ :chapter, :section,:subsection, :subsubsection, :paragraph, :subparagraph,:minisec]
|
143
|
+
@body.content.flatten.each{|el|
|
144
|
+
depth = toc_ids.index((el.ids & toc_ids)[0])
|
145
|
+
#~ puts "#{depth.inspect}\t#{el.content}"
|
146
|
+
if el[:id].content.empty?
|
147
|
+
el[:id] << "toc#{toccnt += 1}"
|
148
|
+
end
|
149
|
+
if depth
|
150
|
+
#~ toc << element(:li,{},[ el.content])
|
151
|
+
toc << element(:a, {:href => "#{el[:id]}" }, [ '*' * depth, el.content ])
|
152
|
+
toc << element(:br).cr
|
153
|
+
end
|
154
|
+
}
|
155
|
+
return toc
|
156
|
+
end
|
157
|
+
#Save the file.
|
158
|
+
#The type of the document is determined by the file extensison.
|
159
|
+
#Supported document types are:
|
160
|
+
#- tex
|
161
|
+
#- html
|
162
|
+
#Depending on a template, different results are created.
|
163
|
+
#
|
164
|
+
#The is a comparison between an already existing file and the new one.
|
165
|
+
#To write a new version, the document must change and overwrite must be true.
|
166
|
+
#
|
167
|
+
#It is possible to give pairs of RegExp (pattern) and replacements to the result.
|
168
|
+
def save( filename, overwrite=false, replacements = {} )
|
169
|
+
|
170
|
+
if ! @template
|
171
|
+
puts "No template available to create #{filename}"
|
172
|
+
return false
|
173
|
+
end
|
174
|
+
|
175
|
+
old = nil
|
176
|
+
prefix = [ nil,
|
177
|
+
"Build by\t#{__FILE__}",
|
178
|
+
"Dir:\t\t#{Dir.pwd}",
|
179
|
+
"Creator:\t#{$0}",
|
180
|
+
"Target:\t\t#{filename}",
|
181
|
+
"#{Time.now.strftime('%Y/%m/%d %H:%M:%S')}",
|
182
|
+
nil,
|
183
|
+
"#{PREFIX_ENDFLAG}"
|
184
|
+
].join("\n\t")
|
185
|
+
if File.exist?( filename )
|
186
|
+
f = File.new( filename )
|
187
|
+
old = f.readlines().to_s
|
188
|
+
f.close
|
189
|
+
end
|
190
|
+
#Determine the target document type, depending on extension.
|
191
|
+
extension = File.basename( filename ).split( /\./).last
|
192
|
+
case extension
|
193
|
+
when /tex/i
|
194
|
+
@target = :latex
|
195
|
+
when /htm[l]?/i
|
196
|
+
@target = :html
|
197
|
+
when /txt/
|
198
|
+
@target = :text
|
199
|
+
when /wiki/
|
200
|
+
@target = :wiki
|
201
|
+
else
|
202
|
+
raise "Unknown Extension #{extension}"
|
203
|
+
end
|
204
|
+
|
205
|
+
@@target = @target if ! UNDER_CONSTRUCTION
|
206
|
+
new = to_element( @target, @template[@target], replacements )
|
207
|
+
|
208
|
+
case @target
|
209
|
+
when :latex
|
210
|
+
prefix.gsub!( /^/, '%' )
|
211
|
+
old.sub!(/\A.*#{PREFIX_ENDFLAG}/m, '<<prefix>>' ) if old
|
212
|
+
when :html
|
213
|
+
#Delete prefix (with generation time) for later compare.
|
214
|
+
old.sub!(/\A.*#{PREFIX_ENDFLAG}/m, "<!--\n<<prefix>>" ) if old
|
215
|
+
when :text
|
216
|
+
when :wiki
|
217
|
+
#~ new.squeeze!("\n")
|
218
|
+
else
|
219
|
+
raise "Unknown target #{@target}"
|
220
|
+
end
|
221
|
+
#Make it a bit more compact.
|
222
|
+
#TeX requires at least 2 \n for paragraph changes
|
223
|
+
new.gsub!(/\n+\n\n/, "\n\n")
|
224
|
+
|
225
|
+
if ! new.kind_of?( String )
|
226
|
+
puts "New is wrong type: #{new.inspect}"
|
227
|
+
end
|
228
|
+
@target = nil
|
229
|
+
|
230
|
+
if new != old
|
231
|
+
new.sub!( '<<prefix>>', prefix)
|
232
|
+
if ( File.exist?( filename ) and !overwrite )
|
233
|
+
puts "Datei #{filename} exist already \nContinue [yn]?"
|
234
|
+
answer = $stdin.gets() if $stdin.tty? #nur bei call aus DOS-Box
|
235
|
+
if ! ( answer =~ /[YyjJ].*/ )
|
236
|
+
puts "Bye"
|
237
|
+
return false
|
238
|
+
end
|
239
|
+
end
|
240
|
+
f = File.new( filename, 'w' )
|
241
|
+
f << new
|
242
|
+
f.close
|
243
|
+
puts "Save changed\t#{filename}" if @@givemessage.include?(:change)
|
244
|
+
#Save copy of old version (attention, *.bak makes no control on tex or html)
|
245
|
+
#~ f = File.new( filename.sub( extension, 'bak'), 'w' )
|
246
|
+
#~ f << old
|
247
|
+
#~ f.close
|
248
|
+
Document.runtex( filename, @runtex ) if @runtex
|
249
|
+
return true
|
250
|
+
elsif old
|
251
|
+
puts "Unchanged\t#{filename}" if @@givemessage.include?(:nochange)
|
252
|
+
return false
|
253
|
+
end
|
254
|
+
end
|
255
|
+
#Build the content for the target format.
|
256
|
+
#Supported tagret formats are:
|
257
|
+
#- :latex
|
258
|
+
#- :html
|
259
|
+
#- :text
|
260
|
+
#If the standard templates are used, there is a <<prefix>> left
|
261
|
+
#(used from Document#save to include some additional information).
|
262
|
+
#
|
263
|
+
#If the method is called directly to prpare document snipplets, you can use:
|
264
|
+
# puts Document#to_element( :latex, '<<body>>')
|
265
|
+
#
|
266
|
+
#It is possible to give pairs of RegExp (pattern) and a replacement to the result.
|
267
|
+
def to_element( target, template=@template[target], replacements = {} )
|
268
|
+
|
269
|
+
@@target = target if ! UNDER_CONSTRUCTION
|
270
|
+
if ! template
|
271
|
+
puts "No template available to create #{target.inspect} #{self.class}"
|
272
|
+
return ''
|
273
|
+
end
|
274
|
+
|
275
|
+
new = template.dup
|
276
|
+
case target
|
277
|
+
when :latex
|
278
|
+
add_option( @language )
|
279
|
+
when :html
|
280
|
+
when :text
|
281
|
+
when :wiki
|
282
|
+
else
|
283
|
+
raise "Unknown Extension #{extension}"
|
284
|
+
end
|
285
|
+
if ! new.kind_of?( String )
|
286
|
+
puts "New is wrong type: #{new.inspect}"
|
287
|
+
end
|
288
|
+
|
289
|
+
@head << self.docinfo()
|
290
|
+
new.sub!( '<<head>>', @head.to_s)
|
291
|
+
new.sub!( '<<body>>', @body.to_s)
|
292
|
+
new.sub!( '<<classoptions>>', @options.join(','))
|
293
|
+
|
294
|
+
replacements.each{|pattern, replace |
|
295
|
+
new.gsub!( pattern, replace ) if replace
|
296
|
+
}
|
297
|
+
return new
|
298
|
+
end #Document#to_element
|
299
|
+
#Return the actual target type.
|
300
|
+
#Needed by Element#to_s to decide which method is used to prepare the output.
|
301
|
+
#
|
302
|
+
#The usage of this technic makes similar processing unposibble.
|
303
|
+
#Set in Document#save.
|
304
|
+
attr_reader :target
|
305
|
+
@@target = nil
|
306
|
+
#Set a major output routine.
|
307
|
+
def Document.target=( target )
|
308
|
+
@@target = target
|
309
|
+
end
|
310
|
+
def Document.target( element )
|
311
|
+
return @@target if @@target #Use global value for multiple outputs
|
312
|
+
case element.part_of_doc.size
|
313
|
+
when 1
|
314
|
+
return element.part_of_doc.first.target
|
315
|
+
when 0
|
316
|
+
puts "Document.target: No related document. Don't know which target to take #{element.inspect} line #{__LINE__}"
|
317
|
+
element.ancestors.flatten.each_with_index{|a,i|
|
318
|
+
puts "\tAncestor #{i}\t#{a.inspect}"
|
319
|
+
puts "\t\t\t#{a.ancestors.inspect}"
|
320
|
+
}
|
321
|
+
#~ puts caller()
|
322
|
+
return :text
|
323
|
+
else
|
324
|
+
puts "Multiple documents. Don't know which target to take #{element.inspect}"
|
325
|
+
element.part_of_doc.each{|d| puts "\t#{d.inspect}" }
|
326
|
+
return :text
|
327
|
+
end
|
328
|
+
end
|
329
|
+
#Call TeX and translate the file.
|
330
|
+
#Experimental
|
331
|
+
#Fixme: Chain
|
332
|
+
def Document.runtex( filename, format = :pdflatex )
|
333
|
+
begin
|
334
|
+
#~ require 'rtex'
|
335
|
+
require 'c:/usr/script/rtex/rtex'
|
336
|
+
rescue LoadError
|
337
|
+
puts "Sorry, didn't find the experimental tex translation tool to translate #{filename}"
|
338
|
+
return false
|
339
|
+
end
|
340
|
+
#~ puts "Unknown texfile #{filename}" if ! filename
|
341
|
+
tex = Chain.new()
|
342
|
+
case format
|
343
|
+
when :latex
|
344
|
+
tex.latex()
|
345
|
+
end
|
346
|
+
#~ Logger.level=3
|
347
|
+
tex.file = filename
|
348
|
+
begin
|
349
|
+
tex.execute()
|
350
|
+
rescue SystemExit
|
351
|
+
puts "rescued a SystemExit exception"
|
352
|
+
return false
|
353
|
+
end
|
354
|
+
end
|
355
|
+
#Make some basic replacemnts for TeX.
|
356
|
+
#There is no sense to use it with HTML.
|
357
|
+
#
|
358
|
+
#Better solution: Puts String into \path, \verb or similar.
|
359
|
+
def Document.texify( input )
|
360
|
+
out = input.strip
|
361
|
+
#~ out.gsub!( /&/, '\\\&') #geht schief. erzeugt <<body>>...
|
362
|
+
#~ out.gsub!( /\\/, '\\\\')
|
363
|
+
out.gsub!( /%/, '\%')
|
364
|
+
out.gsub!( /\$/, '\$')
|
365
|
+
out.gsub!( /&/, '\\\\&')
|
366
|
+
out.gsub!( /_/, '\_')
|
367
|
+
out.gsub!( /�/, '\euro ')
|
368
|
+
return out
|
369
|
+
end
|
370
|
+
def inspect()
|
371
|
+
return "#<Document '#{@title}'>"
|
372
|
+
#~ return "#<Document '#{@title} #{@body.inspect}>'"
|
373
|
+
end
|
374
|
+
end #Document
|