pseudohikiparser 0.0.5 → 0.0.6.develop
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/pseudohiki2html +1 -20
- data/lib/htmlelement/htmltemplate.rb +39 -1
- data/lib/htmlelement.rb +15 -1
- data/lib/pseudohiki/autolink.rb +1 -1
- data/lib/pseudohiki/blockparser.rb +119 -18
- data/lib/pseudohiki/converter.rb +9 -19
- data/lib/pseudohiki/htmlformat.rb +88 -23
- data/lib/pseudohiki/htmlplugin.rb +3 -3
- data/lib/pseudohiki/inlineparser.rb +29 -18
- data/lib/pseudohiki/markdownformat.rb +71 -64
- data/lib/pseudohiki/plaintextformat.rb +25 -25
- data/lib/pseudohiki/shim.rb +30 -0
- data/lib/pseudohiki/sinatra_helpers.rb +23 -0
- data/lib/pseudohiki/treestack.rb +4 -4
- data/lib/pseudohiki/utils.rb +2 -2
- data/lib/pseudohiki/version.rb +1 -1
- data/lib/pseudohikiparser.rb +2 -0
- data/test/test_blockparser.rb +67 -0
- data/test/test_htmlelement.rb +34 -0
- data/test/test_htmlelement_utils.rb +11 -0
- data/test/test_htmlformat.rb +413 -0
- data/test/test_htmltemplate.rb +84 -0
- data/test/test_inlineparser.rb +4 -4
- data/test/test_markdownformat.rb +157 -4
- data/test/test_plaintextformat.rb +85 -0
- data/test/test_pseudohiki2html.rb +24 -7
- metadata +8 -6
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 98aa9c74058bd6a6da9f43b9f2c7d73872db41c9
         | 
| 4 | 
            +
              data.tar.gz: d921304c72c05629e616d47899b28e09c7fc91ab
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 4f1a030cee17f773f7f9489270874d462c4d1da7c6fa57b86830910a13018e5ee0757155d97e8e07de503cd2f22237bd515151de3583d187ac62aaf703120d37
         | 
| 7 | 
            +
              data.tar.gz: 793b3d2c14b5b36fc6ee964c838f9f630a017c3a78cc7e35ab2457fed631c405487ecf0c489da88fd2a5f3342ebb9425831eebd8bb28293682bfdf2834df8481
         | 
    
        data/bin/pseudohiki2html
    CHANGED
    
    | @@ -7,29 +7,10 @@ options.parse_command_line_options | |
| 7 7 |  | 
| 8 8 | 
             
            if $KCODE
         | 
| 9 9 | 
             
              PseudoHiki::OptionManager::ENCODING_REGEXP.each do |pat, encoding|
         | 
| 10 | 
            -
                options[:encoding] = encoding if pat  | 
| 10 | 
            +
                options[:encoding] = encoding if pat.match? $KCODE and not options[:force]
         | 
| 11 11 | 
             
              end
         | 
| 12 12 | 
             
            end
         | 
| 13 13 |  | 
| 14 | 
            -
            unless String.new.respond_to? :encode
         | 
| 15 | 
            -
              require 'iconv'
         | 
| 16 | 
            -
             | 
| 17 | 
            -
              def choose_input_encoding_using_kcode
         | 
| 18 | 
            -
                PseudoHiki::OptionManager::ENCODING_REGEXP.each do |pat, encoding|
         | 
| 19 | 
            -
                  return PseudoHiki::OptionManager::ENCODING_TO_CHARSET[encoding] if pat =~ $KCODE
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
                HtmlElement::CHARSET::UTF8
         | 
| 22 | 
            -
              end
         | 
| 23 | 
            -
              private :choose_input_encoding_using_kcode
         | 
| 24 | 
            -
             | 
| 25 | 
            -
              def encode(to, from=choose_input_encoding_using_kcode)
         | 
| 26 | 
            -
                iconv = Iconv.new(to, from)
         | 
| 27 | 
            -
                str = iconv.iconv(self)
         | 
| 28 | 
            -
                str << iconv.iconv(nil)
         | 
| 29 | 
            -
              end
         | 
| 30 | 
            -
              public :encode
         | 
| 31 | 
            -
            end
         | 
| 32 | 
            -
             | 
| 33 14 | 
             
            PseudoHiki::OptionManager.remove_bom
         | 
| 34 15 | 
             
            input_lines = ARGF.readlines.map {|line| line.encode(options.charset) }
         | 
| 35 16 | 
             
            options.set_options_from_input_file(input_lines)
         | 
| @@ -23,6 +23,11 @@ class HtmlTemplate | |
| 23 23 | 
             
                @title = nil
         | 
| 24 24 | 
             
                @title_element = create_element("title")
         | 
| 25 25 | 
             
                @body = create_element("body")
         | 
| 26 | 
            +
                @default_skip_link_labels = {
         | 
| 27 | 
            +
                  "en" => "Skip to Content",
         | 
| 28 | 
            +
                  "ja" => "\u{672c}\u{6587}\u{3078}", # honbun he
         | 
| 29 | 
            +
                  "fr" => "Aller au contenu"
         | 
| 30 | 
            +
                }
         | 
| 26 31 | 
             
                @html.push @head
         | 
| 27 32 | 
             
                @html.push @body
         | 
| 28 33 | 
             
                [ @content_language,
         | 
| @@ -36,7 +41,7 @@ class HtmlTemplate | |
| 36 41 | 
             
                  @head.push element
         | 
| 37 42 | 
             
                end
         | 
| 38 43 | 
             
              end
         | 
| 39 | 
            -
              attr_reader :title, :head
         | 
| 44 | 
            +
              attr_reader :title, :head, :body
         | 
| 40 45 |  | 
| 41 46 | 
             
              def create_element(*params)
         | 
| 42 47 | 
             
                ELEMENT[self.class].create(*params)
         | 
| @@ -70,6 +75,12 @@ class HtmlTemplate | |
| 70 75 | 
             
                @default_css_link["href"] = file_path
         | 
| 71 76 | 
             
              end
         | 
| 72 77 |  | 
| 78 | 
            +
              def embed_style(css)
         | 
| 79 | 
            +
                style = create_element("style", nil, "type" => "text/css")
         | 
| 80 | 
            +
                @head.push style
         | 
| 81 | 
            +
                style.push format_css(css)
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
             | 
| 73 84 | 
             
              def title=(title)
         | 
| 74 85 | 
             
                @title_element.pop until @title_element.empty?
         | 
| 75 86 | 
             
                @title = title
         | 
| @@ -103,6 +114,10 @@ class HtmlTemplate | |
| 103 114 | 
             
                  @html].join("")
         | 
| 104 115 | 
             
              end
         | 
| 105 116 |  | 
| 117 | 
            +
              def add_skip_link(to="contents", from=@body,label=default_skip_link_label)
         | 
| 118 | 
            +
                skip_link_container(from).unshift create_element("a", label, "href" => "##{to}")
         | 
| 119 | 
            +
              end
         | 
| 120 | 
            +
             | 
| 106 121 | 
             
              private
         | 
| 107 122 |  | 
| 108 123 | 
             
              def create_meta(type, content)
         | 
| @@ -126,6 +141,23 @@ class HtmlTemplate | |
| 126 141 | 
             
                return "" unless base_uri
         | 
| 127 142 | 
             
                create_element("base", nil, "href" => base_uri)
         | 
| 128 143 | 
             
              end
         | 
| 144 | 
            +
             | 
| 145 | 
            +
              def format_css(css)
         | 
| 146 | 
            +
                ["<!--", css.rstrip, "-->", ""].join($/)
         | 
| 147 | 
            +
              end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
              def skip_link_container(from)
         | 
| 150 | 
            +
                return from unless from == @body
         | 
| 151 | 
            +
                create_element("div").tap do |div|
         | 
| 152 | 
            +
                  div["class"] = "skip-link"
         | 
| 153 | 
            +
                  @body.unshift div
         | 
| 154 | 
            +
                end
         | 
| 155 | 
            +
              end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
              def default_skip_link_label
         | 
| 158 | 
            +
                @default_skip_link_labels[@html["lang"]] ||
         | 
| 159 | 
            +
                  @default_skip_link_labels["en"]
         | 
| 160 | 
            +
              end
         | 
| 129 161 | 
             
            end
         | 
| 130 162 |  | 
| 131 163 | 
             
            class XhtmlTemplate < HtmlTemplate
         | 
| @@ -141,6 +173,12 @@ class XhtmlTemplate < HtmlTemplate | |
| 141 173 | 
             
                super(language)
         | 
| 142 174 | 
             
                @html["xml:lang"] = language
         | 
| 143 175 | 
             
              end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
              private
         | 
| 178 | 
            +
             | 
| 179 | 
            +
              def format_css(css)
         | 
| 180 | 
            +
                css.rstrip + $/
         | 
| 181 | 
            +
              end
         | 
| 144 182 | 
             
            end
         | 
| 145 183 |  | 
| 146 184 | 
             
            class Xhtml5Template < XhtmlTemplate
         | 
    
        data/lib/htmlelement.rb
    CHANGED
    
    | @@ -123,7 +123,21 @@ class HtmlElement | |
| 123 123 | 
             
              end
         | 
| 124 124 |  | 
| 125 125 | 
             
              def pop
         | 
| 126 | 
            -
                @children.pop
         | 
| 126 | 
            +
                last_child = @children.pop
         | 
| 127 | 
            +
                last_child.parent = nil if last_child.kind_of? HtmlElement
         | 
| 128 | 
            +
                last_child
         | 
| 129 | 
            +
              end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
              def unshift(child)
         | 
| 132 | 
            +
                @children.unshift child
         | 
| 133 | 
            +
                child.parent = self if child.kind_of? HtmlElement
         | 
| 134 | 
            +
                self
         | 
| 135 | 
            +
              end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
              def shift
         | 
| 138 | 
            +
                first_child = @children.shift
         | 
| 139 | 
            +
                first_child.parent = nil if first_child.kind_of? HtmlElement
         | 
| 140 | 
            +
                first_child
         | 
| 127 141 | 
             
              end
         | 
| 128 142 |  | 
| 129 143 | 
             
              def []=(attribute, value)
         | 
    
        data/lib/pseudohiki/autolink.rb
    CHANGED
    
    | @@ -47,7 +47,7 @@ module PseudoHiki | |
| 47 47 | 
             
                  end
         | 
| 48 48 |  | 
| 49 49 | 
             
                  def link_wiki_name(line)
         | 
| 50 | 
            -
                    return line if WIKI_NAME_RE  | 
| 50 | 
            +
                    return line if not WIKI_NAME_RE.match? line or VERBATIM_LEAF_HEAD_RE.match? line
         | 
| 51 51 | 
             
                    line.gsub(WIKI_NAME_RE) {|url| in_link_tag?($`) ? url : add_tag(url) }
         | 
| 52 52 | 
             
                  end
         | 
| 53 53 |  | 
| @@ -1,5 +1,6 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 2 |  | 
| 3 | 
            +
            require 'pseudohiki/shim'
         | 
| 3 4 | 
             
            require 'pseudohiki/treestack'
         | 
| 4 5 | 
             
            require 'pseudohiki/inlineparser'
         | 
| 5 6 |  | 
| @@ -38,14 +39,21 @@ module PseudoHiki | |
| 38 39 | 
             
                end
         | 
| 39 40 |  | 
| 40 41 | 
             
                class BlockStack < TreeStack
         | 
| 41 | 
            -
                   | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 42 | 
            +
                  attr_reader :stack
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  def pop_with_breaker(breaker=nil)
         | 
| 45 | 
            +
                    current_node.parse_leafs(breaker)
         | 
| 46 | 
            +
                    pop
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  def current_heading_level
         | 
| 50 | 
            +
                    i = @stack.rindex {|node| node.kind_of? BlockElement::HeadingNode }
         | 
| 51 | 
            +
                    @stack[i].level || 0
         | 
| 44 52 | 
             
                  end
         | 
| 45 53 | 
             
                end
         | 
| 46 54 |  | 
| 47 55 | 
             
                class BlockLeaf < BlockStack::Leaf
         | 
| 48 | 
            -
                  attr_accessor :level, :node_id
         | 
| 56 | 
            +
                  attr_accessor :level, :node_id, :decorator
         | 
| 49 57 |  | 
| 50 58 | 
             
                  class << self
         | 
| 51 59 | 
             
                    attr_accessor :head_re
         | 
| @@ -81,7 +89,7 @@ module PseudoHiki | |
| 81 89 | 
             
                    super(stack)
         | 
| 82 90 | 
             
                  end
         | 
| 83 91 |  | 
| 84 | 
            -
                  def parse_leafs
         | 
| 92 | 
            +
                  def parse_leafs(breaker)
         | 
| 85 93 | 
             
                    parsed = InlineParser.parse(join)
         | 
| 86 94 | 
             
                    clear
         | 
| 87 95 | 
             
                    concat(parsed)
         | 
| @@ -131,6 +139,10 @@ module PseudoHiki | |
| 131 139 | 
             
                    first.level if first # @cached_level ||= (first.level if first)
         | 
| 132 140 | 
             
                  end
         | 
| 133 141 |  | 
| 142 | 
            +
                  def decorator
         | 
| 143 | 
            +
                    first.decorator if first
         | 
| 144 | 
            +
                  end
         | 
| 145 | 
            +
             | 
| 134 146 | 
             
                  def push_self(stack)
         | 
| 135 147 | 
             
                    @stack = stack
         | 
| 136 148 | 
             
                    super(stack)
         | 
| @@ -140,24 +152,24 @@ module PseudoHiki | |
| 140 152 | 
             
                    not (kind_of? breaker.block and level == breaker.level)
         | 
| 141 153 | 
             
                  end
         | 
| 142 154 |  | 
| 143 | 
            -
                  def parse_leafs; end
         | 
| 155 | 
            +
                  def parse_leafs(breaker); end
         | 
| 144 156 |  | 
| 145 157 | 
             
                  def add_leaf(line, blockparser)
         | 
| 146 158 | 
             
                    leaf = create_leaf(line, blockparser)
         | 
| 147 | 
            -
                    blockparser.stack. | 
| 159 | 
            +
                    blockparser.stack.pop_with_breaker(leaf) while blockparser.breakable?(leaf)
         | 
| 148 160 | 
             
                    blockparser.stack.push leaf
         | 
| 149 161 | 
             
                  end
         | 
| 150 162 |  | 
| 151 163 | 
             
                  def create_leaf(line, blockparser)
         | 
| 152 | 
            -
                    return BlockElement::VerbatimLeaf.create("".freeze, true) if VERBATIM_BEGIN  | 
| 164 | 
            +
                    return BlockElement::VerbatimLeaf.create("".freeze, true) if VERBATIM_BEGIN.match? line
         | 
| 153 165 | 
             
                    line = blockparser.auto_linker.link(line)
         | 
| 154 166 | 
             
                    blockparser.select_leaf_type(line).create(line)
         | 
| 155 167 | 
             
                  end
         | 
| 156 168 | 
             
                end
         | 
| 157 169 |  | 
| 158 170 | 
             
                class NonNestedBlockNode < BlockNode
         | 
| 159 | 
            -
                  def parse_leafs
         | 
| 160 | 
            -
                    each {|leaf| leaf.parse_leafs }
         | 
| 171 | 
            +
                  def parse_leafs(breaker)
         | 
| 172 | 
            +
                    each {|leaf| leaf.parse_leafs(breaker) }
         | 
| 161 173 | 
             
                  end
         | 
| 162 174 | 
             
                end
         | 
| 163 175 |  | 
| @@ -175,13 +187,15 @@ module PseudoHiki | |
| 175 187 | 
             
                  end
         | 
| 176 188 | 
             
                end
         | 
| 177 189 |  | 
| 190 | 
            +
                class UnmatchedSectioningTagError < StandardError; end
         | 
| 191 | 
            +
             | 
| 178 192 | 
             
                module BlockElement
         | 
| 179 193 | 
             
                  {
         | 
| 180 | 
            -
                    BlockLeaf => %w(DescLeaf VerbatimLeaf TableLeaf CommentOutLeaf BlockNodeEnd HrLeaf),
         | 
| 194 | 
            +
                    BlockLeaf => %w(DescLeaf VerbatimLeaf TableLeaf CommentOutLeaf BlockNodeEnd HrLeaf DecoratorLeaf SectioningNodeEnd),
         | 
| 181 195 | 
             
                    NonNestedBlockLeaf => %w(QuoteLeaf ParagraphLeaf),
         | 
| 182 196 | 
             
                    NestedBlockLeaf => %w(HeadingLeaf),
         | 
| 183 197 | 
             
                    ListTypeLeaf => %w(ListLeaf EnumLeaf),
         | 
| 184 | 
            -
                    BlockNode => %w(DescNode VerbatimNode TableNode CommentOutNode HrNode),
         | 
| 198 | 
            +
                    BlockNode => %w(DescNode VerbatimNode TableNode CommentOutNode HrNode DecoratorNode SectioningNode),
         | 
| 185 199 | 
             
                    NonNestedBlockNode => %w(QuoteNode ParagraphNode),
         | 
| 186 200 | 
             
                    NestedBlockNode => %w(HeadingNode),
         | 
| 187 201 | 
             
                    ListTypeBlockNode => %w(ListNode EnumNode),
         | 
| @@ -204,15 +218,100 @@ module PseudoHiki | |
| 204 218 | 
             
                    attr_accessor :in_block_tag
         | 
| 205 219 |  | 
| 206 220 | 
             
                    def add_leaf(line, blockparser)
         | 
| 207 | 
            -
                      return @stack. | 
| 221 | 
            +
                      return @stack.pop_with_breaker if VERBATIM_END.match? line
         | 
| 208 222 | 
             
                      return super(line, blockparser) unless @in_block_tag
         | 
| 209 | 
            -
                      line = " #{line}" if BlockNodeEnd.head_re  | 
| 223 | 
            +
                      line = " #{line}" if BlockNodeEnd.head_re.match? line and not @in_block_tag
         | 
| 210 224 | 
             
                      @stack.push VerbatimLeaf.create(line, @in_block_tag)
         | 
| 211 225 | 
             
                    end
         | 
| 212 226 | 
             
                  end
         | 
| 213 227 |  | 
| 228 | 
            +
                  class DecoratorNode
         | 
| 229 | 
            +
                    DECORATOR_PAT = /\A(?:([^\[\]:]+))?(?:\[([^\[\]]+)\])?(?::\s*(\S.*))?/o
         | 
| 230 | 
            +
                    LABEL_SEP = [":"]
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                    class DecoratorItem < Struct.new(:string, :type, :id, :value)
         | 
| 233 | 
            +
                      def self.create(leaf)
         | 
| 234 | 
            +
                        m = DECORATOR_PAT.match(leaf.join)
         | 
| 235 | 
            +
                        return nil unless m
         | 
| 236 | 
            +
                        args = m.to_a
         | 
| 237 | 
            +
                        if i = leaf.index(LABEL_SEP)
         | 
| 238 | 
            +
                          value = leaf.dup
         | 
| 239 | 
            +
                          value.shift(i + 1)
         | 
| 240 | 
            +
                          args[-1] = lstrip_value!(value)
         | 
| 241 | 
            +
                        end
         | 
| 242 | 
            +
                        self.new(*args)
         | 
| 243 | 
            +
                      end
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                      def self.lstrip_value!(value)
         | 
| 246 | 
            +
                        head_val = value[0][0]
         | 
| 247 | 
            +
                        if head_val.kind_of? String and head_val.start_with? " ".freeze
         | 
| 248 | 
            +
                          value[0][0] = head_val.lstrip
         | 
| 249 | 
            +
                        end
         | 
| 250 | 
            +
                        value
         | 
| 251 | 
            +
                      end
         | 
| 252 | 
            +
                    end
         | 
| 253 | 
            +
             | 
| 254 | 
            +
                    def parse_leafs(breaker)
         | 
| 255 | 
            +
                      decorator = {}
         | 
| 256 | 
            +
                      breaker.decorator = decorator
         | 
| 257 | 
            +
                      @stack.remove_current_node.each do |leaf|
         | 
| 258 | 
            +
                        if item = DecoratorItem.create(leaf)
         | 
| 259 | 
            +
                          decorator[item.type || :id] = item
         | 
| 260 | 
            +
                        end
         | 
| 261 | 
            +
                      end
         | 
| 262 | 
            +
                    end
         | 
| 263 | 
            +
             | 
| 264 | 
            +
                    def breakable?(breaker)
         | 
| 265 | 
            +
                      return super if breaker.kind_of? DecoratorLeaf
         | 
| 266 | 
            +
                      parse_leafs(breaker)
         | 
| 267 | 
            +
                      @stack.current_node.breakable?(breaker)
         | 
| 268 | 
            +
                    end
         | 
| 269 | 
            +
                  end
         | 
| 270 | 
            +
             | 
| 271 | 
            +
                  class DecoratorLeaf
         | 
| 272 | 
            +
                    def push_sectioning_node(stack, node_class)
         | 
| 273 | 
            +
                      node = node_class.new
         | 
| 274 | 
            +
                      m = DecoratorNode::DECORATOR_PAT.match(join)
         | 
| 275 | 
            +
                      node.node_id = m[2]
         | 
| 276 | 
            +
                      node.section_level = stack.current_heading_level if node.kind_of? SectioningNode
         | 
| 277 | 
            +
                      stack.push(node)
         | 
| 278 | 
            +
                    end
         | 
| 279 | 
            +
             | 
| 280 | 
            +
                    def push_self(stack)
         | 
| 281 | 
            +
                      decorator_type = self[0][0]
         | 
| 282 | 
            +
                      if decorator_type.start_with? "begin[".freeze
         | 
| 283 | 
            +
                        push_sectioning_node(stack, SectioningNode)
         | 
| 284 | 
            +
                      elsif decorator_type.start_with? "end[".freeze
         | 
| 285 | 
            +
                        push_sectioning_node(stack, SectioningNodeEnd)
         | 
| 286 | 
            +
                      else
         | 
| 287 | 
            +
                        super
         | 
| 288 | 
            +
                      end
         | 
| 289 | 
            +
                    end
         | 
| 290 | 
            +
                  end
         | 
| 291 | 
            +
             | 
| 292 | 
            +
                  class SectioningNode
         | 
| 293 | 
            +
                    attr_accessor :section_level
         | 
| 294 | 
            +
             | 
| 295 | 
            +
                    def breakable?(breaker)
         | 
| 296 | 
            +
                      breaker.kind_of? HeadingLeaf and @section_level >= breaker.level
         | 
| 297 | 
            +
                    end
         | 
| 298 | 
            +
                  end
         | 
| 299 | 
            +
             | 
| 300 | 
            +
                  class SectioningNodeEnd
         | 
| 301 | 
            +
                    def push_self(stack)
         | 
| 302 | 
            +
                      n = stack.stack.rindex do |node|
         | 
| 303 | 
            +
                        node.kind_of? SectioningNode and node.node_id == node_id
         | 
| 304 | 
            +
                      end
         | 
| 305 | 
            +
                      raise UnmatchedSectioningTagError unless n
         | 
| 306 | 
            +
                      stack.pop until stack.stack.length == n
         | 
| 307 | 
            +
                    rescue UnmatchedSectioningTagError => e
         | 
| 308 | 
            +
                      STDERR.puts "#{e}: The start tag for '#{node_id}' is not found."
         | 
| 309 | 
            +
                      # FIXME: The handling of this error should be changed appropriately.
         | 
| 310 | 
            +
                    end
         | 
| 311 | 
            +
                  end
         | 
| 312 | 
            +
             | 
| 214 313 | 
             
                  class QuoteNode
         | 
| 215 | 
            -
                    def parse_leafs
         | 
| 314 | 
            +
                    def parse_leafs(breaker)
         | 
| 216 315 | 
             
                      self[0] = BlockParser.parse(self[0], AutoLink::Off)
         | 
| 217 316 | 
             
                    end
         | 
| 218 317 | 
             
                  end
         | 
| @@ -273,7 +372,8 @@ module PseudoHiki | |
| 273 372 | 
             
                 [HrLeaf, HrNode],
         | 
| 274 373 | 
             
                 [ListLeaf, ListNode],
         | 
| 275 374 | 
             
                 [EnumLeaf, EnumNode],
         | 
| 276 | 
            -
                 [BlockNodeEnd, BlockNodeEnd] # special case
         | 
| 375 | 
            +
                 [BlockNodeEnd, BlockNodeEnd], # special case
         | 
| 376 | 
            +
                 [DecoratorLeaf, DecoratorNode]
         | 
| 277 377 | 
             
                ].each do |leaf, node|
         | 
| 278 378 | 
             
                  PARENT_NODE[leaf] = node
         | 
| 279 379 | 
             
                end
         | 
| @@ -286,6 +386,7 @@ module PseudoHiki | |
| 286 386 | 
             
                                      ['!', HeadingLeaf],
         | 
| 287 387 | 
             
                                      ['""', QuoteLeaf],
         | 
| 288 388 | 
             
                                      ['||', TableLeaf],
         | 
| 389 | 
            +
                                      ['//@', DecoratorLeaf],
         | 
| 289 390 | 
             
                                      ['//', CommentOutLeaf],
         | 
| 290 391 | 
             
                                      ['----\s*$', HrLeaf]]
         | 
| 291 392 |  | 
| @@ -331,7 +432,7 @@ module PseudoHiki | |
| 331 432 | 
             
                def read_lines(lines)
         | 
| 332 433 | 
             
                  each_line = lines.respond_to?(:each_line) ? :each_line : :each
         | 
| 333 434 | 
             
                  lines.send(each_line) {|line| @stack.current_node.add_leaf(line, self) }
         | 
| 334 | 
            -
                  @stack. | 
| 435 | 
            +
                  @stack.pop_with_breaker
         | 
| 335 436 | 
             
                end
         | 
| 336 437 | 
             
              end
         | 
| 337 438 |  | 
| @@ -356,7 +457,7 @@ module PseudoHiki | |
| 356 457 | 
             
                  end
         | 
| 357 458 |  | 
| 358 459 | 
             
                  def self.link(line)
         | 
| 359 | 
            -
                    return line unless URI_RE  | 
| 460 | 
            +
                    return line unless URI_RE.match? line and not VERBATIM_LEAF_HEAD_RE.match? line
         | 
| 360 461 | 
             
                    line.gsub(URI_RE) {|url| in_link_tag?($`) ? url : "[[#{url}]]" }
         | 
| 361 462 | 
             
                  end
         | 
| 362 463 |  | 
    
        data/lib/pseudohiki/converter.rb
    CHANGED
    
    | @@ -29,8 +29,6 @@ module PseudoHiki | |
| 29 29 | 
             
                    @options.formatter.format(tree)
         | 
| 30 30 | 
             
                  end
         | 
| 31 31 |  | 
| 32 | 
            -
                  def create_style(path_to_css_file); "".freeze; end
         | 
| 33 | 
            -
             | 
| 34 32 | 
             
                  private
         | 
| 35 33 |  | 
| 36 34 | 
             
                  def toc_item_pat?(node)
         | 
| @@ -87,15 +85,6 @@ module PseudoHiki | |
| 87 85 | 
             
                    end
         | 
| 88 86 | 
             
                  end
         | 
| 89 87 |  | 
| 90 | 
            -
                  def create_style(path_to_css_file)
         | 
| 91 | 
            -
                    style = formatter.create_element("style").tap do |element|
         | 
| 92 | 
            -
                      element["type"] = "text/css"
         | 
| 93 | 
            -
                      open(File.expand_path(path_to_css_file)) do |css_file|
         | 
| 94 | 
            -
                        element.push css_file.read
         | 
| 95 | 
            -
                      end
         | 
| 96 | 
            -
                    end
         | 
| 97 | 
            -
                  end
         | 
| 98 | 
            -
             | 
| 99 88 | 
             
                  private
         | 
| 100 89 |  | 
| 101 90 | 
             
                  def setup_link_manager(options)
         | 
| @@ -200,7 +189,7 @@ module PseudoHiki | |
| 200 189 |  | 
| 201 190 | 
             
                def split_main_heading(input_lines)
         | 
| 202 191 | 
             
                  return "" unless @options[:split_main_heading]
         | 
| 203 | 
            -
                  h1_pos = input_lines.find_index {|line| /^![^!]/o  | 
| 192 | 
            +
                  h1_pos = input_lines.find_index {|line| /^![^!]/o.match? line }
         | 
| 204 193 | 
             
                  return "" unless h1_pos
         | 
| 205 194 | 
             
                  tree = BlockParser.parse([input_lines.delete_at(h1_pos)])
         | 
| 206 195 | 
             
                  @options.formatter.format(tree)
         | 
| @@ -223,8 +212,9 @@ module PseudoHiki | |
| 223 212 | 
             
                  else
         | 
| 224 213 | 
             
                    html = @options.create_html_template_with_current_options
         | 
| 225 214 | 
             
                    embed_css = @options[:embed_css]
         | 
| 226 | 
            -
                    html. | 
| 215 | 
            +
                    html.embed_style(File.read(File.expand_path(embed_css))) if embed_css
         | 
| 227 216 | 
             
                    html.push main || body
         | 
| 217 | 
            +
                    html.add_skip_link if html.kind_of?(HtmlTemplate) and main
         | 
| 228 218 | 
             
                  end
         | 
| 229 219 |  | 
| 230 220 | 
             
                  html
         | 
| @@ -313,7 +303,7 @@ module PseudoHiki | |
| 313 303 | 
             
                end
         | 
| 314 304 |  | 
| 315 305 | 
             
                def win32?
         | 
| 316 | 
            -
                  true if RUBY_PLATFORM  | 
| 306 | 
            +
                  true if RUBY_PLATFORM.match? /win/i
         | 
| 317 307 | 
             
                end
         | 
| 318 308 |  | 
| 319 309 | 
             
                def value_given?(value)
         | 
| @@ -334,9 +324,9 @@ module PseudoHiki | |
| 334 324 |  | 
| 335 325 | 
             
                def base
         | 
| 336 326 | 
             
                  base_dir = self[:base]
         | 
| 337 | 
            -
                  if base_dir and  | 
| 327 | 
            +
                  if base_dir and not /[\/\\]\.*$/o.match? base_dir
         | 
| 338 328 | 
             
                    base_dir = File.join(base_dir, ".")
         | 
| 339 | 
            -
                    base_dir = "file:///" + base_dir if  | 
| 329 | 
            +
                    base_dir = "file:///" + base_dir if not /^\./o.match? base_dir and win32?
         | 
| 340 330 | 
             
                  end
         | 
| 341 331 | 
             
                  base_dir
         | 
| 342 332 | 
             
                end
         | 
| @@ -354,7 +344,7 @@ module PseudoHiki | |
| 354 344 | 
             
                    if v.version == version
         | 
| 355 345 | 
             
                      return self[:html_version] = v
         | 
| 356 346 | 
             
                    else
         | 
| 357 | 
            -
                      self[:html_version] = v if v.opt_pat  | 
| 347 | 
            +
                      self[:html_version] = v if v.opt_pat.match? version
         | 
| 358 348 | 
             
                    end
         | 
| 359 349 | 
             
                  end
         | 
| 360 350 | 
             
                  STDERR.puts "\"#{version}\" is an invalid option for --format-version. \
         | 
| @@ -366,7 +356,7 @@ module PseudoHiki | |
| 366 356 | 
             
                    self[:encoding] = given_opt
         | 
| 367 357 | 
             
                  else
         | 
| 368 358 | 
             
                    ENCODING_REGEXP.each do |pat, encoding|
         | 
| 369 | 
            -
                      self[:encoding] = encoding if pat  | 
| 359 | 
            +
                      self[:encoding] = encoding if pat.match? given_opt
         | 
| 370 360 | 
             
                    end
         | 
| 371 361 | 
             
                    STDERR.puts "\"#{self[:encoding]}\" is chosen as an encoding system, \
         | 
| 372 362 | 
             
            instead of \"#{given_opt}\"."
         | 
| @@ -513,7 +503,7 @@ inside (default: not specified)") do |template| | |
| 513 503 |  | 
| 514 504 | 
             
                def set_options_from_input_file(input_lines)
         | 
| 515 505 | 
             
                  input_lines.each do |line|
         | 
| 516 | 
            -
                    break  | 
| 506 | 
            +
                    break unless FILE_HEADER_PAT.match? line
         | 
| 517 507 | 
             
                    line = line.chomp
         | 
| 518 508 | 
             
                    @options.keys.each do |opt|
         | 
| 519 509 | 
             
                      next if self[opt] and self[:force]
         | 
| @@ -50,12 +50,12 @@ module PseudoHiki | |
| 50 50 | 
             
                  { :auto_link_in_verbatim => @auto_link_in_verbatim }
         | 
| 51 51 | 
             
                end
         | 
| 52 52 |  | 
| 53 | 
            -
                def self.format(tree, options=nil)
         | 
| 53 | 
            +
                def self.format(tree, options=nil, memo=nil)
         | 
| 54 54 | 
             
                  cur_auto_link_setting = @auto_link_in_verbatim
         | 
| 55 55 | 
             
                  options = default_options unless options
         | 
| 56 56 | 
             
                  @auto_link_in_verbatim = options[:auto_link_in_verbatim]
         | 
| 57 57 | 
             
                  formatter = get_plain
         | 
| 58 | 
            -
                  tree.accept(formatter)
         | 
| 58 | 
            +
                  tree.accept(formatter, memo)
         | 
| 59 59 | 
             
                ensure
         | 
| 60 60 | 
             
                  @auto_link_in_verbatim = cur_auto_link_setting
         | 
| 61 61 | 
             
                end
         | 
| @@ -67,18 +67,19 @@ module PseudoHiki | |
| 67 67 | 
             
                  @format_class = self.class
         | 
| 68 68 | 
             
                end
         | 
| 69 69 |  | 
| 70 | 
            -
                def visited_result(element)
         | 
| 70 | 
            +
                def visited_result(element, memo)
         | 
| 71 71 | 
             
                  visitor = @formatter[element.class] || @formatter[PlainNode]
         | 
| 72 | 
            -
                  element.accept(visitor)
         | 
| 72 | 
            +
                  element.accept(visitor, memo)
         | 
| 73 73 | 
             
                end
         | 
| 74 74 |  | 
| 75 | 
            -
                def push_visited_results(element, tree)
         | 
| 76 | 
            -
                  tree.each {|token| element.push visited_result(token) }
         | 
| 75 | 
            +
                def push_visited_results(element, tree, memo)
         | 
| 76 | 
            +
                  tree.each {|token| element.push visited_result(token, memo) }
         | 
| 77 77 | 
             
                end
         | 
| 78 78 |  | 
| 79 | 
            -
                def visit(tree)
         | 
| 79 | 
            +
                def visit(tree, memo)
         | 
| 80 80 | 
             
                  htmlelement = create_element(tree)
         | 
| 81 | 
            -
                   | 
| 81 | 
            +
                  decorate(htmlelement, tree)
         | 
| 82 | 
            +
                  push_visited_results(htmlelement, tree, memo)
         | 
| 82 83 | 
             
                  htmlelement
         | 
| 83 84 | 
             
                end
         | 
| 84 85 |  | 
| @@ -96,6 +97,21 @@ module PseudoHiki | |
| 96 97 | 
             
                  chunks.push tree
         | 
| 97 98 | 
             
                end
         | 
| 98 99 |  | 
| 100 | 
            +
                def decorate(htmlelement, tree)
         | 
| 101 | 
            +
                  each_decorator(htmlelement, tree) do |elm, decorator|
         | 
| 102 | 
            +
                    elm[CLASS] = HtmlElement.escape(decorator[CLASS].id) if decorator[CLASS]
         | 
| 103 | 
            +
                    if id_item = decorator[ID] || decorator[:id]
         | 
| 104 | 
            +
                      elm[ID] = HtmlElement.escape(id_item.id).upcase
         | 
| 105 | 
            +
                    end
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                def each_decorator(element, tree)
         | 
| 110 | 
            +
                  return unless element.kind_of? HtmlElement
         | 
| 111 | 
            +
                  return unless tree.kind_of? BlockParser::BlockNode and tree.decorator
         | 
| 112 | 
            +
                  tree.decorator.tap {|decorator| yield element, decorator }
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
             | 
| 99 115 | 
             
                class ListLeafNodeFormatter < self
         | 
| 100 116 | 
             
                  def create_element(tree)
         | 
| 101 117 | 
             
                    super(tree).tap do |elm|
         | 
| @@ -121,6 +137,7 @@ module PseudoHiki | |
| 121 137 | 
             
                 [EnumNode, "ol"],
         | 
| 122 138 | 
             
                 [TableLeaf, "tr"],
         | 
| 123 139 | 
             
                 [VerbatimNode, "pre"],
         | 
| 140 | 
            +
                 [SectioningNode, "section"],
         | 
| 124 141 | 
             
                 [CommentOutNode, nil],
         | 
| 125 142 | 
             
                 [HeadingNode, "section"],
         | 
| 126 143 | 
             
                 [DescLeaf, DT],
         | 
| @@ -137,8 +154,8 @@ module PseudoHiki | |
| 137 154 | 
             
                # for InlineParser
         | 
| 138 155 |  | 
| 139 156 | 
             
                class << Formatter[PluginNode]
         | 
| 140 | 
            -
                  def visit(tree)
         | 
| 141 | 
            -
                    escape_inline_tags(tree) { super(tree) }
         | 
| 157 | 
            +
                  def visit(tree, memo)
         | 
| 158 | 
            +
                    escape_inline_tags(tree) { super(tree, memo) }
         | 
| 142 159 | 
             
                  end
         | 
| 143 160 |  | 
| 144 161 | 
             
                  def escape_inline_tags(tree)
         | 
| @@ -150,10 +167,10 @@ module PseudoHiki | |
| 150 167 | 
             
                end
         | 
| 151 168 |  | 
| 152 169 | 
             
                class << Formatter[LinkNode]
         | 
| 153 | 
            -
                  def visit(tree)
         | 
| 170 | 
            +
                  def visit(tree, memo)
         | 
| 154 171 | 
             
                    not_from_thumbnail = tree.first.class != LinkNode
         | 
| 155 | 
            -
                    caption, ref = caption_and_ref(tree)
         | 
| 156 | 
            -
                    if IMAGE_SUFFIX_RE  | 
| 172 | 
            +
                    caption, ref = caption_and_ref(tree, memo)
         | 
| 173 | 
            +
                    if IMAGE_SUFFIX_RE.match? ref and not_from_thumbnail
         | 
| 157 174 | 
             
                      htmlelement = ImgFormat.create_element
         | 
| 158 175 | 
             
                      htmlelement[SRC] = ref
         | 
| 159 176 | 
             
                      htmlelement[ALT] = caption.join if caption
         | 
| @@ -165,9 +182,9 @@ module PseudoHiki | |
| 165 182 | 
             
                    htmlelement
         | 
| 166 183 | 
             
                  end
         | 
| 167 184 |  | 
| 168 | 
            -
                  def caption_and_ref(tree)
         | 
| 185 | 
            +
                  def caption_and_ref(tree, memo)
         | 
| 169 186 | 
             
                    caption, ref = split_into_parts(tree, LinkSep)
         | 
| 170 | 
            -
                    caption = ref ? caption.map {|token| visited_result(token) } : nil
         | 
| 187 | 
            +
                    caption = ref ? caption.map {|token| visited_result(token, memo) } : nil
         | 
| 171 188 | 
             
                    return caption, (ref || tree).join
         | 
| 172 189 | 
             
                  rescue NoMethodError
         | 
| 173 190 | 
             
                    raise NoMethodError unless (ref || tree).empty?
         | 
| @@ -176,7 +193,7 @@ module PseudoHiki | |
| 176 193 | 
             
                end
         | 
| 177 194 |  | 
| 178 195 | 
             
                class << Formatter[InlineLeaf]
         | 
| 179 | 
            -
                  def visit(leaf)
         | 
| 196 | 
            +
                  def visit(leaf, memo)
         | 
| 180 197 | 
             
                    @generator.escape(leaf.first)
         | 
| 181 198 | 
             
                  end
         | 
| 182 199 | 
             
                end
         | 
| @@ -189,8 +206,25 @@ module PseudoHiki | |
| 189 206 |  | 
| 190 207 | 
             
                # for BlockParser
         | 
| 191 208 |  | 
| 209 | 
            +
                class << Formatter[TableNode]
         | 
| 210 | 
            +
                  def decorate(htmlelement, tree, memo=nil)
         | 
| 211 | 
            +
                    each_decorator(htmlelement, tree) do |elm, decorator|
         | 
| 212 | 
            +
                      visited_value(decorator["summary"], memo) do |summary|
         | 
| 213 | 
            +
                        htmlelement["summary"] = HtmlElement.escape(summary.join.chomp)
         | 
| 214 | 
            +
                      end
         | 
| 215 | 
            +
                      visited_value(decorator["caption"], memo) do |caption|
         | 
| 216 | 
            +
                        htmlelement.push @generator.create("caption", caption)
         | 
| 217 | 
            +
                      end
         | 
| 218 | 
            +
                    end
         | 
| 219 | 
            +
                  end
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                  def visited_value(decorator_item, memo)
         | 
| 222 | 
            +
                    yield visited_result(decorator_item.value, memo) if decorator_item
         | 
| 223 | 
            +
                  end
         | 
| 224 | 
            +
                end
         | 
| 225 | 
            +
             | 
| 192 226 | 
             
                class << Formatter[VerbatimNode]
         | 
| 193 | 
            -
                  def visit(tree)
         | 
| 227 | 
            +
                  def visit(tree, memo)
         | 
| 194 228 | 
             
                    contents = add_link(@generator.escape(tree.join))
         | 
| 195 229 | 
             
                    create_element.tap {|elm| elm.push contents }
         | 
| 196 230 | 
             
                  end
         | 
| @@ -203,8 +237,39 @@ module PseudoHiki | |
| 203 237 | 
             
                  end
         | 
| 204 238 | 
             
                end
         | 
| 205 239 |  | 
| 240 | 
            +
                class << Formatter[SectioningNode]
         | 
| 241 | 
            +
                  ID_MARK = "#"
         | 
| 242 | 
            +
             | 
| 243 | 
            +
                  alias :orig_create_element :create_element
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                  def section_with_id(tree, node_id)
         | 
| 246 | 
            +
                    orig_create_element(tree).tap do |elm|
         | 
| 247 | 
            +
                      elm[ID] = node_id[1..-1] # remove the first charactor from node_id
         | 
| 248 | 
            +
                    end
         | 
| 249 | 
            +
                  end
         | 
| 250 | 
            +
             | 
| 251 | 
            +
                  def section_for_class(tree, node_id)
         | 
| 252 | 
            +
                    if HtmlElement::HTML5_TAGS.include? node_id
         | 
| 253 | 
            +
                      @generator.create(node_id)
         | 
| 254 | 
            +
                    else
         | 
| 255 | 
            +
                      orig_create_element(tree).tap do |elm|
         | 
| 256 | 
            +
                        elm[CLASS] = elm[CLASS] ? "#{elm[CLASS]} #{node_id}" : node_id
         | 
| 257 | 
            +
                      end
         | 
| 258 | 
            +
                    end
         | 
| 259 | 
            +
                  end
         | 
| 260 | 
            +
             | 
| 261 | 
            +
                  def create_element(tree)
         | 
| 262 | 
            +
                    node_id = tree.node_id
         | 
| 263 | 
            +
                    if node_id.start_with? ID_MARK
         | 
| 264 | 
            +
                      section_with_id(tree, node_id)
         | 
| 265 | 
            +
                    else
         | 
| 266 | 
            +
                      section_for_class(tree, node_id)
         | 
| 267 | 
            +
                    end
         | 
| 268 | 
            +
                  end
         | 
| 269 | 
            +
                end
         | 
| 270 | 
            +
             | 
| 206 271 | 
             
                class << Formatter[CommentOutNode]
         | 
| 207 | 
            -
                  def visit(tree); BLANK; end
         | 
| 272 | 
            +
                  def visit(tree, memo); BLANK; end
         | 
| 208 273 | 
             
                end
         | 
| 209 274 |  | 
| 210 275 | 
             
                class << Formatter[HeadingNode]
         | 
| @@ -218,14 +283,14 @@ module PseudoHiki | |
| 218 283 | 
             
                end
         | 
| 219 284 |  | 
| 220 285 | 
             
                class << Formatter[DescLeaf]
         | 
| 221 | 
            -
                  def visit(tree)
         | 
| 286 | 
            +
                  def visit(tree, memo)
         | 
| 222 287 | 
             
                    elm = @generator::Children.new
         | 
| 223 288 | 
             
                    dt_part, dd_part = split_into_parts(tree, DescSep)
         | 
| 224 | 
            -
                    dt = super(dt_part)
         | 
| 289 | 
            +
                    dt = super(dt_part, memo)
         | 
| 225 290 | 
             
                    elm.push dt
         | 
| 226 291 | 
             
                    unless dd_part.nil? or dd_part.empty?
         | 
| 227 292 | 
             
                      dd = @generator.create(DD)
         | 
| 228 | 
            -
                      push_visited_results(dd, dd_part)
         | 
| 293 | 
            +
                      push_visited_results(dd, dd_part, memo)
         | 
| 229 294 | 
             
                      elm.push dd
         | 
| 230 295 | 
             
                    end
         | 
| 231 296 | 
             
                    elm
         | 
| @@ -233,9 +298,9 @@ module PseudoHiki | |
| 233 298 | 
             
                end
         | 
| 234 299 |  | 
| 235 300 | 
             
                class << Formatter[TableCellNode]
         | 
| 236 | 
            -
                  def visit(tree)
         | 
| 301 | 
            +
                  def visit(tree, memo)
         | 
| 237 302 | 
             
                    @element_name = tree.cell_type
         | 
| 238 | 
            -
                    super(tree).tap do |elm|
         | 
| 303 | 
            +
                    super(tree, memo).tap do |elm|
         | 
| 239 304 | 
             
                      elm[ROWSPAN] = tree.rowspan if tree.rowspan > 1
         | 
| 240 305 | 
             
                      elm[COLSPAN] = tree.colspan if tree.colspan > 1
         | 
| 241 306 | 
             
                      # elm.push " " if elm.empty? #   =   this line would be necessary for HTML 4 or XHTML 1.0
         |