C0 code coverage information

Generated on Tue Aug 12 00:32:09 +0900 2008 with rcov 0.8.1.2


Code reported as executed by Ruby looks like
    this... and this: this line is also marked as
    covered. Lines considered as run by rcov, but
    not reported by Ruby, look like this, and
    this: these lines were inferred by rcov (using simple heuristics).
    Finally, here's a line marked as not
    executed. 
Name Total lines Lines of code Total coverage Code coverage
lib/hikidoc.rb 902 721
90.2%  
87.8%  
 1 #
    Copyright (c) 2005, Kazuhiko <kazuhiko@fdiary.net>  2 # Copyright (c) 2007 Minero Aoki
     3 # All rights reserved.
     4 #  5 # Redistribution and use in source
    and binary forms, with or without  6 # modification, are permitted provided that the
    following conditions are 
    7 # met:  8 #
     9 # * Redistributions of
    source code must retain the above copyright  10 # notice, this list of conditions
    and the following disclaimer.  11 # * Redistributions in binary form must reproduce the
    above  12 # copyright
    notice, this list of conditions and the following  13 # disclaimer in the documentation
    and/or other materials provided  14 # with the distribution.  15 # * Neither the name of the
    HikiDoc nor the names of its  16 # contributors may be used to endorse or promote
    products derived  17 #
    from this software without specific prior written permission.  18 #  19 # THIS SOFTWARE IS PROVIDED BY
    THE COPYRIGHT HOLDERS AND CONTRIBUTORS  20 # "AS IS" AND ANY EXPRESS OR IMPLIED
    WARRANTIES, INCLUDING, BUT NOT  21 # LIMITED TO, THE IMPLIED WARRANTIES OF
    MERCHANTABILITY AND FITNESS FOR  22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
    SHALL THE COPYRIGHT  23
    # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 # SPECIAL,
    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT  25 # LIMITED TO, PROCUREMENT OF
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,  26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    CAUSED AND ON ANY  27 #
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 # (INCLUDING
    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  29 # OF THIS SOFTWARE, EVEN IF
    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  30  31
    require "stringio"  32 require "strscan"  33 require "uri"
     34 begin  35 require
    "syntax/convertors/html"  36 rescue LoadError  37 end  38  39
    class HikiDoc  40 VERSION
    = "0.0.2" # FIXME  41  42
    class Error < StandardError  43 end  44  45
    class UnexpectedError < Error  46 end  47  48
    def HikiDoc.to_html(src, options = {})  49 new(HTMLOutput.new(">"),
    options).compile(src) 
    50 end  51  52 def HikiDoc.to_xhtml(src, options =
    {})  53
    new(HTMLOutput.new(" />"), options).compile(src)  54 end  55  56 def initialize(output, options = {})  57 @output = output  58 @options =
    default_options.merge(options)  59 @header_re = nil  60 @level = options[:level] || 1  61 @plugin_syntax =
    options[:plugin_syntax] || method(:valid_plugin_syntax?)  62 end  63  64 def compile(src)  65 @output.reset  66 escape_plugin_blocks(src) {|escaped|  67 compile_blocks escaped  68 @output.finish  69 }  70 end  71  72 # for backward compatibility  73 def to_html  74 $stderr.puts("warning:
    HikiDoc#to_html is deprecated. Please use HikiDoc.to_html or
    HikiDoc.to_xhtml instead.")  75 self.class.to_html(@output, @options)  76 end  77  78 private  79  80
    def default_options  81
    {  82
    :allow_bracket_inline_image => true,  83 :use_wiki_name => true,  84 :use_not_wiki_name => true,
     85 }  86 end  87  88 # 
    89 # Plugin  90 #
     91  92 def valid_plugin_syntax?(code)
     93 /['"]/ !~
    code.gsub(/'(?:[^\\']+|\\.)*'|"(?:[^\\"]+|\\.)*"/m,
    "")  94 end
     95  96 def escape_plugin_blocks(text)
     97 s =
    StringScanner.new(text) 
    98 buf = ""  99
    @plugin_blocks = [] 100
    while chunk = s.scan_until(/\{\{/) 101 tail = chunk[-2, 2] 102 chunk[-2, 2] = "" 103 buf << chunk 104 # plugin 105 if block = extract_plugin_block(s)
    106 @plugin_blocks.push
    block 107 buf <<
    "\0#{@plugin_blocks.size - 1}\0" 108 else 109 buf << "{{" 110 end 111 end 112 buf << s.rest 113 yield(buf) 114 end 115 116 def restore_plugin_block(str) 117 str.gsub(/\0(\d+)\0/) {
    118 "{{" +
    plugin_block($1.to_i) + "}}" 119 } 120 end 121 122 def evaluate_plugin_block(str, buf = nil)
    123 buf ||=
    @output.container 124
    str.split(/(\0\d+\0)/).each do |s| 125 if s[0, 1] == "\0" and s[-1, 1] ==
    "\0" 126 buf
    << @output.inline_plugin(plugin_block(s[1..-2].to_i)) 127 else 128 buf << @output.text(s)
    129 end 130 end 131 buf 132 end 133 134 def plugin_block(id) 135 @plugin_blocks[id] or raise UnexpectedError,
    "must not happen: #{id.inspect}" 136 end 137 138 def extract_plugin_block(s) 139 pos = s.pos 140 buf = "" 141 while chunk = s.scan_until(/\}\}/)
    142 buf << chunk
    143
    buf.chomp!("}}") 144 if @plugin_syntax.call(buf) 145 return buf 146 end 147 buf << "}}"
    148 end 149 s.pos = pos 150 nil 151 end 152 153 # 154 # Block Level 155 # 156 157 def compile_blocks(src) 158 f =
    LineInput.new(StringIO.new(src)) 159 while line = f.peek 160 case line 161 when COMMENT_RE 162 f.gets 163 when HEADER_RE 164 compile_header f.gets 165 when HRULE_RE 166 f.gets 167 compile_hrule 168 when LIST_RE 169 compile_list f 170 when DLIST_RE 171 compile_dlist f 172 when TABLE_RE 173 compile_table f 174 when BLOCKQUOTE_RE 175 compile_blockquote f 176 when INDENTED_PRE_RE 177 compile_indented_pre f 178 when BLOCK_PRE_OPEN_RE
    179 compile_block_pre f
    180 else 181 if /^$/ =~ line 182 f.gets 183 next 184 end 185 compile_paragraph f 186 end 187 end 188 end 189 190 COMMENT_RE = %r<\A//> 191 192 def skip_comments(f) 193 f.while_match(COMMENT_RE) do |line| 194 end 195 end 196 197 HEADER_RE = /\A!+/ 198 199 def compile_header(line) 200 @header_re ||= /\A!{1,#{7 -
    @level}}/ 201 level =
    @level + (line.slice!(@header_re).size - 1) 202 title = strip(line) 203 @output.headline level, compile_inline(title)
    204 end 205 206 HRULE_RE = /\A----$/ 207 208 def compile_hrule 209 @output.hrule 210 end 211 212 ULIST = "*" 213 OLIST = "#" 214 LIST_RE = /\A#{Regexp.union(ULIST, OLIST)}+/
    215 216 def compile_list(f) 217 typestack = [] 218 level = 0 219 @output.list_begin 220 f.while_match(LIST_RE) do |line|
    221 list_type =
    (line[0,1] == ULIST ? "ul" : "ol") 222 new_level =
    line.slice(LIST_RE).size 223 item = strip(line.sub(LIST_RE, ""))
    224 if new_level >
    level 225 (new_level -
    level).times do 226
    typestack.push list_type 227 @output.list_open list_type 228 @output.listitem_open 229 end 230 @output.listitem
    compile_inline(item) 231
    elsif new_level < level 232 (level - new_level).times do 233 @output.listitem_close
    234 @output.list_close
    typestack.pop 235 end
    236
    @output.listitem_close 237 @output.listitem_open 238 @output.listitem compile_inline(item) 239 elsif list_type == typestack.last
    240
    @output.listitem_close 241 @output.listitem_open 242 @output.listitem compile_inline(item) 243 else 244 @output.listitem_close
    245 @output.list_close
    typestack.pop 246
    @output.list_open list_type 247 @output.listitem_open 248 @output.listitem compile_inline(item) 249 typestack.push list_type
    250 end 251 level = new_level 252 skip_comments f 253 end 254 level.times do 255 @output.listitem_close
    256 @output.list_close
    typestack.pop 257 end
    258 @output.list_end
    259 end 260 261 DLIST_RE = /\A:/ 262 263 def compile_dlist(f) 264 @output.dlist_open 265 f.while_match(DLIST_RE) do |line| 266 dt, dd =
    split_dlitem(line.sub(DLIST_RE, "")) 267 @output.dlist_item
    compile_inline(dt), compile_inline(dd) 268 skip_comments f 269 end 270 @output.dlist_close 271 end 272 273 def split_dlitem(line) 274 re =
    /\A((?:#{BRACKET_LINK_RE}|.)*?):/o 275 if m = re.match(line) 276 return m[1], m.post_match 277 else 278 return line, ""
    279 end 280 end 281 282 TABLE_RE = /\A\|\|/ 283 284 def compile_table(f) 285 lines = [] 286 f.while_match(TABLE_RE) do |line| 287 lines.push line 288 skip_comments f 289 end 290 @output.table_open 291 lines.each do |line| 292 @output.table_record_open
    293
    split_columns(line.sub(TABLE_RE, "")).each do |col| 294 mid = col.sub!(/\A!/,
    "") ? "table_head" : "table_data" 295 span = col.slice!(/\A[\^>]*/)
    296 rs = span_count(span,
    "^") 297 cs =
    span_count(span, ">") 298 @output.__send__(mid, compile_inline(col), rs, cs)
    299 end 300 @output.table_record_close
    301 end 302 @output.table_close 303 end 304 305 def split_columns(str) 306 cols = str.split(/\|\|/)
    307 cols.pop if
    cols.last.chomp.empty? 308 cols 309 end 310 311 def span_count(str, ch) 312 c = str.count(ch) 313 c == 0 ? nil : c + 1 314 end 315 316 BLOCKQUOTE_RE = /\A""[ \t]?/ 317 318 def compile_blockquote(f) 319 @output.blockquote_open
    320 lines = []
    321
    f.while_match(BLOCKQUOTE_RE) do |line| 322 lines.push line.sub(BLOCKQUOTE_RE, "")
    323 skip_comments f
    324 end 325 compile_blocks
    lines.join("") 326 @output.blockquote_close 327 end 328 329 INDENTED_PRE_RE = /\A[ \t]/ 330 331 def compile_indented_pre(f) 332 lines = f.span(INDENTED_PRE_RE)\
    333 .map {|line|
    rstrip(line.sub(INDENTED_PRE_RE, "")) } 334 text =
    restore_plugin_block(lines.join("\n")) 335
    @output.preformatted(@output.text(text)) 336 end 337 338 BLOCK_PRE_OPEN_RE = /\A<<<\s*(\w+)?/
    339 BLOCK_PRE_CLOSE_RE =
    /\A>>>/ 340
    341 def
    compile_block_pre(f) 342
    m = BLOCK_PRE_OPEN_RE.match(f.gets) or raise UnexpectedError, "must not
    happen" 343 str =
    restore_plugin_block(f.break(BLOCK_PRE_CLOSE_RE).join.chomp) 344 f.gets 345 @output.block_preformatted(str,
    m[1]) 346 end
    347 348 BLANK = /\A$/ 349 PARAGRAPH_END_RE =
    Regexp.union(BLANK, 350
    HEADER_RE, HRULE_RE, LIST_RE, DLIST_RE, 351 BLOCKQUOTE_RE, TABLE_RE, 352 INDENTED_PRE_RE,
    BLOCK_PRE_OPEN_RE) 353
    354 def
    compile_paragraph(f) 355
    lines = f.break(PARAGRAPH_END_RE)\ 356 .reject {|line| COMMENT_RE =~ line } 357 if lines.size == 1 and
    /\A\0(\d+)\0\z/ =~ strip(lines[0]) 358 @output.block_plugin plugin_block($1.to_i)
    359 else 360 line_buffer =
    @output.container(:paragraph) 361 lines.each_with_index do |line, i| 362 buffer = @output.container
    363 line_buffer <<
    buffer 364
    compile_inline(lstrip(line).chomp, buffer) 365 end 366 @output.paragraph(line_buffer) 367 end 368 end 369 370 # 371 # Inline Level 372 # 373 374 BRACKET_LINK_RE = /\[\[.+?\]\]/ 375 URI_RE =
    /(?:https?|ftp|file|mailto):[A-Za-z0-9;\/?:@&=+$,\-_.!~*\'()#%]+/
    376 WIKI_NAME_RE =
    /\b(?:[A-Z]+[a-z\d]+){2,}\b/ 377 378 def inline_syntax_re 379 if @options[:use_wiki_name] 380 if @options[:use_not_wiki_name]
    381 /
    (#{BRACKET_LINK_RE}) 382 | (#{URI_RE}) 383 | (#{MODIFIER_RE}) 384 | (\^?#{WIKI_NAME_RE}) 385 /xo 386 else 387 / (#{BRACKET_LINK_RE})
    388 | (#{URI_RE})
    389 | (#{MODIFIER_RE})
    390 | (#{WIKI_NAME_RE})
    391 /xo 392 end 393 else 394 / (#{BRACKET_LINK_RE})
    395 | (#{URI_RE})
    396 | (#{MODIFIER_RE})
    397 /xo 398 end 399 end 400 401 def compile_inline(str, buf = nil) 402 buf ||= @output.container
    403 re = inline_syntax_re
    404 pending_str = nil
    405 while m =
    re.match(str) 406 str =
    m.post_match 407
    408 link, uri, mod,
    wiki_name = m[1, 4] 409
    if wiki_name and wiki_name[0, 1] == "^" 410 pending_str = m.pre_match +
    wiki_name[1..-1] 411 next
    412 end 413 414 pre_str = "#{pending_str}#{m.pre_match}"
    415 pending_str = nil
    416
    evaluate_plugin_block(pre_str, buf) 417 compile_inline_markup(buf, link, uri, mod, wiki_name)
    418 end 419 evaluate_plugin_block(pending_str
    || str, buf) 420 buf
    421 end 422 423 def compile_inline_markup(buf, link, uri, mod,
    wiki_name) 424 case
    425 when link
    426 buf <<
    compile_bracket_link(link[2...-2]) 427 when uri 428 buf << compile_uri_autolink(uri) 429 when mod 430 buf << compile_modifier(mod)
    431 when wiki_name
    432 buf <<
    @output.wiki_name(wiki_name) 433 else 434 raise UnexpectedError, "must not happen"
    435 end 436 end 437 438 def compile_bracket_link(link) 439 if m =
    /\A(?>[^|\\]+|\\.)*\|/.match(link) 440 title = m[0].chop 441 uri = m.post_match 442 fixed_uri = fix_uri(uri) 443 if can_image_link?(uri)
    444
    @output.image_hyperlink(fixed_uri, title) 445 else 446 @output.hyperlink(fixed_uri, compile_modifier(title))
    447 end 448 else 449 fixed_link = fix_uri(link)
    450 if
    can_image_link?(link) 451
    @output.image_hyperlink(fixed_link) 452 else 453 @output.hyperlink(fixed_link, @output.text(link))
    454 end 455 end 456 end 457 458 def can_image_link?(uri) 459 image?(uri) and
    @options[:allow_bracket_inline_image] 460 end 461 462 def compile_uri_autolink(uri) 463 if image?(uri) 464
    @output.image_hyperlink(fix_uri(uri)) 465 else 466 @output.hyperlink(fix_uri(uri), @output.text(uri))
    467 end 468 end 469 470 def fix_uri(uri) 471 if /\A(?:https?|ftp|file):(?!\/\/)/ =~ uri
    472 uri.sub(/\A\w+:/,
    "") 473 else
    474 uri 475 end 476 end 477 478 IMAGE_EXTS = %w(.jpg .jpeg .gif .png) 479 480 def image?(uri) 481 IMAGE_EXTS.include?(File.extname(uri).downcase)
    482 end 483 484 STRONG = "'''" 485 EM = "''" 486 DEL = "==" 487 488 STRONG_RE = /'''.+?'''/ 489 EM_RE = /''.+?''/ 490 DEL_RE = /==.+?==/ 491 492 MODIFIER_RE = Regexp.union(STRONG_RE, EM_RE, DEL_RE)
    493 494 MODTAG = { 495 STRONG => "strong",
    496 EM =>
    "em", 497 DEL
    => "del" 498 } 499 500 def compile_modifier(str) 501 buf = @output.container
    502 while m = /
    (#{MODIFIER_RE}) 503
    /xo.match(str) 504
    evaluate_plugin_block(m.pre_match, buf) 505 case 506 when chunk = m[1] 507 mod, s = split_mod(chunk) 508 mid = MODTAG[mod] 509 buf << @output.__send__(mid,
    compile_inline(s)) 510
    else 511 raise
    UnexpectedError, "must not happen" 512 end 513 str = m.post_match 514 end 515 evaluate_plugin_block(str, buf) 516 buf 517 end 518 519 def split_mod(str) 520 case str 521 when /\A'''/ 522 return str[0, 3], str[3...-3] 523 when /\A''/ 524 return str[0, 2], str[2...-2]
    525 when /\A==/
    526 return str[0, 2],
    str[2...-2] 527 else
    528 raise
    UnexpectedError, "must not happen: #{str.inspect}" 529 end 530 end 531 532 def strip(str) 533 rstrip(lstrip(str)) 534 end 535 536 def rstrip(str) 537 str.sub(/[ \t\r\n\v\f]+\z/, "")
    538 end 539 540 def lstrip(str) 541 str.sub(/\A[ \t\r\n\v\f]+/, "")
    542 end 543 544 545 class HTMLOutput 546 def initialize(suffix = " />")
    547 @suffix = suffix
    548 @f = nil 549 end 550 551 def reset 552 @f = StringIO.new 553 end 554 555 def finish 556 @f.string 557 end 558 559 def container(_for=nil) 560 case _for 561 when :paragraph 562 [] 563 else 564 "" 565 end 566 end 567 568 # 569 # Procedures 570 # 571 572 def headline(level, title) 573 @f.puts
    "<h#{level}>#{title}</h#{level}>" 574 end 575 576 def hrule 577 @f.puts "<hr#{@suffix}" 578 end 579 580 def list_begin 581 end 582 583 def list_end 584 @f.puts 585 end 586 587 def list_open(type) 588 @f.puts "<#{type}>" 589 end 590 591 def list_close(type) 592 @f.print "</#{type}>" 593 end 594 595 def listitem_open 596 @f.print "<li>" 597 end 598 599 def listitem_close 600 @f.puts "</li>" 601 end 602 603 def listitem(item) 604 @f.print item 605 end 606 607 def dlist_open 608 @f.puts "<dl>" 609 end 610 611 def dlist_close 612 @f.puts "</dl>" 613 end 614 615 def dlist_item(dt, dd) 616 case 617 when dd.empty? 618 @f.puts
    "<dt>#{dt}</dt>" 619 when dt.empty? 620 @f.puts "<dd>#{dd}</dd>"
    621 else 622 @f.puts
    "<dt>#{dt}</dt>" 623 @f.puts "<dd>#{dd}</dd>"
    624 end 625 end 626 627 def table_open 628 @f.puts %Q(<table border="1">)
    629 end 630 631 def table_close 632 @f.puts "</table>" 633 end 634 635 def table_record_open 636 @f.print "<tr>" 637 end 638 639 def table_record_close 640 @f.puts "</tr>"
    641 end 642 643 def table_head(item, rs, cs) 644 @f.print "<th#{tdattr(rs,
    cs)}>#{item}</th>" 645 end 646 647 def table_data(item, rs, cs) 648 @f.print "<td#{tdattr(rs,
    cs)}>#{item}</td>" 649 end 650 651 def tdattr(rs, cs) 652 buf = "" 653 buf << %Q( rowspan="#{rs}") if rs
    654 buf << %Q(
    colspan="#{cs}") if cs 655 buf 656 end 657 private :tdattr 658 659 def blockquote_open 660 @f.print "<blockquote>" 661 end 662 663 def blockquote_close 664 @f.puts "</blockquote>" 665 end 666 667 def block_preformatted(str, info) 668 syntax = info ? info.downcase :
    nil 669 if syntax
    670 begin 671 convertor =
    Syntax::Convertors::HTML.for_syntax(syntax) 672 @f.puts convertor.convert(str) 673 return 674 rescue NameError, RuntimeError
    675 end 676 end 677 preformatted(text(str))
    678 end 679 680 def preformatted(str) 681 @f.print "<pre>" 682 @f.print str 683 @f.puts "</pre>"
    684 end 685 686 def paragraph(lines) 687 @f.puts
    "<p>#{lines.join("\n")}</p>" 688 end 689 690 def block_plugin(str) 691 @f.puts %Q(<div
    class="plugin">{{#{escape_html(str)}}}</div>)
    692 end 693 694 # 695 # Functions 696 # 697 698 def hyperlink(uri, title) 699 %Q(<a
    href="#{escape_html_param(uri)}">#{title}</a>)
    700 end 701 702 def wiki_name(name) 703 hyperlink(name, text(name)) 704 end 705 706 def image_hyperlink(uri, alt = nil) 707 alt ||= uri.split(/\//).last
    708 alt =
    escape_html(alt) 709
    %Q(<img src="#{escape_html_param(uri)}"
    alt="#{alt}"#{@suffix}) 710 end 711 712 def strong(item) 713 "<strong>#{item}</strong>"
    714 end 715 716 def em(item) 717 "<em>#{item}</em>" 718 end 719 720 def del(item) 721 "<del>#{item}</del>"
    722 end 723 724 def text(str) 725 escape_html(str) 726 end 727 728 def inline_plugin(src) 729 %Q(<span
    class="plugin">{{#{src}}}</span>) 730 end 731 732 # 733 # Utilities 734 # 735 736 def escape_html_param(str) 737 escape_quote(escape_html(str))
    738 end 739 740 def escape_html(text) 741 text.gsub(/&/,
    "&amp;").gsub(/</, "&lt;").gsub(/>/,
    "&gt;") 742 end 743 744 def unescape_html(text) 745 text.gsub(/&gt;/,
    ">").gsub(/&lt;/, "<").gsub(/&amp;/,
    "&") 746
    end 747 748 def escape_quote(text)
    749 text.gsub(/"/,
    "&quot;") 750 end 751 end 752 753 754 class LineInput 755 def initialize(f) 756 @input = f 757 @buf = [] 758 @lineno = 0 759 @eof_p = false 760 end 761 762 def inspect 763 "\#<#{self.class} file=#{@input.inspect}
    line=#{lineno()}>" 764 end 765 766 def eof? 767 @eof_p 768 end 769 770 def lineno 771 @lineno 772 end 773 774 def gets 775 unless @buf.empty? 776 @lineno += 1 777 return @buf.pop 778 end 779 return nil if @eof_p # to avoid ARGF blocking.
    780 line = @input.gets
    781 line =
    line.sub(/\r\n/, "\n") if line 782 @eof_p = line.nil? 783 @lineno += 1 784 line 785 end 786 787 def ungets(line) 788 return unless line 789 @lineno -= 1 790 @buf.push line 791 line 792 end 793 794 def peek 795 line = gets() 796 ungets line if line 797 line 798 end 799 800 def next? 801 peek() ? true : false 802 end 803 804 def skip_blank_lines 805 n = 0 806 while line = gets()
    807 unless
    line.strip.empty? 808
    ungets line 809 return
    n 810 end 811 n += 1 812 end 813 n 814 end 815 816 def gets_if(re) 817 line = gets() 818 if not line or not (re =~ line) 819 ungets line 820 return nil 821 end 822 line 823 end 824 825 def gets_unless(re) 826 line = gets() 827 if not line or re =~ line
    828 ungets line
    829 return nil
    830 end 831 line 832 end 833 834 def each 835 while line = gets() 836 yield line 837 end 838 end 839 840 def while_match(re) 841 while line = gets() 842 unless re =~ line 843 ungets line 844 return 845 end 846 yield line 847 end 848 nil 849 end 850 851 def getlines_while(re) 852 buf = [] 853 while_match(re) do |line|
    854 buf.push line
    855 end 856 buf 857 end 858 859 alias span getlines_while # from Haskell 860 861 def until_match(re) 862 while line = gets() 863 if re =~ line 864 ungets line 865 return 866 end 867 yield line 868 end 869 nil 870 end 871 872 def getlines_until(re) 873 buf = [] 874 until_match(re) do |line|
    875 buf.push line
    876 end 877 buf 878 end 879 880 alias break getlines_until # from Haskell
    881 882 def until_terminator(re)
    883 while line =
    gets() 884 return if
    re =~ line # discard terminal line 885 yield line 886 end 887 nil 888 end 889 890 def getblock(term_re) 891 buf = [] 892 until_terminator(term_re) do
    |line| 893 buf.push
    line 894 end
    895 buf 896 end 897 end 898 end 899 900 if __FILE__ == $0 901 puts HikiDoc.to_html(ARGF.read(nil)) 902 end 

Generated using the rcov code coverage analysis tool for Ruby version 0.8.1.2.

Valid XHTML 1.0! Valid CSS!