Warning: file_get_contents(https://raw.githubusercontent.com/Den1xxx/Filemanager/master/languages/ru.json): failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php on line 88

Warning: Cannot modify header information - headers already sent by (output started at /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php:88) in /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php on line 215

Warning: Cannot modify header information - headers already sent by (output started at /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php:88) in /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php on line 216

Warning: Cannot modify header information - headers already sent by (output started at /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php:88) in /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php on line 217

Warning: Cannot modify header information - headers already sent by (output started at /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php:88) in /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php on line 218

Warning: Cannot modify header information - headers already sent by (output started at /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php:88) in /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php on line 219

Warning: Cannot modify header information - headers already sent by (output started at /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php:88) in /home/afelisqd/cppseducation.sc.tz/admin/images/photos/17587263121019776732_admin-dbb.php on line 220
PK!8TR8R8simple_markup.rbnu[# = Introduction # # SimpleMarkup parses plain text documents and attempts to decompose # them into their constituent parts. Some of these parts are high-level: # paragraphs, chunks of verbatim text, list entries and the like. Other # parts happen at the character level: a piece of bold text, a word in # code font. This markup is similar in spirit to that used on WikiWiki # webs, where folks create web pages using a simple set of formatting # rules. # # SimpleMarkup itself does no output formatting: this is left to a # different set of classes. # # SimpleMarkup is extendable at runtime: you can add new markup # elements to be recognised in the documents that SimpleMarkup parses. # # SimpleMarkup is intended to be the basis for a family of tools which # share the common requirement that simple, plain-text should be # rendered in a variety of different output formats and media. It is # envisaged that SimpleMarkup could be the basis for formating RDoc # style comment blocks, Wiki entries, and online FAQs. # # = Basic Formatting # # * SimpleMarkup looks for a document's natural left margin. This is # used as the initial margin for the document. # # * Consecutive lines starting at this margin are considered to be a # paragraph. # # * If a paragraph starts with a "*", "-", or with ".", then it is # taken to be the start of a list. The margin in increased to be the # first non-space following the list start flag. Subsequent lines # should be indented to this new margin until the list ends. For # example: # # * this is a list with three paragraphs in # the first item. This is the first paragraph. # # And this is the second paragraph. # # 1. This is an indented, numbered list. # 2. This is the second item in that list # # This is the third conventional paragraph in the # first list item. # # * This is the second item in the original list # # * You can also construct labeled lists, sometimes called description # or definition lists. Do this by putting the label in square brackets # and indenting the list body: # # [cat] a small furry mammal # that seems to sleep a lot # # [ant] a little insect that is known # to enjoy picnics # # A minor variation on labeled lists uses two colons to separate the # label from the list body: # # cat:: a small furry mammal # that seems to sleep a lot # # ant:: a little insect that is known # to enjoy picnics # # This latter style guarantees that the list bodies' left margins are # aligned: think of them as a two column table. # # * Any line that starts to the right of the current margin is treated # as verbatim text. This is useful for code listings. The example of a # list above is also verbatim text. # # * A line starting with an equals sign (=) is treated as a # heading. Level one headings have one equals sign, level two headings # have two,and so on. # # * A line starting with three or more hyphens (at the current indent) # generates a horizontal rule. THe more hyphens, the thicker the rule # (within reason, and if supported by the output device) # # * You can use markup within text (except verbatim) to change the # appearance of parts of that text. Out of the box, SimpleMarkup # supports word-based and general markup. # # Word-based markup uses flag characters around individual words: # # [\*word*] displays word in a *bold* font # [\_word_] displays word in an _emphasized_ font # [\+word+] displays word in a +code+ font # # General markup affects text between a start delimiter and and end # delimiter. Not surprisingly, these delimiters look like HTML markup. # # [\text...] displays word in a *bold* font # [\text...] displays word in an _emphasized_ font # [\text...] displays word in an _emphasized_ font # [\text...] displays word in a +code+ font # # Unlike conventional Wiki markup, general markup can cross line # boundaries. You can turn off the interpretation of markup by # preceding the first character with a backslash, so \\\bold # text and \\\*bold* produce \bold text and \*bold # respectively. # # = Using SimpleMarkup # # For information on using SimpleMarkup programatically, # see SM::SimpleMarkup. # # Author:: Dave Thomas, dave@pragmaticprogrammer.com # Version:: 0.0 # License:: Ruby license require 'rdoc/markup/simple_markup/fragments' require 'rdoc/markup/simple_markup/lines.rb' module SM #:nodoc: # == Synopsis # # This code converts input_string, which is in the format # described in markup/simple_markup.rb, to HTML. The conversion # takes place in the +convert+ method, so you can use the same # SimpleMarkup object to convert multiple input strings. # # require 'rdoc/markup/simple_markup' # require 'rdoc/markup/simple_markup/to_html' # # p = SM::SimpleMarkup.new # h = SM::ToHtml.new # # puts p.convert(input_string, h) # # You can extend the SimpleMarkup parser to recognise new markup # sequences, and to add special processing for text that matches a # regular epxression. Here we make WikiWords significant to the parser, # and also make the sequences {word} and \text... signify # strike-through text. When then subclass the HTML output class to deal # with these: # # require 'rdoc/markup/simple_markup' # require 'rdoc/markup/simple_markup/to_html' # # class WikiHtml < SM::ToHtml # def handle_special_WIKIWORD(special) # "" + special.text + "" # end # end # # p = SM::SimpleMarkup.new # p.add_word_pair("{", "}", :STRIKE) # p.add_html("no", :STRIKE) # # p.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) # # h = WikiHtml.new # h.add_tag(:STRIKE, "", "") # # puts "" + p.convert(ARGF.read, h) + "" # # == Output Formatters # # _missing_ # # class SimpleMarkup SPACE = ?\s # List entries look like: # * text # 1. text # [label] text # label:: text # # Flag it as a list entry, and # work out the indent for subsequent lines SIMPLE_LIST_RE = /^( ( \* (?# bullet) |- (?# bullet) |\d+\. (?# numbered ) |[A-Za-z]\. (?# alphabetically numbered ) ) \s+ )\S/x LABEL_LIST_RE = /^( ( \[.*?\] (?# labeled ) |\S.*:: (?# note ) )(?:\s+|$) )/x ## # take a block of text and use various heuristics to determine # it's structure (paragraphs, lists, and so on). Invoke an # event handler as we identify significant chunks. # def initialize @am = AttributeManager.new @output = nil end ## # Add to the sequences used to add formatting to an individual word # (such as *bold*). Matching entries will generate attibutes # that the output formatters can recognize by their +name+ def add_word_pair(start, stop, name) @am.add_word_pair(start, stop, name) end ## # Add to the sequences recognized as general markup # def add_html(tag, name) @am.add_html(tag, name) end ## # Add to other inline sequences. For example, we could add # WikiWords using something like: # # parser.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) # # Each wiki word will be presented to the output formatter # via the accept_special method # def add_special(pattern, name) @am.add_special(pattern, name) end # We take a string, split it into lines, work out the type of # each line, and from there deduce groups of lines (for example # all lines in a paragraph). We then invoke the output formatter # using a Visitor to display the result def convert(str, op) @lines = Lines.new(str.split(/\r?\n/).collect { |aLine| Line.new(aLine) }) return "" if @lines.empty? @lines.normalize assign_types_to_lines group = group_lines # call the output formatter to handle the result # group.to_a.each {|i| p i} group.accept(@am, op) end ####### private ####### ## # Look through the text at line indentation. We flag each line as being # Blank, a paragraph, a list element, or verbatim text # def assign_types_to_lines(margin = 0, level = 0) while line = @lines.next if line.isBlank? line.stamp(Line::BLANK, level) next end # if a line contains non-blanks before the margin, then it must belong # to an outer level text = line.text for i in 0...margin if text[i] != SPACE @lines.unget return end end active_line = text[margin..-1] # Rules (horizontal lines) look like # # --- (three or more hyphens) # # The more hyphens, the thicker the rule # if /^(---+)\s*$/ =~ active_line line.stamp(Line::RULE, level, $1.length-2) next end # Then look for list entries. First the ones that have to have # text following them (* xxx, - xxx, and dd. xxx) if SIMPLE_LIST_RE =~ active_line offset = margin + $1.length prefix = $2 prefix_length = prefix.length flag = case prefix when "*","-" then ListBase::BULLET when /^\d/ then ListBase::NUMBER when /^[A-Z]/ then ListBase::UPPERALPHA when /^[a-z]/ then ListBase::LOWERALPHA else raise "Invalid List Type: #{self.inspect}" end line.stamp(Line::LIST, level+1, prefix, flag) text[margin, prefix_length] = " " * prefix_length assign_types_to_lines(offset, level + 1) next end if LABEL_LIST_RE =~ active_line offset = margin + $1.length prefix = $2 prefix_length = prefix.length next if handled_labeled_list(line, level, margin, offset, prefix) end # Headings look like # = Main heading # == Second level # === Third # # Headings reset the level to 0 if active_line[0] == ?= and active_line =~ /^(=+)\s*(.*)/ prefix_length = $1.length prefix_length = 6 if prefix_length > 6 line.stamp(Line::HEADING, 0, prefix_length) line.strip_leading(margin + prefix_length) next end # If the character's a space, then we have verbatim text, # otherwise if active_line[0] == SPACE line.strip_leading(margin) if margin > 0 line.stamp(Line::VERBATIM, level) else line.stamp(Line::PARAGRAPH, level) end end end # Handle labeled list entries, We have a special case # to deal with. Because the labels can be long, they force # the remaining block of text over the to right: # # this is a long label that I wrote:: and here is the # block of text with # a silly margin # # So we allow the special case. If the label is followed # by nothing, and if the following line is indented, then # we take the indent of that line as the new margin # # this is a long label that I wrote:: # here is a more reasonably indented block which # will ab attached to the label. # def handled_labeled_list(line, level, margin, offset, prefix) prefix_length = prefix.length text = line.text flag = nil case prefix when /^\[/ flag = ListBase::LABELED prefix = prefix[1, prefix.length-2] when /:$/ flag = ListBase::NOTE prefix.chop! else raise "Invalid List Type: #{self.inspect}" end # body is on the next line if text.length <= offset original_line = line line = @lines.next return(false) unless line text = line.text for i in 0..margin if text[i] != SPACE @lines.unget return false end end i = margin i += 1 while text[i] == SPACE if i >= text.length @lines.unget return false else offset = i prefix_length = 0 @lines.delete(original_line) end end line.stamp(Line::LIST, level+1, prefix, flag) text[margin, prefix_length] = " " * prefix_length assign_types_to_lines(offset, level + 1) return true end # Return a block consisting of fragments which are # paragraphs, list entries or verbatim text. We merge consecutive # lines of the same type and level together. We are also slightly # tricky with lists: the lines following a list introduction # look like paragraph lines at the next level, and we remap them # into list entries instead def group_lines @lines.rewind inList = false wantedType = wantedLevel = nil block = LineCollection.new group = nil while line = @lines.next if line.level == wantedLevel and line.type == wantedType group.add_text(line.text) else group = block.fragment_for(line) block.add(group) if line.type == Line::LIST wantedType = Line::PARAGRAPH else wantedType = line.type end wantedLevel = line.type == Line::HEADING ? line.param : line.level end end block.normalize block end ## for debugging, we allow access to our line contents as text def content @lines.as_text end public :content ## for debugging, return the list of line types def get_line_types @lines.line_types end public :get_line_types end end PK!v??sample/sample.rbnu[# This program illustrates the basic use of the SimpleMarkup # class. It extracts the first comment block from the # simple_markup.rb file and converts it into HTML on # standard output. Run it using # # % ruby sample.rb # # You should be in the sample/ directory when you do this, # as it hardwires the path to the files it needs to require. # This isn't necessary in the code you write once you've # installed the package. # # For a better way of formatting code comment blocks (and more) # see the rdoc package. # $:.unshift "../../.." require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_html' # Extract the comment block from the source file input_string = "" File.foreach("../simple_markup.rb") do |line| break unless line.gsub!(/^\# ?/, '') input_string << line end # Create a markup object markup = SM::SimpleMarkup.new # Attach it to an HTML formatter h = SM::ToHtml.new # And convert out comment block to html. Wrap it a body # tag pair to let browsers view it puts "" puts markup.convert(input_string, h) puts "" PK!^sample/rdoc2latex.rbnu[#!/usr/local/bin/ruby # Illustration of a script to convert an RDoc-style file to a LaTeX # document require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_latex' p = SM::SimpleMarkup.new h = SM::ToLaTeX.new #puts "\\documentclass{report}" #puts "\\usepackage{tabularx}" #puts "\\usepackage{parskip}" #puts "\\begin{document}" puts p.convert(ARGF.read, h) #puts "\\end{document}" PK!w4,,test/TestParse.rbnu[require 'test/unit' $:.unshift "../../.." require 'rdoc/markup/simple_markup' include SM class TestParse < Test::Unit::TestCase class MockOutput def start_accepting @res = [] end def end_accepting @res end def accept_paragraph(am, fragment) @res << fragment.to_s end def accept_verbatim(am, fragment) @res << fragment.to_s end def accept_list_start(am, fragment) @res << fragment.to_s end def accept_list_end(am, fragment) @res << fragment.to_s end def accept_list_item(am, fragment) @res << fragment.to_s end def accept_blank_line(am, fragment) @res << fragment.to_s end def accept_heading(am, fragment) @res << fragment.to_s end def accept_rule(am, fragment) @res << fragment.to_s end end def basic_conv(str) sm = SimpleMarkup.new mock = MockOutput.new sm.convert(str, mock) sm.content end def line_types(str, expected) p = SimpleMarkup.new mock = MockOutput.new p.convert(str, mock) assert_equal(expected, p.get_line_types.map{|type| type.to_s[0,1]}.join('')) end def line_groups(str, expected) p = SimpleMarkup.new mock = MockOutput.new block = p.convert(str, mock) if block != expected rows = (0...([expected.size, block.size].max)).collect{|i| [expected[i]||"nil", block[i]||"nil"] } printf "\n\n%35s %35s\n", "Expected", "Got" rows.each {|e,g| printf "%35s %35s\n", e.dump, g.dump } end assert_equal(expected, block) end def test_tabs str = "hello\n dave" assert_equal(str, basic_conv(str)) str = "hello\n\tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = "hello\n \tdave" assert_equal("hello\n dave", basic_conv(str)) str = ".\t\t." assert_equal(". .", basic_conv(str)) end def test_whitespace assert_equal("hello", basic_conv("hello")) assert_equal("hello", basic_conv(" hello ")) assert_equal("hello", basic_conv(" \t \t hello\t\t")) assert_equal("1\n 2\n 3", basic_conv("1\n 2\n 3")) assert_equal("1\n 2\n 3", basic_conv(" 1\n 2\n 3")) assert_equal("1\n 2\n 3\n1\n 2", basic_conv("1\n 2\n 3\n1\n 2")) assert_equal("1\n 2\n 3\n1\n 2", basic_conv(" 1\n 2\n 3\n 1\n 2")) assert_equal("1\n 2\n\n 3", basic_conv(" 1\n 2\n\n 3")) end def test_types str = "now is the time" line_types(str, 'P') str = "now is the time\nfor all good men" line_types(str, 'PP') str = "now is the time\n code\nfor all good men" line_types(str, 'PVP') str = "now is the time\n code\n more code\nfor all good men" line_types(str, 'PVVP') str = "now is\n---\nthe time" line_types(str, 'PRP') str = %{\ now is * l1 * l2 the time} line_types(str, 'PLLP') str = %{\ now is * l1 l1+ * l2 the time} line_types(str, 'PLPLP') str = %{\ now is * l1 * l1.1 * l2 the time} line_types(str, 'PLLLP') str = %{\ now is * l1 * l1.1 text code code text * l2 the time} line_types(str, 'PLLPVVBPLP') str = %{\ now is 1. l1 * l1.1 2. l2 the time} line_types(str, 'PLLLP') str = %{\ now is [cat] l1 * l1.1 [dog] l2 the time} line_types(str, 'PLLLP') str = %{\ now is [cat] l1 continuation [dog] l2 the time} line_types(str, 'PLPLP') end def test_groups str = "now is the time" line_groups(str, ["L0: Paragraph\nnow is the time"] ) str = "now is the time\nfor all good men" line_groups(str, ["L0: Paragraph\nnow is the time for all good men"] ) str = %{\ now is the time code _line_ here for all good men} line_groups(str, [ "L0: Paragraph\nnow is the time", "L0: Verbatim\n code _line_ here\n", "L0: Paragraph\nfor all good men" ] ) str = "now is the time\n code\n more code\nfor all good men" line_groups(str, [ "L0: Paragraph\nnow is the time", "L0: Verbatim\n code\n more code\n", "L0: Paragraph\nfor all good men" ] ) str = %{\ now is * l1 * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is * l1 l1+ * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1 l1+", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is * l1 * l1.1 * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L2: ListStart\n", "L2: ListItem\nl1.1", "L2: ListEnd\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is * l1 * l1.1 text code code text * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L2: ListStart\n", "L2: ListItem\nl1.1 text", "L2: Verbatim\n code\n code\n", "L2: Paragraph\ntext", "L2: ListEnd\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is 1. l1 * l1.1 2. l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L2: ListStart\n", "L2: ListItem\nl1.1", "L2: ListEnd\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is [cat] l1 * l1.1 [dog] l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L2: ListStart\n", "L2: ListItem\nl1.1", "L2: ListEnd\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) str = %{\ now is [cat] l1 continuation [dog] l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1 continuation", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) end def test_verbatim_merge str = %{\ now is code the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n", "L0: Paragraph\nthe time" ]) str = %{\ now is code code1 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n code1\n", "L0: Paragraph\nthe time" ]) str = %{\ now is code code1 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n\n code1\n", "L0: Paragraph\nthe time" ]) str = %{\ now is code code1 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n\n code1\n", "L0: Paragraph\nthe time" ]) str = %{\ now is code code1 code2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n\n code1\n\n code2\n", "L0: Paragraph\nthe time" ]) # Folds multiple blank lines str = %{\ now is code code1 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L0: Verbatim\n code\n\n code1\n", "L0: Paragraph\nthe time" ]) end def test_list_split str = %{\ now is * l1 1. n1 2. n2 * l2 the time} line_groups(str, [ "L0: Paragraph\nnow is", "L1: ListStart\n", "L1: ListItem\nl1", "L1: ListEnd\n", "L1: ListStart\n", "L1: ListItem\nn1", "L1: ListItem\nn2", "L1: ListEnd\n", "L1: ListStart\n", "L1: ListItem\nl2", "L1: ListEnd\n", "L0: Paragraph\nthe time" ]) end def test_headings str = "= heading one" line_groups(str, [ "L0: Heading\nheading one" ]) str = "=== heading three" line_groups(str, [ "L0: Heading\nheading three" ]) str = "text\n === heading three" line_groups(str, [ "L0: Paragraph\ntext", "L0: Verbatim\n === heading three\n" ]) str = "text\n code\n === heading three" line_groups(str, [ "L0: Paragraph\ntext", "L0: Verbatim\n code\n === heading three\n" ]) str = "text\n code\n=== heading three" line_groups(str, [ "L0: Paragraph\ntext", "L0: Verbatim\n code\n", "L0: Heading\nheading three" ]) end end PK!Z //test/AllTests.rbnu[require 'TestParse.rb' require 'TestInline.rb' PK!=  test/TestInline.rbnu[require "test/unit" $:.unshift "../../.." require "rdoc/markup/simple_markup/inline" class TestInline < Test::Unit::TestCase def setup @am = SM::AttributeManager.new @bold_on = @am.changed_attribute_by_name([], [:BOLD]) @bold_off = @am.changed_attribute_by_name([:BOLD], []) @tt_on = @am.changed_attribute_by_name([], [:TT]) @tt_off = @am.changed_attribute_by_name([:TT], []) @em_on = @am.changed_attribute_by_name([], [:EM]) @em_off = @am.changed_attribute_by_name([:EM], []) @bold_em_on = @am.changed_attribute_by_name([], [:BOLD] | [:EM]) @bold_em_off = @am.changed_attribute_by_name([:BOLD] | [:EM], []) @em_then_bold = @am.changed_attribute_by_name([:EM], [:EM] | [:BOLD]) @em_to_bold = @am.changed_attribute_by_name([:EM], [:BOLD]) @am.add_word_pair("{", "}", :WOMBAT) @wombat_on = @am.changed_attribute_by_name([], [:WOMBAT]) @wombat_off = @am.changed_attribute_by_name([:WOMBAT], []) end def crossref(text) [ @am.changed_attribute_by_name([], [:CROSSREF] | [:_SPECIAL_]), SM::Special.new(33, text), @am.changed_attribute_by_name([:CROSSREF] | [:_SPECIAL_], []) ] end def test_special # class names, variable names, file names, or instance variables @am.add_special(/( \b([A-Z]\w+(::\w+)*) | \#\w+[!?=]? | \b\w+([_\/\.]+\w+)+[!?=]? )/x, :CROSSREF) assert_equal(["cat"], @am.flow("cat")) assert_equal(["cat ", crossref("#fred"), " dog"].flatten, @am.flow("cat #fred dog")) assert_equal([crossref("#fred"), " dog"].flatten, @am.flow("#fred dog")) assert_equal(["cat ", crossref("#fred")].flatten, @am.flow("cat #fred")) end def test_basic assert_equal(["cat"], @am.flow("cat")) assert_equal(["cat ", @bold_on, "and", @bold_off, " dog"], @am.flow("cat *and* dog")) assert_equal(["cat ", @bold_on, "AND", @bold_off, " dog"], @am.flow("cat *AND* dog")) assert_equal(["cat ", @em_on, "And", @em_off, " dog"], @am.flow("cat _And_ dog")) assert_equal(["cat *and dog*"], @am.flow("cat *and dog*")) assert_equal(["*cat and* dog"], @am.flow("*cat and* dog")) assert_equal(["cat *and ", @bold_on, "dog", @bold_off], @am.flow("cat *and *dog*")) assert_equal(["cat ", @em_on, "and", @em_off, " dog"], @am.flow("cat _and_ dog")) assert_equal(["cat_and_dog"], @am.flow("cat_and_dog")) assert_equal(["cat ", @tt_on, "and", @tt_off, " dog"], @am.flow("cat +and+ dog")) assert_equal(["cat ", @bold_on, "a_b_c", @bold_off, " dog"], @am.flow("cat *a_b_c* dog")) assert_equal(["cat __ dog"], @am.flow("cat __ dog")) assert_equal(["cat ", @em_on, "_", @em_off, " dog"], @am.flow("cat ___ dog")) end def test_combined assert_equal(["cat ", @em_on, "and", @em_off, " ", @bold_on, "dog", @bold_off], @am.flow("cat _and_ *dog*")) assert_equal(["cat ", @em_on, "a__nd", @em_off, " ", @bold_on, "dog", @bold_off], @am.flow("cat _a__nd_ *dog*")) end def test_html_like assert_equal(["cat ", @tt_on, "dog", @tt_off], @am.flow("cat dog")) assert_equal(["cat ", @em_on, "and", @em_off, " ", @bold_on, "dog", @bold_off], @am.flow("cat and dog")) assert_equal(["cat ", @em_on, "and ", @em_then_bold, "dog", @bold_em_off], @am.flow("cat and dog")) assert_equal(["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off], @am.flow("cat and dog")) assert_equal(["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off], @am.flow("cat and dog")) assert_equal([@tt_on, "cat", @tt_off, " ", @em_on, "and ", @em_to_bold, "dog", @bold_off], @am.flow("cat and dog")) assert_equal(["cat ", @em_on, "and ", @em_then_bold, "dog", @bold_em_off], @am.flow("cat and dog")) assert_equal(["cat ", @bold_em_on, "and", @bold_em_off, " dog"], @am.flow("cat and dog")) end def test_protect assert_equal(['cat \\ dog'], @am.flow('cat \\ dog')) assert_equal(["cat dog"], @am.flow("cat \\dog")) assert_equal(["cat ", @em_on, "and", @em_off, " dog"], @am.flow("cat and \\dog")) assert_equal(["*word* or text"], @am.flow("\\*word* or \\text")) assert_equal(["_cat_", @em_on, "dog", @em_off], @am.flow("\\_cat_dog")) end def test_adding assert_equal(["cat ", @wombat_on, "and", @wombat_off, " dog" ], @am.flow("cat {and} dog")) # assert_equal(["cat {and} dog" ], @am.flow("cat \\{and} dog")) end end PK!sp--simple_markup/to_html.rbnu[require 'rdoc/markup/simple_markup/fragments' require 'rdoc/markup/simple_markup/inline' require 'cgi' module SM class ToHtml LIST_TYPE_TO_HTML = { ListBase::BULLET => [ "" ], ListBase::NUMBER => [ "
    ", "
" ], ListBase::UPPERALPHA => [ "
    ", "
" ], ListBase::LOWERALPHA => [ "
    ", "
" ], ListBase::LABELED => [ "
", "
" ], ListBase::NOTE => [ "", "
" ], } InlineTag = Struct.new(:bit, :on, :off) def initialize init_tags end ## # Set up the standard mapping of attributes to HTML tags # def init_tags @attr_tags = [ InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "", ""), InlineTag.new(SM::Attribute.bitmap_for(:TT), "", ""), InlineTag.new(SM::Attribute.bitmap_for(:EM), "", ""), ] end ## # Add a new set of HTML tags for an attribute. We allow # separate start and end tags for flexibility # def add_tag(name, start, stop) @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop) end ## # Given an HTML tag, decorate it with class information # and the like if required. This is a no-op in the base # class, but is overridden in HTML output classes that # implement style sheets def annotate(tag) tag end ## # Here's the client side of the visitor pattern def start_accepting @res = "" @in_list_entry = [] end def end_accepting @res end def accept_paragraph(am, fragment) @res << annotate("

") + "\n" @res << wrap(convert_flow(am.flow(fragment.txt))) @res << annotate("

") + "\n" end def accept_verbatim(am, fragment) @res << annotate("
") + "\n"
      @res << CGI.escapeHTML(fragment.txt)
      @res << annotate("
") << "\n" end def accept_rule(am, fragment) size = fragment.param size = 10 if size > 10 @res << "
" end def accept_list_start(am, fragment) @res << html_list_name(fragment.type, true) <<"\n" @in_list_entry.push false end def accept_list_end(am, fragment) if tag = @in_list_entry.pop @res << annotate(tag) << "\n" end @res << html_list_name(fragment.type, false) <<"\n" end def accept_list_item(am, fragment) if tag = @in_list_entry.last @res << annotate(tag) << "\n" end @res << list_item_start(am, fragment) @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n" @in_list_entry[-1] = list_end_for(fragment.type) end def accept_blank_line(am, fragment) # @res << annotate("

") << "\n" end def accept_heading(am, fragment) @res << convert_heading(fragment.head_level, am.flow(fragment.txt)) end # This is a higher speed (if messier) version of wrap def wrap(txt, line_len = 76) res = "" sp = 0 ep = txt.length while sp < ep # scan back for a space p = sp + line_len - 1 if p >= ep p = ep else while p > sp and txt[p] != ?\s p -= 1 end if p <= sp p = sp + line_len while p < ep and txt[p] != ?\s p += 1 end end end res << txt[sp...p] << "\n" sp = p sp += 1 while sp < ep and txt[sp] == ?\s end res end ####################################################################### private ####################################################################### def on_tags(res, item) attr_mask = item.turn_on return if attr_mask.zero? @attr_tags.each do |tag| if attr_mask & tag.bit != 0 res << annotate(tag.on) end end end def off_tags(res, item) attr_mask = item.turn_off return if attr_mask.zero? @attr_tags.reverse_each do |tag| if attr_mask & tag.bit != 0 res << annotate(tag.off) end end end def convert_flow(flow) res = "" flow.each do |item| case item when String res << convert_string(item) when AttrChanger off_tags(res, item) on_tags(res, item) when Special res << convert_special(item) else raise "Unknown flow element: #{item.inspect}" end end res end # some of these patterns are taken from SmartyPants... def convert_string(item) CGI.escapeHTML(item). # convert -- to em-dash, (-- to en-dash) gsub(/---?/, '—'). #gsub(/--/, '–'). # convert ... to elipsis (and make sure .... becomes .) gsub(/\.\.\.\./, '.…').gsub(/\.\.\./, '…'). # convert single closing quote gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1’" }. gsub(%r{\'(?=\W|s\b)}) { "’" }. # convert single opening quote gsub(/'/, '‘'). # convert double closing quote gsub(%r{([^ \t\r\n\[\{\(])\'(?=\W)}) { "#$1”" }. # convert double opening quote gsub(/'/, '“'). # convert copyright gsub(/\(c\)/, '©'). # convert and registered trademark gsub(/\(r\)/, '®') end def convert_special(special) handled = false Attribute.each_name_of(special.type) do |name| method_name = "handle_special_#{name}" if self.respond_to? method_name special.text = send(method_name, special) handled = true end end raise "Unhandled special: #{special}" unless handled special.text end def convert_heading(level, flow) res = annotate("") + convert_flow(flow) + annotate("\n") end def html_list_name(list_type, is_open_tag) tags = LIST_TYPE_TO_HTML[list_type] || raise("Invalid list type: #{list_type.inspect}") annotate(tags[ is_open_tag ? 0 : 1]) end def list_item_start(am, fragment) case fragment.type when ListBase::BULLET, ListBase::NUMBER annotate("

  • ") when ListBase::UPPERALPHA annotate("
  • ") when ListBase::LOWERALPHA annotate("
  • ") when ListBase::LABELED annotate("
    ") + convert_flow(am.flow(fragment.param)) + annotate("
    ") + annotate("
    ") when ListBase::NOTE annotate("") + annotate("") + convert_flow(am.flow(fragment.param)) + annotate("") + annotate("") else raise "Invalid list type" end end def list_end_for(fragment_type) case fragment_type when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA, ListBase::LOWERALPHA "
  • " when ListBase::LABELED "" when ListBase::NOTE "" else raise "Invalid list type" end end end end PK!)simple_markup/fragments.rbnu[require 'rdoc/markup/simple_markup/lines.rb' #require 'rdoc/markup/simple_markup/to_flow.rb' module SM ## # A Fragment is a chunk of text, subclassed as a paragraph, a list # entry, or verbatim text class Fragment attr_reader :level, :param, :txt attr_accessor :type def initialize(level, param, type, txt) @level = level @param = param @type = type @txt = "" add_text(txt) if txt end def add_text(txt) @txt << " " if @txt.length > 0 @txt << txt.tr_s("\n ", " ").strip end def to_s "L#@level: #{self.class.name.split('::')[-1]}\n#@txt" end ###### # This is a simple factory system that lets us associate fragement # types (a string) with a subclass of fragment TYPE_MAP = {} def Fragment.type_name(name) TYPE_MAP[name] = self end def Fragment.for(line) klass = TYPE_MAP[line.type] || raise("Unknown line type: '#{line.type.inspect}:' '#{line.text}'") return klass.new(line.level, line.param, line.flag, line.text) end end ## # A paragraph is a fragment which gets wrapped to fit. We remove all # newlines when we're created, and have them put back on output class Paragraph < Fragment type_name Line::PARAGRAPH end class BlankLine < Paragraph type_name Line::BLANK end class Heading < Paragraph type_name Line::HEADING def head_level @param.to_i end end ## # A List is a fragment with some kind of label # class ListBase < Paragraph # List types BULLET = :BULLET NUMBER = :NUMBER UPPERALPHA = :UPPERALPHA LOWERALPHA = :LOWERALPHA LABELED = :LABELED NOTE = :NOTE end class ListItem < ListBase type_name Line::LIST # def label # am = AttributeManager.new(@param) # am.flow # end end class ListStart < ListBase def initialize(level, param, type) super(level, param, type, nil) end end class ListEnd < ListBase def initialize(level, type) super(level, "", type, nil) end end ## # Verbatim code contains lines that don't get wrapped. class Verbatim < Fragment type_name Line::VERBATIM def add_text(txt) @txt << txt.chomp << "\n" end end ## # A horizontal rule class Rule < Fragment type_name Line::RULE end # Collect groups of lines together. Each group # will end up containing a flow of text class LineCollection def initialize @fragments = [] end def add(fragment) @fragments << fragment end def each(&b) @fragments.each(&b) end # For testing def to_a @fragments.map {|fragment| fragment.to_s} end # Factory for different fragment types def fragment_for(*args) Fragment.for(*args) end # tidy up at the end def normalize change_verbatim_blank_lines add_list_start_and_ends add_list_breaks tidy_blank_lines end def to_s @fragments.join("\n----\n") end def accept(am, visitor) visitor.start_accepting @fragments.each do |fragment| case fragment when Verbatim visitor.accept_verbatim(am, fragment) when Rule visitor.accept_rule(am, fragment) when ListStart visitor.accept_list_start(am, fragment) when ListEnd visitor.accept_list_end(am, fragment) when ListItem visitor.accept_list_item(am, fragment) when BlankLine visitor.accept_blank_line(am, fragment) when Heading visitor.accept_heading(am, fragment) when Paragraph visitor.accept_paragraph(am, fragment) end end visitor.end_accepting end ####### private ####### # If you have: # # normal paragraph text. # # this is code # # and more code # # You'll end up with the fragments Paragraph, BlankLine, # Verbatim, BlankLine, Verbatim, BlankLine, etc # # The BlankLine in the middle of the verbatim chunk needs to # be changed to a real verbatim newline, and the two # verbatim blocks merged # # def change_verbatim_blank_lines frag_block = nil blank_count = 0 @fragments.each_with_index do |frag, i| if frag_block.nil? frag_block = frag if Verbatim === frag else case frag when Verbatim blank_count.times { frag_block.add_text("\n") } blank_count = 0 frag_block.add_text(frag.txt) @fragments[i] = nil # remove out current fragment when BlankLine if frag_block blank_count += 1 @fragments[i] = nil end else frag_block = nil blank_count = 0 end end end @fragments.compact! end # List nesting is implicit given the level of # Make it explicit, just to make life a tad # easier for the output processors def add_list_start_and_ends level = 0 res = [] type_stack = [] @fragments.each do |fragment| # $stderr.puts "#{level} : #{fragment.class.name} : #{fragment.level}" new_level = fragment.level while (level < new_level) level += 1 type = fragment.type res << ListStart.new(level, fragment.param, type) if type type_stack.push type # $stderr.puts "Start: #{level}" end while level > new_level type = type_stack.pop res << ListEnd.new(level, type) if type level -= 1 # $stderr.puts "End: #{level}, #{type}" end res << fragment level = fragment.level end level.downto(1) do |i| type = type_stack.pop res << ListEnd.new(i, type) if type end @fragments = res end # now insert start/ends between list entries at the # same level that have different element types def add_list_breaks res = @fragments @fragments = [] list_stack = [] res.each do |fragment| case fragment when ListStart list_stack.push fragment when ListEnd start = list_stack.pop fragment.type = start.type when ListItem l = list_stack.last if fragment.type != l.type @fragments << ListEnd.new(l.level, l.type) start = ListStart.new(l.level, fragment.param, fragment.type) @fragments << start list_stack.pop list_stack.push start end else ; end @fragments << fragment end end # Finally tidy up the blank lines: # * change Blank/ListEnd into ListEnd/Blank # * remove blank lines at the front def tidy_blank_lines (@fragments.size - 1).times do |i| if @fragments[i].kind_of?(BlankLine) and @fragments[i+1].kind_of?(ListEnd) @fragments[i], @fragments[i+1] = @fragments[i+1], @fragments[i] end end # remove leading blanks @fragments.each_with_index do |f, i| break unless f.kind_of? BlankLine @fragments[i] = nil end @fragments.compact! end end end PK!Vڹsimple_markup/preprocess.rbnu[module SM ## # Handle common directives that can occur in a block of text: # # : include : filename # class PreProcess def initialize(input_file_name, include_path) @input_file_name = input_file_name @include_path = include_path end # Look for common options in a chunk of text. Options that # we don't handle are passed back to our caller # as |directive, param| def handle(text) text.gsub!(/^([ \t#]*):(\w+):\s*(.+)?\n/) do prefix = $1 directive = $2.downcase param = $3 case directive when "include" filename = param.split[0] include_file(filename, prefix) else yield(directive, param) end end end ####### private ####### # Include a file, indenting it correctly def include_file(name, indent) if (full_name = find_include_file(name)) content = File.open(full_name) {|f| f.read} # strip leading '#'s, but only if all lines start with them if content =~ /^[^#]/ content.gsub(/^/, indent) else content.gsub(/^#?/, indent) end else $stderr.puts "Couldn't find file to include: '#{name}'" '' end end # Look for the given file in the directory containing the current # file, and then in each of the directories specified in the # RDOC_INCLUDE path def find_include_file(name) to_search = [ File.dirname(@input_file_name) ].concat @include_path to_search.each do |dir| full_name = File.join(dir, name) stat = File.stat(full_name) rescue next return full_name if stat.readable? end nil end end end PK!7^!!simple_markup/to_latex.rbnu[require 'rdoc/markup/simple_markup/fragments' require 'rdoc/markup/simple_markup/inline' require 'cgi' module SM # Convert SimpleMarkup to basic LaTeX report format class ToLaTeX BS = "\020" # \ OB = "\021" # { CB = "\022" # } DL = "\023" # Dollar BACKSLASH = "#{BS}symbol#{OB}92#{CB}" HAT = "#{BS}symbol#{OB}94#{CB}" BACKQUOTE = "#{BS}symbol#{OB}0#{CB}" TILDE = "#{DL}#{BS}sim#{DL}" LESSTHAN = "#{DL}<#{DL}" GREATERTHAN = "#{DL}>#{DL}" def self.l(str) str.tr('\\', BS).tr('{', OB).tr('}', CB).tr('$', DL) end def l(arg) SM::ToLaTeX.l(arg) end LIST_TYPE_TO_LATEX = { ListBase::BULLET => [ l("\\begin{itemize}"), l("\\end{itemize}") ], ListBase::NUMBER => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\arabic" ], ListBase::UPPERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\Alph" ], ListBase::LOWERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\alph" ], ListBase::LABELED => [ l("\\begin{description}"), l("\\end{description}") ], ListBase::NOTE => [ l("\\begin{tabularx}{\\linewidth}{@{} l X @{}}"), l("\\end{tabularx}") ], } InlineTag = Struct.new(:bit, :on, :off) def initialize init_tags @list_depth = 0 @prev_list_types = [] end ## # Set up the standard mapping of attributes to LaTeX # def init_tags @attr_tags = [ InlineTag.new(SM::Attribute.bitmap_for(:BOLD), l("\\textbf{"), l("}")), InlineTag.new(SM::Attribute.bitmap_for(:TT), l("\\texttt{"), l("}")), InlineTag.new(SM::Attribute.bitmap_for(:EM), l("\\emph{"), l("}")), ] end ## # Escape a LaTeX string def escape(str) # $stderr.print "FE: ", str s = str. # sub(/\s+$/, ''). gsub(/([_\${}&%#])/, "#{BS}\\1"). gsub(/\\/, BACKSLASH). gsub(/\^/, HAT). gsub(/~/, TILDE). gsub(//, GREATERTHAN). gsub(/,,/, ",{},"). gsub(/\`/, BACKQUOTE) # $stderr.print "-> ", s, "\n" s end ## # Add a new set of LaTeX tags for an attribute. We allow # separate start and end tags for flexibility # def add_tag(name, start, stop) @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop) end ## # Here's the client side of the visitor pattern def start_accepting @res = "" @in_list_entry = [] end def end_accepting @res.tr(BS, '\\').tr(OB, '{').tr(CB, '}').tr(DL, '$') end def accept_paragraph(am, fragment) @res << wrap(convert_flow(am.flow(fragment.txt))) @res << "\n" end def accept_verbatim(am, fragment) @res << "\n\\begin{code}\n" @res << fragment.txt.sub(/[\n\s]+\Z/, '') @res << "\n\\end{code}\n\n" end def accept_rule(am, fragment) size = fragment.param size = 10 if size > 10 @res << "\n\n\\rule{\\linewidth}{#{size}pt}\n\n" end def accept_list_start(am, fragment) @res << list_name(fragment.type, true) <<"\n" @in_list_entry.push false end def accept_list_end(am, fragment) if tag = @in_list_entry.pop @res << tag << "\n" end @res << list_name(fragment.type, false) <<"\n" end def accept_list_item(am, fragment) if tag = @in_list_entry.last @res << tag << "\n" end @res << list_item_start(am, fragment) @res << wrap(convert_flow(am.flow(fragment.txt))) << "\n" @in_list_entry[-1] = list_end_for(fragment.type) end def accept_blank_line(am, fragment) # @res << "\n" end def accept_heading(am, fragment) @res << convert_heading(fragment.head_level, am.flow(fragment.txt)) end # This is a higher speed (if messier) version of wrap def wrap(txt, line_len = 76) res = "" sp = 0 ep = txt.length while sp < ep # scan back for a space p = sp + line_len - 1 if p >= ep p = ep else while p > sp and txt[p] != ?\s p -= 1 end if p <= sp p = sp + line_len while p < ep and txt[p] != ?\s p += 1 end end end res << txt[sp...p] << "\n" sp = p sp += 1 while sp < ep and txt[sp] == ?\s end res end ####################################################################### private ####################################################################### def on_tags(res, item) attr_mask = item.turn_on return if attr_mask.zero? @attr_tags.each do |tag| if attr_mask & tag.bit != 0 res << tag.on end end end def off_tags(res, item) attr_mask = item.turn_off return if attr_mask.zero? @attr_tags.reverse_each do |tag| if attr_mask & tag.bit != 0 res << tag.off end end end def convert_flow(flow) res = "" flow.each do |item| case item when String # $stderr.puts "Converting '#{item}'" res << convert_string(item) when AttrChanger off_tags(res, item) on_tags(res, item) when Special res << convert_special(item) else raise "Unknown flow element: #{item.inspect}" end end res end # some of these patterns are taken from SmartyPants... def convert_string(item) escape(item). # convert ... to elipsis (and make sure .... becomes .) gsub(/\.\.\.\./, '.\ldots{}').gsub(/\.\.\./, '\ldots{}'). # convert single closing quote gsub(%r{([^ \t\r\n\[\{\(])\'}) { "#$1'" }. gsub(%r{\'(?=\W|s\b)}) { "'" }. # convert single opening quote gsub(/'/, '`'). # convert double closing quote gsub(%r{([^ \t\r\n\[\{\(])\"(?=\W)}) { "#$1''" }. # convert double opening quote gsub(/"/, "``"). # convert copyright gsub(/\(c\)/, '\copyright{}') end def convert_special(special) handled = false Attribute.each_name_of(special.type) do |name| method_name = "handle_special_#{name}" if self.respond_to? method_name special.text = send(method_name, special) handled = true end end raise "Unhandled special: #{special}" unless handled special.text end def convert_heading(level, flow) res = case level when 1 then "\\chapter{" when 2 then "\\section{" when 3 then "\\subsection{" when 4 then "\\subsubsection{" else "\\paragraph{" end + convert_flow(flow) + "}\n" end def list_name(list_type, is_open_tag) tags = LIST_TYPE_TO_LATEX[list_type] || raise("Invalid list type: #{list_type.inspect}") if tags[2] # enumerate if is_open_tag @list_depth += 1 if @prev_list_types[@list_depth] != tags[2] case @list_depth when 1 roman = "i" when 2 roman = "ii" when 3 roman = "iii" when 4 roman = "iv" else raise("Too deep list: level #{@list_depth}") end @prev_list_types[@list_depth] = tags[2] return l("\\renewcommand{\\labelenum#{roman}}{#{tags[2]}{enum#{roman}}}") + "\n" + tags[0] end else @list_depth -= 1 end end tags[ is_open_tag ? 0 : 1] end def list_item_start(am, fragment) case fragment.type when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA, ListBase::LOWERALPHA "\\item " when ListBase::LABELED "\\item[" + convert_flow(am.flow(fragment.param)) + "] " when ListBase::NOTE convert_flow(am.flow(fragment.param)) + " & " else raise "Invalid list type" end end def list_end_for(fragment_type) case fragment_type when ListBase::BULLET, ListBase::NUMBER, ListBase::UPPERALPHA, ListBase::LOWERALPHA, ListBase::LABELED "" when ListBase::NOTE "\\\\\n" else raise "Invalid list type" end end end end PK!""simple_markup/inline.rbnu[module SM # We manage a set of attributes. Each attribute has a symbol name # and a bit value class Attribute SPECIAL = 1 @@name_to_bitmap = { :_SPECIAL_ => SPECIAL } @@next_bitmap = 2 def Attribute.bitmap_for(name) bitmap = @@name_to_bitmap[name] if !bitmap bitmap = @@next_bitmap @@next_bitmap <<= 1 @@name_to_bitmap[name] = bitmap end bitmap end def Attribute.as_string(bitmap) return "none" if bitmap.zero? res = [] @@name_to_bitmap.each do |name, bit| res << name if (bitmap & bit) != 0 end res.join(",") end def Attribute.each_name_of(bitmap) @@name_to_bitmap.each do |name, bit| next if bit == SPECIAL yield name.to_s if (bitmap & bit) != 0 end end end # An AttrChanger records a change in attributes. It contains # a bitmap of the attributes to turn on, and a bitmap of those to # turn off AttrChanger = Struct.new(:turn_on, :turn_off) class AttrChanger def to_s "Attr: +#{Attribute.as_string(@turn_on)}/-#{Attribute.as_string(@turn_on)}" end end # An array of attributes which parallels the characters in a string class AttrSpan def initialize(length) @attrs = Array.new(length, 0) end def set_attrs(start, length, bits) for i in start ... (start+length) @attrs[i] |= bits end end def [](n) @attrs[n] end end ## # Hold details of a special sequence class Special attr_reader :type attr_accessor :text def initialize(type, text) @type, @text = type, text end def ==(o) self.text == o.text && self.type == o.type end def to_s "Special: type=#{type}, text=#{text.dump}" end end class AttributeManager NULL = "\000".freeze ## # We work by substituting non-printing characters in to the # text. For now I'm assuming that I can substitute # a character in the range 0..8 for a 7 bit character # without damaging the encoded string, but this might # be optimistic # A_PROTECT = 004 PROTECT_ATTR = A_PROTECT.chr # This maps delimiters that occur around words (such as # *bold* or +tt+) where the start and end delimiters # and the same. This lets us optimize the regexp MATCHING_WORD_PAIRS = {} # And this is used when the delimiters aren't the same. In this # case the hash maps a pattern to the attribute character WORD_PAIR_MAP = {} # This maps HTML tags to the corresponding attribute char HTML_TAGS = {} # And this maps _special_ sequences to a name. A special sequence # is something like a WikiWord SPECIAL = {} # Return an attribute object with the given turn_on # and turn_off bits set def attribute(turn_on, turn_off) AttrChanger.new(turn_on, turn_off) end def change_attribute(current, new) diff = current ^ new attribute(new & diff, current & diff) end def changed_attribute_by_name(current_set, new_set) current = new = 0 current_set.each {|name| current |= Attribute.bitmap_for(name) } new_set.each {|name| new |= Attribute.bitmap_for(name) } change_attribute(current, new) end def copy_string(start_pos, end_pos) res = @str[start_pos...end_pos] res.gsub!(/\000/, '') res end # Map attributes like textto the sequence \001\002\001\003, # where is a per-attribute specific character def convert_attrs(str, attrs) # first do matching ones tags = MATCHING_WORD_PAIRS.keys.join("") re = "(^|\\W)([#{tags}])([A-Za-z_]+?)\\2(\\W|\$)" # re = "(^|\\W)([#{tags}])(\\S+?)\\2(\\W|\$)" 1 while str.gsub!(Regexp.new(re)) { attr = MATCHING_WORD_PAIRS[$2]; attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr) $1 + NULL*$2.length + $3 + NULL*$2.length + $4 } # then non-matching unless WORD_PAIR_MAP.empty? WORD_PAIR_MAP.each do |regexp, attr| str.gsub!(regexp) { attrs.set_attrs($`.length + $1.length, $2.length, attr) NULL*$1.length + $2 + NULL*$3.length } end end end def convert_html(str, attrs) tags = HTML_TAGS.keys.join("|") re = "<(#{tags})>(.*?)" 1 while str.gsub!(Regexp.new(re, Regexp::IGNORECASE)) { attr = HTML_TAGS[$1.downcase] html_length = $1.length + 2 seq = NULL * html_length attrs.set_attrs($`.length + html_length, $2.length, attr) seq + $2 + seq + NULL } end def convert_specials(str, attrs) unless SPECIAL.empty? SPECIAL.each do |regexp, attr| str.scan(regexp) do attrs.set_attrs($`.length, $&.length, attr | Attribute::SPECIAL) end end end end # A \ in front of a character that would normally be # processed turns off processing. We do this by turning # \< into <#{PROTECT} PROTECTABLE = [ "<" << "\\" ] #" def mask_protected_sequences protect_pattern = Regexp.new("\\\\([#{Regexp.escape(PROTECTABLE.join(''))}])") @str.gsub!(protect_pattern, "\\1#{PROTECT_ATTR}") end def unmask_protected_sequences @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000") end def initialize add_word_pair("*", "*", :BOLD) add_word_pair("_", "_", :EM) add_word_pair("+", "+", :TT) add_html("em", :EM) add_html("i", :EM) add_html("b", :BOLD) add_html("tt", :TT) add_html("code", :TT) add_special(//, :COMMENT) end def add_word_pair(start, stop, name) raise "Word flags may not start '<'" if start[0] == ?< bitmap = Attribute.bitmap_for(name) if start == stop MATCHING_WORD_PAIRS[start] = bitmap else pattern = Regexp.new("(" + Regexp.escape(start) + ")" + # "([A-Za-z]+)" + "(\\S+)" + "(" + Regexp.escape(stop) +")") WORD_PAIR_MAP[pattern] = bitmap end PROTECTABLE << start[0,1] PROTECTABLE.uniq! end def add_html(tag, name) HTML_TAGS[tag.downcase] = Attribute.bitmap_for(name) end def add_special(pattern, name) SPECIAL[pattern] = Attribute.bitmap_for(name) end def flow(str) @str = str puts("Before flow, str='#{@str.dump}'") if $DEBUG mask_protected_sequences @attrs = AttrSpan.new(@str.length) puts("After protecting, str='#{@str.dump}'") if $DEBUG convert_attrs(@str, @attrs) convert_html(@str, @attrs) convert_specials(str, @attrs) unmask_protected_sequences puts("After flow, str='#{@str.dump}'") if $DEBUG return split_into_flow end def display_attributes puts puts @str.tr(NULL, "!") bit = 1 16.times do |bno| line = "" @str.length.times do |i| if (@attrs[i] & bit) == 0 line << " " else if bno.zero? line << "S" else line << ("%d" % (bno+1)) end end end puts(line) unless line =~ /^ *$/ bit <<= 1 end end def split_into_flow display_attributes if $DEBUG res = [] current_attr = 0 str = "" str_len = @str.length # skip leading invisible text i = 0 i += 1 while i < str_len and @str[i].zero? start_pos = i # then scan the string, chunking it on attribute changes while i < str_len new_attr = @attrs[i] if new_attr != current_attr if i > start_pos res << copy_string(start_pos, i) start_pos = i end res << change_attribute(current_attr, new_attr) current_attr = new_attr if (current_attr & Attribute::SPECIAL) != 0 i += 1 while i < str_len and (@attrs[i] & Attribute::SPECIAL) != 0 res << Special.new(current_attr, copy_string(start_pos, i)) start_pos = i next end end # move on, skipping any invisible characters begin i += 1 end while i < str_len and @str[i].zero? end # tidy up trailing text if start_pos < str_len res << copy_string(start_pos, str_len) end # and reset to all attributes off res << change_attribute(current_attr, 0) if current_attr != 0 return res end end end PK!k simple_markup/lines.rbnu[########################################################################## # # We store the lines we're working on as objects of class Line. # These contain the text of the line, along with a flag indicating the # line type, and an indentation level module SM class Line INFINITY = 9999 BLANK = :BLANK HEADING = :HEADING LIST = :LIST RULE = :RULE PARAGRAPH = :PARAGRAPH VERBATIM = :VERBATIM # line type attr_accessor :type # The indentation nesting level attr_accessor :level # The contents attr_accessor :text # A prefix or parameter. For LIST lines, this is # the text that introduced the list item (the label) attr_accessor :param # A flag. For list lines, this is the type of the list attr_accessor :flag # the number of leading spaces attr_accessor :leading_spaces # true if this line has been deleted from the list of lines attr_accessor :deleted def initialize(text) @text = text.dup @deleted = false # expand tabs 1 while @text.gsub!(/\t+/) { ' ' * (8*$&.length - $`.length % 8)} && $~ #` # Strip trailing whitespace @text.sub!(/\s+$/, '') # and look for leading whitespace if @text.length > 0 @text =~ /^(\s*)/ @leading_spaces = $1.length else @leading_spaces = INFINITY end end # Return true if this line is blank def isBlank? @text.length.zero? end # stamp a line with a type, a level, a prefix, and a flag def stamp(type, level, param="", flag=nil) @type, @level, @param, @flag = type, level, param, flag end ## # Strip off the leading margin # def strip_leading(size) if @text.size > size @text[0,size] = "" else @text = "" end end def to_s "#@type#@level: #@text" end end ############################################################################### # # A container for all the lines # class Lines include Enumerable attr_reader :lines # for debugging def initialize(lines) @lines = lines rewind end def empty? @lines.size.zero? end def each @lines.each do |line| yield line unless line.deleted end end # def [](index) # @lines[index] # end def rewind @nextline = 0 end def next begin res = @lines[@nextline] @nextline += 1 if @nextline < @lines.size end while res and res.deleted and @nextline < @lines.size res end def unget @nextline -= 1 end def delete(a_line) a_line.deleted = true end def normalize margin = @lines.collect{|l| l.leading_spaces}.min margin = 0 if margin == Line::INFINITY @lines.each {|line| line.strip_leading(margin) } if margin > 0 end def as_text @lines.map {|l| l.text}.join("\n") end def line_types @lines.map {|l| l.type } end end end PK!8aU~~simple_markup/to_flow.rbnu[require 'rdoc/markup/simple_markup/fragments' require 'rdoc/markup/simple_markup/inline' require 'cgi' module SM module Flow P = Struct.new(:body) VERB = Struct.new(:body) RULE = Struct.new(:width) class LIST attr_reader :type, :contents def initialize(type) @type = type @contents = [] end def <<(stuff) @contents << stuff end end LI = Struct.new(:label, :body) H = Struct.new(:level, :text) end class ToFlow LIST_TYPE_TO_HTML = { SM::ListBase::BULLET => [ "
      ", "
    " ], SM::ListBase::NUMBER => [ "
      ", "
    " ], SM::ListBase::UPPERALPHA => [ "
      ", "
    " ], SM::ListBase::LOWERALPHA => [ "
      ", "
    " ], SM::ListBase::LABELED => [ "
    ", "
    " ], SM::ListBase::NOTE => [ "", "
    " ], } InlineTag = Struct.new(:bit, :on, :off) def initialize init_tags end ## # Set up the standard mapping of attributes to HTML tags # def init_tags @attr_tags = [ InlineTag.new(SM::Attribute.bitmap_for(:BOLD), "", ""), InlineTag.new(SM::Attribute.bitmap_for(:TT), "", ""), InlineTag.new(SM::Attribute.bitmap_for(:EM), "", ""), ] end ## # Add a new set of HTML tags for an attribute. We allow # separate start and end tags for flexibility # def add_tag(name, start, stop) @attr_tags << InlineTag.new(SM::Attribute.bitmap_for(name), start, stop) end ## # Given an HTML tag, decorate it with class information # and the like if required. This is a no-op in the base # class, but is overridden in HTML output classes that # implement style sheets def annotate(tag) tag end ## # Here's the client side of the visitor pattern def start_accepting @res = [] @list_stack = [] end def end_accepting @res end def accept_paragraph(am, fragment) @res << Flow::P.new((convert_flow(am.flow(fragment.txt)))) end def accept_verbatim(am, fragment) @res << Flow::VERB.new((convert_flow(am.flow(fragment.txt)))) end def accept_rule(am, fragment) size = fragment.param size = 10 if size > 10 @res << Flow::RULE.new(size) end def accept_list_start(am, fragment) @list_stack.push(@res) list = Flow::LIST.new(fragment.type) @res << list @res = list end def accept_list_end(am, fragment) @res = @list_stack.pop end def accept_list_item(am, fragment) @res << Flow::LI.new(fragment.param, convert_flow(am.flow(fragment.txt))) end def accept_blank_line(am, fragment) # @res << annotate("

    ") << "\n" end def accept_heading(am, fragment) @res << Flow::H.new(fragment.head_level, convert_flow(am.flow(fragment.txt))) end ####################################################################### private ####################################################################### def on_tags(res, item) attr_mask = item.turn_on return if attr_mask.zero? @attr_tags.each do |tag| if attr_mask & tag.bit != 0 res << annotate(tag.on) end end end def off_tags(res, item) attr_mask = item.turn_off return if attr_mask.zero? @attr_tags.reverse_each do |tag| if attr_mask & tag.bit != 0 res << annotate(tag.off) end end end def convert_flow(flow) res = "" flow.each do |item| case item when String res << convert_string(item) when AttrChanger off_tags(res, item) on_tags(res, item) when Special res << convert_special(item) else raise "Unknown flow element: #{item.inspect}" end end res end # some of these patterns are taken from SmartyPants... def convert_string(item) CGI.escapeHTML(item) end def convert_special(special) handled = false Attribute.each_name_of(special.type) do |name| method_name = "handle_special_#{name}" if self.respond_to? method_name special.text = send(method_name, special) handled = true end end raise "Unhandled special: #{special}" unless handled special.text end end end PK!/ heading.rbnu[## # A heading with a level (1-6) and text RDoc::Markup::Heading = Struct.new :level, :text do @to_html = nil @to_label = nil ## # A singleton RDoc::Markup::ToLabel formatter for headings. def self.to_label @to_label ||= RDoc::Markup::ToLabel.new end ## # A singleton plain HTML formatter for headings. Used for creating labels # for the Table of Contents def self.to_html return @to_html if @to_html markup = RDoc::Markup.new markup.add_special RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF @to_html = RDoc::Markup::ToHtml.new nil def @to_html.handle_special_CROSSREF special special.text.sub(/^\\/, '') end @to_html end ## # Calls #accept_heading on +visitor+ def accept visitor visitor.accept_heading self end ## # An HTML-safe anchor reference for this header. def aref "label-#{self.class.to_label.convert text.dup}" end ## # Creates a fully-qualified label which will include the label from # +context+. This helps keep ids unique in HTML. def label context = nil label = aref label = [context.aref, label].compact.join '-' if context and context.respond_to? :aref label end ## # HTML markup of the text of this label without the surrounding header # element. def plain_html self.class.to_html.to_html(text.dup) end def pretty_print q # :nodoc: q.group 2, "[head: #{level} ", ']' do q.pp text end end end PK!fР attributes.rbnu[## # We manage a set of attributes. Each attribute has a symbol name and a bit # value. class RDoc::Markup::Attributes ## # The special attribute type. See RDoc::Markup#add_special attr_reader :special ## # Creates a new attributes set. def initialize @special = 1 @name_to_bitmap = [ [:_SPECIAL_, @special], ] @next_bitmap = @special << 1 end ## # Returns a unique bit for +name+ def bitmap_for name bitmap = @name_to_bitmap.assoc name unless bitmap then bitmap = @next_bitmap @next_bitmap <<= 1 @name_to_bitmap << [name, bitmap] else bitmap = bitmap.last end bitmap end ## # Returns a string representation of +bitmap+ def as_string bitmap return 'none' if bitmap.zero? res = [] @name_to_bitmap.each do |name, bit| res << name if (bitmap & bit) != 0 end res.join ',' end ## # yields each attribute name in +bitmap+ def each_name_of bitmap return enum_for __method__, bitmap unless block_given? @name_to_bitmap.each do |name, bit| next if bit == @special yield name.to_s if (bitmap & bit) != 0 end end end PK!'>''list.rbnu[## # A List is a homogeneous set of ListItems. # # The supported list types include: # # :BULLET:: # An unordered list # :LABEL:: # An unordered definition list, but using an alternate RDoc::Markup syntax # :LALPHA:: # An ordered list using increasing lowercase English letters # :NOTE:: # An unordered definition list # :NUMBER:: # An ordered list using increasing Arabic numerals # :UALPHA:: # An ordered list using increasing uppercase English letters # # Definition lists behave like HTML definition lists. Each list item can # describe multiple terms. See RDoc::Markup::ListItem for how labels and # definition are stored as list items. class RDoc::Markup::List ## # The list's type attr_accessor :type ## # Items in the list attr_reader :items ## # Creates a new list of +type+ with +items+. Valid list types are: # +:BULLET+, +:LABEL+, +:LALPHA+, +:NOTE+, +:NUMBER+, +:UALPHA+ def initialize type = nil, *items @type = type @items = [] @items.concat items end ## # Appends +item+ to the list def << item @items << item end def == other # :nodoc: self.class == other.class and @type == other.type and @items == other.items end ## # Runs this list and all its #items through +visitor+ def accept visitor visitor.accept_list_start self @items.each do |item| item.accept visitor end visitor.accept_list_end self end ## # Is the list empty? def empty? @items.empty? end ## # Returns the last item in the list def last @items.last end def pretty_print q # :nodoc: q.group 2, "[list: #{@type} ", ']' do q.seplist @items do |item| q.pp item end end end ## # Appends +items+ to the list def push *items @items.concat items end end PK!H22to_joined_paragraph.rbnu[## # Joins the parts of an RDoc::Markup::Paragraph into a single String. # # This allows for easier maintenance and testing of Markdown support. # # This formatter only works on Paragraph instances. Attempting to process # other markup syntax items will not work. class RDoc::Markup::ToJoinedParagraph < RDoc::Markup::Formatter def initialize # :nodoc: super nil end def start_accepting # :nodoc: end def end_accepting # :nodoc: end ## # Converts the parts of +paragraph+ to a single entry. def accept_paragraph paragraph parts = [] string = false paragraph.parts.each do |part| if String === part then if string then string << part else parts << part string = part end else parts << part string = false end end parts = parts.map do |part| if String === part then part.rstrip else part end end # TODO use Enumerable#chunk when Ruby 1.8 support is dropped #parts = paragraph.parts.chunk do |part| # String === part #end.map do |string, chunk| # string ? chunk.join.rstrip : chunk #end.flatten paragraph.parts.replace parts end alias accept_block_quote ignore alias accept_heading ignore alias accept_list_end ignore alias accept_list_item_end ignore alias accept_list_item_start ignore alias accept_list_start ignore alias accept_raw ignore alias accept_rule ignore alias accept_verbatim ignore end PK!w!! to_html.rbnu[require 'cgi' ## # Outputs RDoc markup as HTML. class RDoc::Markup::ToHtml < RDoc::Markup::Formatter include RDoc::Text # :section: Utilities ## # Maps RDoc::Markup::Parser::LIST_TOKENS types to HTML tags LIST_TYPE_TO_HTML = { :BULLET => ['

      ', '
    '], :LABEL => ['
    ', '
    '], :LALPHA => ['
      ', '
    '], :NOTE => ['
    ', '
    '], :NUMBER => ['
      ', '
    '], :UALPHA => ['
      ', '
    '], } attr_reader :res # :nodoc: attr_reader :in_list_entry # :nodoc: attr_reader :list # :nodoc: ## # The RDoc::CodeObject HTML is being generated for. This is used to # generate namespaced URI fragments attr_accessor :code_object ## # Path to this document for relative links attr_accessor :from_path # :section: ## # Creates a new formatter that will output HTML def initialize options, markup = nil super @code_object = nil @from_path = '' @in_list_entry = nil @list = nil @th = nil @hard_break = "
    \n" # external links @markup.add_special(/(?:link:|https?:|mailto:|ftp:|irc:|www\.)\S+\w/, :HYPERLINK) add_special_RDOCLINK add_special_TIDYLINK init_tags end # :section: Special Handling # # These methods handle special markup added by RDoc::Markup#add_special. def handle_RDOCLINK url # :nodoc: case url when /^rdoc-ref:/ $' when /^rdoc-label:/ text = $' text = case text when /\Alabel-/ then $' when /\Afootmark-/ then $' when /\Afoottext-/ then $' else text end gen_url url, text when /^rdoc-image:/ "" else url =~ /\Ardoc-[a-z]+:/ $' end end ## # +special+ is a
    def handle_special_HARD_BREAK special '
    ' end ## # +special+ is a potential link. The following schemes are handled: # # mailto::: # Inserted as-is. # http::: # Links are checked to see if they reference an image. If so, that image # gets inserted using an tag. Otherwise a conventional # is used. # link::: # Reference to a local file relative to the output directory. def handle_special_HYPERLINK(special) url = special.text gen_url url, url end ## # +special+ is an rdoc-schemed link that will be converted into a hyperlink. # # For the +rdoc-ref+ scheme the named reference will be returned without # creating a link. # # For the +rdoc-label+ scheme the footnote and label prefixes are stripped # when creating a link. All other contents will be linked verbatim. def handle_special_RDOCLINK special handle_RDOCLINK special.text end ## # This +special+ is a link where the label is different from the URL # label[url] or {long label}[url] def handle_special_TIDYLINK(special) text = special.text return text unless text =~ /^\{(.*)\}\[(.*?)\]$/ or text =~ /^(\S+)\[(.*?)\]$/ label = $1 url = $2 label = handle_RDOCLINK label if /^rdoc-image:/ =~ label gen_url url, label end # :section: Visitor # # These methods implement the HTML visitor. ## # Prepares the visitor for HTML generation def start_accepting @res = [] @in_list_entry = [] @list = [] end ## # Returns the generated output def end_accepting @res.join end ## # Adds +block_quote+ to the output def accept_block_quote block_quote @res << "\n
    " block_quote.parts.each do |part| part.accept self end @res << "
    \n" end ## # Adds +paragraph+ to the output def accept_paragraph paragraph @res << "\n

    " text = paragraph.text @hard_break text = text.gsub(/\r?\n/, ' ') @res << wrap(to_html(text)) @res << "

    \n" end ## # Adds +verbatim+ to the output def accept_verbatim verbatim text = verbatim.text.rstrip klass = nil content = if verbatim.ruby? or parseable? text then begin tokens = RDoc::RubyLex.tokenize text, @options klass = ' class="ruby"' RDoc::TokenStream.to_html tokens rescue RDoc::RubyLex::Error CGI.escapeHTML text end else CGI.escapeHTML text end if @options.pipe then @res << "\n
    #{CGI.escapeHTML text}
    \n" else @res << "\n#{content}\n" end end ## # Adds +rule+ to the output def accept_rule rule @res << "
    \n" end ## # Prepares the visitor for consuming +list+ def accept_list_start(list) @list << list.type @res << html_list_name(list.type, true) @in_list_entry.push false end ## # Finishes consumption of +list+ def accept_list_end(list) @list.pop if tag = @in_list_entry.pop @res << tag end @res << html_list_name(list.type, false) << "\n" end ## # Prepares the visitor for consuming +list_item+ def accept_list_item_start(list_item) if tag = @in_list_entry.last @res << tag end @res << list_item_start(list_item, @list.last) end ## # Finishes consumption of +list_item+ def accept_list_item_end(list_item) @in_list_entry[-1] = list_end_for(@list.last) end ## # Adds +blank_line+ to the output def accept_blank_line(blank_line) # @res << annotate("

    ") << "\n" end ## # Adds +heading+ to the output. The headings greater than 6 are trimmed to # level 6. def accept_heading heading level = [6, heading.level].min label = heading.label @code_object @res << if @options.output_decoration "\n" else "\n" end @res << to_html(heading.text) unless @options.pipe then @res << "" @res << " " end @res << "\n" end ## # Adds +raw+ to the output def accept_raw raw @res << raw.parts.join("\n") end # :section: Utilities ## # CGI-escapes +text+ def convert_string(text) CGI.escapeHTML text end ## # Generate a link to +url+ with content +text+. Handles the special cases # for img: and link: described under handle_special_HYPERLINK def gen_url url, text scheme, url, id = parse_url url if %w[http https link].include?(scheme) and url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then "" else text = text.sub %r%^#{scheme}:/*%i, '' text = text.sub %r%^[*\^](\d+)$%, '\1' link = "#{text}" link = "#{link}" if /"foot/ =~ id link end end ## # Determines the HTML list element for +list_type+ and +open_tag+ def html_list_name(list_type, open_tag) tags = LIST_TYPE_TO_HTML[list_type] raise RDoc::Error, "Invalid list type: #{list_type.inspect}" unless tags tags[open_tag ? 0 : 1] end ## # Maps attributes to HTML tags def init_tags add_tag :BOLD, "", "" add_tag :TT, "", "" add_tag :EM, "", "" end ## # Returns the HTML tag for +list_type+, possible using a label from # +list_item+ def list_item_start(list_item, list_type) case list_type when :BULLET, :LALPHA, :NUMBER, :UALPHA then "

  • " when :LABEL, :NOTE then Array(list_item.label).map do |label| "
    #{to_html label}\n" end.join << "
    " else raise RDoc::Error, "Invalid list type: #{list_type.inspect}" end end ## # Returns the HTML end-tag for +list_type+ def list_end_for(list_type) case list_type when :BULLET, :LALPHA, :NUMBER, :UALPHA then "
  • " when :LABEL, :NOTE then "" else raise RDoc::Error, "Invalid list type: #{list_type.inspect}" end end ## # Returns true if Ripper is available it can create a sexp from +text+ def parseable? text text =~ /\b(def|class|module|require) |=>|\{\s?\||do \|/ and text !~ /<%|%>/ end ## # Converts +item+ to HTML using RDoc::Text#to_html def to_html item super convert_flow @am.flow item end end PK!$AEbto_bs.rbnu[## # Outputs RDoc markup with hot backspace action! You will probably need a # pager to use this output format. # # This formatter won't work on 1.8.6 because it lacks String#chars. class RDoc::Markup::ToBs < RDoc::Markup::ToRdoc ## # Returns a new ToBs that is ready for hot backspace action! def initialize markup = nil super @in_b = false @in_em = false end ## # Sets a flag that is picked up by #annotate to do the right thing in # #convert_string def init_tags add_tag :BOLD, '+b', '-b' add_tag :EM, '+_', '-_' add_tag :TT, '' , '' # we need in_tt information maintained end ## # Makes heading text bold. def accept_heading heading use_prefix or @res << ' ' * @indent @res << @headings[heading.level][0] @in_b = true @res << attributes(heading.text) @in_b = false @res << @headings[heading.level][1] @res << "\n" end ## # Turns on or off special handling for +convert_string+ def annotate tag case tag when '+b' then @in_b = true when '-b' then @in_b = false when '+_' then @in_em = true when '-_' then @in_em = false end '' end ## # Calls convert_string on the result of convert_special def convert_special special convert_string super end ## # Adds bold or underline mixed with backspaces def convert_string string return string unless string.respond_to? :chars # your ruby is lame return string unless @in_b or @in_em chars = if @in_b then string.chars.map do |char| "#{char}\b#{char}" end elsif @in_em then string.chars.map do |char| "_\b#{char}" end end chars.join end end PK!Upp to_test.rbnu[## # This Markup outputter is used for testing purposes. class RDoc::Markup::ToTest < RDoc::Markup::Formatter # :stopdoc: ## # :section: Visitor def start_accepting @res = [] @list = [] end def end_accepting @res end def accept_paragraph(paragraph) @res << convert_flow(@am.flow(paragraph.text)) end def accept_raw raw @res << raw.parts.join end def accept_verbatim(verbatim) @res << verbatim.text.gsub(/^(\S)/, ' \1') end def accept_list_start(list) @list << case list.type when :BULLET then '*' when :NUMBER then '1' else list.type end end def accept_list_end(list) @list.pop end def accept_list_item_start(list_item) @res << "#{' ' * (@list.size - 1)}#{@list.last}: " end def accept_list_item_end(list_item) end def accept_blank_line(blank_line) @res << "\n" end def accept_heading(heading) @res << "#{'=' * heading.level} #{heading.text}" end def accept_rule(rule) @res << '-' * rule.weight end # :startdoc: end PK!?||table.rbnu[# frozen_string_literal: true ## # A section of table class RDoc::Markup::Table # headers of each column attr_accessor :header # alignments of each column attr_accessor :align # body texts of each column attr_accessor :body # Creates new instance def initialize(header, align, body) @header, @align, @body = header, align, body end # :stopdoc: def ==(other) self.class == other.class and @header == other.header and @align == other.align and @body == other.body end def accept(visitor) visitor.accept_table @header, @body, @align end def pretty_print(q) q.group 2, '[Table: ', ']' do q.group 2, '[Head: ', ']' do q.seplist @header.zip(@align) do |text, align| q.pp text if align q.text ":" q.breakable q.text align.to_s end end end q.breakable q.group 2, '[Body: ', ']' do q.seplist @body do |body| q.group 2, '[', ']' do q.seplist body do |text| q.pp text end end end end end end end PK!X!to_html_snippet.rbnu[## # Outputs RDoc markup as paragraphs with inline markup only. class RDoc::Markup::ToHtmlSnippet < RDoc::Markup::ToHtml ## # After this many characters the input will be cut off. attr_reader :character_limit ## # The number of characters seen so far. attr_reader :characters # :nodoc: ## # The attribute bitmask attr_reader :mask ## # After this many paragraphs the input will be cut off. attr_reader :paragraph_limit ## # Count of paragraphs found attr_reader :paragraphs ## # Creates a new ToHtmlSnippet formatter that will cut off the input on the # next word boundary after the given number of +characters+ or +paragraphs+ # of text have been encountered. def initialize options, characters = 100, paragraphs = 3, markup = nil super options, markup @character_limit = characters @paragraph_limit = paragraphs @characters = 0 @mask = 0 @paragraphs = 0 @markup.add_special RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF end ## # Adds +heading+ to the output as a paragraph def accept_heading heading @res << "

    #{to_html heading.text}\n" add_paragraph end ## # Raw sections are untrusted and ignored alias accept_raw ignore ## # Rules are ignored alias accept_rule ignore def accept_paragraph paragraph para = @in_list_entry.last || "

    " text = paragraph.text @hard_break @res << "#{para}#{wrap to_html text}\n" add_paragraph end ## # Finishes consumption of +list_item+ def accept_list_item_end list_item end ## # Prepares the visitor for consuming +list_item+ def accept_list_item_start list_item @res << list_item_start(list_item, @list.last) end ## # Prepares the visitor for consuming +list+ def accept_list_start list @list << list.type @res << html_list_name(list.type, true) @in_list_entry.push '' end ## # Adds +verbatim+ to the output def accept_verbatim verbatim throw :done if @characters >= @character_limit input = verbatim.text.rstrip text = truncate input text << ' ...' unless text == input super RDoc::Markup::Verbatim.new text add_paragraph end ## # Prepares the visitor for HTML snippet generation def start_accepting super @characters = 0 end ## # Removes escaping from the cross-references in +special+ def handle_special_CROSSREF special special.text.sub(/\A\\/, '') end ## # +special+ is a
    def handle_special_HARD_BREAK special @characters -= 4 '
    ' end ## # Lists are paragraphs, but notes and labels have a separator def list_item_start list_item, list_type throw :done if @characters >= @character_limit case list_type when :BULLET, :LALPHA, :NUMBER, :UALPHA then "

    " when :LABEL, :NOTE then labels = Array(list_item.label).map do |label| to_html label end.join ', ' labels << " — " unless labels.empty? start = "

    #{labels}" @characters += 1 # try to include the label start else raise RDoc::Error, "Invalid list type: #{list_type.inspect}" end end ## # Returns just the text of +link+, +url+ is only used to determine the link # type. def gen_url url, text if url =~ /^rdoc-label:([^:]*)(?::(.*))?/ then type = "link" elsif url =~ /([A-Za-z]+):(.*)/ then type = $1 else type = "http" end if (type == "http" or type == "https" or type == "link") and url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then '' else text.sub(%r%^#{type}:/*%, '') end end ## # In snippets, there are no lists def html_list_name list_type, open_tag '' end ## # Throws +:done+ when paragraph_limit paragraphs have been encountered def add_paragraph @paragraphs += 1 throw :done if @paragraphs >= @paragraph_limit end ## # Marks up +content+ def convert content catch :done do return super end end_accepting end ## # Converts flow items +flow+ def convert_flow flow throw :done if @characters >= @character_limit res = [] @mask = 0 flow.each do |item| case item when RDoc::Markup::AttrChanger then off_tags res, item on_tags res, item when String then text = convert_string item res << truncate(text) when RDoc::Markup::Special then text = convert_special item res << truncate(text) else raise "Unknown flow element: #{item.inspect}" end if @characters >= @character_limit then off_tags res, RDoc::Markup::AttrChanger.new(0, @mask) break end end res << ' ...' if @characters >= @character_limit res.join end ## # Maintains a bitmask to allow HTML elements to be closed properly. See # RDoc::Markup::Formatter. def on_tags res, item @mask ^= item.turn_on super end ## # Maintains a bitmask to allow HTML elements to be closed properly. See # RDoc::Markup::Formatter. def off_tags res, item @mask ^= item.turn_off super end ## # Truncates +text+ at the end of the first word after the character_limit. def truncate text length = text.length characters = @characters @characters += length return text if @characters < @character_limit remaining = @character_limit - characters text =~ /\A(.{#{remaining},}?)(\s|$)/m # TODO word-break instead of \s? $1 end end PK!:|\llindented_paragraph.rbnu[## # An Indented Paragraph of text class RDoc::Markup::IndentedParagraph < RDoc::Markup::Raw ## # The indent in number of spaces attr_reader :indent ## # Creates a new IndentedParagraph containing +parts+ indented with +indent+ # spaces def initialize indent, *parts @indent = indent super(*parts) end def == other # :nodoc: super and indent == other.indent end ## # Calls #accept_indented_paragraph on +visitor+ def accept visitor visitor.accept_indented_paragraph self end ## # Joins the raw paragraph text and converts inline HardBreaks to the # +hard_break+ text followed by the indent. def text hard_break = nil @parts.map do |part| if RDoc::Markup::HardBreak === part then '%1$s%3$*2$s' % [hard_break, @indent, ' '] if hard_break else part end end.join end end PK!,\\to_markdown.rbnu[# :markup: markdown ## # Outputs parsed markup as Markdown class RDoc::Markup::ToMarkdown < RDoc::Markup::ToRdoc ## # Creates a new formatter that will output Markdown format text def initialize markup = nil super @headings[1] = ['# ', ''] @headings[2] = ['## ', ''] @headings[3] = ['### ', ''] @headings[4] = ['#### ', ''] @headings[5] = ['##### ', ''] @headings[6] = ['###### ', ''] add_special_RDOCLINK add_special_TIDYLINK @hard_break = " \n" end ## # Maps attributes to HTML sequences def init_tags add_tag :BOLD, '**', '**' add_tag :EM, '*', '*' add_tag :TT, '`', '`' end ## # Adds a newline to the output def handle_special_HARD_BREAK special " \n" end ## # Finishes consumption of `list` def accept_list_end list @res << "\n" super end ## # Finishes consumption of `list_item` def accept_list_item_end list_item width = case @list_type.last when :BULLET then 4 when :NOTE, :LABEL then use_prefix 4 else @list_index[-1] = @list_index.last.succ 4 end @indent -= width end ## # Prepares the visitor for consuming `list_item` def accept_list_item_start list_item type = @list_type.last case type when :NOTE, :LABEL then bullets = Array(list_item.label).map do |label| attributes(label).strip end.join "\n" bullets << "\n:" @prefix = ' ' * @indent @indent += 4 @prefix << bullets + (' ' * (@indent - 1)) else bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.' @prefix = (' ' * @indent) + bullet.ljust(4) @indent += 4 end end ## # Prepares the visitor for consuming `list` def accept_list_start list case list.type when :BULLET, :LABEL, :NOTE then @list_index << nil when :LALPHA, :NUMBER, :UALPHA then @list_index << 1 else raise RDoc::Error, "invalid list type #{list.type}" end @list_width << 4 @list_type << list.type end ## # Adds `rule` to the output def accept_rule rule use_prefix or @res << ' ' * @indent @res << '-' * 3 @res << "\n" end ## # Outputs `verbatim` indented 4 columns def accept_verbatim verbatim indent = ' ' * (@indent + 4) verbatim.parts.each do |part| @res << indent unless part == "\n" @res << part end @res << "\n" unless @res =~ /\n\z/ end ## # Creates a Markdown-style URL from +url+ with +text+. def gen_url url, text scheme, url, = parse_url url "[#{text.sub(%r{^#{scheme}:/*}i, '')}](#{url})" end ## # Handles rdoc- type links for footnotes. def handle_rdoc_link url case url when /^rdoc-ref:/ then $' when /^rdoc-label:footmark-(\d+)/ then "[^#{$1}]:" when /^rdoc-label:foottext-(\d+)/ then "[^#{$1}]" when /^rdoc-label:label-/ then gen_url url, $' when /^rdoc-image:/ then "![](#{$'})" when /^rdoc-[a-z]+:/ then $' end end ## # Converts the RDoc markup tidylink into a Markdown.style link. def handle_special_TIDYLINK special text = special.text return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/ label = $1 url = $2 if url =~ /^rdoc-label:foot/ then handle_rdoc_link url else gen_url url, label end end ## # Converts the rdoc-...: links into a Markdown.style links. def handle_special_RDOCLINK special handle_rdoc_link special.text end end PK!3ɀ to_ansi.rbnu[## # Outputs RDoc markup with vibrant ANSI color! class RDoc::Markup::ToAnsi < RDoc::Markup::ToRdoc ## # Creates a new ToAnsi visitor that is ready to output vibrant ANSI color! def initialize markup = nil super @headings.clear @headings[1] = ["\e[1;32m", "\e[m"] # bold @headings[2] = ["\e[4;32m", "\e[m"] # underline @headings[3] = ["\e[32m", "\e[m"] # just green end ## # Maps attributes to ANSI sequences def init_tags add_tag :BOLD, "\e[1m", "\e[m" add_tag :TT, "\e[7m", "\e[m" add_tag :EM, "\e[4m", "\e[m" end ## # Overrides indent width to ensure output lines up correctly. def accept_list_item_end list_item width = case @list_type.last when :BULLET then 2 when :NOTE, :LABEL then if @prefix then @res << @prefix.strip @prefix = nil end @res << "\n" unless res.length == 1 2 else bullet = @list_index.last.to_s @list_index[-1] = @list_index.last.succ bullet.length + 2 end @indent -= width end ## # Adds coloring to note and label list items def accept_list_item_start list_item bullet = case @list_type.last when :BULLET then '*' when :NOTE, :LABEL then labels = Array(list_item.label).map do |label| attributes(label).strip end.join "\n" labels << ":\n" unless labels.empty? labels else @list_index.last.to_s + '.' end case @list_type.last when :NOTE, :LABEL then @indent += 2 @prefix = bullet + (' ' * @indent) else @prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1) width = bullet.gsub(/\e\[[\d;]*m/, '').length + 1 @indent += width end end ## # Starts accepting with a reset screen def start_accepting super @res = ["\e[0m"] end end PK!U to_label.rbnu[require 'cgi' ## # Creates HTML-safe labels suitable for use in id attributes. Tidylinks are # converted to their link part and cross-reference links have the suppression # marks removed (\\SomeClass is converted to SomeClass). class RDoc::Markup::ToLabel < RDoc::Markup::Formatter attr_reader :res # :nodoc: ## # Creates a new formatter that will output HTML-safe labels def initialize markup = nil super nil, markup @markup.add_special RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF @markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\])/, :TIDYLINK) add_tag :BOLD, '', '' add_tag :TT, '', '' add_tag :EM, '', '' @res = [] end ## # Converts +text+ to an HTML-safe label def convert text label = convert_flow @am.flow text CGI.escape label end ## # Converts the CROSSREF +special+ to plain text, removing the suppression # marker, if any def handle_special_CROSSREF special text = special.text text.sub(/^\\/, '') end ## # Converts the TIDYLINK +special+ to just the text part def handle_special_TIDYLINK special text = special.text return text unless text =~ /\{(.*?)\}\[(.*?)\]/ or text =~ /(\S+)\[(.*?)\]/ $1 end alias accept_blank_line ignore alias accept_block_quote ignore alias accept_heading ignore alias accept_list_end ignore alias accept_list_item_end ignore alias accept_list_item_start ignore alias accept_list_start ignore alias accept_paragraph ignore alias accept_raw ignore alias accept_rule ignore alias accept_verbatim ignore alias end_accepting ignore alias handle_special_HARD_BREAK ignore alias start_accepting ignore end PK!i" include.rbnu[## # A file included at generation time. Objects of this class are created by # RDoc::RD for an extension-less include. # # This implementation in incomplete. class RDoc::Markup::Include ## # The filename to be included, without extension attr_reader :file ## # Directories to search for #file attr_reader :include_path ## # Creates a new include that will import +file+ from +include_path+ def initialize file, include_path @file = file @include_path = include_path end def == other # :nodoc: self.class === other and @file == other.file and @include_path == other.include_path end def pretty_print q # :nodoc: q.group 2, '[incl ', ']' do q.text file q.breakable q.text 'from ' q.pp include_path end end end PK!DKz z document.rbnu[## # A Document containing lists, headings, paragraphs, etc. class RDoc::Markup::Document include Enumerable ## # The file this document was created from. See also # RDoc::ClassModule#add_comment attr_reader :file ## # If a heading is below the given level it will be omitted from the # table_of_contents attr_accessor :omit_headings_below ## # The parts of the Document attr_reader :parts ## # Creates a new Document with +parts+ def initialize *parts @parts = [] @parts.concat parts @file = nil @omit_headings_from_table_of_contents_below = nil end ## # Appends +part+ to the document def << part case part when RDoc::Markup::Document then unless part.empty? then parts.concat part.parts parts << RDoc::Markup::BlankLine.new end when String then raise ArgumentError, "expected RDoc::Markup::Document and friends, got String" unless part.empty? else parts << part end end def == other # :nodoc: self.class == other.class and @file == other.file and @parts == other.parts end ## # Runs this document and all its #items through +visitor+ def accept visitor visitor.start_accepting visitor.accept_document self visitor.end_accepting end ## # Concatenates the given +parts+ onto the document def concat parts self.parts.concat parts end ## # Enumerator for the parts of this document def each &block @parts.each(&block) end ## # Does this document have no parts? def empty? @parts.empty? or (@parts.length == 1 and merged? and @parts.first.empty?) end ## # The file this Document was created from. def file= location @file = case location when RDoc::TopLevel then location.relative_name else location end end ## # When this is a collection of documents (#file is not set and this document # contains only other documents as its direct children) #merge replaces # documents in this class with documents from +other+ when the file matches # and adds documents from +other+ when the files do not. # # The information in +other+ is preferred over the receiver def merge other if empty? then @parts = other.parts return self end other.parts.each do |other_part| self.parts.delete_if do |self_part| self_part.file and self_part.file == other_part.file end self.parts << other_part end self end ## # Does this Document contain other Documents? def merged? RDoc::Markup::Document === @parts.first end def pretty_print q # :nodoc: start = @file ? "[doc (#{@file}): " : '[doc: ' q.group 2, start, ']' do q.seplist @parts do |part| q.pp part end end end ## # Appends +parts+ to the document def push *parts self.parts.concat parts end ## # Returns an Array of headings in the document. # # Require 'rdoc/markup/formatter' before calling this method. def table_of_contents accept RDoc::Markup::ToTableOfContents.to_toc end end PK!1q5 list_item.rbnu[## # An item within a List that contains paragraphs, headings, etc. # # For BULLET, NUMBER, LALPHA and UALPHA lists, the label will always be nil. # For NOTE and LABEL lists, the list label may contain: # # * a single String for a single label # * an Array of Strings for a list item with multiple terms # * nil for an extra description attached to a previously labeled list item class RDoc::Markup::ListItem ## # The label for the ListItem attr_accessor :label ## # Parts of the ListItem attr_reader :parts ## # Creates a new ListItem with an optional +label+ containing +parts+ def initialize label = nil, *parts @label = label @parts = [] @parts.concat parts end ## # Appends +part+ to the ListItem def << part @parts << part end def == other # :nodoc: self.class == other.class and @label == other.label and @parts == other.parts end ## # Runs this list item and all its #parts through +visitor+ def accept visitor visitor.accept_list_item_start self @parts.each do |part| part.accept visitor end visitor.accept_list_item_end self end ## # Is the ListItem empty? def empty? @parts.empty? end ## # Length of parts in the ListItem def length @parts.length end def pretty_print q # :nodoc: q.group 2, '[item: ', ']' do case @label when Array then q.pp @label q.text ';' q.breakable when String then q.pp @label q.text ';' q.breakable end q.seplist @parts do |part| q.pp part end end end ## # Adds +parts+ to the ListItem def push *parts @parts.concat parts end end PK!XT\rule.rbnu[## # A horizontal rule with a weight class RDoc::Markup::Rule < Struct.new :weight ## # Calls #accept_rule on +visitor+ def accept visitor visitor.accept_rule self end def pretty_print q # :nodoc: q.group 2, '[rule:', ']' do q.pp weight end end end PK!\cbattr_changer.rbnu[class RDoc::Markup AttrChanger = Struct.new :turn_on, :turn_off # :nodoc: end ## # An AttrChanger records a change in attributes. It contains a bitmap of the # attributes to turn on, and a bitmap of those to turn off. class RDoc::Markup::AttrChanger def to_s # :nodoc: "Attr: +#{turn_on}/-#{turn_off}" end def inspect # :nodoc: '+%d/-%d' % [turn_on, turn_off] end end PK!},$$ formatter.rbnu[## # Base class for RDoc markup formatters # # Formatters are a visitor that converts an RDoc::Markup tree (from a comment) # into some kind of output. RDoc ships with formatters for converting back to # rdoc, ANSI text, HTML, a Table of Contents and other formats. # # If you'd like to write your own Formatter use # RDoc::Markup::FormatterTestCase. If you're writing a text-output formatter # use RDoc::Markup::TextFormatterTestCase which provides extra test cases. class RDoc::Markup::Formatter ## # Tag for inline markup containing a +bit+ for the bitmask and the +on+ and # +off+ triggers. InlineTag = Struct.new(:bit, :on, :off) ## # Converts a target url to one that is relative to a given path def self.gen_relative_url path, target from = File.dirname path to, to_file = File.split target from = from.split "/" to = to.split "/" from.delete '.' to.delete '.' while from.size > 0 and to.size > 0 and from[0] == to[0] do from.shift to.shift end from.fill ".." from.concat to from << to_file File.join(*from) end ## # Creates a new Formatter def initialize options, markup = nil @options = options @markup = markup || RDoc::Markup.new @am = @markup.attribute_manager @am.add_special(/
    /, :HARD_BREAK) @attributes = @am.attributes @attr_tags = [] @in_tt = 0 @tt_bit = @attributes.bitmap_for :TT @hard_break = '' @from_path = '.' end ## # Adds +document+ to the output def accept_document document document.parts.each do |item| case item when RDoc::Markup::Document then # HACK accept_document item else item.accept self end end end ## # Adds a special for links of the form rdoc-...: def add_special_RDOCLINK @markup.add_special(/rdoc-[a-z]+:[^\s\]]+/, :RDOCLINK) end ## # Adds a special for links of the form {}[] and [] def add_special_TIDYLINK @markup.add_special(/(?: \{.*?\} | # multi-word label \b[^\s{}]+? # single-word label ) \[\S+?\] # link target /x, :TIDYLINK) end ## # Add a new set of tags for an attribute. We allow separate start and end # tags for flexibility def add_tag(name, start, stop) attr = @attributes.bitmap_for name @attr_tags << InlineTag.new(attr, start, stop) end ## # Allows +tag+ to be decorated with additional information. def annotate(tag) tag end ## # Marks up +content+ def convert content @markup.convert content, self end ## # Converts flow items +flow+ def convert_flow(flow) res = [] flow.each do |item| case item when String then res << convert_string(item) when RDoc::Markup::AttrChanger then off_tags res, item on_tags res, item when RDoc::Markup::Special then res << convert_special(item) else raise "Unknown flow element: #{item.inspect}" end end res.join end ## # Converts added specials. See RDoc::Markup#add_special def convert_special special return special.text if in_tt? handled = false @attributes.each_name_of special.type do |name| method_name = "handle_special_#{name}" if respond_to? method_name then special.text = send method_name, special handled = true end end unless handled then special_name = @attributes.as_string special.type raise RDoc::Error, "Unhandled special #{special_name}: #{special}" end special.text end ## # Converts a string to be fancier if desired def convert_string string string end ## # Use ignore in your subclass to ignore the content of a node. # # ## # # We don't support raw nodes in ToNoRaw # # alias accept_raw ignore def ignore *node end ## # Are we currently inside tt tags? def in_tt? @in_tt > 0 end ## # Turns on tags for +item+ on +res+ def on_tags res, item attr_mask = item.turn_on return if attr_mask.zero? @attr_tags.each do |tag| if attr_mask & tag.bit != 0 then res << annotate(tag.on) @in_tt += 1 if tt? tag end end end ## # Turns off tags for +item+ on +res+ def off_tags res, item attr_mask = item.turn_off return if attr_mask.zero? @attr_tags.reverse_each do |tag| if attr_mask & tag.bit != 0 then @in_tt -= 1 if tt? tag res << annotate(tag.off) end end end ## # Extracts and a scheme, url and an anchor id from +url+ and returns them. def parse_url url case url when /^rdoc-label:([^:]*)(?::(.*))?/ then scheme = 'link' path = "##{$1}" id = " id=\"#{$2}\"" if $2 when /([A-Za-z]+):(.*)/ then scheme = $1.downcase path = $2 when /^#/ then else scheme = 'http' path = url url = url end if scheme == 'link' then url = if path[0, 1] == '#' then # is this meaningful? path else self.class.gen_relative_url @from_path, path end end [scheme, url, id] end ## # Is +tag+ a tt tag? def tt? tag tag.bit == @tt_bit end end PK!z!!yy to_rdoc.rbnu[## # Outputs RDoc markup as RDoc markup! (mostly) class RDoc::Markup::ToRdoc < RDoc::Markup::Formatter ## # Current indent amount for output in characters attr_accessor :indent ## # Output width in characters attr_accessor :width ## # Stack of current list indexes for alphabetic and numeric lists attr_reader :list_index ## # Stack of list types attr_reader :list_type ## # Stack of list widths for indentation attr_reader :list_width ## # Prefix for the next list item. See #use_prefix attr_reader :prefix ## # Output accumulator attr_reader :res ## # Creates a new formatter that will output (mostly) \RDoc markup def initialize markup = nil super nil, markup @markup.add_special(/\\\S/, :SUPPRESSED_CROSSREF) @width = 78 init_tags @headings = {} @headings.default = [] @headings[1] = ['= ', ''] @headings[2] = ['== ', ''] @headings[3] = ['=== ', ''] @headings[4] = ['==== ', ''] @headings[5] = ['===== ', ''] @headings[6] = ['====== ', ''] @hard_break = "\n" end ## # Maps attributes to HTML sequences def init_tags add_tag :BOLD, "", "" add_tag :TT, "", "" add_tag :EM, "", "" end ## # Adds +blank_line+ to the output def accept_blank_line blank_line @res << "\n" end ## # Adds +paragraph+ to the output def accept_block_quote block_quote @indent += 2 block_quote.parts.each do |part| @prefix = '> ' part.accept self end @indent -= 2 end ## # Adds +heading+ to the output def accept_heading heading use_prefix or @res << ' ' * @indent @res << @headings[heading.level][0] @res << attributes(heading.text) @res << @headings[heading.level][1] @res << "\n" end ## # Finishes consumption of +list+ def accept_list_end list @list_index.pop @list_type.pop @list_width.pop end ## # Finishes consumption of +list_item+ def accept_list_item_end list_item width = case @list_type.last when :BULLET then 2 when :NOTE, :LABEL then if @prefix then @res << @prefix.strip @prefix = nil end @res << "\n" 2 else bullet = @list_index.last.to_s @list_index[-1] = @list_index.last.succ bullet.length + 2 end @indent -= width end ## # Prepares the visitor for consuming +list_item+ def accept_list_item_start list_item type = @list_type.last case type when :NOTE, :LABEL then bullets = Array(list_item.label).map do |label| attributes(label).strip end.join "\n" bullets << ":\n" unless bullets.empty? @prefix = ' ' * @indent @indent += 2 @prefix << bullets + (' ' * @indent) else bullet = type == :BULLET ? '*' : @list_index.last.to_s + '.' @prefix = (' ' * @indent) + bullet.ljust(bullet.length + 1) width = bullet.length + 1 @indent += width end end ## # Prepares the visitor for consuming +list+ def accept_list_start list case list.type when :BULLET then @list_index << nil @list_width << 1 when :LABEL, :NOTE then @list_index << nil @list_width << 2 when :LALPHA then @list_index << 'a' @list_width << list.items.length.to_s.length when :NUMBER then @list_index << 1 @list_width << list.items.length.to_s.length when :UALPHA then @list_index << 'A' @list_width << list.items.length.to_s.length else raise RDoc::Error, "invalid list type #{list.type}" end @list_type << list.type end ## # Adds +paragraph+ to the output def accept_paragraph paragraph text = paragraph.text @hard_break wrap attributes text end ## # Adds +paragraph+ to the output def accept_indented_paragraph paragraph @indent += paragraph.indent text = paragraph.text @hard_break wrap attributes text @indent -= paragraph.indent end ## # Adds +raw+ to the output def accept_raw raw @res << raw.parts.join("\n") end ## # Adds +rule+ to the output def accept_rule rule use_prefix or @res << ' ' * @indent @res << '-' * (@width - @indent) @res << "\n" end ## # Outputs +verbatim+ indented 2 columns def accept_verbatim verbatim indent = ' ' * (@indent + 2) verbatim.parts.each do |part| @res << indent unless part == "\n" @res << part end @res << "\n" unless @res =~ /\n\z/ end ## # Applies attribute-specific markup to +text+ using RDoc::AttributeManager def attributes text flow = @am.flow text.dup convert_flow flow end ## # Returns the generated output def end_accepting @res.join end ## # Removes preceding \\ from the suppressed crossref +special+ def handle_special_SUPPRESSED_CROSSREF special text = special.text text = text.sub('\\', '') unless in_tt? text end ## # Adds a newline to the output def handle_special_HARD_BREAK special "\n" end ## # Prepares the visitor for text generation def start_accepting @res = [""] @indent = 0 @prefix = nil @list_index = [] @list_type = [] @list_width = [] end ## # Adds the stored #prefix to the output and clears it. Lists generate a # prefix for later consumption. def use_prefix prefix, @prefix = @prefix, nil @res << prefix if prefix prefix end ## # Wraps +text+ to #width def wrap text return unless text && !text.empty? text_len = @width - @indent text_len = 20 if text_len < 20 re = /^(.{0,#{text_len}})[ \n]/ next_prefix = ' ' * @indent prefix = @prefix || next_prefix @prefix = nil @res << prefix while text.length > text_len if text =~ re then @res << $1 text.slice!(0, $&.length) else @res << text.slice!(0, text_len) end @res << "\n" << next_prefix end if text.empty? then @res.pop @res.pop else @res << text @res << "\n" end end end PK!+ to_tt_only.rbnu[## # Extracts sections of text enclosed in plus, tt or code. Used to discover # undocumented parameters. class RDoc::Markup::ToTtOnly < RDoc::Markup::Formatter ## # Stack of list types attr_reader :list_type ## # Output accumulator attr_reader :res ## # Creates a new tt-only formatter. def initialize markup = nil super nil, markup add_tag :TT, nil, nil end ## # Adds tts from +block_quote+ to the output def accept_block_quote block_quote tt_sections block_quote.text end ## # Pops the list type for +list+ from #list_type def accept_list_end list @list_type.pop end ## # Pushes the list type for +list+ onto #list_type def accept_list_start list @list_type << list.type end ## # Prepares the visitor for consuming +list_item+ def accept_list_item_start list_item case @list_type.last when :NOTE, :LABEL then Array(list_item.label).map do |label| tt_sections label end.flatten end end ## # Adds +paragraph+ to the output def accept_paragraph paragraph tt_sections(paragraph.text) end ## # Does nothing to +markup_item+ because it doesn't have any user-built # content def do_nothing markup_item end alias accept_blank_line do_nothing # :nodoc: alias accept_heading do_nothing # :nodoc: alias accept_list_item_end do_nothing # :nodoc: alias accept_raw do_nothing # :nodoc: alias accept_rule do_nothing # :nodoc: alias accept_verbatim do_nothing # :nodoc: ## # Extracts tt sections from +text+ def tt_sections text flow = @am.flow text.dup flow.each do |item| case item when String then @res << item if in_tt? when RDoc::Markup::AttrChanger then off_tags res, item on_tags res, item when RDoc::Markup::Special then @res << convert_special(item) if in_tt? # TODO can this happen? else raise "Unknown flow element: #{item.inspect}" end end res end ## # Returns an Array of items that were wrapped in plus, tt or code. def end_accepting @res.compact end ## # Prepares the visitor for gathering tt sections def start_accepting @res = [] @list_type = [] end end PK!8raw.rbnu[## # A section of text that is added to the output document as-is class RDoc::Markup::Raw ## # The component parts of the list attr_reader :parts ## # Creates a new Raw containing +parts+ def initialize *parts @parts = [] @parts.concat parts end ## # Appends +text+ def << text @parts << text end def == other # :nodoc: self.class == other.class and @parts == other.parts end ## # Calls #accept_raw+ on +visitor+ def accept visitor visitor.accept_raw self end ## # Appends +other+'s parts def merge other @parts.concat other.parts end def pretty_print q # :nodoc: self.class.name =~ /.*::(\w{1,4})/i q.group 2, "[#{$1.downcase}: ", ']' do q.seplist @parts do |part| q.pp part end end end ## # Appends +texts+ onto this Paragraph def push *texts self.parts.concat texts end ## # The raw text def text @parts.join ' ' end end PK!Gattribute_manager.rbnu[## # Manages changes of attributes in a block of text class RDoc::Markup::AttributeManager ## # The NUL character NULL = "\000".freeze #-- # We work by substituting non-printing characters in to the text. For now # I'm assuming that I can substitute a character in the range 0..8 for a 7 # bit character without damaging the encoded string, but this might be # optimistic #++ A_PROTECT = 004 # :nodoc: ## # Special mask character to prevent inline markup handling PROTECT_ATTR = A_PROTECT.chr # :nodoc: ## # The attributes enabled for this markup object. attr_reader :attributes ## # This maps delimiters that occur around words (such as *bold* or +tt+) # where the start and end delimiters and the same. This lets us optimize # the regexp attr_reader :matching_word_pairs ## # And this is used when the delimiters aren't the same. In this case the # hash maps a pattern to the attribute character attr_reader :word_pair_map ## # This maps HTML tags to the corresponding attribute char attr_reader :html_tags ## # A \ in front of a character that would normally be processed turns off # processing. We do this by turning \< into <#{PROTECT} attr_reader :protectable ## # And this maps _special_ sequences to a name. A special sequence is # something like a WikiWord attr_reader :special ## # Creates a new attribute manager that understands bold, emphasized and # teletype text. def initialize @html_tags = {} @matching_word_pairs = {} @protectable = %w[<] @special = [] @word_pair_map = {} @attributes = RDoc::Markup::Attributes.new add_word_pair "*", "*", :BOLD add_word_pair "_", "_", :EM add_word_pair "+", "+", :TT add_html "em", :EM add_html "i", :EM add_html "b", :BOLD add_html "tt", :TT add_html "code", :TT end ## # Return an attribute object with the given turn_on and turn_off bits set def attribute(turn_on, turn_off) RDoc::Markup::AttrChanger.new turn_on, turn_off end ## # Changes the current attribute from +current+ to +new+ def change_attribute current, new diff = current ^ new attribute(new & diff, current & diff) end ## # Used by the tests to change attributes by name from +current_set+ to # +new_set+ def changed_attribute_by_name current_set, new_set current = new = 0 current_set.each do |name| current |= @attributes.bitmap_for(name) end new_set.each do |name| new |= @attributes.bitmap_for(name) end change_attribute(current, new) end ## # Copies +start_pos+ to +end_pos+ from the current string def copy_string(start_pos, end_pos) res = @str[start_pos...end_pos] res.gsub!(/\000/, '') res end ## # Map attributes like textto the sequence # \001\002\001\003, where is a per-attribute specific # character def convert_attrs(str, attrs) # first do matching ones tags = @matching_word_pairs.keys.join("") re = /(^|\W)([#{tags}])([#:\\]?[\w.\/-]+?\S?)\2(\W|$)/ 1 while str.gsub!(re) do attr = @matching_word_pairs[$2] attrs.set_attrs($`.length + $1.length + $2.length, $3.length, attr) $1 + NULL * $2.length + $3 + NULL * $2.length + $4 end # then non-matching unless @word_pair_map.empty? then @word_pair_map.each do |regexp, attr| str.gsub!(regexp) { attrs.set_attrs($`.length + $1.length, $2.length, attr) NULL * $1.length + $2 + NULL * $3.length } end end end ## # Converts HTML tags to RDoc attributes def convert_html(str, attrs) tags = @html_tags.keys.join '|' 1 while str.gsub!(/<(#{tags})>(.*?)<\/\1>/i) { attr = @html_tags[$1.downcase] html_length = $1.length + 2 seq = NULL * html_length attrs.set_attrs($`.length + html_length, $2.length, attr) seq + $2 + seq + NULL } end ## # Converts special sequences to RDoc attributes def convert_specials str, attrs @special.each do |regexp, attribute| str.scan(regexp) do capture = $~.size == 1 ? 0 : 1 s, e = $~.offset capture attrs.set_attrs s, e - s, attribute | @attributes.special end end end ## # Escapes special sequences of text to prevent conversion to RDoc def mask_protected_sequences # protect __send__, __FILE__, etc. @str.gsub!(/__([a-z]+)__/i, "_#{PROTECT_ATTR}_#{PROTECT_ATTR}\\1_#{PROTECT_ATTR}_#{PROTECT_ATTR}") @str.gsub!(/(\A|[^\\])\\([#{Regexp.escape @protectable.join}])/m, "\\1\\2#{PROTECT_ATTR}") @str.gsub!(/\\(\\[#{Regexp.escape @protectable.join}])/m, "\\1") end ## # Unescapes special sequences of text def unmask_protected_sequences @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000") end ## # Adds a markup class with +name+ for words wrapped in the +start+ and # +stop+ character. To make words wrapped with "*" bold: # # am.add_word_pair '*', '*', :BOLD def add_word_pair(start, stop, name) raise ArgumentError, "Word flags may not start with '<'" if start[0,1] == '<' bitmap = @attributes.bitmap_for name if start == stop then @matching_word_pairs[start] = bitmap else pattern = /(#{Regexp.escape start})(\S+)(#{Regexp.escape stop})/ @word_pair_map[pattern] = bitmap end @protectable << start[0,1] @protectable.uniq! end ## # Adds a markup class with +name+ for words surrounded by HTML tag +tag+. # To process emphasis tags: # # am.add_html 'em', :EM def add_html(tag, name) @html_tags[tag.downcase] = @attributes.bitmap_for name end ## # Adds a special handler for +pattern+ with +name+. A simple URL handler # would be: # # @am.add_special(/((https?:)\S+\w)/, :HYPERLINK) def add_special pattern, name @special << [pattern, @attributes.bitmap_for(name)] end ## # Processes +str+ converting attributes, HTML and specials def flow str @str = str mask_protected_sequences @attrs = RDoc::Markup::AttrSpan.new @str.length convert_attrs @str, @attrs convert_html @str, @attrs convert_specials @str, @attrs unmask_protected_sequences split_into_flow end ## # Debug method that prints a string along with its attributes def display_attributes puts puts @str.tr(NULL, "!") bit = 1 16.times do |bno| line = "" @str.length.times do |i| if (@attrs[i] & bit) == 0 line << " " else if bno.zero? line << "S" else line << ("%d" % (bno+1)) end end end puts(line) unless line =~ /^ *$/ bit <<= 1 end end ## # Splits the string into chunks by attribute change def split_into_flow res = [] current_attr = 0 str_len = @str.length # skip leading invisible text i = 0 i += 1 while i < str_len and @str[i].chr == "\0" start_pos = i # then scan the string, chunking it on attribute changes while i < str_len new_attr = @attrs[i] if new_attr != current_attr if i > start_pos res << copy_string(start_pos, i) start_pos = i end res << change_attribute(current_attr, new_attr) current_attr = new_attr if (current_attr & @attributes.special) != 0 then i += 1 while i < str_len and (@attrs[i] & @attributes.special) != 0 res << RDoc::Markup::Special.new(current_attr, copy_string(start_pos, i)) start_pos = i next end end # move on, skipping any invisible characters begin i += 1 end while i < str_len and @str[i].chr == "\0" end # tidy up trailing text if start_pos < str_len res << copy_string(start_pos, str_len) end # and reset to all attributes off res << change_attribute(current_attr, 0) if current_attr != 0 res end end PK!ծA hard_break.rbnu[## # A hard-break in the middle of a paragraph. class RDoc::Markup::HardBreak @instance = new ## # RDoc::Markup::HardBreak is a singleton def self.new @instance end ## # Calls #accept_hard_break on +visitor+ def accept visitor visitor.accept_hard_break self end def == other # :nodoc: self.class === other end def pretty_print q # :nodoc: q.text "[break]" end end PK!vaii blank_line.rbnu[## # An empty line. This class is a singleton. class RDoc::Markup::BlankLine @instance = new ## # RDoc::Markup::BlankLine is a singleton def self.new @instance end ## # Calls #accept_blank_line on +visitor+ def accept visitor visitor.accept_blank_line self end def pretty_print q # :nodoc: q.text 'blankline' end end PK!block_quote.rbnu[## # A quoted section which contains markup items. class RDoc::Markup::BlockQuote < RDoc::Markup::Raw ## # Calls #accept_block_quote on +visitor+ def accept visitor visitor.accept_block_quote self end end PK!>.>to_table_of_contents.rbnu[## # Extracts just the RDoc::Markup::Heading elements from a # RDoc::Markup::Document to help build a table of contents class RDoc::Markup::ToTableOfContents < RDoc::Markup::Formatter @to_toc = nil ## # Singleton for table-of-contents generation def self.to_toc @to_toc ||= new end ## # Output accumulator attr_reader :res ## # Omits headings with a level less than the given level. attr_accessor :omit_headings_below def initialize # :nodoc: super nil @omit_headings_below = nil end ## # Adds +document+ to the output, using its heading cutoff if present def accept_document document @omit_headings_below = document.omit_headings_below super end ## # Adds +heading+ to the table of contents def accept_heading heading @res << heading unless suppressed? heading end ## # Returns the table of contents def end_accepting @res end ## # Prepares the visitor for text generation def start_accepting @omit_headings_below = nil @res = [] end ## # Returns true if +heading+ is below the display threshold def suppressed? heading return false unless @omit_headings_below heading.level > @omit_headings_below end # :stopdoc: alias accept_block_quote ignore alias accept_raw ignore alias accept_rule ignore alias accept_blank_line ignore alias accept_paragraph ignore alias accept_verbatim ignore alias accept_list_end ignore alias accept_list_item_start ignore alias accept_list_item_end ignore alias accept_list_end_bullet ignore alias accept_list_start ignore # :startdoc: end PK!RR*//to_html_crossref.rbnu[## # Subclass of the RDoc::Markup::ToHtml class that supports looking up method # names, classes, etc to create links. RDoc::CrossReference is used to # generate those links based on the current context. class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml # :stopdoc: ALL_CROSSREF_REGEXP = RDoc::CrossReference::ALL_CROSSREF_REGEXP CLASS_REGEXP_STR = RDoc::CrossReference::CLASS_REGEXP_STR CROSSREF_REGEXP = RDoc::CrossReference::CROSSREF_REGEXP METHOD_REGEXP_STR = RDoc::CrossReference::METHOD_REGEXP_STR # :startdoc: ## # RDoc::CodeObject for generating references attr_accessor :context ## # Should we show '#' characters on method references? attr_accessor :show_hash ## # Creates a new crossref resolver that generates links relative to +context+ # which lives at +from_path+ in the generated files. '#' characters on # references are removed unless +show_hash+ is true. Only method names # preceded by '#' or '::' are linked, unless +hyperlink_all+ is true. def initialize(options, from_path, context, markup = nil) raise ArgumentError, 'from_path cannot be nil' if from_path.nil? super options, markup @context = context @from_path = from_path @hyperlink_all = @options.hyperlink_all @show_hash = @options.show_hash crossref_re = @hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP @markup.add_special crossref_re, :CROSSREF @cross_reference = RDoc::CrossReference.new @context end ## # Creates a link to the reference +name+ if the name exists. If +text+ is # given it is used as the link text, otherwise +name+ is used. def cross_reference name, text = nil lookup = name name = name[1..-1] unless @show_hash if name[0, 1] == '#' name = "#{CGI.unescape $'} at #{$1}" if name =~ /(.*[^#:])@/ text = name unless text link lookup, text end ## # We're invoked when any text matches the CROSSREF pattern. If we find the # corresponding reference, generate a link. If the name we're looking for # contains no punctuation, we look for it up the module/class chain. For # example, ToHtml is found, even without the RDoc::Markup:: prefix, # because we look for it in module Markup first. def handle_special_CROSSREF(special) name = special.text return name if name =~ /@[\w-]+\.[\w-]/ # labels that look like emails unless @hyperlink_all then # This ensures that words entirely consisting of lowercase letters will # not have cross-references generated (to suppress lots of erroneous # cross-references to "new" in text, for instance) return name if name =~ /\A[a-z]*\z/ end cross_reference name end ## # Handles rdoc-ref: scheme links and allows RDoc::Markup::ToHtml to # handle other schemes. def handle_special_HYPERLINK special return cross_reference $' if special.text =~ /\Ardoc-ref:/ super end ## # +special+ is an rdoc-schemed link that will be converted into a hyperlink. # For the rdoc-ref scheme the cross-reference will be looked up and the # given name will be used. # # All other contents are handled by # {the superclass}[rdoc-ref:RDoc::Markup::ToHtml#handle_special_RDOCLINK] def handle_special_RDOCLINK special url = special.text case url when /\Ardoc-ref:/ then cross_reference $' else super end end ## # Generates links for rdoc-ref: scheme URLs and allows # RDoc::Markup::ToHtml to handle other schemes. def gen_url url, text return super unless url =~ /\Ardoc-ref:/ cross_reference $', text end ## # Creates an HTML link to +name+ with the given +text+. def link name, text original_name = name if name =~ /(.*[^#:])@/ then name = $1 label = $' end ref = @cross_reference.resolve name, text text = ref.output_name @context if RDoc::MethodAttr === ref and text == original_name case ref when String then ref else path = ref.as_href @from_path if path =~ /#/ then path << "-label-#{label}" elsif ref.sections and ref.sections.any? { |section| label == section.title } then path << "##{label}" else path << "#label-#{label}" end if label "#{text}" end end end PK!u verbatim.rbnu[## # A section of verbatim text class RDoc::Markup::Verbatim < RDoc::Markup::Raw ## # Format of this verbatim section attr_accessor :format def initialize *parts # :nodoc: super @format = nil end def == other # :nodoc: super and @format == other.format end ## # Calls #accept_verbatim on +visitor+ def accept visitor visitor.accept_verbatim self end ## # Collapses 3+ newlines into two newlines def normalize parts = [] newlines = 0 @parts.each do |part| case part when /^\s*\n/ then newlines += 1 parts << part if newlines == 1 else newlines = 0 parts << part end end parts.pop if parts.last =~ /\A\r?\n\z/ @parts = parts end def pretty_print q # :nodoc: self.class.name =~ /.*::(\w{1,4})/i q.group 2, "[#{$1.downcase}: ", ']' do if @format then q.text "format: #{@format}" q.breakable end q.seplist @parts do |part| q.pp part end end end ## # Is this verbatim section Ruby code? def ruby? @format ||= nil # TODO for older ri data, switch the tree to marshal_dump @format == :ruby end ## # The text of the section def text @parts.join end end PK![Baregexp_handling.rbnu[# frozen_string_literal: true ## # Hold details of a regexp handling sequence class RDoc::Markup::RegexpHandling ## # Regexp handling type attr_reader :type ## # Regexp handling text attr_accessor :text ## # Creates a new regexp handling sequence of +type+ with +text+ def initialize(type, text) @type, @text = type, text end ## # Regexp handlings are equal when the have the same text and type def ==(o) self.text == o.text && self.type == o.type end def inspect # :nodoc: "#" % [ object_id, @type, text.dump] end def to_s # :nodoc: "RegexpHandling: type=#{type} text=#{text.dump}" end end PK!S: paragraph.rbnu[## # A Paragraph of text class RDoc::Markup::Paragraph < RDoc::Markup::Raw ## # Calls #accept_paragraph on +visitor+ def accept visitor visitor.accept_paragraph self end ## # Joins the raw paragraph text and converts inline HardBreaks to the # +hard_break+ text. def text hard_break = '' @parts.map do |part| if RDoc::Markup::HardBreak === part then hard_break else part end end.join end end PK!aD pre_process.rbnu[## # Handle common directives that can occur in a block of text: # # \:include: filename # # Directives can be escaped by preceding them with a backslash. # # RDoc plugin authors can register additional directives to be handled by # using RDoc::Markup::PreProcess::register. # # Any directive that is not built-in to RDoc (including those registered via # plugins) will be stored in the metadata hash on the CodeObject the comment # is attached to. See RDoc::Markup@Directives for the list of built-in # directives. class RDoc::Markup::PreProcess ## # An RDoc::Options instance that will be filled in with overrides from # directives attr_accessor :options ## # Adds a post-process handler for directives. The handler will be called # with the result RDoc::Comment (or text String) and the code object for the # comment (if any). def self.post_process &block @post_processors << block end ## # Registered post-processors def self.post_processors @post_processors end ## # Registers +directive+ as one handled by RDoc. If a block is given the # directive will be replaced by the result of the block, otherwise the # directive will be removed from the processed text. # # The block will be called with the directive name and the directive # parameter: # # RDoc::Markup::PreProcess.register 'my-directive' do |directive, param| # # replace text, etc. # end def self.register directive, &block @registered[directive] = block end ## # Registered directives def self.registered @registered end ## # Clears all registered directives and post-processors def self.reset @post_processors = [] @registered = {} end reset ## # Creates a new pre-processor for +input_file_name+ that will look for # included files in +include_path+ def initialize(input_file_name, include_path) @input_file_name = input_file_name @include_path = include_path @options = nil end ## # Look for directives in the given +text+. # # Options that we don't handle are yielded. If the block returns false the # directive is restored to the text. If the block returns nil or no block # was given the directive is handled according to the registered directives. # If a String was returned the directive is replaced with the string. # # If no matching directive was registered the directive is restored to the # text. # # If +code_object+ is given and the directive is unknown then the # directive's parameter is set as metadata on the +code_object+. See # RDoc::CodeObject#metadata for details. def handle text, code_object = nil, &block if RDoc::Comment === text then comment = text text = text.text end encoding = text.encoding if defined?(Encoding) # regexp helper (square brackets for optional) # $1 $2 $3 $4 $5 # [prefix][\]:directive:[spaces][param]newline text.gsub!(/^([ \t]*(?:#|\/?\*)?[ \t]*)(\\?):(\w+):([ \t]*)(.+)?(\r?\n|$)/) do # skip something like ':toto::' next $& if $4.empty? and $5 and $5[0, 1] == ':' # skip if escaped next "#$1:#$3:#$4#$5\n" unless $2.empty? # This is not in handle_directive because I didn't want to pass another # argument into it if comment and $3 == 'markup' then next "#{$1.strip}\n" unless $5 comment.format = $5.downcase next "#{$1.strip}\n" end handle_directive $1, $3, $5, code_object, encoding, &block end comment = text unless comment self.class.post_processors.each do |handler| handler.call comment, code_object end text end ## # Performs the actions described by +directive+ and its parameter +param+. # # +code_object+ is used for directives that operate on a class or module. # +prefix+ is used to ensure the replacement for handled directives is # correct. +encoding+ is used for the include directive. # # For a list of directives in RDoc see RDoc::Markup. #-- # When 1.8.7 support is ditched prefix can be defaulted to '' def handle_directive prefix, directive, param, code_object = nil, encoding = nil blankline = "#{prefix.strip}\n" directive = directive.downcase case directive when 'arg', 'args' then return "#{prefix}:#{directive}: #{param}\n" unless code_object code_object.params = param blankline when 'category' then if RDoc::Context === code_object then section = code_object.add_section param code_object.temporary_section = section end blankline # ignore category if we're not on an RDoc::Context when 'doc' then return blankline unless code_object code_object.document_self = true code_object.force_documentation = true blankline when 'enddoc' then return blankline unless code_object code_object.done_documenting = true blankline when 'include' then filename = param.split.first include_file filename, prefix, encoding when 'main' then @options.main_page = param if @options.respond_to? :main_page blankline when 'nodoc' then return blankline unless code_object code_object.document_self = nil # notify nodoc code_object.document_children = param !~ /all/i blankline when 'notnew', 'not_new', 'not-new' then return blankline unless RDoc::AnyMethod === code_object code_object.dont_rename_initialize = true blankline when 'startdoc' then return blankline unless code_object code_object.start_doc code_object.force_documentation = true blankline when 'stopdoc' then return blankline unless code_object code_object.stop_doc blankline when 'title' then @options.default_title = param if @options.respond_to? :default_title= blankline when 'yield', 'yields' then return blankline unless code_object # remove parameter &block code_object.params.sub!(/,?\s*&\w+/, '') if code_object.params code_object.block_params = param blankline else result = yield directive, param if block_given? case result when nil then code_object.metadata[directive] = param if code_object if RDoc::Markup::PreProcess.registered.include? directive then handler = RDoc::Markup::PreProcess.registered[directive] result = handler.call directive, param if handler else result = "#{prefix}:#{directive}: #{param}\n" end when false then result = "#{prefix}:#{directive}: #{param}\n" end result end end ## # Handles the :include: _filename_ directive. # # If the first line of the included file starts with '#', and contains # an encoding information in the form 'coding:' or 'coding=', it is # removed. # # If all lines in the included file start with a '#', this leading '#' # is removed before inclusion. The included content is indented like # the :include: directive. #-- # so all content will be verbatim because of the likely space after '#'? # TODO shift left the whole file content in that case # TODO comment stop/start #-- and #++ in included file must be processed here def include_file name, indent, encoding full_name = find_include_file name unless full_name then warn "Couldn't find file to include '#{name}' from #{@input_file_name}" return '' end content = RDoc::Encoding.read_file full_name, encoding, true # strip magic comment content = content.sub(/\A# .*coding[=:].*$/, '').lstrip # strip leading '#'s, but only if all lines start with them if content =~ /^[^#]/ then content.gsub(/^/, indent) else content.gsub(/^#?/, indent) end end ## # Look for the given file in the directory containing the current file, # and then in each of the directories specified in the RDOC_INCLUDE path def find_include_file(name) to_search = [File.dirname(@input_file_name)].concat @include_path to_search.each do |dir| full_name = File.join(dir, name) stat = File.stat(full_name) rescue next return full_name if stat.readable? end nil end end PK!!] attr_span.rbnu[## # An array of attributes which parallels the characters in a string. class RDoc::Markup::AttrSpan ## # Creates a new AttrSpan for +length+ characters def initialize(length) @attrs = Array.new(length, 0) end ## # Toggles +bits+ from +start+ to +length+ def set_attrs(start, length, bits) for i in start ... (start+length) @attrs[i] |= bits end end ## # Accesses flags for character +n+ def [](n) @attrs[n] end end PK!88 parser.rbnu[require 'strscan' ## # A recursive-descent parser for RDoc markup. # # The parser tokenizes an input string then parses the tokens into a Document. # Documents can be converted into output formats by writing a visitor like # RDoc::Markup::ToHTML. # # The parser only handles the block-level constructs Paragraph, List, # ListItem, Heading, Verbatim, BlankLine and Rule. Inline markup such as # \+blah\+ is handled separately by RDoc::Markup::AttributeManager. # # To see what markup the Parser implements read RDoc. To see how to use # RDoc markup to format text in your program read RDoc::Markup. class RDoc::Markup::Parser include RDoc::Text ## # List token types LIST_TOKENS = [ :BULLET, :LABEL, :LALPHA, :NOTE, :NUMBER, :UALPHA, ] ## # Parser error subclass class Error < RuntimeError; end ## # Raised when the parser is unable to handle the given markup class ParseError < Error; end ## # Enables display of debugging information attr_accessor :debug ## # Token accessor attr_reader :tokens ## # Parses +str+ into a Document. # # Use RDoc::Markup#parse instead of this method. def self.parse str parser = new parser.tokenize str doc = RDoc::Markup::Document.new parser.parse doc end ## # Returns a token stream for +str+, for testing def self.tokenize str parser = new parser.tokenize str parser.tokens end ## # Creates a new Parser. See also ::parse def initialize @binary_input = nil @current_token = nil @debug = false @have_encoding = Object.const_defined? :Encoding @have_byteslice = ''.respond_to? :byteslice @input = nil @input_encoding = nil @line = 0 @line_pos = 0 @s = nil @tokens = [] end ## # Builds a Heading of +level+ def build_heading level type, text, = get text = case type when :TEXT then skip :NEWLINE text else unget '' end RDoc::Markup::Heading.new level, text end ## # Builds a List flush to +margin+ def build_list margin p :list_start => margin if @debug list = RDoc::Markup::List.new label = nil until @tokens.empty? do type, data, column, = get case type when *LIST_TOKENS then if column < margin || (list.type && list.type != type) then unget break end list.type = type peek_type, _, column, = peek_token case type when :NOTE, :LABEL then label = [] unless label if peek_type == :NEWLINE then # description not on the same line as LABEL/NOTE # skip the trailing newline & any blank lines below while peek_type == :NEWLINE get peek_type, _, column, = peek_token end # we may be: # - at end of stream # - at a column < margin: # [text] # blah blah blah # - at the same column, but with a different type of list item # [text] # * blah blah # - at the same column, with the same type of list item # [one] # [two] # In all cases, we have an empty description. # In the last case only, we continue. if peek_type.nil? || column < margin then empty = true elsif column == margin then case peek_type when type empty = :continue when *LIST_TOKENS empty = true else empty = false end else empty = false end if empty then label << data next if empty == :continue break end end else data = nil end if label then data = label << data label = nil end list_item = RDoc::Markup::ListItem.new data parse list_item, column list << list_item else unget break end end p :list_end => margin if @debug if list.empty? then return nil unless label return nil unless [:LABEL, :NOTE].include? list.type list_item = RDoc::Markup::ListItem.new label, RDoc::Markup::BlankLine.new list << list_item end list end ## # Builds a Paragraph that is flush to +margin+ def build_paragraph margin p :paragraph_start => margin if @debug paragraph = RDoc::Markup::Paragraph.new until @tokens.empty? do type, data, column, = get if type == :TEXT and column == margin then paragraph << data break if peek_token.first == :BREAK data << ' ' if skip :NEWLINE else unget break end end paragraph.parts.last.sub!(/ \z/, '') # cleanup p :paragraph_end => margin if @debug paragraph end ## # Builds a Verbatim that is indented from +margin+. # # The verbatim block is shifted left (the least indented lines start in # column 0). Each part of the verbatim is one line of text, always # terminated by a newline. Blank lines always consist of a single newline # character, and there is never a single newline at the end of the verbatim. def build_verbatim margin p :verbatim_begin => margin if @debug verbatim = RDoc::Markup::Verbatim.new min_indent = nil generate_leading_spaces = true line = '' until @tokens.empty? do type, data, column, = get if type == :NEWLINE then line << data verbatim << line line = '' generate_leading_spaces = true next end if column <= margin unget break end if generate_leading_spaces then indent = column - margin line << ' ' * indent min_indent = indent if min_indent.nil? || indent < min_indent generate_leading_spaces = false end case type when :HEADER then line << '=' * data _, _, peek_column, = peek_token peek_column ||= column + data indent = peek_column - column - data line << ' ' * indent when :RULE then width = 2 + data line << '-' * width _, _, peek_column, = peek_token peek_column ||= column + width indent = peek_column - column - width line << ' ' * indent when :BREAK, :TEXT then line << data else # *LIST_TOKENS list_marker = case type when :BULLET then data when :LABEL then "[#{data}]" when :NOTE then "#{data}::" else # :LALPHA, :NUMBER, :UALPHA "#{data}." end line << list_marker peek_type, _, peek_column = peek_token unless peek_type == :NEWLINE then peek_column ||= column + list_marker.length indent = peek_column - column - list_marker.length line << ' ' * indent end end end verbatim << line << "\n" unless line.empty? verbatim.parts.each { |p| p.slice!(0, min_indent) unless p == "\n" } if min_indent > 0 verbatim.normalize p :verbatim_end => margin if @debug verbatim end ## # The character offset for the input string at the given +byte_offset+ def char_pos byte_offset if @have_byteslice then @input.byteslice(0, byte_offset).length elsif @have_encoding then matched = @binary_input[0, byte_offset] matched.force_encoding @input_encoding matched.length else byte_offset end end ## # Pulls the next token from the stream. def get @current_token = @tokens.shift p :get => @current_token if @debug @current_token end ## # Parses the tokens into an array of RDoc::Markup::XXX objects, # and appends them to the passed +parent+ RDoc::Markup::YYY object. # # Exits at the end of the token stream, or when it encounters a token # in a column less than +indent+ (unless it is a NEWLINE). # # Returns +parent+. def parse parent, indent = 0 p :parse_start => indent if @debug until @tokens.empty? do type, data, column, = get case type when :BREAK then parent << RDoc::Markup::BlankLine.new skip :NEWLINE, false next when :NEWLINE then # trailing newlines are skipped below, so this is a blank line parent << RDoc::Markup::BlankLine.new skip :NEWLINE, false next end # indentation change: break or verbatim if column < indent then unget break elsif column > indent then unget parent << build_verbatim(indent) next end # indentation is the same case type when :HEADER then parent << build_heading(data) when :RULE then parent << RDoc::Markup::Rule.new(data) skip :NEWLINE when :TEXT then unget parse_text parent, indent when *LIST_TOKENS then unget parent << build_list(indent) else type, data, column, line = @current_token raise ParseError, "Unhandled token #{type} (#{data.inspect}) at #{line}:#{column}" end end p :parse_end => indent if @debug parent end ## # Small hook that is overridden by RDoc::TomDoc def parse_text parent, indent # :nodoc: parent << build_paragraph(indent) end ## # Returns the next token on the stream without modifying the stream def peek_token token = @tokens.first || [] p :peek => token if @debug token end ## # Creates the StringScanner def setup_scanner input @line = 0 @line_pos = 0 @input = input.dup if @have_encoding and not @have_byteslice then @input_encoding = @input.encoding @binary_input = @input.force_encoding Encoding::BINARY end @s = StringScanner.new input end ## # Skips the next token if its type is +token_type+. # # Optionally raises an error if the next token is not of the expected type. def skip token_type, error = true type, = get return unless type # end of stream return @current_token if token_type == type unget raise ParseError, "expected #{token_type} got #{@current_token.inspect}" if error end ## # Turns text +input+ into a stream of tokens def tokenize input setup_scanner input until @s.eos? do pos = @s.pos # leading spaces will be reflected by the column of the next token # the only thing we loose are trailing spaces at the end of the file next if @s.scan(/ +/) # note: after BULLET, LABEL, etc., # indent will be the column of the next non-newline token @tokens << case # [CR]LF => :NEWLINE when @s.scan(/\r?\n/) then token = [:NEWLINE, @s.matched, *token_pos(pos)] @line_pos = char_pos @s.pos @line += 1 token # === text => :HEADER then :TEXT when @s.scan(/(=+)(\s*)/) then level = @s[1].length header = [:HEADER, level, *token_pos(pos)] if @s[2] =~ /^\r?\n/ then @s.pos -= @s[2].length header else pos = @s.pos @s.scan(/.*/) @tokens << header [:TEXT, @s.matched.sub(/\r$/, ''), *token_pos(pos)] end # --- (at least 3) and nothing else on the line => :RULE when @s.scan(/(-{3,}) *\r?$/) then [:RULE, @s[1].length - 2, *token_pos(pos)] # * or - followed by white space and text => :BULLET when @s.scan(/([*-]) +(\S)/) then @s.pos -= @s[2].bytesize # unget \S [:BULLET, @s[1], *token_pos(pos)] # A. text, a. text, 12. text => :UALPHA, :LALPHA, :NUMBER when @s.scan(/([a-z]|\d+)\. +(\S)/i) then # FIXME if tab(s), the column will be wrong # either support tabs everywhere by first expanding them to # spaces, or assume that they will have been replaced # before (and provide a check for that at least in debug # mode) list_label = @s[1] @s.pos -= @s[2].bytesize # unget \S list_type = case list_label when /[a-z]/ then :LALPHA when /[A-Z]/ then :UALPHA when /\d/ then :NUMBER else raise ParseError, "BUG token #{list_label}" end [list_type, list_label, *token_pos(pos)] # [text] followed by spaces or end of line => :LABEL when @s.scan(/\[(.*?)\]( +|\r?$)/) then [:LABEL, @s[1], *token_pos(pos)] # text:: followed by spaces or end of line => :NOTE when @s.scan(/(.*?)::( +|\r?$)/) then [:NOTE, @s[1], *token_pos(pos)] # anything else: :TEXT else @s.scan(/(.*?)( )?\r?$/) token = [:TEXT, @s[1], *token_pos(pos)] if @s[2] then @tokens << token [:BREAK, @s[2], *token_pos(pos + @s[1].length)] else token end end end self end ## # Calculates the column (by character) and line of the current token based # on +byte_offset+. def token_pos byte_offset offset = char_pos byte_offset [offset - @line_pos, @line] end ## # Returns the current token to the token stream def unget token = @current_token p :unget => token if @debug raise Error, 'too many #ungets' if token == @tokens.first @tokens.unshift token if token end end PK!AWDaCaCformatter_test_case.rbnu[require 'minitest/unit' ## # Test case for creating new RDoc::Markup formatters. See # test/test_rdoc_markup_to_*.rb for examples. # # This test case adds a variety of tests to your subclass when # #add_visitor_tests is called. Most tests set up a scenario then call a # method you will provide to perform the assertion on the output. # # Your subclass must instantiate a visitor and assign it to @to. # # For example, test_accept_blank_line sets up a RDoc::Markup::BlockLine then # calls accept_blank_line on your visitor. You are responsible for asserting # that the output is correct. # # Example: # # class TestRDocMarkupToNewFormat < RDoc::Markup::FormatterTestCase # # add_visitor_tests # # def setup # super # # @to = RDoc::Markup::ToNewFormat.new # end # # def accept_blank_line # assert_equal :junk, @to.res.join # end # # # ... # # end class RDoc::Markup::FormatterTestCase < RDoc::TestCase ## # Call #setup when inheriting from this test case. # # Provides the following instance variables: # # +@m+:: RDoc::Markup.new # +@RM+:: RDoc::Markup # to reduce typing # +@bullet_list+:: @RM::List.new :BULLET, # ... # +@label_list+:: @RM::List.new :LABEL, # ... # +@lalpha_list+:: @RM::List.new :LALPHA, # ... # +@note_list+:: @RM::List.new :NOTE, # ... # +@number_list+:: @RM::List.new :NUMBER, # ... # +@ualpha_list+:: @RM::List.new :UALPHA, # ... def setup super @options = RDoc::Options.new @m = @RM.new @bullet_list = @RM::List.new(:BULLET, @RM::ListItem.new(nil, @RM::Paragraph.new('l1')), @RM::ListItem.new(nil, @RM::Paragraph.new('l2'))) @label_list = @RM::List.new(:LABEL, @RM::ListItem.new('cat', @RM::Paragraph.new('cats are cool')), @RM::ListItem.new('dog', @RM::Paragraph.new('dogs are cool too'))) @lalpha_list = @RM::List.new(:LALPHA, @RM::ListItem.new(nil, @RM::Paragraph.new('l1')), @RM::ListItem.new(nil, @RM::Paragraph.new('l2'))) @note_list = @RM::List.new(:NOTE, @RM::ListItem.new('cat', @RM::Paragraph.new('cats are cool')), @RM::ListItem.new('dog', @RM::Paragraph.new('dogs are cool too'))) @number_list = @RM::List.new(:NUMBER, @RM::ListItem.new(nil, @RM::Paragraph.new('l1')), @RM::ListItem.new(nil, @RM::Paragraph.new('l2'))) @ualpha_list = @RM::List.new(:UALPHA, @RM::ListItem.new(nil, @RM::Paragraph.new('l1')), @RM::ListItem.new(nil, @RM::Paragraph.new('l2'))) end ## # Call to add the visitor tests to your test case def self.add_visitor_tests class_eval do ## # Calls start_accepting which needs to verify startup state def test_start_accepting @to.start_accepting start_accepting end ## # Calls end_accepting on your test case which needs to call # @to.end_accepting and verify document generation def test_end_accepting @to.start_accepting @to.res << 'hi' end_accepting end ## # Calls accept_blank_line def test_accept_blank_line @to.start_accepting @to.accept_blank_line @RM::BlankLine.new accept_blank_line end ## # Calls accept_block_quote def test_accept_block_quote @to.start_accepting @to.accept_block_quote block para 'quote' accept_block_quote end ## # Test case that calls @to.accept_document def test_accept_document @to.start_accepting @to.accept_document @RM::Document.new @RM::Paragraph.new 'hello' accept_document end ## # Calls accept_heading with a level 5 RDoc::Markup::Heading def test_accept_heading @to.start_accepting @to.accept_heading @RM::Heading.new(5, 'Hello') accept_heading end ## # Calls accept_heading_1 with a level 1 RDoc::Markup::Heading def test_accept_heading_1 @to.start_accepting @to.accept_heading @RM::Heading.new(1, 'Hello') accept_heading_1 end ## # Calls accept_heading_2 with a level 2 RDoc::Markup::Heading def test_accept_heading_2 @to.start_accepting @to.accept_heading @RM::Heading.new(2, 'Hello') accept_heading_2 end ## # Calls accept_heading_3 with a level 3 RDoc::Markup::Heading def test_accept_heading_3 # HACK this doesn't belong here skip "No String#chars, upgrade your ruby" unless ''.respond_to? :chars @to.start_accepting @to.accept_heading @RM::Heading.new(3, 'Hello') accept_heading_3 end ## # Calls accept_heading_4 with a level 4 RDoc::Markup::Heading def test_accept_heading_4 @to.start_accepting @to.accept_heading @RM::Heading.new(4, 'Hello') accept_heading_4 end ## # Calls accept_heading_b with a bold level 1 RDoc::Markup::Heading def test_accept_heading_b @to.start_accepting @to.accept_heading @RM::Heading.new(1, '*Hello*') accept_heading_b end ## # Calls accept_heading_suppressed_crossref with a level 1 # RDoc::Markup::Heading containing a suppressed crossref def test_accept_heading_suppressed_crossref # HACK to_html_crossref test @to.start_accepting @to.accept_heading @RM::Heading.new(1, '\\Hello') accept_heading_suppressed_crossref end ## # Calls accept_paragraph def test_accept_paragraph @to.start_accepting @to.accept_paragraph @RM::Paragraph.new('hi') accept_paragraph end ## # Calls accept_paragraph_b with a RDoc::Markup::Paragraph containing # bold words def test_accept_paragraph_b @to.start_accepting @to.accept_paragraph @RM::Paragraph.new('reg bold words reg') accept_paragraph_b end ## # Calls accept_paragraph_br with a RDoc::Markup::Paragraph containing # a \
    def test_accept_paragraph_br @to.start_accepting @to.accept_paragraph para 'one
    two' accept_paragraph_br end ## # Calls accept_paragraph with a Paragraph containing a hard break def test_accept_paragraph_break @to.start_accepting @to.accept_paragraph para('hello', hard_break, 'world') accept_paragraph_break end ## # Calls accept_paragraph_i with a RDoc::Markup::Paragraph containing # emphasized words def test_accept_paragraph_i @to.start_accepting @to.accept_paragraph @RM::Paragraph.new('reg italic words reg') accept_paragraph_i end ## # Calls accept_paragraph_plus with a RDoc::Markup::Paragraph containing # teletype words def test_accept_paragraph_plus @to.start_accepting @to.accept_paragraph @RM::Paragraph.new('reg +teletype+ reg') accept_paragraph_plus end ## # Calls accept_paragraph_star with a RDoc::Markup::Paragraph containing # bold words def test_accept_paragraph_star @to.start_accepting @to.accept_paragraph @RM::Paragraph.new('reg *bold* reg') accept_paragraph_star end ## # Calls accept_paragraph_underscore with a RDoc::Markup::Paragraph # containing emphasized words def test_accept_paragraph_underscore @to.start_accepting @to.accept_paragraph @RM::Paragraph.new('reg _italic_ reg') accept_paragraph_underscore end ## # Calls accept_verbatim with a RDoc::Markup::Verbatim def test_accept_verbatim @to.start_accepting @to.accept_verbatim @RM::Verbatim.new("hi\n", " world\n") accept_verbatim end ## # Calls accept_raw with a RDoc::Markup::Raw def test_accept_raw @to.start_accepting @to.accept_raw @RM::Raw.new("", "
    NameCount", "
    a1", "
    b2", "
    ") accept_raw end ## # Calls accept_rule with a RDoc::Markup::Rule def test_accept_rule @to.start_accepting @to.accept_rule @RM::Rule.new(4) accept_rule end ## # Calls accept_list_item_start_bullet def test_accept_list_item_start_bullet @to.start_accepting @to.accept_list_start @bullet_list @to.accept_list_item_start @bullet_list.items.first accept_list_item_start_bullet end ## # Calls accept_list_item_start_label def test_accept_list_item_start_label @to.start_accepting @to.accept_list_start @label_list @to.accept_list_item_start @label_list.items.first accept_list_item_start_label end ## # Calls accept_list_item_start_lalpha def test_accept_list_item_start_lalpha @to.start_accepting @to.accept_list_start @lalpha_list @to.accept_list_item_start @lalpha_list.items.first accept_list_item_start_lalpha end ## # Calls accept_list_item_start_note def test_accept_list_item_start_note @to.start_accepting @to.accept_list_start @note_list @to.accept_list_item_start @note_list.items.first accept_list_item_start_note end ## # Calls accept_list_item_start_note_2 def test_accept_list_item_start_note_2 list = list(:NOTE, item('teletype', para('teletype description'))) @to.start_accepting list.accept @to @to.end_accepting accept_list_item_start_note_2 end ## # Calls accept_list_item_start_note_multi_description def test_accept_list_item_start_note_multi_description list = list(:NOTE, item(%w[label], para('description one')), item(nil, para('description two'))) @to.start_accepting list.accept @to @to.end_accepting accept_list_item_start_note_multi_description end ## # Calls accept_list_item_start_note_multi_label def test_accept_list_item_start_note_multi_label list = list(:NOTE, item(%w[one two], para('two headers'))) @to.start_accepting list.accept @to @to.end_accepting accept_list_item_start_note_multi_label end ## # Calls accept_list_item_start_number def test_accept_list_item_start_number @to.start_accepting @to.accept_list_start @number_list @to.accept_list_item_start @number_list.items.first accept_list_item_start_number end ## # Calls accept_list_item_start_ualpha def test_accept_list_item_start_ualpha @to.start_accepting @to.accept_list_start @ualpha_list @to.accept_list_item_start @ualpha_list.items.first accept_list_item_start_ualpha end ## # Calls accept_list_item_end_bullet def test_accept_list_item_end_bullet @to.start_accepting @to.accept_list_start @bullet_list @to.accept_list_item_start @bullet_list.items.first @to.accept_list_item_end @bullet_list.items.first accept_list_item_end_bullet end ## # Calls accept_list_item_end_label def test_accept_list_item_end_label @to.start_accepting @to.accept_list_start @label_list @to.accept_list_item_start @label_list.items.first @to.accept_list_item_end @label_list.items.first accept_list_item_end_label end ## # Calls accept_list_item_end_lalpha def test_accept_list_item_end_lalpha @to.start_accepting @to.accept_list_start @lalpha_list @to.accept_list_item_start @lalpha_list.items.first @to.accept_list_item_end @lalpha_list.items.first accept_list_item_end_lalpha end ## # Calls accept_list_item_end_note def test_accept_list_item_end_note @to.start_accepting @to.accept_list_start @note_list @to.accept_list_item_start @note_list.items.first @to.accept_list_item_end @note_list.items.first accept_list_item_end_note end ## # Calls accept_list_item_end_number def test_accept_list_item_end_number @to.start_accepting @to.accept_list_start @number_list @to.accept_list_item_start @number_list.items.first @to.accept_list_item_end @number_list.items.first accept_list_item_end_number end ## # Calls accept_list_item_end_ualpha def test_accept_list_item_end_ualpha @to.start_accepting @to.accept_list_start @ualpha_list @to.accept_list_item_start @ualpha_list.items.first @to.accept_list_item_end @ualpha_list.items.first accept_list_item_end_ualpha end ## # Calls accept_list_start_bullet def test_accept_list_start_bullet @to.start_accepting @to.accept_list_start @bullet_list accept_list_start_bullet end ## # Calls accept_list_start_label def test_accept_list_start_label @to.start_accepting @to.accept_list_start @label_list accept_list_start_label end ## # Calls accept_list_start_lalpha def test_accept_list_start_lalpha @to.start_accepting @to.accept_list_start @lalpha_list accept_list_start_lalpha end ## # Calls accept_list_start_note def test_accept_list_start_note @to.start_accepting @to.accept_list_start @note_list accept_list_start_note end ## # Calls accept_list_start_number def test_accept_list_start_number @to.start_accepting @to.accept_list_start @number_list accept_list_start_number end ## # Calls accept_list_start_ualpha def test_accept_list_start_ualpha @to.start_accepting @to.accept_list_start @ualpha_list accept_list_start_ualpha end ## # Calls accept_list_end_bullet def test_accept_list_end_bullet @to.start_accepting @to.accept_list_start @bullet_list @to.accept_list_end @bullet_list accept_list_end_bullet end ## # Calls accept_list_end_label def test_accept_list_end_label @to.start_accepting @to.accept_list_start @label_list @to.accept_list_end @label_list accept_list_end_label end ## # Calls accept_list_end_lalpha def test_accept_list_end_lalpha @to.start_accepting @to.accept_list_start @lalpha_list @to.accept_list_end @lalpha_list accept_list_end_lalpha end ## # Calls accept_list_end_number def test_accept_list_end_number @to.start_accepting @to.accept_list_start @number_list @to.accept_list_end @number_list accept_list_end_number end ## # Calls accept_list_end_note def test_accept_list_end_note @to.start_accepting @to.accept_list_start @note_list @to.accept_list_end @note_list accept_list_end_note end ## # Calls accept_list_end_ualpha def test_accept_list_end_ualpha @to.start_accepting @to.accept_list_start @ualpha_list @to.accept_list_end @ualpha_list accept_list_end_ualpha end ## # Calls list_nested with a two-level list def test_list_nested doc = @RM::Document.new( @RM::List.new(:BULLET, @RM::ListItem.new(nil, @RM::Paragraph.new('l1'), @RM::List.new(:BULLET, @RM::ListItem.new(nil, @RM::Paragraph.new('l1.1')))), @RM::ListItem.new(nil, @RM::Paragraph.new('l2')))) doc.accept @to list_nested end ## # Calls list_verbatim with a list containing a verbatim block def test_list_verbatim # HACK overblown doc = doc( list(:BULLET, item(nil, para('list stuff'), blank_line, verb("* list\n", " with\n", "\n", " second\n", "\n", " 1. indented\n", " 2. numbered\n", "\n", " third\n", "\n", "* second\n")))) doc.accept @to list_verbatim end end end end PK!coXX inline.rbnu[warn "requiring rdoc/markup/inline is deprecated and will be removed in RDoc 4." if $-w PK!| text_formatter_test_case.rbnu[## # Test case for creating new plain-text RDoc::Markup formatters. See also # RDoc::Markup::FormatterTestCase # # See test_rdoc_markup_to_rdoc.rb for a complete example. # # Example: # # class TestRDocMarkupToNewTextFormat < RDoc::Markup::TextFormatterTestCase # # add_visitor_tests # add_text_tests # # def setup # super # # @to = RDoc::Markup::ToNewTextFormat.new # end # # def accept_blank_line # assert_equal :junk, @to.res.join # end # # # ... # # end class RDoc::Markup::TextFormatterTestCase < RDoc::Markup::FormatterTestCase ## # Adds test cases to the calling TestCase. def self.add_text_tests self.class_eval do ## # Test case that calls @to.accept_heading def test_accept_heading_indent @to.start_accepting @to.indent = 3 @to.accept_heading @RM::Heading.new(1, 'Hello') accept_heading_indent end ## # Test case that calls @to.accept_rule def test_accept_rule_indent @to.start_accepting @to.indent = 3 @to.accept_rule @RM::Rule.new(1) accept_rule_indent end ## # Test case that calls @to.accept_verbatim def test_accept_verbatim_indent @to.start_accepting @to.indent = 2 @to.accept_verbatim @RM::Verbatim.new("hi\n", " world\n") accept_verbatim_indent end ## # Test case that calls @to.accept_verbatim with a big indent def test_accept_verbatim_big_indent @to.start_accepting @to.indent = 2 @to.accept_verbatim @RM::Verbatim.new("hi\n", "world\n") accept_verbatim_big_indent end ## # Test case that calls @to.accept_paragraph with an indent def test_accept_paragraph_indent @to.start_accepting @to.indent = 3 @to.accept_paragraph @RM::Paragraph.new(('words ' * 30).strip) accept_paragraph_indent end ## # Test case that calls @to.accept_paragraph with a long line def test_accept_paragraph_wrap @to.start_accepting @to.accept_paragraph @RM::Paragraph.new(('words ' * 30).strip) accept_paragraph_wrap end ## # Test case that calls @to.attributes with an escaped # cross-reference. If this test doesn't pass something may be very # wrong. def test_attributes assert_equal 'Dog', @to.attributes("\\Dog") end end end end PK!Gss special.rbnu[## # Hold details of a special sequence class RDoc::Markup::Special ## # Special type attr_reader :type ## # Special text attr_accessor :text ## # Creates a new special sequence of +type+ with +text+ def initialize(type, text) @type, @text = type, text end ## # Specials are equal when the have the same text and type def ==(o) self.text == o.text && self.type == o.type end def inspect # :nodoc: "#" % [ object_id, @type, text.dump] end def to_s # :nodoc: "Special: type=#{type} text=#{text.dump}" end end PK!8TR8R8simple_markup.rbnu[PK!v??8sample/sample.rbnu[PK!^=sample/rdoc2latex.rbnu[PK!w4,,>test/TestParse.rbnu[PK!Z //ktest/AllTests.rbnu[PK!=  cltest/TestInline.rbnu[PK!sp--ŀsimple_markup/to_html.rbnu[PK!):simple_markup/fragments.rbnu[PK!Vڹsimple_markup/preprocess.rbnu[PK!7^!!simple_markup/to_latex.rbnu[PK!""simple_markup/inline.rbnu[PK!k Osimple_markup/lines.rbnu[PK!8aU~~simple_markup/to_flow.rbnu[PK!/ T#heading.rbnu[PK!fР [)attributes.rbnu[PK!'>''8.list.rbnu[PK!H225to_joined_paragraph.rbnu[PK!w!! <to_html.rbnu[PK!$AEbG^to_bs.rbnu[PK!Upp .eto_test.rbnu[PK!?||itable.rbnu[PK!X!nto_html_snippet.rbnu[PK!:|\ll~indented_paragraph.rbnu[PK!,\\/to_markdown.rbnu[PK!3ɀ ɖto_ansi.rbnu[PK!U to_label.rbnu[PK!i" hinclude.rbnu[PK!DKz z document.rbnu[PK!1q5 vlist_item.rbnu[PK!XT\nrule.rbnu[PK!\cb¾attr_changer.rbnu[PK!},$$ formatter.rbnu[PK!z!!yy to_rdoc.rbnu[PK!+ to_tt_only.rbnu[PK!8raw.rbnu[PK!Gattribute_manager.rbnu[PK!ծA hard_break.rbnu[PK!vaii blank_line.rbnu[PK!9block_quote.rbnu[PK!>.>U to_table_of_contents.rbnu[PK!RR*//5'to_html_crossref.rbnu[PK!u 8verbatim.rbnu[PK![Ba=regexp_handling.rbnu[PK!S: @paragraph.rbnu[PK!aD Cpre_process.rbnu[PK!!] cattr_span.rbnu[PK!88 eparser.rbnu[PK!AWDaCaCȞformatter_test_case.rbnu[PK!coXX oinline.rbnu[PK!| text_formatter_test_case.rbnu[PK!Gss <special.rbnu[PK33