docgenerator 2.1.0 → 2.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.
- checksums.yaml +7 -0
- data/examples/creole_example.rb +0 -1
- data/examples/creole_example_new_plugin.rb +51 -0
- data/examples/creole_example_tabular.rb +3 -1
- data/examples/wiki2docgenerator_example.rb +2 -2
- data/lib/creole/creole2doc.rb +697 -680
- data/lib/creole/creole_characters.rb +90 -26
- data/lib/creole/creole_inclusion_and_plugins.rb +25 -43
- data/lib/creole/creole_inclusions.rb +87 -75
- data/lib/creole/creole_placeholder.rb +87 -89
- data/lib/creole/creole_plugins.rb +149 -117
- data/lib/creole/creole_tabular.rb +247 -141
- data/lib/creole/plugins/todonotes.rb +48 -48
- data/lib/docgenerator/characters.rb +106 -8
- data/lib/docgenerator/compatibility_v1.rb +7 -1
- data/lib/docgenerator/document.rb +34 -19
- data/lib/docgenerator/element.rb +1 -0
- data/lib/docgenerator/element_meta.rb +1 -1
- data/lib/docgenerator/elements.rb +594 -535
- data/lib/docgenerator/environments.rb +131 -99
- data/lib/docgenerator/index.rb +110 -0
- data/lib/docgenerator/lists.rb +2 -1
- data/lib/docgenerator/packages/caption.rb +32 -34
- data/lib/docgenerator/packages/hyperref.rb +1 -0
- data/lib/docgenerator/packages/multicol.rb +3 -2
- data/lib/docgenerator/packages/pdfpages.rb +71 -20
- data/lib/docgenerator/packages/scrpage2.rb +99 -142
- data/lib/docgenerator/packages/url.rb +75 -81
- data/lib/docgenerator/sections.rb +98 -98
- data/lib/docgenerator/standard.rb +8 -1
- data/lib/docgenerator/tabular.rb +44 -25
- data/lib/docgenerator/templates/docgenerator_template.yaml +28 -0
- data/lib/docgenerator/version.rb +146 -0
- data/lib/docgenerator.rb +20 -15
- data/meta_test_and_doc/build_doc.rb +39 -10
- data/meta_test_and_doc/build_test.rb +34 -12
- data/meta_test_and_doc/manpages/characters.rb +452 -20
- data/meta_test_and_doc/manpages/elementlist.rb +304 -0
- data/meta_test_and_doc/manpages/elements.rb +305 -42
- data/meta_test_and_doc/manpages/others.rb +403 -0
- data/meta_test_and_doc/manpages/pdfpages.rb +117 -18
- data/meta_test_and_doc/manpages/readme.rdoc +3 -1
- data/meta_test_and_doc/manpages/scrpage2.rb +0 -80
- data/meta_test_and_doc/manpages/tables.rb +6 -6
- data/readme.rdoc +11 -120
- data/unittest/expected/test_comment.html +1 -0
- data/unittest/expected/test_comment.latex +5 -0
- data/unittest/expected/test_comment_complex.html +3 -0
- data/unittest/expected/test_comment_complex.latex +15 -0
- data/unittest/expected_creole/test_creole_characters_all.html +6 -5
- data/unittest/expected_creole/test_creole_characters_all.latex +10 -8
- data/unittest/expected_creole/test_creole_creole1.0test.latex +5 -5
- data/unittest/expected_creole/test_creole_input.normsource +11 -9
- data/unittest/expected_creole/test_creole_list_ul.normsource +57 -51
- data/unittest/expected_creole/test_creole_list_ulul_without_ul.html +6 -0
- data/unittest/expected_creole/test_creole_list_ulul_without_ul.latex +12 -0
- data/unittest/expected_creole/test_creole_paragraphs.normsource +12 -10
- data/unittest/expected_creole/test_creole_pictures.latex +2 -2
- data/unittest/expected_creole/test_creole_pictures_css.latex +2 -2
- data/unittest/expected_creole/test_creole_pictures_imgclass.latex +2 -2
- data/unittest/expected_creole/test_creole_pictures_width.latex +1 -1
- data/unittest/expected_creole/test_creole_tabular.latex +3 -3
- data/unittest/expected_creole/test_creole_tabular_creole.latex +2 -2
- data/unittest/expected_creole/test_creole_tabular_css.latex +3 -3
- data/unittest/expected_creole/test_creole_tabular_row_parameters.latex +22 -0
- data/unittest/expected_templates/test_standalone.tex +34 -0
- data/unittest/expected_wikimedia/test_wiki_picture.latex +12 -12
- data/unittest/unittest_creole.rb +22 -3
- data/unittest/unittest_creole_tabular.rb +34 -1
- data/unittest/unittest_docgenerator.rb +46 -3
- data/unittest/unittest_docgenerator_characters.rb +527 -82
- data/unittest/unittest_templates.rb +1 -1
- metadata +149 -108
data/lib/creole/creole2doc.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#encoding:
|
1
|
+
#encoding: utf-8
|
2
2
|
=begin rdoc
|
3
3
|
This is a Creole-to-Docgenerator converter.
|
4
4
|
The Docgenerator-data can be exported as
|
@@ -24,45 +24,46 @@ Collect the classes to handle Creole-input.
|
|
24
24
|
|
25
25
|
More about creole at http://www.wikicreole.org/
|
26
26
|
=end
|
27
|
-
module Creole
|
27
|
+
module Creole
|
28
28
|
|
29
29
|
=begin rdoc
|
30
30
|
Some class definitions for the Creole-class.
|
31
31
|
=end
|
32
|
-
class Creole
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
32
|
+
class Creole
|
33
|
+
|
34
|
+
#Little structure to store the parsing result.
|
35
|
+
Creole_line = Struct.new('Creole_line', :type, :content, :add_info)
|
36
|
+
|
37
|
+
#Hash with Characters.
|
38
|
+
#This characters will be converted into elements.
|
39
|
+
CHARACTERS = {
|
40
|
+
'%' => element(:'%'),
|
41
|
+
'$' => element(:'$'),
|
42
|
+
'&' => element(:ampersand),
|
43
|
+
'->' => element(:rightarrow),
|
44
|
+
'=>' => element(:Rightarrow),
|
45
|
+
'<-' => element(:leftarrow),
|
46
|
+
'<=' => element(:Leftarrow),
|
47
|
+
'_' => element(:underscore),
|
48
|
+
'…' => element(:ldots),
|
49
|
+
'‚' => element(:sbquo), # einfaches low-9-Zeichen, U+201A , ‚
|
50
|
+
'’' => element(:rsquo), #'zu ’
|
51
|
+
'„' => element(:bdquo), #"auf „ #bottom double quote
|
52
|
+
'“' => element(:ldquo), #"zu “ #left double quote
|
53
|
+
'”' => element(:rdquo), #right double quote
|
54
|
+
'–' => element(:ndash), # –
|
55
|
+
'—' => element(:mdash), # –
|
56
|
+
}
|
56
57
|
|
57
58
|
=begin rdoc
|
58
59
|
Add a quick online-help.
|
59
60
|
=end
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
61
|
+
def self.help( option = :syntax)
|
62
|
+
hlp = []
|
63
|
+
hlp << "==Creole help #{option}"
|
64
|
+
case option
|
65
|
+
when :syntax
|
66
|
+
hlp << <<Syntax
|
66
67
|
Headings:
|
67
68
|
= Level 1 (largest) =
|
68
69
|
== Level 2 ==
|
@@ -75,18 +76,18 @@ You can close them. If not, the markup end with the paragraph.
|
|
75
76
|
|
76
77
|
Links: See Creole.help(:links)
|
77
78
|
|
78
|
-
|
79
|
+
Coming from Wikimedia/wiki2docgenerator? Check Creole.help(:wikimedia)
|
79
80
|
Familiar with Creole? Check Creole.help(:creole) for differences.
|
80
81
|
Syntax
|
81
|
-
|
82
|
-
|
82
|
+
when :creole
|
83
|
+
hlp << <<creole
|
83
84
|
creole2doc has some special features:
|
84
85
|
*headings allows labels ([key] direct after the =)
|
85
86
|
*line breaks are ignored, the text is wrapped.
|
86
87
|
(you can set it off with option :wrap_at => 0)
|
87
88
|
creole
|
88
|
-
|
89
|
-
|
89
|
+
when :wikimedia
|
90
|
+
hlp << <<tripfalls
|
90
91
|
Main Trippfalls when you used wiki2docgenerator before:
|
91
92
|
|
92
93
|
Lists: You need an empty line after a list.
|
@@ -94,8 +95,8 @@ Lists: You need an empty line after a list.
|
|
94
95
|
|
95
96
|
Text afterwords
|
96
97
|
tripfalls
|
97
|
-
|
98
|
-
|
98
|
+
when :headings
|
99
|
+
hlp << <<headings
|
99
100
|
Headings:
|
100
101
|
= Level 1 (largest) =
|
101
102
|
== Level 2 ==
|
@@ -114,8 +115,8 @@ Headings with label:
|
|
114
115
|
The content is not parsed.
|
115
116
|
Details see http://www.wikicreole.org/wiki/Headings
|
116
117
|
headings
|
117
|
-
|
118
|
-
|
118
|
+
when :links
|
119
|
+
hlp << <<links
|
119
120
|
Explicit:
|
120
121
|
* [[http://ruby.lickert.net/docgenerator]]
|
121
122
|
* [[http://ruby.lickert.net/docgenerator|Details on docgenerator.rb]]
|
@@ -123,8 +124,8 @@ Explicit:
|
|
123
124
|
Implicit:
|
124
125
|
* http://ruby.lickert.net/docgenerator
|
125
126
|
links
|
126
|
-
|
127
|
-
|
127
|
+
when :tabular
|
128
|
+
hlp << <<tabular
|
128
129
|
Wikimedia-like syntax:
|
129
130
|
<<<tabular
|
130
131
|
|!columns=3
|
@@ -142,21 +143,21 @@ Wikimedia-like syntax:
|
|
142
143
|
|three
|
143
144
|
>>>
|
144
145
|
tabular
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
end #Creole
|
146
|
+
else
|
147
|
+
hlp << "Undefined help for #{option.inspect}"
|
148
|
+
end
|
149
|
+
return hlp.join("\n")
|
150
|
+
end
|
151
|
+
end #Creole
|
151
152
|
|
152
|
-
#Load sub-classes.
|
153
|
-
#~ Dir.chdir(File.dirname(__FILE__)){
|
154
|
-
require_relative 'creole_placeholder.rb'
|
155
|
-
require_relative 'creole_tabular.rb'
|
156
|
-
require_relative 'creole_inclusion_and_plugins.rb'
|
157
|
-
#~ begin require 'privat/creole_affiliate.rb'; rescue LoadError; end #Just some privat extension
|
153
|
+
#Load sub-classes.
|
154
|
+
#~ Dir.chdir(File.dirname(__FILE__)){
|
155
|
+
require_relative 'creole_placeholder.rb'
|
156
|
+
require_relative 'creole_tabular.rb'
|
157
|
+
require_relative 'creole_inclusion_and_plugins.rb'
|
158
|
+
#~ begin require 'privat/creole_affiliate.rb'; rescue LoadError; end #Just some privat extension
|
158
159
|
|
159
|
-
require 'log4r'
|
160
|
+
require 'log4r'
|
160
161
|
|
161
162
|
=begin rdoc
|
162
163
|
Build a document.
|
@@ -167,7 +168,7 @@ multiple HTML (corresponding to pages).
|
|
167
168
|
|
168
169
|
HTML-pagebreak could be forced with ======== or something similar.
|
169
170
|
=end
|
170
|
-
class Creole_document
|
171
|
+
class Creole_document
|
171
172
|
|
172
173
|
=begin rdoc
|
173
174
|
Define a creole document. The settings are forwarded to Document#new()
|
@@ -177,65 +178,63 @@ Some settings are used only directly in Creole_document.
|
|
177
178
|
- :content: Wiki-text. Same as Creole_document#<<
|
178
179
|
- :logname: Name for Creole#log
|
179
180
|
=end
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
@creole << content
|
214
|
-
end
|
181
|
+
def initialize( settings = {} )
|
182
|
+
@with_toc = settings[:with_toc ]
|
183
|
+
settings.delete(:with_toc) #Avoid error message in Document.new
|
184
|
+
settings[:logname] ||= 'CreoleDoc' #Just a name for easier debugging/logging
|
185
|
+
|
186
|
+
@creole = Creole.new(
|
187
|
+
#Get content if available and delete setting to avoid error message in Document.new
|
188
|
+
:logname => settings.delete(:logname), #for logger
|
189
|
+
:content => settings.delete(:content),
|
190
|
+
:ignore => settings.delete(:ignore),
|
191
|
+
:targetdir => settings.delete(:targetdir)
|
192
|
+
)
|
193
|
+
#fixme/ideen parameter
|
194
|
+
#preamble -> vor wiki-texten
|
195
|
+
#post -> nach wiki-texten
|
196
|
+
|
197
|
+
@doc = Document.new(settings)
|
198
|
+
|
199
|
+
@doc.runtex = settings[:runtex] if settings[:runtex]
|
200
|
+
|
201
|
+
@log = @doc.log
|
202
|
+
|
203
|
+
@doc.body << creole
|
204
|
+
|
205
|
+
end
|
206
|
+
#The related document
|
207
|
+
attr_reader :doc
|
208
|
+
#The related creole-object
|
209
|
+
attr_reader :creole
|
210
|
+
#Add content to the wiki.
|
211
|
+
def << (content)
|
212
|
+
@creole << content
|
213
|
+
end
|
215
214
|
=begin rdoc
|
216
215
|
Save the creole document.
|
217
216
|
|
218
217
|
If requested, the tableofcontents is added.
|
219
218
|
The first Creole_document#save decides, which variant is added (html/tex)
|
220
219
|
=end
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
end
|
220
|
+
def save( filename, options = {} )
|
221
|
+
if @with_toc
|
222
|
+
@doc.body.insertbefore(creole, element(:htmlonly,{}, creole.toc(:level => @with_toc )))
|
223
|
+
@doc.body.insertbefore(creole, element(:latexonly,{},element(:tableofcontents).cr))
|
224
|
+
case @with_toc
|
225
|
+
when Numeric
|
226
|
+
@doc.head << element(:latexonly,{},"\\setcounter{tocdepth}{#{@with_toc}}\n")
|
227
|
+
end
|
228
|
+
@with_toc = false #Add it only once
|
229
|
+
end #@with_toc
|
230
|
+
|
231
|
+
@doc.save(filename, options )
|
232
|
+
end
|
233
|
+
#Use runtex if available.
|
234
|
+
def runtex=(option)
|
235
|
+
@doc.runtex = option
|
236
|
+
end
|
237
|
+
end
|
239
238
|
=begin rdoc
|
240
239
|
Creole is a standard wiki-syntax for wikitexts.
|
241
240
|
Definition see http://www.wikicreole.org
|
@@ -248,98 +247,112 @@ This class gets a creole-text and translate it to elements of the docgenerator,
|
|
248
247
|
they can be used by Document or directly like Element#to_doc.
|
249
248
|
|
250
249
|
Example:
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
250
|
+
wiki = Creole.new()
|
251
|
+
wiki << <<txt
|
252
|
+
=Test document
|
253
|
+
This is a little test text with **bold** and //italic// text.
|
254
|
+
txt
|
255
|
+
wiki.to_latex()
|
257
256
|
|
258
257
|
Often I use it in combination with "Here"-Documents with __END__:
|
259
258
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
259
|
+
require 'creole/creole2doc'
|
260
|
+
|
261
|
+
doc = Creole_document.new()
|
262
|
+
doc << DATA
|
263
|
+
doc.save('test.html')
|
264
|
+
__ END__
|
265
|
+
Content
|
266
|
+
--
|
267
|
+
Im Code beispiel steht __<space>END__
|
268
|
+
Würde dort __END__ stehen, hätte rdoc einen Fehler.
|
269
|
+
++
|
267
270
|
=end
|
268
|
-
class Creole
|
271
|
+
class Creole
|
272
|
+
class << Creole
|
273
|
+
#Define a default for targetdir-option in Creole.new.
|
274
|
+
attr_accessor :targetdir
|
275
|
+
end
|
276
|
+
|
269
277
|
=begin rdoc
|
270
278
|
Define the Creole-object.
|
271
279
|
|
272
280
|
Options:
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
281
|
+
* :log => Logger to catch information.
|
282
|
+
|
283
|
+
Alternativ you have access to the default logger via Creole#log
|
284
|
+
* :targetdir => directory, where you want to save the result.
|
285
|
+
|
286
|
+
This directory is important for checks for internal links.
|
287
|
+
|
288
|
+
You may change the default '.' with
|
289
|
+
Docgenerator::Creole::Creole.targetdir = 'mysubdir'
|
290
|
+
* :ignore: A regex describing parts to be ignored during text parsing. e.g. /^#~.*$/ for usage with scite.
|
291
|
+
* :encoding: The encoding used for creole.
|
279
292
|
Default is UTF-8
|
280
293
|
=end
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
294
|
+
def initialize( options = {} )
|
295
|
+
@options = {
|
296
|
+
:logname => 'Creole', #Just a name for easier debugging/logging
|
297
|
+
:targetdir => self.class.targetdir || '.',
|
298
|
+
:wrap_at => 75, #Default line wrapping
|
299
|
+
#~ :parsetest => false #Make an immediate test for parsing #fixme
|
300
|
+
#~ :placeholders =
|
301
|
+
#Definition how to handle the sectioning.
|
302
|
+
:title_levels => {
|
303
|
+
0 => nil,
|
304
|
+
1 => :h1,
|
305
|
+
2 => :h2,
|
306
|
+
3 => :h3,
|
307
|
+
4 => :h4,
|
308
|
+
5 => :h5,
|
309
|
+
6 => :h6,
|
310
|
+
},
|
311
|
+
:ignore => nil, #Define a "local" comment, e.g /^#~.*$/
|
312
|
+
:encoding => __ENCODING__,
|
313
|
+
}.update(options)
|
314
|
+
@placeholders = Placeholders::Collection.dup
|
315
|
+
@inclusions = Inclusions::Collection.dup
|
316
|
+
@plugins = Plugins::Collection.dup
|
317
|
+
|
318
|
+
#Store the given source text
|
319
|
+
@source = []
|
320
|
+
#Store the pre-parsed content
|
321
|
+
@normsource = []
|
322
|
+
@toc = [] #Collection of all heading lines
|
323
|
+
@footnotegroups = {} #Collection of footnote groups
|
324
|
+
|
325
|
+
@targetdir = @options[:targetdir] if @options[:targetdir]
|
326
|
+
|
327
|
+
@log = @options[:log]
|
328
|
+
@log = Log4r::Logger.new(@options[:logname], Log4r::INFO) unless @log
|
329
|
+
@log.outputters = Log4r::StdoutOutputter.new('log_stdout') if @log.outputters.empty?
|
330
|
+
|
331
|
+
@creation_caller = caller.first
|
332
|
+
self << @options[:content] if @options[:content]
|
333
|
+
end
|
334
|
+
|
335
|
+
#Hash with placeholders.
|
336
|
+
#
|
337
|
+
#Placeholders are used with <<<'name'.
|
338
|
+
#This accessor is needed to add more placeholders for specific wikis.
|
339
|
+
#Default: Creole::Placeholders
|
340
|
+
attr_reader :placeholders
|
341
|
+
attr_reader :options
|
342
|
+
|
343
|
+
#Hash with inclusions.
|
344
|
+
#This accessor is needed to add more inclusions for specific wikis.
|
345
|
+
#Default: Creole::Inclusions
|
346
|
+
attr_reader :inclusions
|
347
|
+
#Hash with all plugins
|
348
|
+
#This accessor is needed to add more plugins for specific wikis.
|
349
|
+
#Default: Creole::Plugins
|
350
|
+
attr_reader :plugins
|
351
|
+
#All footnotegroups of the wiki
|
352
|
+
attr_reader :footnotegroups
|
353
|
+
|
354
|
+
#Error Class
|
355
|
+
class InputError < ArgumentError; end
|
343
356
|
=begin rdoc
|
344
357
|
Get some content.
|
345
358
|
Strings are taken like strings.
|
@@ -351,246 +364,248 @@ In case of ruby scripts, the part after __END__ is used as input.
|
|
351
364
|
Content added with << starts always with a new paragraph, but it may contain
|
352
365
|
multiple paragraphs, lists...
|
353
366
|
=end
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
367
|
+
def << ( input )
|
368
|
+
case input
|
369
|
+
when String
|
370
|
+
source = input
|
371
|
+
when Array
|
372
|
+
#Items of the array are handled like single lines.
|
373
|
+
#The chomp avoid double \n (the array items may already have their own newlines).
|
374
|
+
source = input.map{|item| item.chomp}.join("\n") #ohne doppelte xx
|
375
|
+
when File
|
376
|
+
#If file is a ruby script, then use the wiki-code after __END__
|
377
|
+
#
|
378
|
+
#Often scripts contains there own text content after __END__.
|
379
|
+
#So we have to catch, if << is called with DATA
|
380
|
+
if /\.rb\Z/ =~ input.path and $0 != input.path
|
381
|
+
@log.info("Take content of #{input.inspect} after __END__") if @log.info?
|
382
|
+
begin
|
383
|
+
line = input.readline while line != "__END__\n"
|
384
|
+
rescue EOFError
|
385
|
+
@log.error("No __END__ found in #{input.inspect}") if @log.error?
|
386
|
+
end
|
387
|
+
end
|
388
|
+
#Read the code
|
389
|
+
source = input.readlines.join
|
390
|
+
else
|
391
|
+
raise InputError, "Don't know, how to handle #{input.class} in Creole#<<"
|
392
|
+
end
|
369
393
|
begin
|
370
|
-
|
371
|
-
rescue
|
372
|
-
@log.
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
@log.warn("Encoding conversion error <#{err}>") if @log.warn?
|
384
|
-
source_enc = source.encode(@options[:encoding], :undef => :replace)
|
385
|
-
end
|
386
|
-
@source << source_enc
|
387
|
-
#Parse the given source.
|
388
|
-
#This is done immediate, so you have a chance to localize the line, where an error occurs.
|
389
|
-
#(Some errors are reported later during to_doc).
|
390
|
-
#fixme: option to parse immediate at << or later
|
391
|
-
#immediate_parse => true...
|
392
|
-
@normsource.push( *parse( source_enc ) )
|
393
|
-
end #<< ( input )
|
394
|
+
source_enc = source.encode(@options[:encoding])
|
395
|
+
rescue Encoding::UndefinedConversionError => err
|
396
|
+
@log.warn("Encoding conversion error <#{err}>") if @log.warn?
|
397
|
+
source_enc = source.encode(@options[:encoding], :undef => :replace)
|
398
|
+
end
|
399
|
+
@source << source_enc
|
400
|
+
#Parse the given source.
|
401
|
+
#This is done immediate, so you have a chance to localize the line, where an error occurs.
|
402
|
+
#(Some errors are reported later during to_doc).
|
403
|
+
#fixme: option to parse immediate at << or later
|
404
|
+
#immediate_parse => true...
|
405
|
+
@normsource.push( *parse( source_enc ) )
|
406
|
+
end #<< ( input )
|
394
407
|
=begin rdoc
|
395
408
|
Parse the given creole code and build a "normalized source"
|
396
409
|
=end
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
else
|
408
|
-
@log.fatal("Unable to parse #{source.class}: #{source.inspect}" ) if @log.fatal?
|
409
|
-
return normsource
|
410
|
-
end
|
411
|
-
end
|
412
|
-
|
413
|
-
|
414
|
-
#
|
415
|
-
#Check code line by line
|
416
|
-
#
|
417
|
-
source.each_with_index{|line, lineno|
|
418
|
-
#Check special status
|
419
|
-
case statusflag
|
420
|
-
when nil #Nothing to do
|
421
|
-
when :pre
|
422
|
-
line =~ /\}\}\}/ ? statusflag = nil : normsource.last.content << line
|
423
|
-
next
|
424
|
-
when :placeholder
|
425
|
-
if line =~ /^>>>$/
|
426
|
-
statusflag = nil
|
427
|
-
normsource.last.content.close
|
410
|
+
def parse( source = @source )
|
411
|
+
|
412
|
+
normsource = []
|
413
|
+
statusflag = nil #Variable to store the actual status. nil = nothing special.
|
414
|
+
normsource << Creole_line.new(:dummy)
|
415
|
+
|
416
|
+
if ! source.respond_to?(:each_with_index)
|
417
|
+
#Ruby 1.9 removed each from String
|
418
|
+
if source.respond_to? :each_line
|
419
|
+
source = source.each_line
|
428
420
|
else
|
429
|
-
|
421
|
+
@log.fatal("Unable to parse #{source.class}: #{source.inspect}" ) if @log.fatal?
|
422
|
+
return normsource
|
430
423
|
end
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
end #statusflag
|
435
|
-
|
436
|
-
#
|
437
|
-
#Parse the wiki text on line level (main structure)
|
438
|
-
case line
|
439
|
-
#Skip this line, if it correspond to a special comment-pattern.
|
440
|
-
#Can be used for application-specific comments.
|
424
|
+
end
|
425
|
+
|
426
|
+
|
441
427
|
#
|
442
|
-
#
|
443
|
-
# :ignore => /^#~.*$/
|
444
|
-
#This comment is created by scite using Ctrl-Q (for ruby-scripts).
|
445
|
-
when @options[:ignore]
|
446
|
-
@log.info("Found comment #{$1} : #{line.inspect}" ) if @log.info?
|
447
|
-
#Headings
|
448
|
-
#http://www.wikicreole.org/wiki/Headings
|
428
|
+
#Check code line by line
|
449
429
|
#
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
430
|
+
source.each_with_index{|line, lineno|
|
431
|
+
#Check special status
|
432
|
+
case statusflag
|
433
|
+
when nil #Nothing to do
|
434
|
+
when :pre
|
435
|
+
line =~ /\}\}\}/ ? statusflag = nil : normsource.last.content << line
|
436
|
+
next
|
437
|
+
when :placeholder
|
438
|
+
#~ if line =~ /^>>>$/ #did not catch each system specific line end.
|
439
|
+
if line =~ /^>>>(\r\n?|\n)/
|
440
|
+
statusflag = nil
|
441
|
+
normsource.last.content.close
|
442
|
+
else
|
443
|
+
normsource.last.content << line
|
444
|
+
end
|
445
|
+
next
|
446
|
+
else
|
447
|
+
@log.fatal("Undefinded status #{statusflag}: #{line.inspect}" ) if @log.fatal?
|
448
|
+
end #statusflag
|
449
|
+
|
450
|
+
#
|
451
|
+
#Parse the wiki text on line level (main structure)
|
452
|
+
case line
|
453
|
+
#Skip this line, if it correspond to a special comment-pattern.
|
454
|
+
#Can be used for application-specific comments.
|
455
|
+
#
|
456
|
+
#Example:
|
457
|
+
# :ignore => /^(#~.*)$/
|
458
|
+
#This comment is created by scite using Ctrl-Q (for ruby-scripts).
|
459
|
+
when @options[:ignore]
|
460
|
+
@log.info("Found comment in line %2i: %s" % [
|
461
|
+
lineno, #line.inspect
|
462
|
+
[$~.pre_match, '<<', $1, '>>', $~.post_match].join.strip,
|
463
|
+
]) if @log.info?
|
464
|
+
#Headings
|
465
|
+
#http://www.wikicreole.org/wiki/Headings
|
466
|
+
#
|
467
|
+
#Modification of standard: Labels are possible.
|
468
|
+
when /^(=+)(?:\[(.*)\])?(.+?)(=*)\s*$/
|
469
|
+
normsource << Creole_line.new(:title, $3, :level => $1.size, :label => $2 )
|
470
|
+
@toc << normsource.last
|
471
|
+
#Creole doesn't need a trailing ===, but when it is ther, it should be correct
|
472
|
+
if $1.size != $4.size and $4.size > 0
|
473
|
+
@log.warn("Heading problem #{$1} doesn't match <#{$4}>: #{line.inspect}" ) if @log.warn?
|
474
|
+
end
|
475
|
+
if $~.post_match !~ /\s*/
|
476
|
+
@log.warn("Ignore text #{$~.post_match.inspect} after title <#{line.inspect}>" ) if @log.warn?
|
477
|
+
end
|
478
|
+
#And close the actual level
|
479
|
+
#See unit test test_creole_mix_titles_list
|
480
|
+
normsource << Creole_line.new(:dummy )
|
481
|
+
#Empty line
|
482
|
+
when /^\s*$/
|
483
|
+
normsource << Creole_line.new(:dummy )
|
484
|
+
when /^----\s*$/
|
485
|
+
normsource << Creole_line.new(:hr )
|
486
|
+
#List entry
|
487
|
+
when /^\s*((\*|\#)+)/
|
488
|
+
normsource << Creole_line.new(:list, $~.post_match, :listtype => $1 )
|
489
|
+
#Tabular
|
490
|
+
when /^\|/
|
491
|
+
#fixme tab soll in par...
|
492
|
+
#~ normsource.last << Creole_line.new(:placeholder,
|
493
|
+
#~ ... unless anpassen...
|
494
|
+
normsource << Creole_line.new(:placeholder,
|
495
|
+
@placeholders['creole_tabular'].new(self),
|
496
|
+
:start => lineno
|
497
|
+
) unless normsource.last.content.is_a?(Creole_tab)
|
498
498
|
normsource.last.content << line
|
499
|
+
#http://www.wikicreole.org/wiki/PreformattedAndNowiki
|
500
|
+
when /^\{\{\{\s*$/ #Kind of verbatim
|
501
|
+
normsource << Creole_line.new(:pre, [], :start => lineno )
|
502
|
+
statusflag = :pre
|
503
|
+
#~ when /^<<<(.*)\|?(.*?)/ #fixme options for placeholders?
|
504
|
+
when /^<<<(.*)/
|
505
|
+
ph, par = $1.split(/\|/,2)
|
506
|
+
placeholder = @placeholders[ph].new(self, par)
|
507
|
+
if placeholder.instance_of?(Placeholders::Dummy)
|
508
|
+
@log.warn("Unknown placeholder #{ph.inspect} used in line #{lineno}" ) if @log.warn?
|
509
|
+
end
|
510
|
+
normsource << Creole_line.new(:placeholder, placeholder, :start => lineno )
|
511
|
+
statusflag = :placeholder
|
499
512
|
else
|
500
|
-
normsource
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
513
|
+
case normsource.last.type
|
514
|
+
when :par, :list
|
515
|
+
normsource.last.content << line
|
516
|
+
else
|
517
|
+
normsource << Creole_line.new(:par, line )
|
518
|
+
end
|
519
|
+
end
|
520
|
+
}
|
521
|
+
case statusflag
|
522
|
+
when nil #ok
|
523
|
+
when :pre
|
524
|
+
@log.warn("Unclosed verbatim found (start at #{normsource.last.add_info[:start]})" ) if @log.warn?
|
525
|
+
#~ raise ''
|
526
|
+
when :placeholder
|
527
|
+
#One possible source: Regexp $ is system specific.
|
528
|
+
@log.warn("Unclosed placeholder #{normsource.last.type} (start at #{normsource.last.add_info[:start]})" ) if @log.warn?
|
529
|
+
else
|
530
|
+
@log.warn("Wiki ends with status #{statusflag.inspect}" ) if @log.warn?
|
531
|
+
end
|
532
|
+
return normsource
|
533
|
+
end #parse
|
534
|
+
#Logger to collect messages.
|
535
|
+
attr_reader :log
|
536
|
+
#Returns the source as it was received
|
537
|
+
attr_reader :source
|
538
|
+
#The pre-parsed content.
|
539
|
+
attr_reader :normsource
|
540
|
+
#Directory for the target.
|
541
|
+
#Can be used to check internal links (images, local files...)
|
542
|
+
attr_reader :targetdir
|
528
543
|
|
529
544
|
=begin rdoc
|
530
545
|
Return a table of contents as a list.
|
531
546
|
=end
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
547
|
+
def toc( i_options = {})
|
548
|
+
options = {
|
549
|
+
:listtype => :ul,
|
550
|
+
:level => 4,
|
551
|
+
#~ :startlevel => 1,
|
552
|
+
}.update(i_options)
|
553
|
+
|
554
|
+
if ! options[:level].is_a?(Fixnum)
|
555
|
+
@log.error("Toc: toclevel is no number but '#{options[:level].inspect}'. Set 4") if @log.error?
|
556
|
+
options[:level] = 4
|
557
|
+
end
|
543
558
|
|
544
559
|
|
545
|
-
|
546
|
-
|
547
|
-
listtype = '*'
|
548
|
-
case options[:listtype]
|
549
|
-
when '*', :ul, :itemize
|
560
|
+
toclist = []
|
561
|
+
toclabel = [0] #help variable to construct labels
|
550
562
|
listtype = '*'
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
level = tocentry.add_info[:level]
|
559
|
-
#Skip deeper levels then wanted.
|
560
|
-
next if level > options[:level]
|
561
|
-
|
562
|
-
#Build the label
|
563
|
-
if level > toclabel.size
|
564
|
-
toclabel << 0
|
565
|
-
elsif level < toclabel.size
|
566
|
-
toclabel.pop
|
567
|
-
end
|
568
|
-
#Happens if there is a jump gap on section levels (subsubsection inside section without subsection)
|
569
|
-
if ! toclabel[level-1]
|
570
|
-
@log.warn("Missing toclevel for <#{tocentry.content}> #{tocentry.add_info.inspect}")
|
571
|
-
#add dummy level
|
572
|
-
toclabel << 0
|
573
|
-
toclist << "#{listtype * ( level - 1)} ---"
|
574
|
-
end
|
575
|
-
toclabel[level-1] = toclabel[level-1] + 1
|
576
|
-
|
577
|
-
#Check if there was already a label.
|
578
|
-
#If yes: use it. If not: build a new one with the help of toclabel.
|
579
|
-
if tocentry.add_info[:label]
|
580
|
-
label = tocentry.add_info[:label]
|
581
|
-
else
|
582
|
-
label = tocentry.add_info[:label] = toclabel.join('-')
|
563
|
+
case options[:listtype]
|
564
|
+
when '*', :ul, :itemize
|
565
|
+
listtype = '*'
|
566
|
+
when '#', :ol, :enumerate
|
567
|
+
listtype = '#'
|
568
|
+
else
|
569
|
+
@log.error("Toc: Unknown listtype #{options[:listtype]}") if @log.error?
|
583
570
|
end
|
584
571
|
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
572
|
+
@toc.each{|tocentry|
|
573
|
+
level = tocentry.add_info[:level]
|
574
|
+
#Skip deeper levels then wanted.
|
575
|
+
next if level > options[:level]
|
576
|
+
|
577
|
+
#Build the label
|
578
|
+
if level > toclabel.size
|
579
|
+
toclabel << 0
|
580
|
+
elsif level < toclabel.size
|
581
|
+
toclabel.pop
|
582
|
+
end
|
583
|
+
#Happens if there is a jump gap on section levels (subsubsection inside section without subsection)
|
584
|
+
if ! toclabel[level-1]
|
585
|
+
@log.warn("Missing toclevel for <#{tocentry.content}> #{tocentry.add_info.inspect}")
|
586
|
+
#add dummy level
|
587
|
+
toclabel << 0
|
588
|
+
toclist << "#{listtype * ( level - 1)} ---"
|
589
|
+
end
|
590
|
+
toclabel[level-1] = toclabel[level-1] + 1
|
591
|
+
|
592
|
+
#Check if there was already a label.
|
593
|
+
#If yes: use it. If not: build a new one with the help of toclabel.
|
594
|
+
if tocentry.add_info[:label]
|
595
|
+
label = tocentry.add_info[:label]
|
596
|
+
else
|
597
|
+
label = tocentry.add_info[:label] = toclabel.join('-')
|
598
|
+
end
|
599
|
+
|
600
|
+
#Feature to create the toc if higher levels are missing /start at h3...)
|
601
|
+
#~ if level < options[:startlevel]
|
602
|
+
#~ @log.warn( "toc: TOC starts not at #{options[:startlevel]}, but level #{level}" ) if @log.warn?
|
603
|
+
#~ next
|
604
|
+
#~ end
|
605
|
+
|
606
|
+
toclist << "#{listtype * level}[[##{label}|#{tocentry.content}]]"
|
607
|
+
}
|
608
|
+
toclist = <<toc
|
594
609
|
<<<html
|
595
610
|
<div class = 'toc'>
|
596
611
|
>>>
|
@@ -600,8 +615,8 @@ Return a table of contents as a list.
|
|
600
615
|
>>>
|
601
616
|
toc
|
602
617
|
|
603
|
-
|
604
|
-
|
618
|
+
return Creole.new( :content => toclist, :log => @log )
|
619
|
+
end #toc
|
605
620
|
=begin rdoc
|
606
621
|
Wrapping mechanism for texts.
|
607
622
|
|
@@ -610,251 +625,253 @@ Don't do anything, if line_width is 0.
|
|
610
625
|
See also http://stackoverflow.com/questions/7548968/format-output-to-40-characters-long-per-line/7549032#7549032
|
611
626
|
and http://forum.ruby-portal.de/viewtopic.php?t=3844&p=24578
|
612
627
|
=end
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
628
|
+
def word_wrap(text, line_width = @options[:wrap_at] )
|
629
|
+
return text if line_width <= 0
|
630
|
+
text.gsub(/\n/, ' ').gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip
|
631
|
+
end
|
617
632
|
=begin rdoc
|
618
633
|
Prepare document.
|
619
634
|
=end
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
635
|
+
def to_doc( target, options = {} )
|
636
|
+
options[:log] = @log unless options[:log]
|
637
|
+
#
|
638
|
+
#Delete again all footnotegroups.
|
639
|
+
#Else you get footnotes doubled.
|
640
|
+
@footnotegroups = {} #Collection of footnote groups
|
641
|
+
return normsource2elements( @normsource, options ).to_doc(target, options)
|
642
|
+
end #to_doc
|
628
643
|
=begin rdoc
|
629
644
|
Take the given normsource and build a list of elements.
|
630
645
|
Used by
|
631
646
|
- Creole#to_doc
|
632
647
|
- Creole_ruby#to_doc
|
633
648
|
=end
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
649
|
+
def normsource2elements( normsource, options )
|
650
|
+
doc = []
|
651
|
+
elements = {} #little collector for lists
|
652
|
+
normsource.each{|line|
|
653
|
+
case line.type
|
654
|
+
when :dummy
|
655
|
+
elements = {}
|
656
|
+
#Here we define the sectioning.
|
657
|
+
#line.add_info[:level] contains the number of = from the wiki.
|
658
|
+
#
|
659
|
+
when :title
|
660
|
+
|
661
|
+
doc << element(@options[:title_levels][line.add_info[:level]], {
|
662
|
+
:id => line.add_info[:label]
|
663
|
+
#inline or not?
|
664
|
+
#Required for filenames with _
|
665
|
+
#But: http://www.wikicreole.org/wiki/Headings says no.
|
666
|
+
#Make decision depending on a setting?
|
667
|
+
}, line.content ).cr
|
668
|
+
#~ }, inline(line.content, options ) ).cr
|
669
|
+
when :list
|
670
|
+
key = line.add_info[:listtype]
|
671
|
+
if ! elements[key]
|
672
|
+
case key[-1,1]
|
673
|
+
when '*'; elements[key] = element(:ul).cR
|
674
|
+
when '#'; elements[key] = element(:ol).cR
|
675
|
+
else
|
676
|
+
options[:log].error("Undefined listtype #{key[-1,1]}") if options[:log].error?
|
677
|
+
end
|
678
|
+
if key.size == 1 #new list, add to document
|
679
|
+
doc << elements[key]
|
680
|
+
elsif parent_list = elements[key[0,key.size-1]] #new sublist, add to "parent"
|
681
|
+
parent_list << element(:li).cr unless parent_list.content.last.is_a?(:li)
|
682
|
+
parent_list.content.last << elements[key]
|
683
|
+
else #sublist without parent.
|
684
|
+
options[:log].error("List #{key} with missing superlist") if options[:log].error?
|
685
|
+
doc << element(:comment,{},'Sublist without superlist - move on top level').cr #add pending list on top level.
|
686
|
+
doc << elements[key] #add pending list on top level.
|
687
|
+
end
|
688
|
+
end
|
689
|
+
elements.each{|ekey, list|
|
690
|
+
case ekey
|
691
|
+
when key
|
692
|
+
list << element(:li,{}, inline(line.content, options) ).cr
|
693
|
+
else
|
694
|
+
elements.delete(ekey) if ekey.size >= key.size
|
695
|
+
end
|
696
|
+
}
|
697
|
+
when :pre
|
698
|
+
doc << element(:verbatim, {}, line.content ).cR
|
699
|
+
when :hr
|
700
|
+
doc << element(:hr).cr
|
701
|
+
when :placeholder
|
702
|
+
doc << line.content
|
703
|
+
when :par
|
704
|
+
doc << element(:par, {}, inline(line.content, options)).cR
|
705
|
+
else
|
706
|
+
options[:log].error("Wrong line type #{ line.type.inspect }") if options[:log].error?
|
671
707
|
end
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
else
|
677
|
-
elements.delete(ekey) if ekey.size >= key.size
|
678
|
-
end
|
679
|
-
}
|
680
|
-
when :pre
|
681
|
-
doc << element(:verbatim, {}, line.content ).cR
|
682
|
-
when :hr
|
683
|
-
doc << element(:hr).cr
|
684
|
-
when :placeholder
|
685
|
-
doc << line.content
|
686
|
-
when :par
|
687
|
-
doc << element(:par, {}, inline(line.content, options)).cR
|
688
|
-
else
|
689
|
-
options[:log].error("Wrong line type #{ line.type.inspect }") if options[:log].error?
|
690
|
-
end
|
691
|
-
}
|
692
|
-
|
693
|
-
return doc
|
694
|
-
end #to_doc_internal
|
708
|
+
}
|
709
|
+
|
710
|
+
return doc
|
711
|
+
end #to_doc_internal
|
695
712
|
=begin rdoc
|
696
713
|
Parse the inline text.
|
697
714
|
|
698
715
|
Options is a Hash and may contain:
|
699
716
|
* :log (default: @log)
|
700
717
|
=end
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
718
|
+
def inline( text, options )
|
719
|
+
|
720
|
+
raise ArgumentError, "Creole#inline: Options no Hash" unless options.is_a?(Hash)
|
721
|
+
options[:log] = @log unless options[:log]
|
722
|
+
options[:plugins] = @plugins unless options[:plugins]
|
723
|
+
options[:inclusions] = @inclusions unless options[:inclusions]
|
724
|
+
|
725
|
+
res = [] #result
|
726
|
+
stack = [] #
|
727
|
+
|
728
|
+
#~ http_regex =
|
729
|
+
#fixme: Only once to reduce runtime
|
730
|
+
splitregex = Regexp.new(
|
731
|
+
'(' + [
|
732
|
+
'\[\[.+?\]\]', # [[...links]]
|
733
|
+
'https?:\/\/.+?(\s|\Z)', #including the next space!!
|
734
|
+
'\*\*', #bold
|
735
|
+
'\/\/', #emph
|
736
|
+
'\\\\\\\\', #newline
|
737
|
+
'\{\{\{.*?\}\}\}', #inline verbatim
|
738
|
+
'\{\{.*?\}\}', #images/inclusion
|
739
|
+
'<<.*?>>', #Plugins
|
740
|
+
CHARACTERS.keys.join('|')
|
741
|
+
].join('|') + ')'
|
742
|
+
)
|
743
|
+
#Splitt along 'active' elements.
|
744
|
+
#~ @options[:wrap_at]
|
745
|
+
#~ text.gsub(/\n/, ' ').split(splitregex).each{|el|
|
746
|
+
text.split(splitregex).each{|el|
|
747
|
+
case el
|
748
|
+
when '**' #bold
|
749
|
+
if stack.last.is_a?(:textbf)
|
750
|
+
stack.pop #leave bold area
|
751
|
+
else
|
752
|
+
stack << newel = element(:textbf) #enter bold area
|
753
|
+
if stack.size > 1
|
754
|
+
stack[-2] << newel
|
755
|
+
else
|
756
|
+
res << newel
|
757
|
+
end
|
758
|
+
end
|
759
|
+
when '//' #italic
|
760
|
+
if stack.last.is_a?(:emph)
|
761
|
+
stack.pop #leave italic area
|
762
|
+
else
|
763
|
+
stack << newel = element(:emph) #enter italic area
|
764
|
+
if stack.size > 1
|
765
|
+
stack[-2] << newel
|
766
|
+
else
|
767
|
+
res << newel
|
768
|
+
end
|
769
|
+
end
|
770
|
+
when '\\\\' #newline
|
771
|
+
( stack.last ? stack.last : res ) << element(:newline).cr
|
772
|
+
#Something like [[http:...]]
|
773
|
+
when %r{^\[\[(.+?)(?:\|(.*?))?\]\]} #Link
|
774
|
+
link = $1
|
775
|
+
linktext = $2 ? $2 : $1
|
776
|
+
case link
|
777
|
+
when /^(https?|ftp):\/\/.+?/
|
778
|
+
link = link
|
779
|
+
#local file via file://...
|
780
|
+
when /^(file):\/\/(.+)/
|
781
|
+
link = link
|
782
|
+
check_link_existence( $2, options[:log] )
|
783
|
+
when /^\./, /\S:[\\\/]/ #lokal file
|
784
|
+
link = link
|
785
|
+
check_link_existence( link, options[:log] )
|
786
|
+
when /^#/ #internal link
|
787
|
+
link = link
|
788
|
+
#fixme tex?
|
789
|
+
else #internal link
|
790
|
+
#This is normally the wiki-links.
|
791
|
+
#But this is no wiki, it's a documentgenerator with wiki syntax.
|
792
|
+
options[:log].warn("Unclear link <#{el}> #{self.inspect}") if options[:log].warn?
|
793
|
+
link = link
|
794
|
+
end
|
795
|
+
if link == linktext #Avoid replacement of // inside linktext
|
796
|
+
href = element(:a, {:href=>link}, linktext )
|
797
|
+
else
|
798
|
+
href = element(:a, {:href=>link}, inline(linktext, options) )
|
799
|
+
end
|
800
|
+
if stack.last
|
801
|
+
stack.last << href
|
802
|
+
else
|
803
|
+
res << href
|
804
|
+
end
|
805
|
+
#All links should be catched before
|
806
|
+
when %r{\[\[(.*)\]\]}
|
807
|
+
options[:log].error("Lost link <#{el}>") if options[:log].error?
|
808
|
+
#fixme: there are obsolete 2 additional spaces in the result.
|
809
|
+
when /^http/ #implicit link
|
810
|
+
#~ href = element(:a, {:href=>el.strip}, el.strip ) #This makes problems with TeX (unmasked _,%...)
|
811
|
+
href = element(:url, {}, el.strip )
|
812
|
+
el =~ /(\s|\Z)$/ #get the end-space/newline if available
|
813
|
+
endspace = ( $1.empty? ? nil : $1 )
|
814
|
+
if stack.last
|
815
|
+
stack.last << href
|
816
|
+
#~ stack.last << last_char #add again the
|
817
|
+
else
|
818
|
+
res << href
|
819
|
+
#~ res << last_char #add again the end-space/newline
|
820
|
+
end
|
821
|
+
#No-wiki inline: {{{text}}}
|
822
|
+
when /\{\{\{(.*)\}\}\}/
|
823
|
+
if stack.last
|
824
|
+
stack.last << element(:verb,{},$1)
|
825
|
+
else
|
826
|
+
res << element(:verb,{},$1)
|
827
|
+
end
|
828
|
+
#Inclusion
|
829
|
+
#creole2doc implements a general inclusion.
|
830
|
+
#Main usage are pictures/images ({{picname|alt}}),
|
831
|
+
#but it can be more...
|
832
|
+
#
|
833
|
+
#Available inclusions are defined in Creole::Inclusions resp. Creole#inclusions,
|
834
|
+
when /\{\{(.+?)(?:\|(.*))?\}\}/
|
835
|
+
if stack.last
|
836
|
+
stack.last << inclusion_or_plugin($1, $2, options[:inclusions])
|
837
|
+
else
|
838
|
+
res << inclusion_or_plugin($1, $2, options[:inclusions])
|
839
|
+
end
|
840
|
+
#Plugin
|
841
|
+
#Used like Inclusions.
|
842
|
+
#
|
843
|
+
#available plugins are defined in Creole::Plugins resp. Creole#plugins
|
844
|
+
when /<<(.+?)(?:\|(.*))?>>/
|
845
|
+
if stack.last
|
846
|
+
stack.last << inclusion_or_plugin($1, $2, options[:plugins])
|
847
|
+
else
|
848
|
+
res << inclusion_or_plugin($1, $2, options[:plugins])
|
849
|
+
end
|
850
|
+
#No special wiki command. The text is "normal" text.
|
851
|
+
else #text to add
|
852
|
+
#Replace characters.
|
853
|
+
if CHARACTERS[el]
|
854
|
+
insertion = CHARACTERS[el]
|
855
|
+
startspace = endspace = nil
|
856
|
+
else
|
857
|
+
startspace = ( el[0,1] =~ /\s/ )
|
858
|
+
endspace = ( el[-1,1] =~ /\s/ )
|
859
|
+
insertion = word_wrap( el ) #wrap content
|
860
|
+
end
|
861
|
+
if stack.last
|
862
|
+
stack.last << insertion
|
863
|
+
#This adds some obsolete spaces in case of newlines at the end.
|
864
|
+
#But if I compare with ' ', then words will be concatenated without separator.
|
865
|
+
stack.last << ' ' if endspace
|
866
|
+
else #Just some text without any format
|
867
|
+
res << ' ' if startspace #Keep space
|
868
|
+
res << insertion
|
869
|
+
res << ' ' if endspace #Keep space
|
870
|
+
end
|
751
871
|
end
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
#Something like [[http:...]]
|
756
|
-
when %r{^\[\[(.+?)(?:\|(.*?))?\]\]} #Link
|
757
|
-
link = $1
|
758
|
-
linktext = $2 ? $2 : $1
|
759
|
-
case link
|
760
|
-
when /^(https?|ftp):\/\/.+?/
|
761
|
-
link = link
|
762
|
-
#local file via file://...
|
763
|
-
when /^(file):\/\/(.+)/
|
764
|
-
link = link
|
765
|
-
check_link_existence( $2, options[:log] )
|
766
|
-
when /^\./, /\S:[\\\/]/ #lokal file
|
767
|
-
link = link
|
768
|
-
check_link_existence( link, options[:log] )
|
769
|
-
when /^#/ #internal link
|
770
|
-
link = link
|
771
|
-
#fixme tex?
|
772
|
-
else #internal link
|
773
|
-
#This is normally the wiki-links.
|
774
|
-
#But this is no wiki, it's a documentgenerator with wiki syntax.
|
775
|
-
options[:log].warn("Unclear link <#{el}> #{self.inspect}") if options[:log].warn?
|
776
|
-
link = link
|
777
|
-
end
|
778
|
-
if link == linktext #Avoid replacement of // inside linktext
|
779
|
-
href = element(:a, {:href=>link}, linktext )
|
780
|
-
else
|
781
|
-
href = element(:a, {:href=>link}, inline(linktext, options) )
|
782
|
-
end
|
783
|
-
if stack.last
|
784
|
-
stack.last << href
|
785
|
-
else
|
786
|
-
res << href
|
787
|
-
end
|
788
|
-
#All links should be catched before
|
789
|
-
when %r{\[\[(.*)\]\]}
|
790
|
-
options[:log].error("Lost link <#{el}>") if options[:log].error?
|
791
|
-
#fixme: there are obsolete 2 additional spaces in the result.
|
792
|
-
when /^http/ #implicit link
|
793
|
-
#~ href = element(:a, {:href=>el.strip}, el.strip ) #This makes problems with TeX (unmasked _,%...)
|
794
|
-
href = element(:url, {}, el.strip )
|
795
|
-
el =~ /(\s|\Z)$/ #get the end-space/newline if available
|
796
|
-
endspace = ( $1.empty? ? nil : $1 )
|
797
|
-
if stack.last
|
798
|
-
stack.last << href
|
799
|
-
#~ stack.last << last_char #add again the
|
800
|
-
else
|
801
|
-
res << href
|
802
|
-
#~ res << last_char #add again the end-space/newline
|
803
|
-
end
|
804
|
-
#No-wiki inline: {{{text}}}
|
805
|
-
when /\{\{\{(.*)\}\}\}/
|
806
|
-
if stack.last
|
807
|
-
stack.last << element(:verb,{},$1)
|
808
|
-
else
|
809
|
-
res << element(:verb,{},$1)
|
810
|
-
end
|
811
|
-
#Inclusion
|
812
|
-
#creole2doc implements a general inclusion.
|
813
|
-
#Main usage are pictures/images ({{picname|alt}}),
|
814
|
-
#but it can be more...
|
815
|
-
#
|
816
|
-
#Available inclusions are defined in Creole::Inclusions resp. Creole#inclusions,
|
817
|
-
when /\{\{(.+?)(?:\|(.*))?\}\}/
|
818
|
-
if stack.last
|
819
|
-
stack.last << inclusion_or_plugin($1, $2, options[:inclusions])
|
820
|
-
else
|
821
|
-
res << inclusion_or_plugin($1, $2, options[:inclusions])
|
822
|
-
end
|
823
|
-
#Plugin
|
824
|
-
#Used like Inclusions.
|
825
|
-
#
|
826
|
-
#available plugins are defined in Creole::Plugins resp. Creole#plugins
|
827
|
-
when /<<(.+?)(?:\|(.*))?>>/
|
828
|
-
if stack.last
|
829
|
-
stack.last << inclusion_or_plugin($1, $2, options[:plugins])
|
830
|
-
else
|
831
|
-
res << inclusion_or_plugin($1, $2, options[:plugins])
|
832
|
-
end
|
833
|
-
#No special wiki command. The text is "normal" text.
|
834
|
-
else #text to add
|
835
|
-
#Replace characters.
|
836
|
-
if CHARACTERS[el]
|
837
|
-
insertion = CHARACTERS[el]
|
838
|
-
startspace = endspace = nil
|
839
|
-
else
|
840
|
-
startspace = ( el[0,1] =~ /\s/ )
|
841
|
-
endspace = ( el[-1,1] =~ /\s/ )
|
842
|
-
insertion = word_wrap( el ) #wrap content
|
843
|
-
end
|
844
|
-
if stack.last
|
845
|
-
stack.last << insertion
|
846
|
-
#This adds some obsolete spaces in case of newlines at the end.
|
847
|
-
#But if I compare with ' ', then words will be concatenated without separator.
|
848
|
-
stack.last << ' ' if endspace
|
849
|
-
else #Just some text without any format
|
850
|
-
res << ' ' if startspace #Keep space
|
851
|
-
res << insertion
|
852
|
-
res << ' ' if endspace #Keep space
|
853
|
-
end
|
854
|
-
end
|
855
|
-
}
|
856
|
-
res
|
857
|
-
end #inline
|
872
|
+
}
|
873
|
+
res
|
874
|
+
end #inline
|
858
875
|
=begin rdoc
|
859
876
|
Inclusion or Plugin.
|
860
877
|
creole2doc implements a general inclusion.
|
@@ -863,24 +880,24 @@ but it can be more...
|
|
863
880
|
|
864
881
|
The last paramter contains a hash with the supported inclusions/plugins.
|
865
882
|
=end
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
883
|
+
def inclusion_or_plugin( link, p_additions, inclusions )
|
884
|
+
|
885
|
+
addition, additions = nil
|
886
|
+
#Splitt additions at |
|
887
|
+
if p_additions
|
888
|
+
addition, *additions = p_additions.split(/\|/)
|
889
|
+
end
|
873
890
|
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
891
|
+
inclusion = inclusions[link]
|
892
|
+
#check inclusion.ancestors?
|
893
|
+
#~ if inclusion.superclass != Creole_inclusion_and_plugin
|
894
|
+
if inclusion.is_a?(Creole_inclusion_and_plugin)
|
895
|
+
@log.error( "Wrong inclusion/plugin definition for #{link} (#{inclusion.inspect}, expected #{inclusions.default.superclass})") if @log.error?
|
896
|
+
return nil
|
897
|
+
end
|
898
|
+
ip = inclusion.new( link, addition, additions, self )
|
899
|
+
return ip
|
900
|
+
end #inclusion
|
884
901
|
=begin rdoc
|
885
902
|
Check for links and pictures if the target exist.
|
886
903
|
|
@@ -889,27 +906,27 @@ Relative pathes are searched from @options[:targetdir] (default '.').
|
|
889
906
|
|
890
907
|
Different locations are not supported (e.g. to implement LaTeXs \graphicspath)
|
891
908
|
=end
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
909
|
+
def check_link_existence( filename, log )
|
910
|
+
case filename
|
911
|
+
when /^.:/#absolute DOS-path (e.g. c:\...)
|
912
|
+
path = filename.dup
|
913
|
+
else #relative path
|
914
|
+
path = "#{@options[:targetdir]}/#{filename}".sub(/^\//, '')
|
915
|
+
end
|
916
|
+
path.sub!(/(\.html?)#.*$/, '\1') #Don't check anchor inside html
|
917
|
+
if ! File.exist?(path)
|
918
|
+
log.warn("Reference not found: <#{filename}> (looking at <#{path}>)") if log.warn?
|
919
|
+
#~ log.debug("Reference not found: <#{path}>") if log.debug?
|
920
|
+
fpath = File.expand_path("#{Dir.pwd}/#{path}")
|
921
|
+
log.debug("Reference not found: <#{fpath}>") if log.debug?
|
922
|
+
end
|
923
|
+
end #check_link_existence
|
907
924
|
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
end #Creole
|
912
|
-
end #module Creole
|
925
|
+
def inspect()
|
926
|
+
"<#{self.class} (created #{@creation_caller})>"
|
927
|
+
end
|
928
|
+
end #Creole
|
929
|
+
end #module Creole
|
913
930
|
end #module Docgenerator
|
914
931
|
|
915
932
|
|