Class: Ripdoc

Inherits:
Ripper::Filter
  • Object
show all
Defined in:
lib/assert2/ripdoc.rb

Overview

TODO reflect the banner anchor at generation time, to figure out what to hotlink to

Constant Summary collapse

HomePath =
(Pathname.new(__FILE__).dirname + '../..').expand_path
STYLES =
{
  CHAR:               'color: brown; font-weight: bolder;',
  const:              "color: #FF4F00; font-weight: bolder;",
  backref:            "color: #f4f; font-weight: bolder;",
  comment:            "font-style: italic; color: #446; font-family: Times; font-size: 110%;",
     # TODO  use "font: Times italic 110%" to save space
  embdoc:             "background-color: #FFe; font-family: Times; font-size: 133%;",
  embdoc_beg:         "display: none;",
  embdoc_end:         "display: none;",
  embexpr:            "background-color: #ccc;",
  embexpr_delimiter:  "background-color: #aaa;",
  gvar:               "color: #8f5902; font-weight: bolder;",
  ivar:               "color: #240;",
  int:                "color: #336600; font-weight: bolder;",
  operator:           "font-weight: bolder; font-size: 120%;",
  kw:                 "color: purple;",
  regexp_delimiter:   "background-color: #faf;",
  regexp:             "background-color: #fcf;",
  string:             "background-color: white;", #dfc
  string_delimiter:   "background-color: #cfa;",
  symbol:             "color: #066;",
  tstring_content: 'background: url(images/tstring.png) right;',
  tstring_internal: 'background: url(images/tstring.png) right;',  #  TODO  merge these two!
  tregexp_content: 'background: url(images/hot_pink.png);'
}
DOCTYPE =
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' +
"\n"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#embdocsObject

Returns the value of attribute embdocs.



350
351
352
# File 'lib/assert2/ripdoc.rb', line 350

def embdocs
  @embdocs
end

#in_no_docObject

Returns the value of attribute in_no_doc.



350
351
352
# File 'lib/assert2/ripdoc.rb', line 350

def in_no_doc
  @in_no_doc
end

#owed_preObject

Returns the value of attribute owed_pre.



350
351
352
# File 'lib/assert2/ripdoc.rb', line 350

def owed_pre
  @owed_pre
end

#spans_owedObject

Returns the value of attribute spans_owed.



350
351
352
# File 'lib/assert2/ripdoc.rb', line 350

def spans_owed
  @spans_owed
end

Class Method Details

.compile(f) ⇒ Object



365
366
367
368
369
370
# File 'lib/assert2/ripdoc.rb', line 365

def Ripdoc.compile(f)
  return DOCTYPE +
          '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr"
          ><head>' + 
         '</head><body>' + compile_fragment(f) + '</body></html>'
end

.compile_fragment(f) ⇒ Object



372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/assert2/ripdoc.rb', line 372

def Ripdoc.compile_fragment(f)
  buf = StringIO.new
  parser = Ripdoc.new(f)
  parser.in_no_doc = false
  parser.owed_pre = true
  parser.parse(buf, f)
  result = buf.string
  parser.spans_owed.times{ result += '</span>' }

  return '<div id="content"><pre>' + result +
             "#{'</pre>' if parser.owed_pre }</div>"

end

.generate(filename, title) ⇒ Object



41
42
43
44
45
46
47
48
49
50
# File 'lib/assert2/ripdoc.rb', line 41

def self.generate(filename, title)
  @sauce = compile_fragment(File.read(filename))
  @title = title
  @string_background = :tstring_content
  erb = ERB.new((HomePath + 'lib/assert2/ripdoc.html.erb').read, nil, '>')
  xhtml = erb.result(binding())
  xhtml.gsub! /\<pre>\s*\<\/pre>/m, ''
  xhtml.gsub! /\<p>\s*\<\/p>/m, ''
  return xhtml
end

Instance Method Details

#deformat(line, f) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/assert2/ripdoc.rb', line 72

def deformat(line, f)
  if line =~ /^\s/   #  CONSIDER why the line-height broke??
    f << "</p>" if @owed_p
    f << "<pre style='line-height: 75%;'>\n" unless @owed_pre
    @owed_p = false
    @owed_pre = true
    f << enline(line) << "\n"
    return
  end
  
  f << '</pre>' if @owed_pre
  @owed_pre = false
  f << '<p>' unless @owed_p
  @owed_p = true
  f << enline(line)
end

#dequote(attributes) ⇒ Object



52
53
54
# File 'lib/assert2/ripdoc.rb', line 52

def dequote(attributes)
  return attributes.gsub('&quot;', '"')
end

#end_panel(f) ⇒ Object



134
135
136
137
138
139
140
141
142
143
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
# File 'lib/assert2/ripdoc.rb', line 134

def end_panel(f)
    if banner = @embdocs.shift  #  accordion_toggle_active
      f << '<h1 class="accordion_toggle">'
      f << name_toggle(banner)
      f << enline(banner)
      f << '</h1>'
    end
    
    f << '<div class="accordion_content">'
      f << '<p>'
      @owed_p = true
      prior = false

      @embdocs.each do |doc|
        if doc.strip == ''
          f << "</p>\n<p>" if @owed_p
          prior = false
        elsif doc.strip =~ /^\#\!link\!(.*)/ #!link!froot!loop
          target, contents = $1.split('!')  #  TODO  permit a ! in the contents
          puts '#!link!anchor!text tags work best with text after the last bang!' unless contents
          contents ||= ''
          f << "<a href='\##{target}' onclick='raise(\"#{target}\")'>"
          f << enline(contents)
          f << '</a>'
        else
          f << ' ' if prior
          deformat(doc, f)
          prior = true
        end
      end
      
      f << '</p>' if @owed_p
  f << '<pre>' unless @owed_pre
  @owed_pre = true
  @embdocs = []
  return f
end

#enline(line) ⇒ Object

TODO complex ‘“? if we can’t it might be a good thing…



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/assert2/ripdoc.rb', line 56

def enline(line)
  line = CGI.escapeHTML(line)
  return line.gsub( /&lt;a(.*?)&gt;/){ "<a #{dequote($1)}>" }.
              gsub('&lt;/a&gt;', '</a>').
              gsub(/&lt;br\s*\/&gt;/, '<br/>').
              gsub( '&lt;code&gt;', '<code style="font-weight: bolder; font-style: normal;">').
              gsub('&lt;/code&gt;', '</code>').
              gsub( '&lt;em&gt;', '<em>').
              gsub('&lt;/em&gt;', '</em>').
              gsub( '&lt;li&gt;', '<li>').
              gsub('&lt;/li&gt;', '</li>').
              gsub( '&lt;ul&gt;', '<ul>').
              gsub('&lt;/ul&gt;', '</ul>').
              gsub('&amp;mdash;', '&mdash;')
end

#finish_one_span(f) ⇒ Object



239
240
241
242
243
244
# File 'lib/assert2/ripdoc.rb', line 239

def finish_one_span(f)
  if @spans_owed > 0
    f << '</span>' 
    @spans_owed -= 1
  end
end

#is_no_doc?(tok) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
# File 'lib/assert2/ripdoc.rb', line 98

def is_no_doc?(tok)
  tok.strip =~ /^\#\!nodoc\!/ or tok.strip =~ /^\#\!no_doc\!/
end

#name_toggle(banner) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/assert2/ripdoc.rb', line 120

def name_toggle(banner)
  banner = banner.gsub(/<.*?>/, '').
                  gsub(/&.*?;/, '').
                  scan(/[ _[:alnum:]]/).
                  map{|x| x == ' ' ? '_' : x }.
                  join.
                  gsub(/_+/, '_').
                  gsub(/_$/, '')

  return "<a href='#' name='#{banner}' id='#{banner}_'></a>" # CONSIDER this can't use <a ../> because enline() would mangle it...
    #  CONSIDER  the _ is due to a bug in libxml - it squeaks at a name and id that are the same - 
     #                                     despite that's a common idiom!
end

#on_CHAR(tok, f) ⇒ Object



215
216
217
218
219
# File 'lib/assert2/ripdoc.rb', line 215

def on_CHAR(tok, f)
  return f if @in_no_doc
  on_kw tok, f, 'CHAR'
  return f
end

#on_comment(tok, f) ⇒ Object



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/assert2/ripdoc.rb', line 195

def on_comment(tok, f)
  if tok.strip =~ /^\#\!end_panel\!/
    f << '</pre>' if @owed_pre
    @owed_pre = false
    f << '</div>'
    return f
  end

  nodoc = is_no_doc?(tok)

  if !nodoc and !@in_no_doc and tok.strip !~ /^\s*#\!/
    f << span(:comment) << enline(tok.rstrip) << '</span>'
    on_nl nil, f
  end
  
  @in_no_doc ||= nodoc
  @in_no_doc = nil if tok.strip =~ /^\#\!doc\!/
  return f
end

#on_default(event, tok, f) ⇒ Object

TODO linefeeds inside %w() and possibly ”

TODO colorize :"" and :"#{}" correctly


224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/assert2/ripdoc.rb', line 224

def on_default(event, tok, f)
  return f if @in_no_doc

  if @symbol_begun
    @symbol_begun = false
    f << %Q[#{span(:symbol)}#{CGI.escapeHTML(tok)}</span>]
  elsif tok =~ /^[[:punct:]]+$/
    f << %Q[#{span(:operator)}#{CGI.escapeHTML(tok)}</span>]
  else
    on_kw tok, f, event.to_s.sub(/^on_/, '')
  end

  return f
end

#on_embdoc(tok, f) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
# File 'lib/assert2/ripdoc.rb', line 102

def on_embdoc(tok, f)
  return f if @in_no_doc
  
  if is_no_doc? tok
    @in_no_doc = true
  else
    @embdocs << tok
  end
  
  return f
end

#on_embdoc_beg(tok, f) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/assert2/ripdoc.rb', line 89

def on_embdoc_beg(tok, f)
  return f if @in_no_doc
  @embdocs = []
  f << "</pre>\n" if @owed_pre
  @owed_pre = false
  return f
  # on_kw tok, f, 'embdoc_beg'
end

#on_embdoc_end(tok, f) ⇒ Object



114
115
116
117
118
# File 'lib/assert2/ripdoc.rb', line 114

def on_embdoc_end(tok, f)
  return f if @in_no_doc
  return end_panel(f)
  return f
end

#on_embexpr_beg(tok, f) ⇒ Object



304
305
306
307
308
# File 'lib/assert2/ripdoc.rb', line 304

def on_embexpr_beg(tok, f)
  return f if @in_no_doc
  spanit :embexpr, f, tok
  return f
end

#on_ignored_nl(tok, f) ⇒ Object

TODO single-line mode for nodoc



312
313
314
315
# File 'lib/assert2/ripdoc.rb', line 312

def on_ignored_nl(tok, f)
  return f if @in_no_doc
  on_nl nil, f
end

#on_ivar(tok, f) ⇒ Object

TODO syntax hilite the inner language of regices? how about XPathics?

escapes in strings??


345
346
347
348
# File 'lib/assert2/ripdoc.rb', line 345

def on_ivar(tok, f)
  return f if @in_no_doc
  f << %Q[#{span(:ivar)}#{CGI.escapeHTML(tok)}</span>]
end

#on_kw(tok, f, klass = 'kw') ⇒ Object



189
190
191
192
193
# File 'lib/assert2/ripdoc.rb', line 189

def on_kw(tok, f, klass = 'kw')
  return f if @in_no_doc
  f << span(klass) << CGI.escapeHTML(tok)
  f << '</span>'
end

#on_lbrace(tok, f) ⇒ Object



322
323
324
325
326
# File 'lib/assert2/ripdoc.rb', line 322

def on_lbrace(tok, f)
  return f if @in_no_doc
  spanit '', f, '' # tok  CONSIDER  wonder who is actually emitting the { ??
  f << tok
end

#on_nl(tok, f) ⇒ Object



317
318
319
320
# File 'lib/assert2/ripdoc.rb', line 317

def on_nl(tok, f)
  return f if @in_no_doc
  f << "\n"
end

#on_rbrace(tok, f) ⇒ Object



328
329
330
331
332
333
# File 'lib/assert2/ripdoc.rb', line 328

def on_rbrace(tok, f)
  return f if @in_no_doc
  f << tok
  finish_one_span(f)  #  TODO  these things might wrap lines!
  return f
end

#on_regexp_beg(tok, f) ⇒ Object

TODO report to ripper author the bug where on_tstring_end contains the whole string



289
290
291
292
293
294
295
# File 'lib/assert2/ripdoc.rb', line 289

def on_regexp_beg(tok, f)
  return f if @in_no_doc
  @spans_owed += 1
  f << span(:regexp)
  @string_background = :tregexp_content
  f << %Q[#{span(:regexp_delimiter)}#{CGI.escapeHTML(tok)}</span>]
end

#on_regexp_end(tok, f) ⇒ Object



297
298
299
300
301
302
# File 'lib/assert2/ripdoc.rb', line 297

def on_regexp_end(tok, f)
  return f if @in_no_doc
  f << %Q[#{span(:regexp_delimiter)}#{CGI.escapeHTML(tok)}</span>]
  finish_one_span(f)
  return f
end

#on_string_stretch(tok, f, klass = 'TODO remove me') ⇒ Object



267
268
269
270
271
# File 'lib/assert2/ripdoc.rb', line 267

def on_string_stretch(tok, f, klass = 'TODO remove me')
  return f if @in_no_doc
  f << span(@string_background.to_s) << CGI.escapeHTML(tok)
  f << '</span>'
end

#on_symbeg(tok, f) ⇒ Object



335
336
337
338
339
340
# File 'lib/assert2/ripdoc.rb', line 335

def on_symbeg(tok, f)
  return f if @in_no_doc
  on_default(:on_symbeg, tok, f)
  @symbol_begun = true
  return f
end

#on_tstring_beg(tok, f) ⇒ Object



246
247
248
249
250
251
252
# File 'lib/assert2/ripdoc.rb', line 246

def on_tstring_beg(tok, f)
  return f if @in_no_doc
  @spans_owed += 1
  f << span(:string)
  @string_background = :tstring_content
  f << %Q[#{span(:string_delimiter)}#{CGI.escapeHTML(tok)}</span>]
end

#on_tstring_content(tok, f, style = 'tstring_content') ⇒ Object



254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/assert2/ripdoc.rb', line 254

def on_tstring_content(tok, f, style = 'tstring_content')
  tok.split(/\n/).each_with_index do |sub_tok, index|
    if index == 0
      on_string_stretch(sub_tok, f, style)
    else
      space, sub_tok = sub_tok.scan(/(\s*)(.*)/).first
      f << space
      on_string_stretch(sub_tok, f, style)
    end
  end
  return f
end

#on_tstring_end(tok, f) ⇒ Object

TODO fix end-of-delim bug in // and %w() and %{} etc



275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/assert2/ripdoc.rb', line 275

def on_tstring_end(tok, f)
  return f if @in_no_doc
  
  if tok.length > 1
    margin, content, tok = tok.scan(/^(\s*)(.*)(.)$/).first
    f << margin if margin
    on_tstring_content content, f, 'tstring_internal' if content  #  TODO  is this used??
  end
  
  f << %Q[#{span(:string_delimiter)}#{CGI.escapeHTML(tok.to_s)}</span>]
  finish_one_span(f)
  return f
end

#parse(buf, f) ⇒ Object



355
356
357
358
359
# File 'lib/assert2/ripdoc.rb', line 355

def parse(buf, f)
  @spans_owed = 0
  @symbol_begun = false
  super(buf)
end

#span(kode) ⇒ Object

TODO need a tregexp_content to distinguish them!



174
175
176
177
178
179
180
181
# File 'lib/assert2/ripdoc.rb', line 174

def span(kode)
  if STYLES[kode.to_sym]
    # class="#{kode}" 
    return %Q[<span style="#{STYLES[kode.to_sym]}">]
  else
    return '<span>'
  end
end

#spanit(kode, f, tok) ⇒ Object



183
184
185
186
187
# File 'lib/assert2/ripdoc.rb', line 183

def spanit(kode, f, tok)
  @spans_owed ||= 0
  @spans_owed += 1
  f << span(kode) << CGI.escapeHTML(tok)
end