class HikiDoc

Constants

BLANK
BLOCKQUOTE_RE
BLOCK_PRE_CLOSE_RE
BLOCK_PRE_OPEN_RE

Inline Level

COMMENT_RE
DEL
DEL_RE
DLIST_RE
EM
EM_RE
HEADER_RE
HRULE_RE
IMAGE_EXTS
INDENTED_PRE_RE
LIST_RE
MODIFIER_RE
MODTAG
OLIST
PARAGRAPH_END_RE
STRONG
STRONG_RE
TABLE_RE
TT
TT_RE
ULIST
URI_RE
VERSION
WIKI_NAME_RE

Public Class Methods

new(output, options = {}) click to toggle source
# File lib/hikidoc.rb, line 56
def initialize(output, options = {})
  @output = output
  @options = default_options.merge(options)
  @header_re = nil
  @level = options[:level] || 1
  @plugin_syntax = options[:plugin_syntax] || method(:valid_plugin_syntax?)
end
to_html(src, options = {}) click to toggle source
# File lib/hikidoc.rb, line 48
def HikiDoc.to_html(src, options = {})
  new(HTMLOutput.new(">"), options).compile(src)
end
to_xhtml(src, options = {}) click to toggle source
# File lib/hikidoc.rb, line 52
def HikiDoc.to_xhtml(src, options = {})
  new(HTMLOutput.new(" />"), options).compile(src)
end

Public Instance Methods

compile(src) click to toggle source
# File lib/hikidoc.rb, line 64
def compile(src)
  @output.reset
  escape_plugin_blocks(src) {|escaped|
    compile_blocks escaped
    @output.finish
  }
end
to_html() click to toggle source

for backward compatibility

# File lib/hikidoc.rb, line 73
def to_html
  $stderr.puts("warning: HikiDoc#to_html is deprecated. Please use HikiDoc.to_html or HikiDoc.to_xhtml instead.")
  self.class.to_html(@output, @options)
end

Private Instance Methods

compile_block_pre(f) click to toggle source
# File lib/hikidoc.rb, line 339
def compile_block_pre(f)
  m = BLOCK_PRE_OPEN_RE.match(f.gets) or raise UnexpectedError, "must not happen"
  str = restore_plugin_block(f.break(BLOCK_PRE_CLOSE_RE).join.chomp)
  f.gets
  @output.block_preformatted(str, m[1])
end
compile_blockquote(f) click to toggle source
# File lib/hikidoc.rb, line 316
def compile_blockquote(f)
  @output.blockquote_open
  lines = []
  f.while_match(BLOCKQUOTE_RE) do |line|
    lines.push line.sub(BLOCKQUOTE_RE, "")
    skip_comments f
  end
  compile_blocks lines.join("")
  @output.blockquote_close
end
compile_blocks(src) click to toggle source

Block Level

# File lib/hikidoc.rb, line 155
def compile_blocks(src)
  f = LineInput.new(StringIO.new(src))
  while line = f.peek
    case line
    when COMMENT_RE
      f.gets
    when HEADER_RE
      compile_header f.gets
    when HRULE_RE
      f.gets
      compile_hrule
    when LIST_RE
      compile_list f
    when DLIST_RE
      compile_dlist f
    when TABLE_RE
      compile_table f
    when BLOCKQUOTE_RE
      compile_blockquote f
    when INDENTED_PRE_RE
      compile_indented_pre f
    when BLOCK_PRE_OPEN_RE
      compile_block_pre f
    else
      if /^$/ =~ line
        f.gets
        next
      end
      compile_paragraph f
    end
  end
end
compile_dlist(f) click to toggle source
# File lib/hikidoc.rb, line 261
def compile_dlist(f)
  @output.dlist_open
  f.while_match(DLIST_RE) do |line|
    dt, dd = split_dlitem(line.sub(DLIST_RE, ""))
    @output.dlist_item compile_inline(dt), compile_inline(dd)
    skip_comments f
  end
  @output.dlist_close
end
compile_header(line) click to toggle source
# File lib/hikidoc.rb, line 197
def compile_header(line)
  @header_re ||= /\A!{1,#{7 - @level}}/
  level = @level + (line.slice!(@header_re).size - 1)
  title = strip(line)
  @output.headline level, compile_inline(title)
end
compile_hrule() click to toggle source
# File lib/hikidoc.rb, line 206
def compile_hrule
  @output.hrule
end
compile_indented_pre(f) click to toggle source
# File lib/hikidoc.rb, line 329
def compile_indented_pre(f)
  lines = f.span(INDENTED_PRE_RE)         .map {|line| rstrip(line.sub(INDENTED_PRE_RE, "")) }
  text = restore_plugin_block(lines.join("\n"))
  @output.preformatted(@output.text(text))
end
compile_inline(str, buf = nil) click to toggle source
# File lib/hikidoc.rb, line 399
def compile_inline(str, buf = nil)
  buf ||= @output.container
  re = inline_syntax_re
  pending_str = nil
  while m = re.match(str)
    str = m.post_match

    link, uri, mod, wiki_name = m[1, 4]
    if wiki_name and wiki_name[0, 1] == "^"
      pending_str = m.pre_match + wiki_name[1..-1] + str
      next
    end

    pre_str = "#{pending_str}#{m.pre_match}"
    pending_str = nil
    evaluate_plugin_block(pre_str, buf)
    compile_inline_markup(buf, link, uri, mod, wiki_name)
  end
  evaluate_plugin_block(pending_str || str, buf)
  buf
end
compile_inline_markup(buf, link, uri, mod, wiki_name) click to toggle source
# File lib/hikidoc.rb, line 421
def compile_inline_markup(buf, link, uri, mod, wiki_name)
  case
  when link
    buf << compile_bracket_link(link[2...-2])
  when uri
    buf << compile_uri_autolink(uri)
  when mod
    buf << compile_modifier(mod)
  when wiki_name
    buf << @output.wiki_name(wiki_name)
  else
    raise UnexpectedError, "must not happen"
  end
end
compile_list(f) click to toggle source
# File lib/hikidoc.rb, line 214
def compile_list(f)
  typestack = []
  level = 0
  @output.list_begin
  f.while_match(LIST_RE) do |line|
    list_type = (line[0,1] == ULIST ? "ul" : "ol")
    new_level = line.slice(LIST_RE).size
    item = strip(line.sub(LIST_RE, ""))
    if new_level > level
      (new_level - level).times do
        typestack.push list_type
        @output.list_open list_type
        @output.listitem_open
      end
      @output.listitem compile_inline(item)
    elsif new_level < level
      (level - new_level).times do
        @output.listitem_close
        @output.list_close typestack.pop
      end
      @output.listitem_close
      @output.listitem_open
      @output.listitem compile_inline(item)
    elsif list_type == typestack.last
      @output.listitem_close
      @output.listitem_open
      @output.listitem compile_inline(item)
    else
      @output.listitem_close
      @output.list_close typestack.pop
      @output.list_open list_type
      @output.listitem_open
      @output.listitem compile_inline(item)
      typestack.push list_type
    end
    level = new_level
    skip_comments f
  end
  level.times do
    @output.listitem_close
    @output.list_close typestack.pop
  end
  @output.list_end
end
compile_modifier(str) click to toggle source
# File lib/hikidoc.rb, line 501
def compile_modifier(str)
  buf = @output.container
  while m = / (#{MODIFIER_RE})
            /o.match(str)
    evaluate_plugin_block(m.pre_match, buf)
    case
    when chunk = m[1]
      mod, s = split_mod(chunk)
      mid = MODTAG[mod]
      buf << @output.__send__(mid, compile_inline(s))
    else
      raise UnexpectedError, "must not happen"
    end
    str = m.post_match
  end
  evaluate_plugin_block(str, buf)
  buf
end
compile_paragraph(f) click to toggle source
# File lib/hikidoc.rb, line 352
def compile_paragraph(f)
  lines = f.break(PARAGRAPH_END_RE)         .reject {|line| COMMENT_RE =~ line }
  if lines.size == 1 and /\A\0(\d+)\0\z/ =~ strip(lines[0])
    @output.block_plugin plugin_block($1.to_i)
  else
    line_buffer = @output.container(:paragraph)
    lines.each_with_index do |line, i|
      buffer = @output.container
      line_buffer << buffer
      compile_inline(lstrip(line).chomp, buffer)
    end
    @output.paragraph(line_buffer)
  end
end
compile_table(f) click to toggle source
# File lib/hikidoc.rb, line 282
def compile_table(f)
  lines = []
  f.while_match(TABLE_RE) do |line|
    lines.push line
    skip_comments f
  end
  @output.table_open
  lines.each do |line|
    @output.table_record_open
    split_columns(line.sub(TABLE_RE, "")).each do |col|
      mid = col.sub!(/\A!/, "") ? "table_head" : "table_data"
      span = col.slice!(/\A[\^>]*/)
      rs = span_count(span, "^")
      cs = span_count(span, ">")
      @output.__send__(mid, compile_inline(col), rs, cs)
    end
    @output.table_record_close
  end
  @output.table_close
end
default_options() click to toggle source
# File lib/hikidoc.rb, line 80
def default_options
  {
    allow_bracket_inline_image: true,
    use_wiki_name: true,
    use_not_wiki_name: true,
  }
end
escape_plugin_blocks(text) { |buf| ... } click to toggle source
# File lib/hikidoc.rb, line 96
def escape_plugin_blocks(text)
  s = StringScanner.new(text)
  buf = ""
  @plugin_blocks = []
  while chunk = s.scan_until(/\{\{/)
    chunk[-2, 2] = ""
    buf << chunk
    if block = extract_plugin_block(s)
      @plugin_blocks.push block
      buf << "\00##{@plugin_blocks.size - 1}\00""
    else
      buf << "{{"
    end
  end
  buf << s.rest
  yield(buf)
end
evaluate_plugin_block(str, buf = nil) click to toggle source
# File lib/hikidoc.rb, line 120
def evaluate_plugin_block(str, buf = nil)
  buf ||= @output.container
  str.split(/(\0\d+\0)/).each do |s|
    if s[0, 1] == "\00"" and s[-1, 1] == "\00""
      buf << @output.inline_plugin(plugin_block(s[1..-2].to_i))
    else
      buf << @output.text(s)
    end
  end
  buf
end
extract_plugin_block(s) click to toggle source
# File lib/hikidoc.rb, line 136
def extract_plugin_block(s)
  pos = s.pos
  buf = ""
  while chunk = s.scan_until(/\}\}/)
    buf << chunk
    buf.chomp!("}}")
    if @plugin_syntax.call(buf)
      return buf
    end
    buf << "}}"
  end
  s.pos = pos
  nil
end
fix_uri(uri) click to toggle source
# File lib/hikidoc.rb, line 468
def fix_uri(uri)
  if /\A(?:https?|ftp|file):(?!\/\/)/ =~ uri
    uri.sub(/\A\w+:/, "")
  else
    uri
  end
end
image?(uri) click to toggle source
# File lib/hikidoc.rb, line 478
def image?(uri)
  IMAGE_EXTS.include?(uri[/\.[^.]+\z/].to_s.downcase)
end
inline_syntax_re() click to toggle source
# File lib/hikidoc.rb, line 376
def inline_syntax_re
  if @options[:use_wiki_name]
    if @options[:use_not_wiki_name]
      / (#{BRACKET_LINK_RE})
      | (#{URI_RE})
      | (#{MODIFIER_RE})
      | (\^?#{WIKI_NAME_RE})
      /o
    else
      / (#{BRACKET_LINK_RE})
      | (#{URI_RE})
      | (#{MODIFIER_RE})
      | (#{WIKI_NAME_RE})
      /o
    end
  else
    / (#{BRACKET_LINK_RE})
    | (#{URI_RE})
    | (#{MODIFIER_RE})
    /o
  end
end
lstrip(str) click to toggle source
# File lib/hikidoc.rb, line 543
def lstrip(str)
  str.sub(/\A[ \t\r\n\v\f]+/, "")
end
plugin_block(id) click to toggle source
# File lib/hikidoc.rb, line 132
def plugin_block(id)
  @plugin_blocks[id] or raise UnexpectedError, "must not happen: #{id.inspect}"
end
restore_plugin_block(str) click to toggle source
# File lib/hikidoc.rb, line 114
def restore_plugin_block(str)
  str.gsub(/\0(\d+)\0/) {
    "{{" + plugin_block($1.to_i) + "}}"
  }
end
rstrip(str) click to toggle source
# File lib/hikidoc.rb, line 539
def rstrip(str)
  str.sub(/[ \t\r\n\v\f]+\z/, "")
end
skip_comments(f) click to toggle source
# File lib/hikidoc.rb, line 190
def skip_comments(f)
  f.while_match(COMMENT_RE) do |line|
  end
end
span_count(str, ch) click to toggle source
# File lib/hikidoc.rb, line 309
def span_count(str, ch)
  c = str.count(ch)
  c == 0 ? nil : c + 1
end
split_columns(str) click to toggle source
# File lib/hikidoc.rb, line 303
def split_columns(str)
  cols = str.split(/\|\|/)
  cols.pop if cols.last.chomp.empty?
  cols
end
split_dlitem(line) click to toggle source
# File lib/hikidoc.rb, line 271
def split_dlitem(line)
  re = /\A((?:#{BRACKET_LINK_RE}|.)*?):/
  if m = re.match(line)
    return m[1], m.post_match
  else
    return line, ""
  end
end
split_mod(str) click to toggle source
# File lib/hikidoc.rb, line 520
def split_mod(str)
  case str
  when /\A'''/
    return str[0, 3], str[3...-3]
  when /\A''/
    return str[0, 2], str[2...-2]
  when /\A==/
    return str[0, 2], str[2...-2]
  when /\A``/
    return str[0, 2], str[2...-2]
  else
    raise UnexpectedError, "must not happen: #{str.inspect}"
  end
end
strip(str) click to toggle source
# File lib/hikidoc.rb, line 535
def strip(str)
  rstrip(lstrip(str))
end
valid_plugin_syntax?(code) click to toggle source

Plugin

# File lib/hikidoc.rb, line 92
def valid_plugin_syntax?(code)
  /['"]/ !~ code.gsub(/\\/, "").gsub(/\['"]/,"").gsub(/'[^']*'|"[^"]*"/, "")
end