~ubuntu-branches/ubuntu/oneiric/ctioga2/oneiric

« back to all changes in this revision

Viewing changes to lib/ctioga2/commands/doc/markup.rb

  • Committer: Bazaar Package Importer
  • Author(s): Vincent Fourmond
  • Date: 2011-01-24 21:36:06 UTC
  • Revision ID: james.westby@ubuntu.com-20110124213606-9ettx0ugl83z0bzp
Tags: upstream-0.1
ImportĀ upstreamĀ versionĀ 0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# markup.rb: simple markup system used wirhin the documentation.
 
2
# copyright (c) 2009 by Vincent Fourmond
 
3
 
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
 
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details (in the COPYING file).
 
13
 
 
14
require 'ctioga2/utils'
 
15
require 'ctioga2/log'
 
16
 
 
17
module CTioga2
 
18
 
 
19
  Version::register_svn_info('$Revision: 216 $', '$Date: 2010-12-31 16:18:17 +0100 (Fri, 31 Dec 2010) $')
 
20
 
 
21
  module Commands
 
22
 
 
23
    module Documentation
 
24
 
 
25
      # The documentation strings are written in a simple markup
 
26
      # language.
 
27
      #
 
28
      # \todo we should provide tags to specifically mark TODO items
 
29
      # in documentation, in such a way that it would be easy to make
 
30
      # a list of them, and possibly ignore it for output.
 
31
      class MarkedUpText
 
32
 
 
33
        # Do we really need logging ?
 
34
        include Log
 
35
 
 
36
        # The base class for markup items.
 
37
        class MarkupItem
 
38
          # The documentation object
 
39
          attr_accessor :doc
 
40
 
 
41
          def initialize(doc)
 
42
            @doc = doc
 
43
          end
 
44
 
 
45
          def to_s
 
46
          end
 
47
 
 
48
          def dump_string
 
49
            return ""
 
50
          end
 
51
 
 
52
        end
 
53
 
 
54
        # A markup item representing plain text.
 
55
        class MarkupText < MarkupItem
 
56
          # The text
 
57
          attr_accessor :text
 
58
          
 
59
          # The kind of markup, nil means no markup
 
60
          attr_accessor :kind
 
61
          
 
62
          def initialize(doc, text = "", strip = true, 
 
63
                         kind = nil)
 
64
            super(doc)
 
65
            @text = text
 
66
            @kind = kind
 
67
            if strip
 
68
              @text.gsub!(/\n/, " ")
 
69
            end
 
70
          end
 
71
 
 
72
          def to_s
 
73
            return text
 
74
          end
 
75
 
 
76
          def dump_string
 
77
            return "text: #{@text}"
 
78
          end
 
79
 
 
80
        end
 
81
 
 
82
        # A markup item representing verbatim text, with the given
 
83
        # class
 
84
        class MarkupVerbatim < MarkupItem
 
85
          # The text
 
86
          attr_accessor :text
 
87
 
 
88
          # The verbatim text class
 
89
          attr_accessor :cls
 
90
          
 
91
          def initialize(doc, text, cls)
 
92
            super(doc)
 
93
            @text = text
 
94
            @cls = cls
 
95
          end
 
96
 
 
97
          def to_s
 
98
            return text
 
99
          end
 
100
 
 
101
          def dump_string
 
102
            return "#{@cls}: #{@text}"
 
103
          end
 
104
 
 
105
        end
 
106
 
 
107
        # A link to a type/group/command
 
108
        class MarkupLink < MarkupItem
 
109
          # The object target of the link
 
110
          attr_accessor :target
 
111
          
 
112
          # _target_ is the name of the target, which can be of _type_
 
113
          # 'group', 'command', 'backend', 'type' and 'url'
 
114
          def initialize(doc, target, type)
 
115
            super(doc)
 
116
            if type =~ /url/
 
117
              @target = target
 
118
            else
 
119
              @target = doc.send("#{type}s")[target]
 
120
            end
 
121
          end
 
122
 
 
123
          def to_s
 
124
            if @target 
 
125
              begin
 
126
                return @target.name
 
127
              rescue NoMethodError
 
128
                return @target
 
129
              end
 
130
            else
 
131
              return "unknown"
 
132
            end
 
133
          end
 
134
 
 
135
          def dump_string
 
136
            return "link: #{@target}"
 
137
          end
 
138
        end
 
139
 
 
140
        # An itemize object 
 
141
        class MarkupItemize < MarkupItem
 
142
 
 
143
          # An array of arrays of MarkupItem, each representing an
 
144
          # element of the itemize object.
 
145
          attr_accessor :items
 
146
          
 
147
          def initialize(doc, items = [])
 
148
            super(doc)
 
149
            @items = items
 
150
          end
 
151
          
 
152
          def to_s
 
153
            str = ""
 
154
            for i in @items
 
155
              str << " * "
 
156
              for j in i
 
157
                str << j.to_s 
 
158
              end
 
159
              str << "\n"
 
160
            end
 
161
            return str
 
162
          end
 
163
          
 
164
          def dump_string
 
165
            return @items.map {|x|
 
166
              "* #{x.map do |y| y.dump_string; end}\n"
 
167
            }.join('')
 
168
          end
 
169
 
 
170
        end
 
171
 
 
172
        # An item that contains a paragraph
 
173
        class MarkupParagraph < MarkupItem
 
174
          attr_accessor :elements
 
175
          
 
176
          def initialize(doc, elements)
 
177
            super(doc)
 
178
            @elements = elements
 
179
          end
 
180
 
 
181
          def to_s
 
182
            return @elements.map {|x| x.to_s }.join('')
 
183
          end
 
184
 
 
185
          def dump_string
 
186
            return "par: " + @elements.map {|x|
 
187
              "  #{x.dump_string}\n"
 
188
            }.join('')
 
189
          end
 
190
 
 
191
        end
 
192
 
 
193
        # The reference Doc object
 
194
        attr_accessor :doc
 
195
 
 
196
        # The elements that make up the MarkedUpText
 
197
        attr_accessor :elements
 
198
 
 
199
        # Creates a MarkedUpText object.
 
200
        def initialize(doc, text = nil)
 
201
          @elements = []
 
202
          @doc = doc
 
203
          if text
 
204
            parse_from_string(text)
 
205
          end
 
206
        end
 
207
 
 
208
 
 
209
        def dump
 
210
          puts "Number of elements: #{@elements.size}"
 
211
          for el in @elements
 
212
            puts "#{el.class} -> #{el.to_s}"
 
213
          end
 
214
        end
 
215
 
 
216
 
 
217
        # Parses the given _string_ and append the results to the
 
218
        # MarkedUpText's elements.
 
219
        #
 
220
        # Markup elements:
 
221
        #
 
222
        # * a line beginning with '> ' is an example for command-line
 
223
        # * a line beginning with '# ' is an example for use within a
 
224
        #   command file.
 
225
        # * a line beginning with '@ ' is a generic verbatim text.
 
226
        # * a line beginning with ' *' is an element of an
 
227
        #   itemize. The itemize finishes when a new paragraph is
 
228
        #   starting.
 
229
        # * a {group: ...} or {type: ...} or {command: ...} is a link
 
230
        #   to the element.
 
231
        # * a blank line marks a paragraph break.
 
232
        #
 
233
        # \todo Add elements to do some inline markup (such as bold,
 
234
        # code, italics; mostly code for now will do very fine)
 
235
        def parse_from_string(string)
 
236
          @last_type = nil
 
237
          @last_string = ""
 
238
 
 
239
          lines = string.split(/[ \t]*\n/)
 
240
          for l in lines
 
241
            l.chomp!
 
242
            case l
 
243
            when /^[#>@]\s(.*)/  # a verbatim line
 
244
              case l[0,1]
 
245
              when '#'
 
246
                type = :cmdfile
 
247
              when '>'
 
248
                type = :cmdline
 
249
              else
 
250
                type = :example
 
251
              end
 
252
              if @last_type == type
 
253
                @last_string << "#{$1}\n"
 
254
              else
 
255
                flush_element
 
256
                @last_type = type
 
257
                @last_string = "#{$1}\n"
 
258
              end
 
259
            when /^\s\*\s*(.*)/
 
260
              flush_element
 
261
              @last_type = :item
 
262
              @last_string = "#{$1}\n"
 
263
            when /^\s*$/          # Blank line:
 
264
              flush_element
 
265
              @last_type = nil
 
266
              @last_string = ""
 
267
            else
 
268
              case @last_type
 
269
              when :item, :paragraph # simply go on
 
270
                @last_string << "#{l}\n"
 
271
              else
 
272
                flush_element
 
273
                @last_type = :paragraph
 
274
                @last_string = "#{l}\n"
 
275
              end
 
276
            end
 
277
          end
 
278
          flush_element
 
279
        end
 
280
 
 
281
        protected 
 
282
 
 
283
        # A few constants to help writing out the paragraph markup
 
284
        LinkRE = /\{(group|type|command|backend|url):\s*([^}]+?)\s*\}/
 
285
 
 
286
        MarkOnceRE = /@([^@]+)@/
 
287
        
 
288
 
 
289
        # Parses the markup found within a paragraph (ie: links and
 
290
        # other text attributes, but not verbatim, list or other
 
291
        # markings) and returns an array containing the MarkupItem
 
292
        # elements.
 
293
        def parse_paragraph_markup(doc, string)
 
294
          els = []
 
295
          while string =~ /#{LinkRE}|#{MarkOnceRE}/
 
296
            els << MarkupText.new(doc, $`)
 
297
            if $1
 
298
              els << MarkupLink.new(doc, $2, $1) 
 
299
            elsif $3
 
300
              els << MarkupText.new(doc, $3, true, :code)
 
301
            end
 
302
            string = $'
 
303
          end
 
304
          els << MarkupText.new(doc, string)
 
305
          return els
 
306
        end
 
307
 
 
308
        # Adds the element accumulated so far to the @elements array.
 
309
        def flush_element
 
310
          case @last_type
 
311
          when :cmdline, :cmdfile
 
312
            @elements << MarkupVerbatim.new(@doc, @last_string, 
 
313
                                            "examples-#{@last_type}")
 
314
          when :example
 
315
            @elements << MarkupVerbatim.new(@doc, @last_string, "examples")
 
316
          when :paragraph
 
317
            @elements << 
 
318
              MarkupParagraph.new(@doc, 
 
319
                                  parse_paragraph_markup(doc, @last_string))
 
320
          when :item
 
321
            if @elements.last.is_a?(MarkupItemize)
 
322
              @elements.last.items << 
 
323
                parse_paragraph_markup(doc, @last_string)
 
324
            else
 
325
              @elements << 
 
326
                MarkupItemize.new(@doc, 
 
327
                                  [ parse_paragraph_markup(doc, @last_string)])
 
328
            end
 
329
          else                  # In principle, nil
 
330
            return
 
331
          end
 
332
        end
 
333
 
 
334
 
 
335
      end
 
336
      
 
337
      # A class dumping markup information to standard output
 
338
      class Markup
 
339
        # The Doc object the Markup class should dump
 
340
        attr_accessor :doc
 
341
 
 
342
        def initialize(doc)
 
343
          @doc = doc
 
344
        end
 
345
        
 
346
        # Dumps the markup of all commands
 
347
        def write_commands(out = STDOUT)
 
348
          cmds, groups = @doc.documented_commands
 
349
 
 
350
          for g in groups
 
351
            out.puts "Group markup: #{g.name}"
 
352
            out.puts dump_markup(g.description)
 
353
 
 
354
            commands = cmds[g].sort {|a,b|
 
355
              a.name <=> b.name
 
356
            }
 
357
            
 
358
            for cmd in commands
 
359
              out.puts "Command: #{cmd.name}"
 
360
              out.puts dump_markup(cmd.long_description)
 
361
            end
 
362
          end
 
363
        end
 
364
 
 
365
        # Dumps the markup of all types
 
366
        def write_types(out = STDOUT)
 
367
          types = @doc.types.sort.map { |d| d[1]}
 
368
          for t in types
 
369
            out.puts "Type: #{t.name}"
 
370
            out.puts dump_markup(t.description)
 
371
          end
 
372
        end
 
373
 
 
374
        def dump_markup(items)
 
375
          if items.is_a? String 
 
376
            mup = MarkedUpText.new(@doc, items)
 
377
            return dump_markup(mup.elements)
 
378
          end
 
379
          return items.map { |x| "-> #{x.dump_string}\n"}
 
380
        end
 
381
 
 
382
      end
 
383
    end
 
384
 
 
385
  end
 
386
end