Class: Docgenerator::Creole::Creole

Inherits:
Object
  • Object
show all
Defined in:
lib/docgenerator/creole/creole.rb

Overview

Creole is a standard wiki-syntax for wikitexts. Definition see www.wikicreole.org

I liked this definition. When you look at the website, you get a definition and you get an explanation, why it is like this. - great!

This class gets a creole-text and translate it to elements of the docgenerator, they can be used by Document or directly like Element#to_doc.

Example:

wiki = Creole.new()
wiki << <<txt
=Test document
This is a little test text with **bold** and //italic// text.
txt
wiki.to_latex()

Often I use it in combination with “Here”-Documents with __END__:

require 'docgenerator/creole'

doc = Docgenerator::Creole::Creole_document.new()
doc << DATA
doc.save('test.html')
__ END__
Content

– Im Code beispiel steht __<space>END__ Würde dort __END__ stehen, hätte rdoc einen Fehler. ++

Defined Under Namespace

Classes: InputError

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Creole

Define the Creole-object.

Options:

  • :log => Logger to catch information.

    Alternativ you have access to the default logger via Creole#log

  • :targetdir => directory, where you want to save the result.

    This directory is important for checks for internal links.

    You may change the default ‘.’ with

    Docgenerator::Creole::Creole.targetdir = 'mysubdir'
    
  • :ignore: A regex describing parts to be ignored during text parsing. e.g. /^#~.*$/ for usage with scite.

  • :encoding: The encoding used for creole. Default is UTF-8



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/docgenerator/creole/creole.rb', line 71

def initialize( options = {} )
  @options = {
    :logname => 'Creole',  #Just a name for easier debugging/logging
    :targetdir  => self.class.targetdir || '.',
    :wrap_at  => 75,    #Default line wrapping
    #~ :parsetest             => false  #Make an immediate test for parsing #fixme
    #~ :placeholders = 
    #Definition how to handle the sectioning.
    :title_levels => {
      0 => nil,
      1 => :h1,
      2 => :h2,
      3 => :h3,
      4 => :h4,
      5 => :h5,
      6 => :h6,
    },
    :ignore => nil, #Define a "local" comment, e.g /^#~.*$/ 
    :encoding => __ENCODING__,
  }.update(options)        
  @placeholders = Placeholders::Collection.dup
  @inclusions     = Inclusions::Collection.dup
  @plugins        = Plugins::Collection.dup
  
  #Store the given source text
  @source  = []
  #Store the pre-parsed content
  @normsource  = []
  @toc  = []  #Collection of all heading lines
  @footnotegroups = {}  #Collection of footnote groups
  
  @targetdir  = @options[:targetdir] if @options[:targetdir]
  
  @log  = @options[:log]
  @log = Log4r::Logger.new(@options[:logname], Log4r::INFO) unless @log
  @log.outputters = Log4r::StdoutOutputter.new('log_stdout') if  @log.outputters.empty?

  @creation_caller = caller.first
  self  <<  @options[:content]  if @options[:content]
end

Class Attribute Details

.targetdirObject

Define a default for targetdir-option in Creole.new.



51
52
53
# File 'lib/docgenerator/creole/creole.rb', line 51

def targetdir
  @targetdir
end

Instance Attribute Details

#footnotegroupsObject (readonly)

All footnotegroups of the wiki



129
130
131
# File 'lib/docgenerator/creole/creole.rb', line 129

def footnotegroups
  @footnotegroups
end

#inclusionsObject (readonly)

Hash with inclusions. This accessor is needed to add more inclusions for specific wikis. Default: Creole::Inclusions



123
124
125
# File 'lib/docgenerator/creole/creole.rb', line 123

def inclusions
  @inclusions
end

#logObject (readonly)

Logger to collect messages.



312
313
314
# File 'lib/docgenerator/creole/creole.rb', line 312

def log
  @log
end

#normsourceObject (readonly)

The pre-parsed content.



316
317
318
# File 'lib/docgenerator/creole/creole.rb', line 316

def normsource
  @normsource
end

#optionsObject (readonly)

Returns the value of attribute options.



118
119
120
# File 'lib/docgenerator/creole/creole.rb', line 118

def options
  @options
end

#placeholdersObject (readonly)

Hash with placeholders.

Placeholders are used with <<<‘name’. This accessor is needed to add more placeholders for specific wikis. Default: Creole::Placeholders



117
118
119
# File 'lib/docgenerator/creole/creole.rb', line 117

def placeholders
  @placeholders
end

#pluginsObject (readonly)

Hash with all plugins This accessor is needed to add more plugins for specific wikis. Default: Creole::Plugins



127
128
129
# File 'lib/docgenerator/creole/creole.rb', line 127

def plugins
  @plugins
end

#sourceObject (readonly)

Returns the source as it was received



314
315
316
# File 'lib/docgenerator/creole/creole.rb', line 314

def source
  @source
end

#targetdirObject (readonly)

Directory for the target. Can be used to check internal links (images, local files…)



319
320
321
# File 'lib/docgenerator/creole/creole.rb', line 319

def targetdir
  @targetdir
end

Instance Method Details

#<<(input) ⇒ Object

Get some content. Strings are taken like strings. Array items are handled like lines.

It is possible to add the content of a file. Just add the open file handle. In case of ruby scripts, the part after __END__ is used as input.

Content added with << starts always with a new paragraph, but it may contain multiple paragraphs, lists…



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/docgenerator/creole/creole.rb', line 144

def << ( input )
  case input
    when String
    source = input
  when Array
    #Items of the array are handled like single lines.
    #The chomp avoid double \n (the array items may already have their own newlines).
    source = input.map{|item| item.chomp}.join("\n")  #ohne doppelte xx 
  when File
    #If file is a ruby script, then use the wiki-code after __END__
    #
    #Often scripts contains there own text content after __END__.
    #So we have to catch, if << is called with DATA
    if /\.rb\Z/ =~ input.path and $0 != input.path
      @log.info("Take content of #{input.inspect} after __END__") if @log.info?
      begin
        line = input.readline while line != "__END__\n"
      rescue EOFError
        @log.error("No __END__ found in #{input.inspect}") if @log.error?
      end  
    end
    #Read the code
    source = input.readlines.join
  else
    raise InputError, "Don't know, how to handle #{input.class} in Creole#<<"      
  end
  begin
    source_enc = source.encode(@options[:encoding])
  rescue Encoding::UndefinedConversionError => err
    @log.warn("Encoding conversion error <#{err}>") if @log.warn?
    source_enc = source.encode(@options[:encoding], :undef => :replace)
  end
  @source << source_enc 
  #Parse the given source.
  #This is done immediate, so you have a chance to localize the line, where an error occurs.
  #(Some errors are reported later during to_doc).
  #fixme: option to parse immediate at << or later
  #immediate_parse => true...
  @normsource.push( *parse( source_enc  ) )
end

Check for links and pictures if the target exist.

Absolute DOS-Pathes are detected (C:...). Relative pathes are searched from @options (default ‘.’).

Different locations are not supported (e.g. to implement LaTeXs graphicspath)



687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
# File 'lib/docgenerator/creole/creole.rb', line 687

def check_link_existence( filename, log )
  case filename
    when /^.:/#absolute DOS-path (e.g. c:\...)
      path = filename.dup
    else  #relative path
      path = "#{@options[:targetdir]}/#{filename}".sub(/^\//, '')
    end
  path.sub!(/(\.html?)#.*$/, '\1') #Don't check anchor inside html
  if ! File.exist?(path)
    log.warn("Reference not found: <#{filename}> (looking at <#{path}>)") if log.warn?
    #~ log.debug("Reference not found: <#{path}>") if log.debug?
    fpath = File.expand_path("#{Dir.pwd}/#{path}")
    log.debug("Reference not found: <#{fpath}>") if log.debug?
  end
end

#inclusion_or_plugin(link, p_additions, inclusions) ⇒ Object

Inclusion or Plugin. Creole implements a general inclusion. Main usage are pictures/images ({picname|alt}), but it can be more…

The last paramter contains a hash with the supported inclusions/plugins.



661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
# File 'lib/docgenerator/creole/creole.rb', line 661

def inclusion_or_plugin( link, p_additions, inclusions )
  
  addition, additions = nil
  #Splitt additions at | 
  if p_additions
    addition, *additions = p_additions.split(/\|/)
  end

  inclusion = inclusions[link]
  #check inclusion.ancestors?
  #~ if inclusion.superclass != Creole_inclusion_and_plugin
  if inclusion.is_a?(Creole_inclusion_and_plugin)
    @log.error( "Wrong inclusion/plugin definition for #{link} (#{inclusion.inspect}, expected #{inclusions.default.superclass})") if @log.error?
    return nil
  end
  ip = inclusion.new( link, addition, additions, self )
  return ip
end

#inline(text, options) ⇒ Object

Parse the inline text.

Options is a Hash and may contain:

  • :log (default: @log)

Raises:

  • (ArgumentError)


495
496
497
498
499
500
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
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
# File 'lib/docgenerator/creole/creole.rb', line 495

def inline( text,  options )
  
  raise ArgumentError, "Creole#inline: Options no Hash" unless options.is_a?(Hash)
  options[:log]           = @log unless options[:log]
  options[:plugins]      = @plugins unless options[:plugins]
  options[:inclusions]  = @inclusions unless options[:inclusions]
  
  res = []  #result
  stack = []  #

  #~ http_regex  = 
  #fixme: Only once to reduce runtime
  splitregex = Regexp.new(
    '(' + [
          '\[\[.+?\]\]',  # [[...links]]
          'https?:\/\/.+?(\s|\Z)', #including the next space!!
          '\*\*', #bold
          '\/\/', #emph
          '\\\\\\\\', #newline
          '\{\{\{.*?\}\}\}', #inline verbatim
          '\{\{.*?\}\}', #images/inclusion
          '<<.*?>>',   #Plugins
          #Catch characters with special meaning in regexp, e.g. $
          CHARACTERS.keys.map{|key| key.sub(/([\$])/, '\\\\\1')}.join('|')
          ].join('|')  + ')'
  )
  #Splitt along 'active' elements.
  #~ @options[:wrap_at]
  #~ text.gsub(/\n/, ' ').split(splitregex).each{|el|
  text.split(splitregex).each{|el|
    case el
      when '**' #bold
        if stack.last.is_a?(:textbf)
            stack.pop #leave bold area
        else 
          stack << newel = element(:textbf) #enter bold area
          if stack.size > 1
            stack[-2] << newel
          else
            res << newel 
          end
        end
      when '//' #italic
        if stack.last.is_a?(:emph)
          stack.pop #leave italic area
        else
          stack << newel = element(:emph) #enter italic area
          if stack.size > 1
            stack[-2] << newel 
          else
            res << newel 
          end
        end
      when '\\\\' #newline
        ( stack.last ? stack.last  : res ) << element(:newline).cr
      #Something like [[http:...]]
      when %r{^\[\[(.+?)(?:\|(.*?))?\]\]}  #Link
        link = $1
        linktext = $2 ? $2 : $1
        case link
          when /^(https?|ftp):\/\/.+?/
            link = link
          #local file via file://...
          when /^(file):\/\/(.+)/
            link = link
            check_link_existence( $2, options[:log] )
          when /^\./, /\S:[\\\/]/  #lokal file
            link = link
            check_link_existence( link, options[:log] )
          when /^#/   #internal link
            link = link
            #fixme tex?
          else  #internal link
            #This is normally the wiki-links.
            #But this is no wiki, it's a documentgenerator with wiki syntax.
            options[:log].warn("Unclear link <#{el}> #{self.inspect}") if options[:log].warn?
            link = link
        end
        if link == linktext #Avoid replacement of // inside linktext
          href = element(:a, {:href=>link}, linktext )
        else
          href = element(:a, {:href=>link}, inline(linktext, options) )
        end
        if stack.last  
          stack.last << href 
        else
          res << href
        end
      #All links should be catched before
      when %r{\[\[(.*)\]\]}
        options[:log].error("Lost link <#{el}>") if options[:log].error?
      #fixme: there are obsolete 2 additional spaces in the result.
      when /^http/ #implicit link
        #~ href = element(:a, {:href=>el.strip}, el.strip ) #This makes problems with TeX (unmasked _,%...)
        href = element(:url, {}, el.strip )
        el =~ /(\s|\Z)$/  #get the end-space/newline if available
        endspace = ( $1.empty? ? nil : $1 )
        if stack.last  
          stack.last << href
          #~ stack.last << last_char #add again the 
        else
          res << href
          #~ res << last_char  #add again the end-space/newline
        end
      #No-wiki inline: {{{text}}}
      when /\{\{\{(.*)\}\}\}/     #verbatim
        if stack.last  
          stack.last << element(:verb,{},$1)
        else
          res << element(:verb,{},$1)
        end
      #Inclusion 
      #creole implements a general inclusion.
      #Main usage are pictures/images ({{picname|alt}}),
      #but it can be more...
      #
      #Available inclusions are defined in Creole::Inclusions resp. Creole#inclusions,
      when /\{\{(.+?)(?:\|(.*))?\}\}/     #Inclusion (e.g. images)
        if stack.last  
          stack.last << inclusion_or_plugin($1, $2, options[:inclusions])
        else
          res << inclusion_or_plugin($1, $2, options[:inclusions])
        end
      #Plugin
      #Used like Inclusions.
      #
      #available plugins are defined in Creole::Plugins resp. Creole#plugins
      when /<<(.+?)(?:\|(.*))?>>/
        if stack.last  
          stack.last << inclusion_or_plugin($1, $2, options[:plugins])
        else
          res << inclusion_or_plugin($1, $2, options[:plugins])
        end
      #No special wiki command. The text is "normal" text.
      else  #text to add
        #Replace characters.
        if CHARACTERS[el]
          insertion = CHARACTERS[el]
          startspace = endspace = nil
        else
          startspace = ( el[0,1] =~ /\s/ )
          endspace = ( el[-1,1] =~ /\s/ )
          insertion = word_wrap( el )         #wrap content
        end
        if stack.last 
          stack.last << insertion
          #This adds some obsolete spaces in case of newlines at the end.
          #But if I compare with ' ', then words will be concatenated without separator.
          stack.last << ' ' if endspace
        else  #Just some text without any format
          res << ' ' if startspace #Keep space
          res << insertion
          res << ' ' if endspace #Keep space
        end
      end
  }
  res
end

#inspectObject

check_link_existence



703
704
705
# File 'lib/docgenerator/creole/creole.rb', line 703

def inspect()
  "<#{self.class} (created #{@creation_caller})>"
end

#normsource2elements(normsource, options) ⇒ Object

Take the given normsource and build a list of elements. Used by

  • Creole#to_doc

  • Creole_ruby#to_doc



426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
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
# File 'lib/docgenerator/creole/creole.rb', line 426

def normsource2elements( normsource, options )
  doc = []    
  elements = {} #little collector for lists
  normsource.each{|line|
    case line.type
      when :dummy
        elements  = {}
      #Here we define the sectioning.
      #line.add_info[:level] contains the number of = from the wiki.
      #
      when :title
        options[:log].error("%s: Undefined title level %i" % [__method__,line.add_info[:level]]) if options[:log].error? and ! @options[:title_levels][line.add_info[:level]]
        doc << element(@options[:title_levels][line.add_info[:level]], {
                            :id => line.add_info[:label]
                            #inline or not? 
                            #Required for filenames with _ 
                            #But: http://www.wikicreole.org/wiki/Headings says no.
                            #Make decision depending on a setting?
                            }, line.content ).cr          
                            #~ }, inline(line.content, options ) ).cr          
      when :list
        key = line.add_info[:listtype]
        if ! elements[key]
          case key[-1,1]
          when '*';  elements[key] = element(:ul).cR
          when '#';  elements[key] = element(:ol).cR
          else
            options[:log].error("Undefined listtype #{key[-1,1]}") if options[:log].error?
          end
          if key.size == 1  #new list, add to document
            doc << elements[key] 
          elsif parent_list = elements[key[0,key.size-1]] #new sublist, add to "parent"
            parent_list << element(:li).cr unless parent_list.content.last.is_a?(:li)
            parent_list.content.last << elements[key] 
          else  #sublist without parent.
            options[:log].error("List #{key} with missing superlist") if options[:log].error?
            doc << element(:comment,{},'Sublist without superlist - move on top level').cr #add pending list on top level.
            doc << elements[key] #add pending list on top level.
          end
        end
        elements.each{|ekey, list|
          case ekey
            when key
              list << element(:li,{}, inline(line.content, options) ).cr
            else
              elements.delete(ekey) if ekey.size >= key.size
          end
        }
    when :pre
      doc << element(:verbatim, {}, line.content ).cR
    when :hr
      doc << element(:hr).cr
    when :placeholder
      doc << line.content
    when :par
      doc << element(:par, {}, inline(line.content, options)).cR
    else
      options[:log].error("Wrong line type #{ line.type.inspect }") if options[:log].error?
    end
  }
  
  return doc
end

#parse(source = @source) ⇒ Object

Parse the given creole code and build a “normalized source”



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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
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
# File 'lib/docgenerator/creole/creole.rb', line 187

def parse( source = @source )
  
  normsource = []    
  statusflag = nil  #Variable to store the actual status. nil = nothing special.
  normsource << Creole_line.new(:dummy)

  if ! source.respond_to?(:each_with_index)
    #Ruby 1.9 removed each from String
    if source.respond_to? :each_line
      source = source.each_line 
    else
      @log.fatal("Unable to parse #{source.class}: #{source.inspect}" ) if @log.fatal?
      return normsource
    end
  end


  #
  #Check code line by line
  #
  source.each_with_index{|line, lineno|
    #Check special status
    case statusflag
      when nil  #Nothing to do
      when :pre
        line =~ /\}\}\}/ ? statusflag = nil : normsource.last.content << line
        next
      when :placeholder
        #~ if line =~ /^>>>$/ #did not catch each system specific line end.
        if line =~ /^>>>(\r\n?|\n)/   #finish placeholder (started with <<<)
          statusflag = nil 
          normsource.last.content.close
        else
          normsource.last.content << line
        end
        next
      else
        @log.fatal("Undefined status #{statusflag}: #{line.inspect}" ) if @log.fatal?
      end #statusflag
      
    #
    #Parse the wiki text on line level (main structure)
    case line
      #Skip this line, if it correspond to a special comment-pattern.
      #Can be used for application-specific comments.
      #
      #Example: 
      #   :ignore => /^(#~.*)$/
      #This comment is created by scite using Ctrl-Q (for ruby-scripts).
      when @options[:ignore]
          @log.info("Found comment in line %2i: %s" % [
            lineno, #line.inspect
            [$~.pre_match, '<<', $1, '>>', $~.post_match].join.strip,
          ]) if @log.info?
      #Headings
      #http://www.wikicreole.org/wiki/Headings
      #
      #Modification of standard: Labels are possible.
      when /^(=+)(?:\[(.*)\])?(.+?)(=*)\s*$/
        normsource << Creole_line.new(:title, $3, :level => $1.size, :label => $2 )
        @toc << normsource.last
        #Creole doesn't need a trailing ===, but when it is ther, it should be correct
        if $1.size != $4.size and $4.size > 0
          @log.warn("Heading problem #{$1} doesn't match <#{$4}>: #{line.inspect}" ) if @log.warn?
        end
        if $~.post_match !~ /\s*/
          @log.warn("Ignore text #{$~.post_match.inspect} after title  <#{line.inspect}>" ) if @log.warn?
        end
        #And close the actual level
        #See unit test test_creole_mix_titles_list
        normsource << Creole_line.new(:dummy )
      #Empty line
      when /^\s*$/
        normsource << Creole_line.new(:dummy )
      when /^----\s*$/
        normsource << Creole_line.new(:hr )
      #List entry
      when /^\s*((\*|\#)+)/
        normsource << Creole_line.new(:list, $~.post_match, :listtype => $1 )
      #Tabular
      when /^\|/
        #fixme tab soll in par...
        #~ normsource.last << Creole_line.new(:placeholder, 
        #~ ... unless anpassen...
        normsource << Creole_line.new(:placeholder, 
                                      @placeholders['creole_tabular'].new(self),
                                      :start => lineno
                                    ) unless normsource.last.content.is_a?(Creole_tab)
        normsource.last.content << line
      #http://www.wikicreole.org/wiki/PreformattedAndNowiki
      when /^\{\{\{\s*$/  #Kind of verbatim
        normsource << Creole_line.new(:pre, [], :start => lineno )
        statusflag = :pre
      #~ when /^<<<(.*)\|?(.*?)/ #fixme options for placeholders?
      when /^<<<(.*)/       #placeholder (collect everything until >>>
        ph, par = $1.split(/\|/,2)
        placeholder = @placeholders[ph].new(self, par)
        if placeholder.instance_of?(Placeholders::Dummy)
          @log.warn("Unknown placeholder #{ph.inspect} used in line #{lineno}" ) if @log.warn?
        end
        normsource << Creole_line.new(:placeholder, placeholder, :start => lineno )
        statusflag = :placeholder
      else
        case normsource.last.type
          when :par, :list
            normsource.last.content << line
          else
            normsource << Creole_line.new(:par, line )
          end
    end
  }
  case statusflag
    when nil  #ok
    when :pre
      @log.warn("Unclosed verbatim found (start at #{normsource.last.add_info[:start]})" ) if @log.warn?
      #~ raise ''
    when :placeholder
      #One possible source: Regexp $ is system specific.
      @log.warn("Unclosed placeholder #{normsource.last.type} (start at #{normsource.last.add_info[:start]})" ) if @log.warn?
    else
      @log.warn("Wiki ends with status #{statusflag.inspect}" ) if @log.warn?
  end
  return normsource
end

#to_doc(target, options = {}) ⇒ Object

Prepare document.



412
413
414
415
416
417
418
419
# File 'lib/docgenerator/creole/creole.rb', line 412

def to_doc( target, options = {} )
  options[:log] = @log unless options[:log]
  #
  #Delete again all footnotegroups.
  #Else you get footnotes doubled.
  @footnotegroups = {}  #Collection of footnote groups
  return normsource2elements( @normsource, options ).to_doc(target, options)
end

#toc(i_options = {}) ⇒ Object

Return a table of contents as a list.



324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/docgenerator/creole/creole.rb', line 324

def toc( i_options = {})
  options = {
    :listtype  => :ul,
    :level    => 4,
    #~ :startlevel  => 1,
    }.update(i_options)

  if ! options[:level].is_a?(Integer)
    @log.error("Toc: toclevel is no number but '#{options[:level].inspect}'. Set 4") if @log.error?
    options[:level] = 4
  end


  toclist = []
  toclabel = [0] #help variable to construct labels
  listtype = '*'
  case options[:listtype]
    when '*', :ul, :itemize
      listtype = '*'
    when '#', :ol, :enumerate
      listtype = '#'
    else
      @log.error("Toc: Unknown listtype #{options[:listtype]}") if @log.error?
  end
  
  @toc.each{|tocentry|
      level = tocentry.add_info[:level]
      #Skip deeper levels then wanted.
      next if level > options[:level]

      #Build the label
      if level > toclabel.size
        toclabel << 0
      elsif level < toclabel.size
        toclabel.pop
      end
      #Happens if there is a jump gap on section levels (subsubsection inside section without subsection)
      if ! toclabel[level-1]
        @log.warn("Missing toclevel for <#{tocentry.content}> #{tocentry.add_info.inspect}")
        #add dummy level 
        toclabel << 0
        toclist << "#{listtype * ( level - 1)} ---"
      end
      toclabel[level-1] = toclabel[level-1] + 1 

      #Check if there was already a label.
      #If yes: use it. If not: build a new one with the help of toclabel.
      if tocentry.add_info[:label]
        label = tocentry.add_info[:label]
      else
        label = tocentry.add_info[:label] = toclabel.join('-')
      end
      
      #Feature to create the toc if higher levels are missing /start at h3...)
      #~ if level < options[:startlevel]
        #~ @log.warn( "toc: TOC starts not at #{options[:startlevel]}, but level #{level}" ) if @log.warn?
        #~ next 
      #~ end
      
      toclist << "#{listtype * level}[[##{label}|#{tocentry.content}]]"
    }
    toclist = <<toc
<<<html
<div class = 'toc'>
>>>
#{toclist.join("\n")}
<<<html
</div>
>>>
toc

  return Creole.new( :content => toclist, :log => @log )
end

#word_wrap(text, line_width = ) ⇒ Object



405
406
407
408
# File 'lib/docgenerator/creole/creole.rb', line 405

def word_wrap(text, line_width = @options[:wrap_at] ) 
  return text if line_width <= 0        
  text.gsub(/\n/, ' ').gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip
end