Class: Kramdown::Parser::RFC2629Kramdown

Inherits:
Kramdown show all
Defined in:
lib/kramdown-rfc2629.rb

Constant Summary collapse

XREF_BASE =

a token for a reference

/#{REXML::XMLTokens::NAME_CHAR}+/
XREF_TXT =

parenthesized text

/(?:[^\(]|\([^\)]*\))+/
XREF_RE =
/#{XREF_BASE}(?: \(#{XREF_TXT}\))?/
XREF_RE_M =

matching version of XREF_RE

/\A(#{XREF_BASE})(?: \((#{XREF_TXT})\))?/
XREF_SINGLE =
/(?:Section|Appendix) #{XREF_RE}/
XREF_MULTI =
/(?:Sections|Appendices) (?:#{XREF_RE}, )*#{XREF_RE},? and #{XREF_RE}/
XREF_ANY =
/(?:#{XREF_SINGLE}|#{XREF_MULTI})/
SECTIONS_RE =
/(?:#{XREF_ANY} and )?#{XREF_ANY}/
XREF_START =
/\{\{(?:(?:\{(.*?\n??.*?)\}(?:\{(.*?\n??.*?)\})?)|(\X*?))((?:\}\})|\})/u
IREF_START =
/\(\(\((.*?)\)\)\)/u
PI_BLOCK_START =

warn [:OPT_SPACE, OPT_SPACE, HTML_INSTRUCTION_RE].inspect

/^#{OPT_SPACE}<\?/u
PI_SPAN_START =
/<\?/u

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*doc) ⇒ RFC2629Kramdown

Returns a new instance of RFC2629Kramdown.



52
53
54
55
56
57
58
# File 'lib/kramdown-rfc2629.rb', line 52

def initialize(*doc)
  super
  @span_parsers.unshift(:xref)
  @span_parsers.unshift(:iref)
  @span_parsers.unshift(:span_pi)
  @block_parsers.unshift(:block_pi)
end

Class Method Details

.idref_cleanup(href) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
# File 'lib/kramdown-rfc2629.rb', line 69

def self.idref_cleanup(href)
  # can't start an IDREF with a number or reserved start
  if href =~ / /
    if $options.v3
      warn "** space(s) in cross-reference '#{href}' -- are you trying to use section references?"
    else
      warn "** space(s) in cross-reference '#{href}' -- note that section references are supported in v3 mode only."
    end
  end
  href.gsub(/\A(?:[0-9]|section-|u-|figure-|table-|iref-)/) { "_#{$&}" }
end

Instance Method Details

#handle_bares(s, attr, format, href, last_join = nil) ⇒ Object



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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/kramdown-rfc2629.rb', line 86

def handle_bares(s, attr, format, href, last_join = nil)
  if s.match(/\A(#{XREF_ANY}) and (#{XREF_ANY})\z/)
    handle_bares($1, {}, nil, href, " and ")
    handle_bares($2, {}, nil, href, " of ")
    return
  end

  href = href.split(' ')[0] # Remove any trailing (...)
  target1, target2 = href.split("@", 2)
  multi = last_join != nil
  (sn, s) = s.split(' ', 2)
  loop do
    m = s.match(/\A#{XREF_RE_M}(, (?:and )?| and )?/)
    break if not m

    if not multi and not m[2] and not m[3] and not target2
      # Modify |attr| if there is a single reference.  This can only be
      # used if there is only one section reference and the section part
      # has no title.
      attr['section'] = m[1]
      attr['sectionFormat'] = format
      attr['text'] = m[2]
      return
    end

    if sn
      @tree.children << Element.new(:text, "#{sn} ", {})
      sn = nil
    end

    multi = true
    s[m[0]] = ''

    attr1 = { 'target' => target1, 'section' => m[1], 'sectionFormat' => 'bare', 'text' => m[2] }
    @tree.children << Element.new(:xref, nil, attr1)
    andof = m[3] || last_join || " of "
    if andof == " of " && target2
      andof += rfc_mention(target1)
    end
    @tree.children << Element.new(:text, andof, {})
  end
end

#parse_block_piObject



217
218
219
220
221
222
223
224
225
226
227
# File 'lib/kramdown-rfc2629.rb', line 217

def parse_block_pi
  # warn [:BLOCK].inspect
  line = @src.current_line_number
  if (result = @src.scan(HTML_INSTRUCTION_RE))
    @tree.children << Element.new(:xml_pi, result, nil, category: :block, location: line)
    @src.scan(TRAILING_WHITESPACE)
    true
  else
    false
  end
end

#parse_irefObject

Introduce new (((target))) syntax for irefs



203
204
205
206
207
208
# File 'lib/kramdown-rfc2629.rb', line 203

def parse_iref
  @src.pos += @src.matched_size
  href = @src[1]
  el = Element.new(:iref, nil, {'target' => href}) # XXX
  @tree.children << el
end

#parse_span_piObject



232
233
234
235
236
237
238
239
240
# File 'lib/kramdown-rfc2629.rb', line 232

def parse_span_pi
  # warn [:SPAN].inspect
  line = @src.current_line_number
  if (result = @src.scan(HTML_INSTRUCTION_RE))
    @tree.children << Element.new(:xml_pi, result, nil, category: :span, location: line)
  else
    add_text(@src.getch)
  end
end

#parse_xrefObject

Introduce new {target} syntax for empty xrefs, which would otherwise be an ugly ![!](target) or ![ ](target) (I’d rather use [[target]], but that somehow clashes with links.)



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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/kramdown-rfc2629.rb', line 134

def parse_xref
  @src.pos += @src.matched_size
  unless @src[4] == "}}"
    warn "*** #{@src[0]}: unmatched braces #{@src[4].inspect}"
  end
  if contact_name = @src[1]
    attr = {'fullname' => contact_name.gsub("\n", " ")}
    if ascii_name = @src[2]
      attr["asciiFullname"] = ascii_name.gsub("\n", " ")
    end
    el = Element.new(:contact, nil, attr)
  else
    href = @src[3]
    attr = {}
    handled_subref = false
    if $options.v3
      # match Section ... of ...; set section, sectionFormat
      case href.gsub(/[\u00A0\s]+/, ' ') # may need nbsp and/or newlines
      when /\A(#{SECTIONS_RE}) of (.*)\z/
        href = $2
        handle_bares($1, attr, "of", href)
        handled_subref = true
      when /\A(.*), (#{SECTIONS_RE})\z/
        href = $1
        handle_bares($2, attr, "comma", href)
        handled_subref = true
      when /\A(.*) \((#{SECTIONS_RE})\)\z/
        href = $1
        handle_bares($2, attr, "parens", href)
        handled_subref = true
      when /#{XREF_RE_M}<(.+)\z/
        href = $3
        if $2
          attr['section'] = $2
          attr['relative'] = "#" << $1
        else
          attr['section'] = $1
        end
        attr['sectionFormat'] = 'bare'
      when /\A<<(.+)\z/
        href = $1
        attr['format'] = 'title'
      when /\A<(.+)\z/
        href = $1
        attr['format'] = 'counter'
      end
    end
    if href.match(/#{XREF_RE_M}\z/)
      href = $1
      attr['text'] = $2
    end
    target1, target2 = href.split("@", 2) # should do this only for sectionref...
    if target2
      href = target2
      unless handled_subref
        @tree.children << Element.new(:text, rfc_mention(target1), {})
      end
    end
    href = self.class.idref_cleanup(href)
    attr['target'] = href
    el = Element.new(:xref, nil, attr)
  end
  @tree.children << el
end

#replace_abbreviations(el, regexps = nil) ⇒ Object



40
41
42
43
44
45
46
47
48
49
# File 'lib/kramdown-rfc2629.rb', line 40

def replace_abbreviations(el, regexps = nil)
  unless regexps          # DUPLICATED AND MODIFIED CODE FROM UPSTREAM, CHECK ON UPSTREAM UPGRADE
    sorted_abbrevs = @root.options[:abbrev_defs].keys.sort {|a, b| b.length <=> a.length }
    regexps = [Regexp.union(*sorted_abbrevs.map {|k|
                              /#{Regexp.escape(k).gsub(/\\\s/, "[\\s\\p{Z}]+").force_encoding(Encoding::UTF_8)}/})]
    regexps << /(?=(?:\W|^)#{regexps.first}(?!\w))/ # regexp should only match on word boundaries
    # warn regexps.inspect
  end
  super(el, regexps)
end

#rfc_mention(target1) ⇒ Object

only works for RFCnnnn



81
82
83
84
# File 'lib/kramdown-rfc2629.rb', line 81

def rfc_mention(target1)  # only works for RFCnnnn
  target1 =~ /\A([A-Z]*)(.*)\z/
  "#$1 #$2 "
end