module MaRuKu::In::Markdown::SpanLevelParser

Constants

CharSource

Choose!

Close_class
EscapedCharInInlineCode
EscapedCharInQuotes
EscapedCharInText
Punct_class
R_REF_ID

R_REF_ID = Regexp.compile(/(s]*)(s*])/) R_REF_ID = Regexp.compile(/(s]*)(s*])/)

Rules
SPACE

Public Instance Methods

apply_one_rule(reg, subst, input) click to toggle source

note: input will be destroyed

# File lib/maruku/input/rubypants.rb, line 192
def apply_one_rule(reg, subst, input)
        output = []
        while first = input.shift
                if first.kind_of?(String) && (m = reg.match(first))
                        output.push    m. pre_match if m. pre_match.size > 0
                         input.unshift m.post_match if m.post_match.size > 0
                        subst.reverse.each do |x|
                                input.unshift( x == :one ? m[1] : md_entity(x.to_s) ) end
                else
                        output.push first
                end
        end
        return output
end
describe_pos(buffer, buffer_index) click to toggle source
# File lib/maruku/input/charsource.rb, line 154
def describe_pos(buffer, buffer_index)
        len = 75
        num_before = [len/2, buffer_index].min
        num_after = [len/2, buffer.size-buffer_index].min
        num_before_max = buffer_index
        num_after_max = buffer.size-buffer_index
        
#               puts "num #{num_before} #{num_after}"
        num_before = [num_before_max, len-num_after].min
        num_after  = [num_after_max, len-num_before].min
#               puts "num #{num_before} #{num_after}"
        
        index_start = [buffer_index - num_before, 0].max
        index_end   = [buffer_index + num_after, buffer.size].min
        
        size = index_end- index_start
        
#               puts "- #{index_start} #{size}"

        str = buffer[index_start, size]
        str.gsub!("\n",'N')
        str.gsub!("\t",'T')
        
        if index_end == buffer.size 
                str += "EOF"
        end
                
        pre_s = buffer_index-index_start
        pre_s = [pre_s, 0].max
        pre_s2 = [len-pre_s,0].max
#               puts "pre_S = #{pre_s}"
        pre =" "*(pre_s) 
        
        "-"*len+"\n"+
        str + "\n" +
        "-"*pre_s + "|" + "-"*(pre_s2)+"\n"+
#               pre + "|\n"+
        pre + "+--- Byte #{buffer_index}\n"+
        
        "Shown bytes [#{index_start} to #{size}] of #{buffer.size}:\n"+
        add_tabs(buffer,1,">")
        
#               "CharSource: At character #{@buffer_index} of block "+
#               " beginning with:\n    #{@buffer[0,50].inspect} ...\n"+
#               " before: \n     ... #{cur_chars(50).inspect} ... "
end
educate(elements) click to toggle source
# File lib/maruku/input/rubypants.rb, line 207
def educate(elements)
        Rules.each do |reg, subst|
                elements = apply_one_rule(reg, subst, elements)
        end
        # strips empty strings
        elements.delete_if {|x| x.kind_of?(String) && x.size == 0}
        final = []
        # join consecutive strings
        elements.each do |x|
                if x.kind_of?(String) && final.last.kind_of?(String)
                        final.last << x
                else
                        final << x
                end
        end
        return final
end
extension_meta(src, con, break_on_chars) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 301
        def extension_meta(src, con, break_on_chars)
                if m = src.read_regexp(/([^\s\:\"\]+):/)
                        name = m[1]
                        al = read_attribute_list(src, con, break_on_chars)
#                       puts "#{name}=#{al.inspect}"
                        self.doc.ald[name] = al
                      con.push md_ald(name, al)
                else
                        al = read_attribute_list(src, con, break_on_chars)
                        self.doc.ald[name] = al
                        con.push md_ial(al)
                end
        end
interpret_extension(src, con, break_on_chars) click to toggle source

Start: cursor on character *after* '{' End: curson on '}' or EOF

# File lib/maruku/input/parse_span_better.rb, line 277
def interpret_extension(src, con, break_on_chars)
        case src.cur_char
        when ?:
                src.ignore_char # :
                extension_meta(src, con, break_on_chars)
        when ?#, ?.
                extension_meta(src, con, break_on_chars)
        else
                stuff = read_simple(src, escaped=[?}], break_on_chars, [])
                if stuff =~ /^(\w+\s|[^\w])/
                        extension_id = $1.strip
                        if false
                        else
                                maruku_recover "I don't know what to do with extension '#{extension_id}'\n"+
                                        "I will threat this:\n\t{#{stuff}} \n as meta-data.\n", src, con
                                extension_meta(src, con, break_on_chars)
                        end
                else 
                        maruku_recover "I will threat this:\n\t{#{stuff}} \n as meta-data.\n", src, con
                        extension_meta(src, con, break_on_chars)
                end
        end
end
is_ial(e) click to toggle source

We need a helper

# File lib/maruku/attributes.rb, line 196
def is_ial(e); e.kind_of? MDElement and e.node_type == :ial end
md_al(s=[]) click to toggle source
# File lib/maruku/attributes.rb, line 132
def md_al(s=[]); AttributeList.new(s) end
merge_ial(elements, src, con) click to toggle source
# File lib/maruku/attributes.rb, line 198
def merge_ial(elements, src, con)      

        # Apply each IAL to the element before
        elements.each_with_index do |e, i| 
        if is_ial(e) && i>= 1 then
                before = elements[i-1]
                after = elements[i+1]
                if before.kind_of? MDElement
                        before.al = e.ial
                elsif after.kind_of? MDElement
                        after.al = e.ial
                else
                        maruku_error "It is not clear to me what element this IAL {:#{e.ial.to_md}} \n"+
                        "is referring to. The element before is a #{before.class.to_s}, \n"+
                        "the element after is a #{after.class.to_s}.\n"+
                        "\n before: #{before.inspect}"+
                        "\n after: #{after.inspect}",
                        src, con
                        # xxx dire se c'รจ empty vicino
                end
        end 
        end
        
        if not Globals[:debug_keep_ials]
                elements.delete_if {|x| is_ial(x) unless x == elements.first} 
        end
end
parse_lines_as_span(lines, parent=nil) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 35
def parse_lines_as_span(lines, parent=nil)
        parse_span_better lines.join("\n"), parent
end
parse_span_better(string, parent=nil) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 39
def parse_span_better(string, parent=nil)
        if not string.kind_of? String then 
                error "Passed #{string.class}." end

        st = (string + "")
        st.freeze
        src = CharSource.new(st, parent)
        read_span(src, EscapedCharInText, [nil])
end
read_attribute_list(src, con, break_on_chars) click to toggle source

returns nil or an AttributeList

# File lib/maruku/attributes.rb, line 135
def read_attribute_list(src, con, break_on_chars)
        
        separators = break_on_chars + [?=,?\ ,?\t]
        escaped = Maruku::EscapedCharInQuotes
                
        al = AttributeList.new
        while true
                src.consume_whitespace
                break if break_on_chars.include? src.cur_char

                case src.cur_char
                when nil 
                        maruku_error "Attribute list terminated by EOF:\n "+
                                     "#{al.inspect}" , src, con
                        tell_user "I try to continue and return partial attribute list:\n"+
                                al.inspect
                        break
                when ?=     # error
                        maruku_error "In attribute lists, cannot start identifier with `=`."
                        tell_user "I try to continue"
                        src.ignore_char
                when ?#     # id definition
                        src.ignore_char
                        if id = read_quoted_or_unquoted(src, con, escaped, separators)
                                al.push_id id
                        else
                                maruku_error 'Could not read `id` attribute.', src, con
                                tell_user 'Trying to ignore bad `id` attribute.'
                        end
                when ?.     # class definition
                        src.ignore_char
                        if klass = read_quoted_or_unquoted(src, con, escaped, separators)
                                al.push_class klass
                        else
                                maruku_error 'Could not read `class` attribute.', src, con
                                tell_user 'Trying to ignore bad `class` attribute.'
                        end
                else
                        if key = read_quoted_or_unquoted(src, con, escaped, separators)
                                if src.cur_char == ?=
                                        src.ignore_char # skip the =
                                        if val = read_quoted_or_unquoted(src, con, escaped, separators)
                                                al.push_key_val(key, val)
                                        else
                                                maruku_error "Could not read value for key #{key.inspect}.",
                                                        src, con
                                                tell_user "Ignoring key #{key.inspect}."
                                        end
                                else
                                        al.push_ref key
                                end
                        else
                                maruku_error 'Could not read key or reference.'
                        end
                end # case
        end # while true
        al
end
read_em(src, delim) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 421
def read_em(src, delim)
        src.ignore_char
        children = read_span(src, EscapedCharInText, nil, [delim])
        src.ignore_char
        md_em(children)
end
read_email_el(src,con) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 323
def read_email_el(src,con)
        src.ignore_char # leading <
        mail = read_simple(src, [], [?>])
        src.ignore_char # closing >
        
        address = mail.gsub(/^mailto:/,'')
        con.push_element md_email(address)
end
read_emstrong(src, delim) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 435
def read_emstrong(src, delim)
        src.ignore_chars(3)
        children = read_span(src, EscapedCharInText, nil, [delim])
        src.ignore_chars(3)
        md_emstrong(children)
end
read_footnote_ref(src,con) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 462
def read_footnote_ref(src,con)
        ref = read_ref_id(src,con)
        con.push_element md_foot_ref(ref)
end
read_image(src, con) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 615
def read_image(src, con)
        src.ignore_chars(2) # opening "!["
        alt_text = read_span(src, EscapedCharInText, [?]])
        src.ignore_char # closing bracket
        # ignore space
        if src.cur_char == SPACE and 
                (src.next_char == ?[ or src.next_char == ?( )
                src.ignore_char
        end
        case src.cur_char
        when ?(
                src.ignore_char # opening (
                src.consume_whitespace
                url = read_url(src, [SPACE,?\t,?)])
                if not url
                        error "Could not read url from #{src.cur_chars(10).inspect}",
                                src,con
                end
                src.consume_whitespace
                title = nil
                if src.cur_char != ?) # we have a title
                        quote_char = src.cur_char
                        title = read_quoted(src,con)
                        if not title
                                maruku_error 'Must quote title',src,con
                        else                                
                                # Tries to read a title with quotes: ![a](url "ti"tle")
                                # this is the most ugly thing in Markdown
                                if not src.next_matches(/\s*\)/)
                                        # if there is not a closing par ), then read
                                        # the rest and guess it's title with quotes
                                        rest = read_simple(src, escaped=[], break_on_chars=[?)], 
                                                break_on_strings=[])
                                        # chop the closing char
                                        rest.chop!
                                        title << quote_char << rest
                                end
                        end
                end
                src.consume_whitespace
                closing = src.shift_char # closing )
                if closing != ?)
                        error( ("Unclosed link: '"<<closing<<"'")+
                                " Read url=#{url.inspect} title=#{title.inspect}",src,con)
                end
                con.push_element md_im_image(alt_text, url, title)
        when ?[ # link ref
                ref_id = read_ref_id(src,con)
                if not ref_id # TODO: check around
                        error('Reference not closed.', src, con)
                        ref_id = ""
                end
                if ref_id.size == 0
                        ref_id =  alt_text.to_s
                end

                ref_id = sanitize_ref_id(ref_id)

                con.push_element md_image(alt_text, ref_id)
        else # no stuff
                ref_id =  sanitize_ref_id(alt_text.to_s)
                con.push_element md_image(alt_text, ref_id)
        end
end
read_inline_code(src, con) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 510
        def read_inline_code(src, con)
                # Count the number of ticks
                num_ticks = 0
                while src.cur_char == ?` 
                        num_ticks += 1
                        src.ignore_char
                end
                # We will read until this string
                end_string = "`"*num_ticks

                code = 
                        read_simple(src, escaped=[], break_on_chars=[], 
                                break_on_strings=[end_string])
                
#               puts "Now I expects #{num_ticks} ticks: #{src.cur_chars(10).inspect}"
                src.ignore_chars num_ticks
                
                # Ignore at most one space
                if num_ticks > 1 && code[0] == SPACE
                        code = code[1, code.size-1]
                end
                
                # drop last space 
                if num_ticks > 1 && code[-1] == SPACE
                        code = code[0,code.size-1]
                end

#               puts "Read `` code: #{code.inspect}; after: #{src.cur_chars(10).inspect} "
                con.push_element md_code(code)
        end
read_inline_html(src, con) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 467
def read_inline_html(src, con)
        h = HTMLHelper.new
        begin
                # This is our current buffer in the context
                next_stuff = src.current_remaining_buffer
                
                consumed = 0
                while true
                        if consumed >= next_stuff.size
                                maruku_error "Malformed HTML starting at #{next_stuff.inspect}", src, con
                                break
                        end

                        h.eat_this next_stuff[consumed].chr; consumed += 1
                        break if h.is_finished? 
                end
                src.ignore_chars(consumed)
                con.push_element md_html(h.stuff_you_read)
                
                #start = src.current_remaining_buffer
                # h.eat_this start
                # if not h.is_finished?
                #    error "inline_html: Malformed:\n "+
                #            "#{start.inspect}\n #{h.inspect}",src,con
                # end
                # 
                # consumed = start.size - h.rest.size 
                # if consumed > 0
                #    con.push_element md_html(h.stuff_you_read)
                #    src.ignore_chars(consumed)
                # else
                #    puts "HTML helper did not work on #{start.inspect}"
                #    con.push_char src.shift_char
                # end
        rescue Exception => e
                maruku_error "Bad html: \n" + 
                        add_tabs(e.inspect+e.backtrace.join("\n"),1,'>'),
                        src,con
                maruku_recover "I will try to continue after bad HTML.", src, con
                con.push_char src.shift_char
        end
end
read_quoted(src, con) click to toggle source

Tries to read a quoted value. If stream does not start with ' or โ€œ, returns nil.

# File lib/maruku/input/parse_span_better.rb, line 365
        def read_quoted(src, con)
                case src.cur_char
                        when ?', ?"
                                quote_char = src.shift_char # opening quote
                                string = read_simple(src, EscapedCharInQuotes, [quote_char])
                                src.ignore_char # closing quote
                                return string
                        else 
#                               puts "Asked to read quote from: #{src.cur_chars(10).inspect}"
                                return nil
                end
        end
read_quoted_or_unquoted(src, con, escaped, exit_on_chars) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 354
def read_quoted_or_unquoted(src, con, escaped, exit_on_chars)
        case src.cur_char
        when ?', ?"
                read_quoted(src, con)
        else
                read_simple(src, escaped, exit_on_chars)
        end
end
read_ref_id(src, con) click to toggle source

Reads a bracketed id โ€œ[refid]โ€. Consumes also both brackets.

# File lib/maruku/input/parse_span_better.rb, line 449
        def read_ref_id(src, con)
                src.ignore_char # [
                src.consume_whitespace
#               puts "Next: #{src.cur_chars(10).inspect}"
                if m = src.read_regexp(R_REF_ID) 
#                       puts "Got: #{m[1].inspect} Ignored: #{m[2].inspect}"
#                       puts "Then: #{src.cur_chars(10).inspect}"
                        m[1]
                else
                        nil
                end
        end
read_simple(src, escaped, exit_on_chars, exit_on_strings=nil) click to toggle source

Reads a simple string (no formatting) until one of break_on_chars, while escaping the escaped. If the string is empty, it returns nil. Raises on error if the string terminates unexpectedly.

# If eat_delim is true, and if the delim is not the EOF, then the delim
# gets eaten from the stream.
# File lib/maruku/input/parse_span_better.rb, line 384
        def read_simple(src, escaped, exit_on_chars, exit_on_strings=nil)
                text = ""
                while true
#                       puts "Reading simple #{text.inspect}"
                        c = src.cur_char
                        if exit_on_chars && exit_on_chars.include?(c)
#                               src.ignore_char if eat_delim
                                break
                        end
                        
                        break if exit_on_strings && 
                                exit_on_strings.any? {|x| src.cur_chars_are x}
                        
                        case c
                        when nil
                                s= "String finished while reading (break on "+
                                "#{exit_on_chars.map{|x|""<<x}.inspect})"+
                                " already read: #{text.inspect}"
                                maruku_error s, src
                                maruku_recover "I boldly continue", src
                                break
                        when ?\                                 d = src.next_char
                                if escaped.include? d
                                        src.ignore_chars(2)
                                        text << d
                                else
                                        text << src.shift_char
                                end
                        else 
                                text << src.shift_char
                        end
                end
#               puts "Read simple #{text.inspect}"
                text.empty? ? nil : text
        end
read_span(src, escaped, exit_on_chars, exit_on_strings=nil) click to toggle source

This is the main loop for reading span elements

It's long, but not complex or difficult to understand.

# File lib/maruku/input/parse_span_better.rb, line 54
def read_span(src, escaped, exit_on_chars, exit_on_strings=nil)
        con = SpanContext.new
        c = d = nil
        while true
                c = src.cur_char

                # This is only an optimization which cuts 50% of the time used.
                # (but you can't use a-zA-z in exit_on_chars)
                if c && ((c>=?a && c<=?z) || ((c>=?A && c<=?Z)))
                        con.cur_string << src.shift_char
                        next
                end

                break if exit_on_chars && exit_on_chars.include?(c)
                break if exit_on_strings && exit_on_strings.any? {|x| src.cur_chars_are x}
                
                # check if there are extensions
                if check_span_extensions(src, con)
                        next
                end
                
                case c = src.cur_char        
                when ?\ # it's space (32)
                        if src.cur_chars_are "  \n"
                                src.ignore_chars(3)
                                con.push_element  md_br()
                                next
                        else
                                src.ignore_char
                                con.push_space 
                        end
                when ?\n, ?\t 
                        src.ignore_char
                        con.push_space 
                when ?`
                        read_inline_code(src,con)
                when ?<
                        # It could be:
                        # 1) HTML "<div ..."
                        # 2) HTML "<!-- ..."
                        # 3) url "<http:// ", "<ftp:// ..."
                        # 4) email "<andrea@... ", "<mailto:andrea@..."
                        # 5) on itself! "a < b      "
                        # 6) Start of <<guillemettes>>
                        
                        case d = src.next_char
                                when ?<;  # guillemettes
                                        src.ignore_chars(2)
                                        con.push_char ?<
                                        con.push_char ?<
                                when ?!; 
                                        if src.cur_chars_are '<!--'
                                                read_inline_html(src, con)
                                        else 
                                                con.push_char src.shift_char
                                        end
                                when ?? 
                                        read_xml_instr_span(src, con) 
                                when ?\ , ?\t 
                                        con.push_char src.shift_char
                                else
                                        if src.next_matches(/<mailto:/) or
                                           src.next_matches(/<[\w\.]+\@/)
                                                read_email_el(src, con)
                                        elsif src.next_matches(/<\w+:/)
                                                read_url_el(src, con)
                                        elsif src.next_matches(/<\w/)
                                                #puts "This is HTML: #{src.cur_chars(20)}"
                                                read_inline_html(src, con)
                                        else 
                                                #puts "This is NOT HTML: #{src.cur_chars(20)}"
                                                con.push_char src.shift_char
                                        end
                        end
                when ?\                                 d = src.next_char
                        if d == ?'
                                src.ignore_chars(2)
                                con.push_element md_entity('apos')
                        elsif d == ?"
                                src.ignore_chars(2)
                                con.push_element md_entity('quot')
                        elsif escaped.include? d
                                src.ignore_chars(2)
                                con.push_char d
                        else
                                con.push_char src.shift_char
                        end
                when ?[
                        if markdown_extra? && src.next_char == ?^
                                read_footnote_ref(src,con)
                        else
                                read_link(src, con)
                        end
                when ?!
                        if src.next_char == ?[
                                read_image(src, con)
                        else
                                con.push_char src.shift_char
                        end
                when ?&
                        # named references
                        if m = src.read_regexp(/\&([\w\d]+);/)
                                con.push_element md_entity(m[1])
                        # numeric
                        elsif m = src.read_regexp(/\&\#(x)?([\w\d]+);/)
                                num = m[1]  ? m[2].hex : m[2].to_i
                                con.push_element md_entity(num)
                        else
                                con.push_char src.shift_char
                        end
                when ?*
                        if not src.next_char
                                maruku_error "Opening * as last char.", src, con
                                maruku_recover "Threating as literal"
                                con.push_char src.shift_char
                        else
                                follows = src.cur_chars(4)
                                if follows =~ /^\*\*\*[^\s\*]/
                                        con.push_element read_emstrong(src,'***')
                                elsif follows  =~ /^\*\*[^\s\*]/
                                        con.push_element read_strong(src,'**')
                                elsif follows =~ /^\*[^\s\*]/
                                        con.push_element read_em(src,'*')
                                else # * is just a normal char
                                        con.push_char src.shift_char
                                end
                        end
                when ?_
                        if not src.next_char
                                maruku_error "Opening _ as last char", src, con
                                maruku_recover "Threating as literal", src, con
                                con.push_char src.shift_char
                        else
                                # we don't want "mod_ruby" to start an emphasis
                                # so we start one only if
                                # 1) there's nothing else in the span (first char)
                                # or 2) the last char was a space
                                # or 3) the current string is empty
                                #if con.elements.empty? ||
                                if  (con.cur_string =~ /\s\Z/) || (con.cur_string.size == 0)
                                        # also, we check the next characters
                                        follows = src.cur_chars(4)
                                        if  follows =~ /^\_\_\_[^\s\_]/
                                                con.push_element read_emstrong(src,'___')
                                        elsif follows  =~ /^\_\_[^\s\_]/
                                                con.push_element read_strong(src,'__')
                                        elsif follows =~ /^\_[^\s\_]/
                                                con.push_element read_em(src,'_')
                                        else # _ is just a normal char
                                                con.push_char src.shift_char
                                        end
                                else
                                        # _ is just a normal char
                                                con.push_char src.shift_char
                                end
                        end
                when ?{ # extension
                        if [?#, ?., ?:].include? src.next_char
                                src.ignore_char # {
                                interpret_extension(src, con, [?}])
                                src.ignore_char # }
                        else
                                con.push_char src.shift_char
                        end
                when nil
                        maruku_error( ("Unclosed span (waiting for %s"+
                         "#{exit_on_strings.inspect})") % [
                                        exit_on_chars ? "#{exit_on_chars.inspect} or" : ""],
                                        src,con)
                        break
                else # normal text
                        con.push_char src.shift_char
                end # end case
        end # end while true
        con.push_string_if_present 

        # Assign IAL to elements
        merge_ial(con.elements, src, con)
        
        
        # Remove leading space
        if (s = con.elements.first).kind_of? String
                if s[0] == ?\ then con.elements[0] = s[1, s.size-1] end
                con.elements.shift if s.size == 0 
        end
        
        # Remove final spaces
        if (s = con.elements.last).kind_of? String
                s.chop! if s[-1] == ?\ 
                con.elements.pop if s.size == 0 
        end
        
        educated = educate(con.elements)

        educated
end
read_strong(src, delim) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 428
def read_strong(src, delim)
        src.ignore_chars(2)
        children = read_span(src, EscapedCharInText, nil, [delim])
        src.ignore_chars(2)
        md_strong(children)
end
read_url(src, break_on) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 332
def read_url(src, break_on)
        if [?',?"].include? src.cur_char 
                error 'Invalid char for url', src
        end
        
        url = read_simple(src, [], break_on)
        if not url # empty url
                url = ""
        end
        
        if url[0] == ?< && url[-1] == ?>
                url = url[1, url.size-2]
        end
        
        if url.size == 0 
                return nil
        end
        
        url
end
read_url_el(src,con) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 315
def read_url_el(src,con)
        src.ignore_char # leading <
        url = read_simple(src, [], [?>])
        src.ignore_char # closing >
        
        con.push_element md_url(url)
end
read_xml_instr_span(src, con) click to toggle source
# File lib/maruku/input/parse_span_better.rb, line 253
def read_xml_instr_span(src, con) 
        src.ignore_chars(2) # starting <?

        # read target <?target code... ?>
        target = if m = src.read_regexp(/(\w+)/)
                m[1]
        else
                ''
        end
        
        delim = "?>"
        
        code = 
                read_simple(src, escaped=[], break_on_chars=[], 
                break_on_strings=[delim])
        
        src.ignore_chars delim.size
        
        code = (code || "").strip
        con.push_element md_xml_instr(target, code)
end
unit_tests_for_attribute_lists() click to toggle source
# File lib/maruku/attributes.rb, line 80
def unit_tests_for_attribute_lists
        [
                [ "",     [], "Empty lists are allowed" ], 
                [ "=",    :throw, "Bad char to begin a list with." ], 
                [ "a =b", :throw, "No whitespace before `=`." ], 
                [ "a= b", :throw, "No whitespace after `=`." ], 

                [ "a b", [[:ref, 'a'],[:ref, 'b']], "More than one ref" ], 
                [ "a b c", [[:ref, 'a'],[:ref, 'b'],[:ref, 'c']], "More than one ref" ], 
                [ "hello notfound", [[:ref, 'hello'],[:ref, 'notfound']]], 

                [ "'a'",  [[:ref, 'a']], "Quoted value." ], 
                [ '"a"'   ], 

                [ "a=b",  [['a','b']], "Simple key/val" ], 
                [ "'a'=b"   ], 
                [ "'a'='b'" ], 
                [ "a='b'"   ], 

                [ 'a="b\"',  [['a',"b\'"]], "Key/val with quotes" ],
                [ 'a=b\'],
                [ 'a="\\b\"',  [['a',"\'b\'"]], "Key/val with quotes" ], 
                
                ['"', :throw, "Unclosed quotes"],
                ["'"],
                ["'a "],
                ['"a '],
                
                [ "#a",  [[:id, 'a']], "Simple ID" ], 
                [ "#'a'" ], 
                [ '#"a"' ], 

                [ "#",  :throw, "Unfinished '#'." ], 
                [ ".",  :throw, "Unfinished '.'." ], 
                [ "# a",  :throw, "No white-space after '#'." ], 
                [ ". a",  :throw, "No white-space after '.' ." ], 
                
                [ "a=b c=d",  [['a','b'],['c','d']], "Tabbing" ], 
                [ " \ta=b \tc='d' "],
                [ "\t a=b\t c='d'\t\t"],
                
                [ ".\"a'",  :throw, "Mixing quotes is bad." ], 
                
        ].map { |s, expected, comment| 
                @expected = (expected ||= @expected)
                @comment  = (comment  ||= (last=@comment) )
                (comment == last && (comment += (@count+=1).to_s)) || @count = 1
                expected = [md_ial(expected)] if expected.kind_of? Array
                ["{#{MagicChar}#{s}}", expected, "Attributes: #{comment}"]
        }
end