diff options
126 files changed, 20701 insertions, 0 deletions
diff --git a/vendor/gems/rdoc-2.4.3/.document b/vendor/gems/rdoc-2.4.3/.document new file mode 100644 index 000000000..1c483f467 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/.document @@ -0,0 +1,4 @@ +History.txt +README.txt +RI.txt +lib diff --git a/vendor/gems/rdoc-2.4.3/.specification b/vendor/gems/rdoc-2.4.3/.specification new file mode 100644 index 000000000..7686b6c1b --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/.specification @@ -0,0 +1,57 @@ +--- !ruby/object:Gem::Specification +name: rdoc +version: !ruby/object:Gem::Version + version: 2.4.3 +platform: ruby +authors: [] + +autorequire: +bindir: bin +cert_chain: [] + +date: 2011-08-24 00:00:00 +01:00 +default_executable: +dependencies: [] + +description: +email: +executables: [] + +extensions: [] + +extra_rdoc_files: [] + +files: +- lib +- lib/rdoc +- lib/rdoc.rb +has_rdoc: false +homepage: +post_install_message: +rdoc_options: [] + +require_paths: +- bin +- bin +- lib +required_ruby_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +required_rubygems_version: !ruby/object:Gem::Requirement + requirements: + - - ">=" + - !ruby/object:Gem::Version + version: "0" + version: +requirements: [] + +rubyforge_project: +rubygems_version: 1.2.0 +signing_key: +specification_version: 2 +summary: +test_files: [] + diff --git a/vendor/gems/rdoc-2.4.3/History.txt b/vendor/gems/rdoc-2.4.3/History.txt new file mode 100644 index 000000000..be15d1420 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/History.txt @@ -0,0 +1,260 @@ +=== 2.4.3 / 2009-04-01 + +* 2 Bug Fixes + * Corrected patch for file links + * Corrected display of file popup + +=== 2.4.2 / 2009-03-25 + +* 2 Minor Enhancements + * Added --pipe for turning RDoc on stdin into HTML + * Added rdoc/task.rb containing a replacement for rake/rdoctask.rb. Use + RDoc::Task now instead of Rake::RDocTask. + +* 10 Bug Fixes + * Writing the ri cache file to the proper directory. Bug #24459 by Lars + Christensen. + * Possible fix for Dir::[] and Pathname interaction on 1.9. Bug #24650 by + tiburon. + * Fixed scanning constants for if/end, etc. pairs. Bug #24609 by Ryan + Davis. + * Fixed private methods in the C parser. Bug #24599 by Aaron Patterson. + * Fixed display of markup on RDoc main page. Bug #24168 by rhubarb. + * Fixed display of \\ character in documentation proceeding words. + Bug #22112 by James Gray. See RDoc for details. + * Fixed parsing and display of arg params for some corner cases. Bug #21113 + by Csiszár Attila. + * Fixed links in Files box. Patch #24403 by Eric Wong. + * Toplevel methods now appear in Object. Bug #22677 by Ryan Davis. + * Added back --promiscuous which didn't do anything you cared about. Why + did you enable it? Nobody looked at that page! Oh, it warns, too. + +=== 2.4.1 / 2009-02-26 + +* 1 Minor Enhancements + * Added :attr:, :attr_reader:, :attr_writer:, :attr_accessor: directives. + Replaces --accessor. See RDoc::Parser::Ruby for details. + +* 3 Bug Fixes + * Don't complain when exiting normally. Bug by Matt Neuburg. + * Restore --inline-source that warns + * Fixed links to files in Darkfish output + +=== 2.4.0 / 2009-02-24 + +* 9 Minor Enhancements + * `ri -f html` is now XHTML-happy + * Clarified RDoc::Markup link syntax. Bug #23517 by Eric Armstrong. + * Number of threads to parse with is now configurable + * Darkfish can now use alternate templates from $LOAD_PATH via -T + * Removed F95 parser in favor of the rdoc-f95 gem + * Moved HTML and XML generators to unmaintained + * No gem will be provided as it's too difficult to make them work + * Removed options --one-file, --style=, --inline-source, --promiscuous, + --op-name + * Removed support for --accessor, use regular documentation or + the method directive instead. See RDoc::Parser::Ruby + * Removed --ri-system as it is unused by Ruby's makefiles + * Added method list to index.html + +* 6 Bug Fixes + * nodoc'd classes no longer appear in the index. Bug #23751 by Clifford + Heath. + * Fix 1.9 compatibility issues. Bug #23815 by paddor. + * Darkfish now respects --charset + * RDoc no longer attempts to be lazy when building HTML. This is a + workaround. Bug #23893 by Stefano Crocco. + * RDoc doesn't crash with def (blah).foo() end + * RDoc doesn't crash with #define functions + +=== 2.3.0 / 2009-01-28 + +* 3 Major Enhancements + * Michael Granger's Darkfish generator is now the default for HTML output + * Various rdoc generation speedups by Hongli Lai. Patches #22555, #22556, + #22557, #22562, #22565. + * rdoc/discover.rb files are loaded automatically from installed gems + +* 8 Minor Enhancements + * Added a space after the commas in ri class method lists. RubyForge + enhancement #22182. + * Improved ri --interactive + * Generators can now override generated file locations + * Moved unmaintained CHM generator to it's own package + * Moved unmaintained extra HTML templates to their own package + * Removed experimental texinfo generator + * Converted to minitest + * Known classes and modules list outputs once per line now for grep + +* 11 Bug Fixes + * Fix missing superclass in ri output + * Fix an RDoc crash when told to parse an empty file + * Ignore nonexistent files instead of crashing + * .txt and .rdoc files are always considered text. Patch #22897 by Aaron + Patterson. + * When merging ri data with a nonexistant directory, RDoc no longer crashes + * Fix visibility of methods in XML output. Issue by Yehuda Katz. + * Fixed relative link generation + * Fix crash, RDoc now ignores comments above local variable assignments in + modules + * RDoc now only accepts adjacent comments for rb_define_module and + rb_define_class + * C file RDoc is no longer included in token stream + * Scan all gem paths to match gem name for ri output + +=== 2.2.1 / 2008-09-24 +This version provides some minor fixes and enhancements to 2.2.0 intended +to polish RDoc for Ruby 1.9.1. + +* 3 Minor Enhancements + * Support for parsing RDoc from SWIG. Ruby patch #10742 by Gonzalo + Garramuno, #13993 by Steven Jenkins. + * Simple support for Perl POD documentation. Patch by Hugh Sasse. + * Changed the default character set of RDoc's output from iso-8859-1 to + utf-8. + +* 9 Bug Fixes + * Explicitly set the html template's text color, so that the generated + documentation will display correctly on browsers with custom text and + background color settings (patch by Luther Thompson). + * Ensure that RDoc correctly will associate an alias and a method, even + if it encounters the alias first because the alias lives in a different + file. + * Fix the parsing of multiline constants (patch by Chris Alfeld and + Joel VanderWerf) + * Make --exclude usuable. Ruby patch #11671 by Trans. + * Detect inline C functions. Ruby Bug #11993 by Florian Frank. + * Fix an issue in which RDoc might not document a class' + superclass correctly if the class was defined in multiple files and + depending on the order in which RDoc processed the files. This should + ensure that the child class -> parent class relationship is correct in + ri documentation, allowing ri to lookup inherited methods (i.e., File.read). + * Stop ri from crashing when it looks for a completely bogus method (i.e., + File#reada). Now, ri exits with a helpful error message. + * Fixed missing display of constant values in ri. + * Fixed display of constants in ri's html output. + +=== 2.2.0 / 2008-09-19 +This version includes some significant enhancements to ri. See RI.txt for +documentation about ri. + +* 5 Major Enhancements + * More extensive unit tests (special thanks to Chris Lowis for contributing + a test). + * Made ri twice as fast for the most common use case of displaying + information for a class or a fully-qualified method + (i.e., ri Array#flatten, after ri has created a cache the first time that + it runs). + * Made ri many times faster when searching for an unqualified method (i.e., + ri read, again after the first such search has populated ri's cache) + * Changed ri to do regular expression searches for unqualified methods; + now, a regular expression for a method can be passed to ri on the + command-line. + * Added an interactive mode to ri (patch by Daniel Choi). Now, when ri + is given a -i argument, it will allow the user to disambiguate + unqualified methods if more than one is present and also will allow a + user to get information for a class' method. + +* 8 Minor Enhancements + * RDoc now adds the package title to the web pages that it generates + for files and classes/modules, which helps them appear better in + search engine results. + * RDoc now automatically generates cross-reference links for classes and + methods specified relative to the global namespace (i.e., ::A::B::C#method). + * All built-in templates now output valid, strict XHTML. + * The documentation is slightly better organized (the markup details were + merged into the RDoc module's documentation). + * Improved rdoc's HTML generation speed by about 20% (on Windows, the + boost seems larger). + * Provided an ri command-line option to control its caching behavior. + * Improved RDoc's documentation. Added RI.txt to document ri. + * Allow HTML templates distributed as gems to be loaded with the -T option, + just like the standard templates in rdoc/generator/html (so an HTML + template lib/new_template.rb in a gem can be used with rdoc -T new_template) + +* 25 Bug fixes: + * Fixed prototype detection in C parser. Can process ruby 1.8 C files + again. + * Fixed the main page for frameless template. Patch by Marcin Raczkowski. + * Fixed the main page for frame templates. Now, if no main page is + specified, RDoc will default to the README. + * Fixed missing stylesheet in generated chm. Patch by Gordon Thiesfeld. + * Fixed the parsing of module names starting with '::'. Patch by + Giuseppe Bilotta. + * Fixed a case where RDoc first would encounter Foo::Bar and then would + encounter class Foo. Previously, RDoc erroneously would have considered + that both a Foo class and a Foo module existed. + * Fix a clase where RDoc would not generate correct cross-reference links + to a class contained within a module of the same name (i.e. RDoc::RDoc) + * Prevented RDoc from trying to parse binary files, which would produce + garbage output. + * RDoc now correctly converts ' characters to apostrophes, opening single + quotes, and closing single quotes in most cases (smart single quotes). + * RDoc now correctly converts " characters to opening double quotes and + and closing double quotes in most cases (smart double quotes). + * (c) correctly is converted into the copyright symbol. + * '&' characters in text now correctly are translated to HTML character codes. + * Fixed missing stylesheet in generated chm. Patch by Gordon Thiesfeld. + * Fixed broken method links in the built-in templates. + * RDoc properly links to files and classes in the one page HTML template. + * The kilmer and hefss templates properly syntax highlight when inlining + source code. + * The kilmer and hefss template class pages properly display methods again. + * Fixed broken class, file, and method links in the frameless template. + * Fixed the clipping of source code in the html and frameless templates when + the source code cannot fit into the window; a scrollbar now will allow + all of the source code to be viewed. + * Fixed the missing constant descriptions in the html and frameless + templates. + * Fixed the ri command-line options that customize the directories to be + searched for documentation. + * Fixed the XML generator. Patch by Anthony Durity. + * Stopped the XML template from generating invalid XML due to malformed + embedded ruby. + * Adding missing information about a class' constants to the XML template. + * Fixed the horizontal rule markup (---) so that it correctly adds a + horizontal rule rather than suppressing all text that follows. + +=== 2.1.0 / 2008-07-20 + +* 3 Major Enhancements: + * RDoc now knows about meta-programmed methods, see RDoc::Parser::Ruby + * Reorganized parsers under RDoc::Parser base class + * ri now walks the ancestors of a class looking for a method e.g. ri + File#read displays documentation for IO#read (may require regeneration of + ri data) +* 5 Minor Enhancements: + * Allow links to files + * Default options now taken from RDOCOPT environment variable + * Class method documentation can be found at toplevel now (def X.foo) + * Allow HTML templates distributed as gems to be loaded with the -T option, + just like the standard templates in rdoc/generator/html (so an HTML + template lib/new_template.rb in a gem can be used with rdoc -T new_template) + * `rdoc -v` prints out files, classes, modules and methods as it goes +* 11 Bug Fixes: + * `ri Foo.bar` now looks for class methods also + * Sections work in the default template again + * Doesn't warn about :foo:: list item being an unrecognized directive + * RDoc no longer converts characters inside tt tags + * Fixed "unitialized constant RDoc::Markup::ToHtml::HTML" + * Fixed generation of relative links + * Fixed various diagram generation issues + * Fixed templates broken by switch to erb + * Fixed issue with <!-- --> style comments + * Lowercase words are no longer rdoc'd as methods without leading #, as + described in the documentation + * RDoc now correctly sets superclasses if they were originally unknown + +=== 2.0.0 / 2008-04-10 + +* 3 Major Enhancements: + * Renamespaced everything RDoc under the RDoc module. + * New `ri` implementation. + * Reads from a cache in ~/.ri/ for enhanced speed. + * RubyGems aware, only searches latest gem versions. + * Now up to over 100 tests and 200 assertions. +* 4 Minor Enhancements: + * Switched to an ERb-based TemplatePage, see RDoc::TemplatePage. + * Class/module ri now displays attribute and constant comments. + * Cross-references can be disabled with a leading \. + * Relaxed parsing for some RDoc inline markup. diff --git a/vendor/gems/rdoc-2.4.3/Manifest.txt b/vendor/gems/rdoc-2.4.3/Manifest.txt new file mode 100644 index 000000000..bccf64e52 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/Manifest.txt @@ -0,0 +1,126 @@ +.autotest +.document +History.txt +Manifest.txt +README.txt +RI.txt +Rakefile +bin/rdoc +bin/ri +lib/rdoc.rb +lib/rdoc/alias.rb +lib/rdoc/anon_class.rb +lib/rdoc/any_method.rb +lib/rdoc/attr.rb +lib/rdoc/cache.rb +lib/rdoc/class_module.rb +lib/rdoc/code_object.rb +lib/rdoc/code_objects.rb +lib/rdoc/constant.rb +lib/rdoc/context.rb +lib/rdoc/diagram.rb +lib/rdoc/dot.rb +lib/rdoc/generator.rb +lib/rdoc/generator/darkfish.rb +lib/rdoc/generator/markup.rb +lib/rdoc/generator/ri.rb +lib/rdoc/generator/template/darkfish/.document +lib/rdoc/generator/template/darkfish/classpage.rhtml +lib/rdoc/generator/template/darkfish/filepage.rhtml +lib/rdoc/generator/template/darkfish/images/brick.png +lib/rdoc/generator/template/darkfish/images/brick_link.png +lib/rdoc/generator/template/darkfish/images/bug.png +lib/rdoc/generator/template/darkfish/images/bullet_black.png +lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png +lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png +lib/rdoc/generator/template/darkfish/images/date.png +lib/rdoc/generator/template/darkfish/images/find.png +lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif +lib/rdoc/generator/template/darkfish/images/macFFBgHack.png +lib/rdoc/generator/template/darkfish/images/package.png +lib/rdoc/generator/template/darkfish/images/page_green.png +lib/rdoc/generator/template/darkfish/images/page_white_text.png +lib/rdoc/generator/template/darkfish/images/page_white_width.png +lib/rdoc/generator/template/darkfish/images/plugin.png +lib/rdoc/generator/template/darkfish/images/ruby.png +lib/rdoc/generator/template/darkfish/images/tag_green.png +lib/rdoc/generator/template/darkfish/images/wrench.png +lib/rdoc/generator/template/darkfish/images/wrench_orange.png +lib/rdoc/generator/template/darkfish/images/zoom.png +lib/rdoc/generator/template/darkfish/index.rhtml +lib/rdoc/generator/template/darkfish/js/darkfish.js +lib/rdoc/generator/template/darkfish/js/jquery.js +lib/rdoc/generator/template/darkfish/js/quicksearch.js +lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js +lib/rdoc/generator/template/darkfish/rdoc.css +lib/rdoc/ghost_method.rb +lib/rdoc/include.rb +lib/rdoc/known_classes.rb +lib/rdoc/markup.rb +lib/rdoc/markup/attribute_manager.rb +lib/rdoc/markup/formatter.rb +lib/rdoc/markup/fragments.rb +lib/rdoc/markup/inline.rb +lib/rdoc/markup/lines.rb +lib/rdoc/markup/preprocess.rb +lib/rdoc/markup/to_flow.rb +lib/rdoc/markup/to_html.rb +lib/rdoc/markup/to_html_crossref.rb +lib/rdoc/markup/to_latex.rb +lib/rdoc/markup/to_test.rb +lib/rdoc/markup/to_texinfo.rb +lib/rdoc/meta_method.rb +lib/rdoc/normal_class.rb +lib/rdoc/normal_module.rb +lib/rdoc/options.rb +lib/rdoc/parser.rb +lib/rdoc/parser/c.rb +lib/rdoc/parser/perl.rb +lib/rdoc/parser/ruby.rb +lib/rdoc/parser/simple.rb +lib/rdoc/rdoc.rb +lib/rdoc/require.rb +lib/rdoc/ri.rb +lib/rdoc/ri/cache.rb +lib/rdoc/ri/descriptions.rb +lib/rdoc/ri/display.rb +lib/rdoc/ri/driver.rb +lib/rdoc/ri/formatter.rb +lib/rdoc/ri/paths.rb +lib/rdoc/ri/reader.rb +lib/rdoc/ri/util.rb +lib/rdoc/ri/writer.rb +lib/rdoc/single_class.rb +lib/rdoc/stats.rb +lib/rdoc/task.rb +lib/rdoc/tokenstream.rb +lib/rdoc/top_level.rb +test/binary.dat +test/test.ja.rdoc +test/test.ja.txt +test/test_attribute_manager.rb +test/test_rdoc_any_method.rb +test/test_rdoc_code_object.rb +test/test_rdoc_constant.rb +test/test_rdoc_context.rb +test/test_rdoc_include.rb +test/test_rdoc_markup.rb +test/test_rdoc_markup_attribute_manager.rb +test/test_rdoc_markup_to_html.rb +test/test_rdoc_markup_to_html_crossref.rb +test/test_rdoc_normal_module.rb +test/test_rdoc_parser.rb +test/test_rdoc_parser_c.rb +test/test_rdoc_parser_perl.rb +test/test_rdoc_parser_ruby.rb +test/test_rdoc_require.rb +test/test_rdoc_ri_attribute_formatter.rb +test/test_rdoc_ri_default_display.rb +test/test_rdoc_ri_driver.rb +test/test_rdoc_ri_formatter.rb +test/test_rdoc_ri_html_formatter.rb +test/test_rdoc_ri_overstrike_formatter.rb +test/test_rdoc_task.rb +test/test_rdoc_top_level.rb +test/xref_data.rb +test/xref_test_case.rb diff --git a/vendor/gems/rdoc-2.4.3/README.txt b/vendor/gems/rdoc-2.4.3/README.txt new file mode 100644 index 000000000..14a5c3134 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/README.txt @@ -0,0 +1,47 @@ += \RDoc + +* {RDoc Project Page}[http://rubyforge.org/projects/rdoc/] +* {RDoc Documentation}[http://rdoc.rubyforge.org/] +* {RDoc Bug Tracker}[http://rubyforge.org/tracker/?atid=2472&group_id=627&func=browse] + +== DESCRIPTION: + +RDoc is an application that produces documentation for one or more Ruby source +files. RDoc includes the +rdoc+ and +ri+ tools for generating and displaying +online documentation. + +At this point in time, RDoc 2.x is a work in progress and may incur further +API changes beyond what has been made to RDoc 1.0.1. Command-line tools are +largely unaffected, but internal APIs may shift rapidly. + +See RDoc for a description of RDoc's markup and basic use. + +== SYNOPSIS: + + gem 'rdoc' + require 'rdoc/rdoc' + # ... see RDoc + +== BUGS: + +The markup engine has lots of little bugs. In particular: +* Escaping does not work for all markup. +* Typesetting is not always correct. +* Some output formats (ri, for example) do not correctly handle all of the + markup. + +RDoc has some subtle bugs processing classes that are split across multiple +files (bugs that may or may not manifest depending on the order in which +the files are encountered). This issue can be tracked here[http://rubyforge.org/tracker/index.php?func=detail&aid=22135&group_id=627&atid=2475]. + +If you find a bug, please report it at the RDoc project's +tracker[http://rubyforge.org/tracker/?group_id=627] on RubyForge: + +== LICENSE: + +RDoc is Copyright (c) 2001-2003 Dave Thomas, The Pragmatic Programmers. +Portions (c) 2007-2009 Eric Hodel. Portions copyright others, see individual +files for details. + +It is free software, and may be redistributed under the terms specified in the +README file of the Ruby distribution. diff --git a/vendor/gems/rdoc-2.4.3/RI.txt b/vendor/gems/rdoc-2.4.3/RI.txt new file mode 100644 index 000000000..27f9e2be7 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/RI.txt @@ -0,0 +1,58 @@ += RI +== Background ++ri+ is a tool that allows Ruby documentation to be viewed on the command-line. +It is part of RDoc and is expected to work on any platform supported by Ruby. + ++ri+ will be a bit slow the first time that it runs (or any time that the +underlying documentation changes) because it builds a cache in the +.ri+ +directory within the user's home directory in order to make future accesses +faster. + +== Usage +To see information for a class, do: + ri class_name + +For example, for the +Array+ class, do + ri Array + +To see information for an instance method, do: + ri class_name#method_name + +For example, for Array's +join+ method, do: + ri Array#join + +To see information for a class method, do: + ri class_name.method_name + +For example, for Module's +private+ method, do: + ri Module.private + +To search for all methods containing +read+, do: + ri read + +To search for all methods starting with +read+, do: + ri '^read' + +To search for all +read+ methods, do: + ri '^read$' + +== Options ++ri+ supports a variety of options, all of which can be viewed via +--help+. +Of particular interest, are: +[-d directory] + List of directories from which to source documentation in addition to + the standard directories. May be repeated. This can be used to specify + the location of site-specific documentation (which can be generated with + RDoc). +[-i] + This makes +ri+ go into interactive mode. When +ri+ is in interactive mode, + it will allow the user to disambiguate lists of methods in case multiple + methods match against a method search string. It also will allow the user + to enter in a method name (with auto-completion, if readline is supported) + when viewing a class. +[-T] + Send output to stdout, rather than to a pager. + +All options also can be specified through the +RI+ environment variable. +Command-line options always override those specified in the +RI+ environment +variable. diff --git a/vendor/gems/rdoc-2.4.3/Rakefile b/vendor/gems/rdoc-2.4.3/Rakefile new file mode 100644 index 000000000..efe2e5635 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/Rakefile @@ -0,0 +1,71 @@ +require 'hoe' + +$rdoc_rakefile = true + +$:.unshift 'lib' +require 'rdoc' + +Hoe.new "rdoc", RDoc::VERSION do |rdoc| + rdoc.developer 'Eric Hodel', 'drbrain@segment7.net' + rdoc.developer 'Dave Thomas', '' + rdoc.developer 'Phil Hagelberg', 'technomancy@gmail.com' + rdoc.developer 'Tony Strauss', 'tony.strauss@designingpatterns.com' + rdoc.remote_rdoc_dir = '' + rdoc.testlib = :minitest + + rdoc.extra_dev_deps << ['minitest', '~> 1.3'] + rdoc.spec_extras['required_rubygems_version'] = '>= 1.3' + rdoc.spec_extras['homepage'] = 'http://rdoc.rubyforge.org' +end + +# These tasks expect to have the following directory structure: +# +# git/git.rubini.us/code # Rubinius git HEAD checkout +# svn/ruby/trunk # ruby subversion HEAD checkout +# svn/rdoc/trunk # RDoc subversion HEAD checkout +# +# If you don't have this directory structure, set RUBY_PATH and/or +# RUBINIUS_PATH. + +diff_options = "-urpN --exclude '*svn*' --exclude '*swp' --exclude '*rbc'" +rsync_options = "-avP --exclude '*svn*' --exclude '*swp' --exclude '*rbc' --exclude '*.rej' --exclude '*.orig'" + +rubinius_dir = ENV['RUBINIUS_PATH'] || '../../../git/git.rubini.us/code' +ruby_dir = ENV['RUBY_PATH'] || '../../ruby/trunk' + +desc "Updates Ruby HEAD with the currently checked-out copy of RDoc." +task :update_ruby do + sh "rsync #{rsync_options} bin/rdoc #{ruby_dir}/bin/rdoc" + sh "rsync #{rsync_options} bin/ri #{ruby_dir}/bin/ri" + sh "rsync #{rsync_options} lib/ #{ruby_dir}/lib" + sh "rsync #{rsync_options} test/ #{ruby_dir}/test/rdoc" +end + +desc "Diffs Ruby HEAD with the currently checked-out copy of RDoc." +task :diff_ruby do + options = "-urpN --exclude '*svn*' --exclude '*swp' --exclude '*rbc'" + + sh "diff #{diff_options} bin/rdoc #{ruby_dir}/bin/rdoc; true" + sh "diff #{diff_options} bin/ri #{ruby_dir}/bin/ri; true" + sh "diff #{diff_options} lib/rdoc.rb #{ruby_dir}/lib/rdoc.rb; true" + sh "diff #{diff_options} lib/rdoc #{ruby_dir}/lib/rdoc; true" + sh "diff #{diff_options} test #{ruby_dir}/test/rdoc; true" +end + +desc "Updates Rubinius HEAD with the currently checked-out copy of RDoc." +task :update_rubinius do + sh "rsync #{rsync_options} bin/rdoc #{rubinius_dir}/lib/bin/rdoc.rb" + sh "rsync #{rsync_options} bin/ri #{rubinius_dir}/lib/bin/ri.rb" + sh "rsync #{rsync_options} lib/ #{rubinius_dir}/lib" + sh "rsync #{rsync_options} test/ #{rubinius_dir}/test/rdoc" +end + +desc "Diffs Rubinius HEAD with the currently checked-out copy of RDoc." +task :diff_rubinius do + sh "diff #{diff_options} bin/rdoc #{rubinius_dir}/lib/bin/rdoc.rb; true" + sh "diff #{diff_options} bin/ri #{rubinius_dir}/lib/bin/ri.rb; true" + sh "diff #{diff_options} lib/rdoc.rb #{rubinius_dir}/lib/rdoc.rb; true" + sh "diff #{diff_options} lib/rdoc #{rubinius_dir}/lib/rdoc; true" + sh "diff #{diff_options} test #{rubinius_dir}/test/rdoc; true" +end + diff --git a/vendor/gems/rdoc-2.4.3/bin/rdoc b/vendor/gems/rdoc-2.4.3/bin/rdoc new file mode 100755 index 000000000..a94f4232e --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/bin/rdoc @@ -0,0 +1,35 @@ +#!/usr/bin/env ruby +# +# RDoc: Documentation tool for source code +# (see lib/rdoc/rdoc.rb for more information) +# +# Copyright (c) 2003 Dave Thomas +# Released under the same terms as Ruby +# +# $Revision: 15033 $ + +require 'rdoc/rdoc' + +begin + r = RDoc::RDoc.new + r.document ARGV +rescue Interrupt + $stderr.puts + $stderr.puts "Interrupted" + exit 1 +rescue SystemExit + raise +rescue Exception => e + if $DEBUG_RDOC then + $stderr.puts e.message + $stderr.puts "#{e.backtrace.join "\n\t"}" + $stderr.puts + else + $stderr.puts "uh-oh! RDoc had a problem:" + $stderr.puts e.message + $stderr.puts + $stderr.puts "run with --debug for full backtrace" + end + exit 1 +end + diff --git a/vendor/gems/rdoc-2.4.3/bin/ri b/vendor/gems/rdoc-2.4.3/bin/ri new file mode 100755 index 000000000..243557403 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/bin/ri @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby + +require 'rdoc/ri/driver' + +RDoc::RI::Driver.run ARGV diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc.rb new file mode 100644 index 000000000..bb085ec15 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc.rb @@ -0,0 +1,398 @@ +$DEBUG_RDOC = nil + +# :main: README.txt + +## +# = \RDoc - Ruby Documentation System +# +# This package contains RDoc and RDoc::Markup. RDoc is an application that +# produces documentation for one or more Ruby source files. It works similarly +# to JavaDoc, parsing the source, and extracting the definition for classes, +# modules, and methods (along with includes and requires). It associates with +# these optional documentation contained in the immediately preceding comment +# block, and then renders the result using a pluggable output formatter. +# RDoc::Markup is a library that converts plain text into various output +# formats. The markup library is used to interpret the comment blocks that +# RDoc uses to document methods, classes, and so on. +# +# == Roadmap +# +# * If you want to use RDoc to create documentation for your Ruby source files, +# read on. +# * If you want to include extensions written in C, see RDoc::Parser::C +# * If you want to drive RDoc programmatically, see RDoc::RDoc. +# * If you want to use the library to format text blocks into HTML, have a look +# at RDoc::Markup. +# * If you want to try writing your own HTML output template, see +# RDoc::Generator::HTML +# +# == Summary +# +# Once installed, you can create documentation using the +rdoc+ command +# +# % rdoc [options] [names...] +# +# For an up-to-date option summary, type +# % rdoc --help +# +# A typical use might be to generate documentation for a package of Ruby +# source (such as RDoc itself). +# +# % rdoc +# +# This command generates documentation for all the Ruby and C source +# files in and below the current directory. These will be stored in a +# documentation tree starting in the subdirectory +doc+. +# +# You can make this slightly more useful for your readers by having the +# index page contain the documentation for the primary file. In our +# case, we could type +# +# % rdoc --main rdoc.rb +# +# You'll find information on the various formatting tricks you can use +# in comment blocks in the documentation this generates. +# +# RDoc uses file extensions to determine how to process each file. File names +# ending +.rb+ and +.rbw+ are assumed to be Ruby source. Files +# ending +.c+ are parsed as C files. All other files are assumed to +# contain just Markup-style markup (with or without leading '#' comment +# markers). If directory names are passed to RDoc, they are scanned +# recursively for C and Ruby source files only. +# +# == \Options +# +# rdoc can be passed a variety of command-line options. In addition, +# options can be specified via the +RDOCOPT+ environment variable, which +# functions similarly to the +RUBYOPT+ environment variable. +# +# % export RDOCOPT="-S" +# +# will make rdoc default to inline method source code. Command-line options +# always will override those in +RDOCOPT+. +# +# Run: +# +# rdoc --help +# +# for full details on rdoc's options. +# +# == Documenting Source Code +# +# Comment blocks can be written fairly naturally, either using <tt>#</tt> on +# successive lines of the comment, or by including the comment in +# a =begin/=end block. If you use the latter form, the =begin line must be +# flagged with an RDoc tag: +# +# =begin rdoc +# Documentation to be processed by RDoc. +# +# ... +# =end +# +# RDoc stops processing comments if it finds a comment line containing +# a <tt>--</tt>. This can be used to separate external from internal +# comments, or to stop a comment being associated with a method, class, or +# module. Commenting can be turned back on with a line that starts with a +# <tt>++</tt>. +# +# ## +# # Extract the age and calculate the date-of-birth. +# #-- +# # FIXME: fails if the birthday falls on February 29th +# #++ +# # The DOB is returned as a Time object. +# +# def get_dob(person) +# # ... +# end +# +# Names of classes, files, and any method names containing an +# underscore or preceded by a hash character are automatically hyperlinked +# from comment text to their description. +# +# Method parameter lists are extracted and displayed with the method +# description. If a method calls +yield+, then the parameters passed to yield +# will also be displayed: +# +# def fred +# ... +# yield line, address +# +# This will get documented as: +# +# fred() { |line, address| ... } +# +# You can override this using a comment containing ':yields: ...' immediately +# after the method definition +# +# def fred # :yields: index, position +# # ... +# +# yield line, address +# +# which will get documented as +# +# fred() { |index, position| ... } +# +# +:yields:+ is an example of a documentation directive. These appear +# immediately after the start of the document element they are modifying. +# +# RDoc automatically cross-references words with underscores or camel-case. +# To suppress cross-references, prefix the word with a \\ character. To +# include special characters like "\\n", you'll need to use two \\ +# characters like "\\\\\\n". +# +# == \Markup +# +# * The markup engine 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 "<digit>.", 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, RDoc::Markup +# supports word-based and general markup. +# +# Word-based markup uses flag characters around individual words: +# +# [<tt>\*word*</tt>] displays word in a *bold* font +# [<tt>\_word_</tt>] displays word in an _emphasized_ font +# [<tt>\+word+</tt>] 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. +# +# [<tt>\<b>text...</b></tt>] displays word in a *bold* font +# [<tt>\<em>text...</em></tt>] displays word in an _emphasized_ font +# [<tt>\<i>text...</i></tt>] displays word in an <i>italicized</i> font +# [<tt>\<tt>text...\</tt></tt>] 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. This only works for +# simple markup, not HTML-style markup. +# +# * Hyperlinks to the web starting http:, mailto:, ftp:, or www. are +# recognized. An HTTP url that references an external image file is +# converted into an inline \<IMG..>. Hyperlinks starting 'link:' are +# assumed to refer to local files whose path is relative to the --op +# directory. +# +# Hyperlinks can also be of the form <tt>label</tt>[url], in which +# case the label is used in the displayed text, and +url+ is +# used as the target. If +label+ contains multiple words, +# put it in braces: <em>{multi word label}[</em>url<em>]</em>. +# +# Example hyperlinks: +# +# link:RDoc.html +# http://rdoc.rubyforge.org +# mailto:user@example.com +# {RDoc Documentation}[http://rdoc.rubyforge.org] +# {RDoc Markup}[link:RDoc/Markup.html] +# +# == Directives +# +# [+:nodoc:+ / +:nodoc:+ all] +# This directive prevents documentation for the element from +# being generated. For classes and modules, the methods, aliases, +# constants, and attributes directly within the affected class or +# module also will be omitted. By default, though, modules and +# classes within that class of module _will_ be documented. This is +# turned off by adding the +all+ modifier. +# +# module MyModule # :nodoc: +# class Input +# end +# end +# +# module OtherModule # :nodoc: all +# class Output +# end +# end +# +# In the above code, only class <tt>MyModule::Input</tt> will be documented. +# The +:nodoc:+ directive is global across all files for the class or module +# to which it applies, so use +:stopdoc:+/+:startdoc:+ to suppress +# documentation only for a particular set of methods, etc. +# +# [+:doc:+] +# Forces a method or attribute to be documented even if it wouldn't be +# otherwise. Useful if, for example, you want to include documentation of a +# particular private method. +# +# [+:notnew:+] +# Only applicable to the +initialize+ instance method. Normally RDoc +# assumes that the documentation and parameters for +initialize+ are +# actually for the +new+ method, and so fakes out a +new+ for the class. +# The +:notnew:+ modifier stops this. Remember that +initialize+ is private, +# so you won't see the documentation unless you use the +-a+ command line +# option. +# +# Comment blocks can contain other directives: +# +# [<tt>:section: title</tt>] +# Starts a new section in the output. The title following +:section:+ is +# used as the section heading, and the remainder of the comment containing +# the section is used as introductory text. Subsequent methods, aliases, +# attributes, and classes will be documented in this section. A :section: +# comment block may have one or more lines before the :section: directive. +# These will be removed, and any identical lines at the end of the block are +# also removed. This allows you to add visual cues such as: +# +# # ---------------------------------------- +# # :section: My Section +# # This is the section that I wrote. +# # See it glisten in the noon-day sun. +# # ---------------------------------------- +# +# [+:call-seq:+] +# Lines up to the next blank line in the comment are treated as the method's +# calling sequence, overriding the default parsing of method parameters and +# yield arguments. +# +# [+:include:+ _filename_] +# \Include the contents of the named file at this point. The file will be +# searched for in the directories listed by the +--include+ option, or in +# the current directory by default. The contents of the file will be +# shifted to have the same indentation as the ':' at the start of +# the :include: directive. +# +# [+:title:+ _text_] +# Sets the title for the document. Equivalent to the <tt>--title</tt> +# command line parameter. (The command line parameter overrides any :title: +# directive in the source). +# +# [+:enddoc:+] +# Document nothing further at the current level. +# +# [+:main:+ _name_] +# Equivalent to the <tt>--main</tt> command line parameter. +# +# [+:stopdoc:+ / +:startdoc:+] +# Stop and start adding new documentation elements to the current container. +# For example, if a class has a number of constants that you don't want to +# document, put a +:stopdoc:+ before the first, and a +:startdoc:+ after the +# last. If you don't specify a +:startdoc:+ by the end of the container, +# disables documentation for the entire class or module. +# +# == Other stuff +# +# RDoc is currently being maintained by Eric Hodel <drbrain@segment7.net> +# +# Dave Thomas <dave@pragmaticprogrammer.com> is the original author of RDoc. +# +# == Credits +# +# * The Ruby parser in rdoc/parse.rb is based heavily on the outstanding +# work of Keiju ISHITSUKA of Nippon Rational Inc, who produced the Ruby +# parser for irb and the rtags package. +# +# * Code to diagram classes and modules was written by Sergey A Yanovitsky +# (Jah) of Enticla. +# +# * Charset patch from MoonWolf. +# +# * Rich Kilmer wrote the kilmer.rb output template. +# +# * Dan Brickley led the design of the RDF format. +# +# == License +# +# RDoc is Copyright (c) 2001-2003 Dave Thomas, The Pragmatic Programmers. It +# is free software, and may be redistributed under the terms specified +# in the README file of the Ruby distribution. +# +# == Warranty +# +# This software is provided "as is" and without any express or implied +# warranties, including, without limitation, the implied warranties of +# merchantibility and fitness for a particular purpose. + +module RDoc + + ## + # Exception thrown by any rdoc error. + + class Error < RuntimeError; end + + RDocError = Error # :nodoc: + + ## + # RDoc version you are using + + VERSION = '2.4.3' + + ## + # Name of the dotfile that contains the description of files to be processed + # in the current directory + + DOT_DOC_FILENAME = ".document" + + GENERAL_MODIFIERS = %w[nodoc].freeze + + CLASS_MODIFIERS = GENERAL_MODIFIERS + + ATTR_MODIFIERS = GENERAL_MODIFIERS + + CONSTANT_MODIFIERS = GENERAL_MODIFIERS + + METHOD_MODIFIERS = GENERAL_MODIFIERS + + %w[arg args yield yields notnew not-new not_new doc] + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/alias.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/alias.rb new file mode 100644 index 000000000..74a8d4e7c --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/alias.rb @@ -0,0 +1,54 @@ +require 'rdoc/code_object' + +## +# Represent an alias, which is an old_name/new_name pair associated with a +# particular context + +class RDoc::Alias < RDoc::CodeObject + + ## + # Allow comments to be overridden + + attr_writer :comment + + ## + # Aliased name + + attr_accessor :new_name + + ## + # Aliasee's name + + attr_accessor :old_name + + ## + # Source file token stream + + attr_accessor :text + + ## + # Creates a new Alias with a token stream of +text+ that aliases +old_name+ + # to +new_name+ and has +comment+ + + def initialize(text, old_name, new_name, comment) + super() + @text = text + @old_name = old_name + @new_name = new_name + self.comment = comment + end + + def inspect # :nodoc: + "#<%s:0x%x %s.alias_method %s, %s>" % [ + self.class, object_id, + parent.name, @old_name, @new_name, + ] + end + + def to_s # :nodoc: + "alias: #{self.old_name} -> #{self.new_name}\n#{self.comment}" + end + +end + + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/anon_class.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/anon_class.rb new file mode 100644 index 000000000..0a684f2df --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/anon_class.rb @@ -0,0 +1,10 @@ +require 'rdoc/class_module' + +## +# An anonymous class like: +# +# c = Class.new do end + +class RDoc::AnonClass < RDoc::ClassModule +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/any_method.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/any_method.rb new file mode 100644 index 000000000..b65fd9ab9 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/any_method.rb @@ -0,0 +1,190 @@ +require 'rdoc/code_object' +require 'rdoc/tokenstream' + +## +# AnyMethod is the base class for objects representing methods + +class RDoc::AnyMethod < RDoc::CodeObject + + ## + # Method name + + attr_writer :name + + ## + # public, protected, private + + attr_accessor :visibility + + ## + # Parameters yielded by the called block + + attr_accessor :block_params + + ## + # Don't rename \#initialize to \::new + + attr_accessor :dont_rename_initialize + + ## + # Is this a singleton method? + + attr_accessor :singleton + + ## + # Source file token stream + + attr_reader :text + + ## + # Array of other names for this method + + attr_reader :aliases + + ## + # Fragment reference for this method + + attr_reader :aref + + ## + # The method we're aliasing + + attr_accessor :is_alias_for + + ## + # Parameters for this method + + attr_overridable :params, :param, :parameters, :parameter + + ## + # Different ways to call this method + + attr_accessor :call_seq + + include RDoc::TokenStream + + ## + # Resets method fragment reference counter + + def self.reset + @@aref = 'M000000' + end + + reset + + def initialize(text, name) + super() + @text = text + @name = name + @token_stream = nil + @visibility = :public + @dont_rename_initialize = false + @block_params = nil + @aliases = [] + @is_alias_for = nil + @call_seq = nil + + @aref = @@aref + @@aref = @@aref.succ + end + + ## + # Order by #singleton then #name + + def <=>(other) + [@singleton ? 0 : 1, @name] <=> [other.singleton ? 0 : 1, other.name] + end + + ## + # Adds +method+ as an alias for this method + + def add_alias(method) + @aliases << method + end + + ## + # HTML id-friendly method name + + def html_name + @name.gsub(/[^a-z]+/, '-') + end + + def inspect # :nodoc: + alias_for = @is_alias_for ? " (alias for #{@is_alias_for.name})" : nil + "#<%s:0x%x %s%s%s (%s)%s>" % [ + self.class, object_id, + parent_name, + singleton ? '::' : '#', + name, + visibility, + alias_for, + ] + end + + ## + # Full method name including namespace + + def full_name + "#{@parent.full_name}#{pretty_name}" + end + + ## + # Method name + + def name + return @name if @name + + @name = @call_seq[/^.*?\.(\w+)/, 1] || @call_seq + end + + ## + # Pretty parameter list for this method + + def param_seq + params = params.gsub(/\s*\#.*/, '') + params = params.tr("\n", " ").squeeze(" ") + params = "(#{params})" unless p[0] == ?( + + if block = block_params then # yes, = + # If this method has explicit block parameters, remove any explicit + # &block + params.sub!(/,?\s*&\w+/) + + block.gsub!(/\s*\#.*/, '') + block = block.tr("\n", " ").squeeze(" ") + if block[0] == ?( + block.sub!(/^\(/, '').sub!(/\)/, '') + end + params << " { |#{block}| ... }" + end + + params + end + + ## + # Path to this method + + def path + "#{@parent.path}##{@aref}" + end + + ## + # Method name with class/instance indicator + + def pretty_name + "#{singleton ? '::' : '#'}#{@name}" + end + + def to_s # :nodoc: + "#{self.class.name}: #{full_name} (#{@text})\n#{@comment}" + end + + ## + # Type of method (class or instance) + + def type + singleton ? 'class' : 'instance' + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/attr.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/attr.rb new file mode 100644 index 000000000..235a5ab23 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/attr.rb @@ -0,0 +1,79 @@ +require 'rdoc/code_object' + +## +# An attribute created by \#attr, \#attr_reader, \#attr_writer or +# \#attr_accessor + +class RDoc::Attr < RDoc::CodeObject + + ## + # Name of the attribute + + attr_accessor :name + + ## + # Is the attribute readable, writable or both? + + attr_accessor :rw + + ## + # Source file token stream + + attr_accessor :text + + ## + # public, protected, private + + attr_accessor :visibility + + def initialize(text, name, rw, comment) + super() + @text = text + @name = name + @rw = rw + @visibility = :public + self.comment = comment + end + + ## + # Attributes are ordered by name + + def <=>(other) + self.name <=> other.name + end + + ## + # An HTML id-friendly representation of #name + + def html_name + @name.gsub(/[^a-z]+/, '-') + end + + def inspect # :nodoc: + attr = case rw + when 'RW' then :attr_accessor + when 'R' then :attr_reader + when 'W' then :attr_writer + else + " (#{rw})" + end + + "#<%s:0x%x %s.%s :%s>" % [ + self.class, object_id, + parent_name, attr, @name, + ] + end + + ## + # URL path for this attribute + + def path + "#{@parent.path}##{@name}" + end + + def to_s # :nodoc: + "attr: #{self.name} #{self.rw}\n#{self.comment}" + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/cache.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/cache.rb new file mode 100644 index 000000000..bdd830a13 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/cache.rb @@ -0,0 +1,41 @@ +require 'thread' +require 'singleton' + +## +# A generic, thread-safe in-memory cache. It's used for caching +# RDoc::TemplatePage objects when generating RDoc output. + +class RDoc::Cache + + include Singleton + + ## + # Creates a new, empty cache + + def initialize + @contents = {} + @lock = Mutex.new + end + + ## + # Checks whether there's a value in the cache with key +key+. If so, then + # that value will be returned. Otherwise, the given block will be run, and + # its return value will be put into the cache, and returned. + + def cache(key) + @lock.synchronize do + @contents[key] ||= yield + end + end + + ## + # Clears the contents of the cache + + def clear + @lock.synchronize do + @contents.clear + end + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/class_module.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/class_module.rb new file mode 100644 index 000000000..dc8874f9f --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/class_module.rb @@ -0,0 +1,87 @@ +require 'rdoc/context' + +## +# ClassModule is the base class for objects representing either a class or a +# module. + +class RDoc::ClassModule < RDoc::Context + + attr_accessor :diagram + + ## + # Creates a new ClassModule with +name+ with optional +superclass+ + + def initialize(name, superclass = 'Object') + @diagram = nil + @full_name = nil + @name = name + @superclass = superclass + super() + end + + ## + # Finds a class or module with +name+ in this namespace or its descendents + + def find_class_named(name) + return self if full_name == name + @classes.each_value {|c| return c if c.find_class_named(name) } + nil + end + + ## + # Return the fully qualified name of this class or module + + def full_name + @full_name ||= if RDoc::ClassModule === @parent then + "#{@parent.full_name}::#{@name}" + else + @name + end + end + + ## + # 'module' or 'class' + + def type + module? ? 'module' : 'class' + end + + ## + # Does this object represent a module? + + def module? + false + end + + ## + # Path to this class or module + + def path + http_url RDoc::RDoc.current.generator.class_dir + end + + ## + # Get the superclass of this class. Attempts to retrieve the superclass + # object, returns the name if it is not known. + + def superclass + raise NoMethodError, "#{full_name} is a module" if module? + + RDoc::TopLevel.find_class_named(@superclass) || @superclass + end + + ## + # Set the superclass of this class to +superclass+ + + def superclass=(superclass) + raise NoMethodError, "#{full_name} is a module" if module? + + @superclass = superclass if @superclass.nil? or @superclass == 'Object' + end + + def to_s # :nodoc: + "#{self.class}: #{full_name} #{@comment} #{super}" + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/code_object.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/code_object.rb new file mode 100644 index 000000000..2b7d9cded --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/code_object.rb @@ -0,0 +1,152 @@ +require 'rdoc' + +## +# We contain the common stuff for contexts (which are containers) and other +# elements (methods, attributes and so on) + +class RDoc::CodeObject + + ## + # Our comment + + attr_reader :comment + + ## + # Do we document our children? + + attr_reader :document_children + + ## + # Do we document ourselves? + + attr_reader :document_self + + ## + # Are we done documenting (ie, did we come across a :enddoc:)? + + attr_accessor :done_documenting + + ## + # Force documentation of this CodeObject + + attr_accessor :force_documentation + + ## + # Our parent CodeObject + + attr_accessor :parent + + ## + # Which section are we in + + attr_accessor :section + + ## + # We are the model of the code, but we know that at some point we will be + # worked on by viewers. By implementing the Viewable protocol, viewers can + # associated themselves with these objects. + + attr_accessor :viewer + + ## + # There's a wee trick we pull. Comment blocks can have directives that + # override the stuff we extract during the parse. So, we have a special + # class method, attr_overridable, that lets code objects list those + # directives. When a comment is assigned, we then extract out any matching + # directives and update our object + + def self.attr_overridable(name, *aliases) + @overridables ||= {} + + attr_accessor name + + aliases.unshift name + + aliases.each do |directive_name| + @overridables[directive_name.to_s] = name + end + end + + ## + # Creates a new CodeObject that will document itself and its children + + def initialize + @comment = nil + @document_children = true + @document_self = true + @done_documenting = false + @force_documentation = false + @parent = nil + end + + ## + # Replaces our comment with +comment+, unless it is empty. + + def comment=(comment) + @comment = comment unless comment.empty? + end + + ## + # Enables or disables documentation of this CodeObject's children. Calls + # remove_classes_and_modules when disabling. + + def document_children=(document_children) + @document_children = document_children + remove_classes_and_modules unless document_children + end + + ## + # Enables or disables documentation of this CodeObject. Calls + # remove_methods_etc when disabling. + + def document_self=(document_self) + @document_self = document_self + remove_methods_etc unless document_self + end + + ## + # File name of our parent + + def parent_file_name + @parent ? @parent.base_name : '(unknown)' + end + + ## + # Name of our parent + + def parent_name + @parent ? @parent.full_name : '(unknown)' + end + + ## + # Callback called upon disabling documentation of children. See + # #document_children= + + def remove_classes_and_modules + end + + ## + # Callback called upon disabling documentation of ourself. See + # #document_self= + + def remove_methods_etc + end + + ## + # Enable capture of documentation + + def start_doc + @document_self = true + @document_children = true + end + + ## + # Disable capture of documentation + + def stop_doc + @document_self = false + @document_children = false + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/code_objects.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/code_objects.rb new file mode 100644 index 000000000..c60dad92d --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/code_objects.rb @@ -0,0 +1,23 @@ +# We represent the various high-level code constructs that appear in Ruby +# programs: classes, modules, methods, and so on. + +require 'rdoc/code_object' +require 'rdoc/context' +require 'rdoc/top_level' + +require 'rdoc/class_module' +require 'rdoc/normal_class' +require 'rdoc/normal_module' +require 'rdoc/anon_class' +require 'rdoc/single_class' + +require 'rdoc/any_method' +require 'rdoc/alias' +require 'rdoc/ghost_method' +require 'rdoc/meta_method' + +require 'rdoc/attr' +require 'rdoc/constant' +require 'rdoc/require' +require 'rdoc/include' + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/constant.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/constant.rb new file mode 100644 index 000000000..56566da8c --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/constant.rb @@ -0,0 +1,36 @@ +require 'rdoc/code_object' + +## +# A constant + +class RDoc::Constant < RDoc::CodeObject + + ## + # The constant's name + + attr_accessor :name + + ## + # The constant's value + + attr_accessor :value + + ## + # Creates a new constant with +name+, +value+ and +comment+ + + def initialize(name, value, comment) + super() + @name = name + @value = value + self.comment = comment + end + + ## + # Path to this constant + + def path + "#{@parent.path}##{@name}" + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/context.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/context.rb new file mode 100644 index 000000000..b6763991d --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/context.rb @@ -0,0 +1,712 @@ +require 'thread' +require 'rdoc/code_object' + +## +# A Context is something that can hold modules, classes, methods, attributes, +# aliases, requires, and includes. Classes, modules, and files are all +# Contexts. + +class RDoc::Context < RDoc::CodeObject + + ## + # Types of methods + + TYPES = %w[class instance] + + ## + # Method visibilities + + VISIBILITIES = [:public, :protected, :private] + + ## + # Aliased methods + + attr_reader :aliases + + ## + # attr* methods + + attr_reader :attributes + + ## + # Constants defined + + attr_reader :constants + + ## + # Current section of documentation + + attr_reader :current_section + + ## + # Files this context is found in + + attr_reader :in_files + + ## + # Modules this context includes + + attr_reader :includes + + ## + # Methods defined in this context + + attr_reader :method_list + + ## + # Name of this class excluding namespace. See also full_name + + attr_reader :name + + ## + # Files this context requires + + attr_reader :requires + + ## + # Sections in this context + + attr_reader :sections + + ## + # Aliases that haven't been resolved to a method + + attr_accessor :unmatched_alias_lists + + ## + # Current visibility of this context + + attr_reader :visibility + + ## + # A per-comment section of documentation like: + # + # # :SECTION: The title + # # The body + + class Section + + ## + # Section comment + + attr_reader :comment + + ## + # Context this Section lives in + + attr_reader :parent + + ## + # Section sequence number (for linking) + + attr_reader :sequence + + ## + # Section title + + attr_reader :title + + @@sequence = "SEC00000" + @@sequence_lock = Mutex.new + + ## + # Creates a new section with +title+ and +comment+ + + def initialize(parent, title, comment) + @parent = parent + @title = title + + @@sequence_lock.synchronize do + @@sequence.succ! + @sequence = @@sequence.dup + end + + set_comment comment + end + + ## + # Sections are equal when they have the same #sequence + + def ==(other) + self.class === other and @sequence == other.sequence + end + + def inspect # :nodoc: + "#<%s:0x%x %s %p>" % [ + self.class, object_id, + @sequence, title + ] + end + + ## + # Set the comment for this section from the original comment block If + # the first line contains :section:, strip it and use the rest. + # Otherwise remove lines up to the line containing :section:, and look + # for those lines again at the end and remove them. This lets us write + # + # # blah blah blah + # # + # # :SECTION: The title + # # The body + + def set_comment(comment) + return unless comment + + if comment =~ /^#[ \t]*:section:.*\n/ then + start = $` + rest = $' + + if start.empty? + @comment = rest + else + @comment = rest.sub(/#{start.chomp}\Z/, '') + end + else + @comment = comment + end + + @comment = nil if @comment.empty? + end + + end + + ## + # Creates an unnamed empty context with public visibility + + def initialize + super + + @in_files = [] + + @name ||= "unknown" + @comment ||= "" + @parent = nil + @visibility = :public + + @current_section = Section.new self, nil, nil + @sections = [@current_section] + + initialize_methods_etc + initialize_classes_and_modules + end + + ## + # Sets the defaults for classes and modules + + def initialize_classes_and_modules + @classes = {} + @modules = {} + end + + ## + # Sets the defaults for methods and so-forth + + def initialize_methods_etc + @method_list = [] + @attributes = [] + @aliases = [] + @requires = [] + @includes = [] + @constants = [] + + # This Hash maps a method name to a list of unmatched aliases (aliases of + # a method not yet encountered). + @unmatched_alias_lists = {} + end + + ## + # Contexts are sorted by full_name + + def <=>(other) + full_name <=> other.full_name + end + + ## + # Adds +an_alias+ that is automatically resolved + + def add_alias(an_alias) + meth = find_instance_method_named(an_alias.old_name) + + if meth then + add_alias_impl an_alias, meth + else + add_to @aliases, an_alias + unmatched_alias_list = @unmatched_alias_lists[an_alias.old_name] ||= [] + unmatched_alias_list.push an_alias + end + + an_alias + end + + ## + # Adds +an_alias+ pointing to +meth+ + + def add_alias_impl(an_alias, meth) + new_meth = RDoc::AnyMethod.new an_alias.text, an_alias.new_name + new_meth.is_alias_for = meth + new_meth.singleton = meth.singleton + new_meth.params = meth.params + new_meth.comment = "Alias for \##{meth.name}" + meth.add_alias new_meth + add_method new_meth + end + + ## + # Adds +attribute+ + + def add_attribute(attribute) + add_to @attributes, attribute + end + + ## + # Adds a class named +name+ with +superclass+. + # + # Given <tt>class Container::Item</tt> RDoc assumes +Container+ is a module + # unless it later sees <tt>class Container</tt>. add_class automatically + # upgrades +name+ to a class in this case. + + def add_class(class_type, name, superclass = 'Object') + klass = add_class_or_module @classes, class_type, name, superclass + + # If the parser encounters Container::Item before encountering + # Container, then it assumes that Container is a module. This may not + # be the case, so remove Container from the module list if present and + # transfer any contained classes and modules to the new class. + + RDoc::TopLevel.lock.synchronize do + mod = RDoc::TopLevel.modules_hash.delete klass.full_name + + if mod then + klass.classes_hash.update mod.classes_hash + klass.modules_hash.update mod.modules_hash + klass.method_list.concat mod.method_list + + @modules.delete klass.name + end + + RDoc::TopLevel.classes_hash[klass.full_name] = klass + end + + klass + end + + ## + # Instantiates a +class_type+ named +name+ and adds it the modules or + # classes Hash +collection+. + + def add_class_or_module(collection, class_type, name, superclass = nil) + full_name = if RDoc::TopLevel === self then # HACK + name + else + "#{self.full_name}::#{name}" + end + mod = collection[name] + + if mod then + mod.superclass = superclass unless mod.module? + else + all = nil + + RDoc::TopLevel.lock.synchronize do + all = if class_type == RDoc::NormalModule then + RDoc::TopLevel.modules_hash + else + RDoc::TopLevel.classes_hash + end + + mod = all[full_name] + end + + unless mod then + mod = class_type.new name, superclass + else + # If the class has been encountered already, check that its + # superclass has been set (it may not have been, depending on the + # context in which it was encountered). + if class_type == RDoc::NormalClass then + mod.superclass = superclass unless mod.superclass + end + end + + unless @done_documenting then + RDoc::TopLevel.lock.synchronize do + all[full_name] = mod + end + collection[name] = mod + end + + mod.section = @current_section + mod.parent = self + end + + mod + end + + ## + # Adds +constant+ + + def add_constant(constant) + add_to @constants, constant + end + + ## + # Adds included module +include+ + + def add_include(include) + add_to @includes, include + end + + ## + # Adds +method+ + + def add_method(method) + method.visibility = @visibility + add_to @method_list, method + + unmatched_alias_list = @unmatched_alias_lists[method.name] + if unmatched_alias_list then + unmatched_alias_list.each do |unmatched_alias| + add_alias_impl unmatched_alias, method + @aliases.delete unmatched_alias + end + + @unmatched_alias_lists.delete method.name + end + end + + ## + # Adds a module named +name+. If RDoc already knows +name+ is a class then + # that class is returned instead. See also #add_class + + def add_module(class_type, name) + return @classes[name] if @classes.key? name + + add_class_or_module @modules, class_type, name, nil + end + + ## + # Adds +require+ to this context's top level + + def add_require(require) + if RDoc::TopLevel === self then + add_to @requires, require + else + parent.add_require require + end + end + + ## + # Adds +thing+ to the collection +array+ + + def add_to(array, thing) + array << thing if @document_self and not @done_documenting + thing.parent = self + thing.section = @current_section + end + + ## + # Array of classes in this context + + def classes + @classes.values + end + + ## + # All classes and modules in this namespace + + def classes_and_modules + classes + modules + end + + ## + # Hash of classes keyed by class name + + def classes_hash + @classes + end + + ## + # Is part of this thing was defined in +file+? + + def defined_in?(file) + @in_files.include?(file) + end + + ## + # Iterator for attributes + + def each_attribute # :yields: attribute + @attributes.each {|a| yield a} + end + + ## + # Iterator for classes and modules + + def each_classmodule(&block) # :yields: module + classes_and_modules.sort.each(&block) + end + + ## + # Iterator for constants + + def each_constant # :yields: constant + @constants.each {|c| yield c} + end + + ## + # Iterator for included modules + + def each_include # :yields: include + @includes.each do |i| yield i end + end + + ## + # Iterator for methods + + def each_method # :yields: method + @method_list.sort.each {|m| yield m} + end + + ## + # Finds an attribute with +name+ in this context + + def find_attribute_named(name) + @attributes.find { |m| m.name == name } + end + + ## + # Finds a constant with +name+ in this context + + def find_constant_named(name) + @constants.find {|m| m.name == name} + end + + ## + # Find a module at a higher scope + + def find_enclosing_module_named(name) + parent && parent.find_module_named(name) + end + + ## + # Finds a file with +name+ in this context + + def find_file_named(name) + top_level.class.find_file_named(name) + end + + ## + # Finds an instance method with +name+ in this context + + def find_instance_method_named(name) + @method_list.find { |meth| meth.name == name && !meth.singleton } + end + + ## + # Finds a method, constant, attribute, module or files named +symbol+ in + # this context + + def find_local_symbol(symbol) + find_method_named(symbol) or + find_constant_named(symbol) or + find_attribute_named(symbol) or + find_module_named(symbol) or + find_file_named(symbol) + end + + ## + # Finds a instance or module method with +name+ in this context + + def find_method_named(name) + @method_list.find { |meth| meth.name == name } + end + + ## + # Find a module with +name+ using ruby's scoping rules + + def find_module_named(name) + res = @modules[name] || @classes[name] + return res if res + return self if self.name == name + find_enclosing_module_named name + end + + ## + # Look up +symbol+. If +method+ is non-nil, then we assume the symbol + # references a module that contains that method. + + def find_symbol(symbol, method = nil) + result = nil + + case symbol + when /^::(.*)/ then + result = top_level.find_symbol($1) + when /::/ then + modules = symbol.split(/::/) + + unless modules.empty? then + module_name = modules.shift + result = find_module_named(module_name) + + if result then + modules.each do |name| + result = result.find_module_named name + break unless result + end + end + end + + else + # if a method is specified, then we're definitely looking for + # a module, otherwise it could be any symbol + if method then + result = find_module_named symbol + else + result = find_local_symbol symbol + if result.nil? then + if symbol =~ /^[A-Z]/ then + result = parent + while result && result.name != symbol do + result = result.parent + end + end + end + end + end + + if result and method then + fail unless result.respond_to? :find_local_symbol + result = result.find_local_symbol(method) + end + + result + end + + ## + # URL for this with a +prefix+ + + def http_url(prefix) + path = full_name + path = path.gsub(/<<\s*(\w*)/, 'from-\1') if path =~ /<</ + path = [prefix] + path.split('::') + + File.join(*path.compact) + '.html' + end + + ## + # Breaks method_list into a nested hash by type (class or instance) and + # visibility (public, protected private) + + def methods_by_type + methods = {} + + TYPES.each do |type| + visibilities = {} + VISIBILITIES.each do |vis| + visibilities[vis] = [] + end + + methods[type] = visibilities + end + + each_method do |method| + methods[method.type][method.visibility] << method + end + + methods + end + + ## + # Yields Method and Attr entries matching the list of names in +methods+. + # Attributes are only returned when +singleton+ is false. + + def methods_matching(methods, singleton = false) + count = 0 + + @method_list.each do |m| + if methods.include? m.name and m.singleton == singleton then + yield m + count += 1 + end + end + + return if count == methods.size || singleton + + @attributes.each do |a| + yield a if methods.include? a.name + end + end + + ## + # Array of modules in this context + + def modules + @modules.values + end + + ## + # Hash of modules keyed by module name + + def modules_hash + @modules + end + + ## + # Changes the visibility for new methods to +visibility+ + + def ongoing_visibility=(visibility) + @visibility = visibility + end + + ## + # Record which file +top_level+ is in + + def record_location(top_level) + @in_files << top_level unless @in_files.include?(top_level) + end + + ## + # If a class's documentation is turned off after we've started collecting + # methods etc., we need to remove the ones we have + + def remove_methods_etc + initialize_methods_etc + end + + ## + # Given an array +methods+ of method names, set the visibility of each to + # +visibility+ + + def set_visibility_for(methods, visibility, singleton = false) + methods_matching methods, singleton do |m| + m.visibility = visibility + end + end + + ## + # Removes classes and modules when we see a :nodoc: all + + def remove_classes_and_modules + initialize_classes_and_modules + end + + ## + # Creates a new section with +title+ and +comment+ + + def set_current_section(title, comment) + @current_section = Section.new self, title, comment + @sections << @current_section + end + + ## + # Return the TopLevel that owns us + + def top_level + return @top_level if defined? @top_level + @top_level = self + @top_level = @top_level.parent until RDoc::TopLevel === @top_level + @top_level + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/diagram.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/diagram.rb new file mode 100644 index 000000000..9cddd5b39 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/diagram.rb @@ -0,0 +1,340 @@ +# A wonderful hack by to draw package diagrams using the dot package. +# Originally written by Jah, team Enticla. +# +# You must have the V1.7 or later in your path +# http://www.research.att.com/sw/tools/graphviz/ + +require 'rdoc/dot' + +module RDoc + + ## + # Draw a set of diagrams representing the modules and classes in the + # system. We draw one diagram for each file, and one for each top-level + # class or module. This means there will be overlap. However, it also + # means that you'll get better context for objects. + # + # To use, simply + # + # d = Diagram.new(info) # pass in collection of top level infos + # d.draw + # + # The results will be written to the +dot+ subdirectory. The process + # also sets the +diagram+ attribute in each object it graphs to + # the name of the file containing the image. This can be used + # by output generators to insert images. + + class Diagram + + FONT = "Arial" + + DOT_PATH = "dot" + + ## + # Pass in the set of top level objects. The method also creates the + # subdirectory to hold the images + + def initialize(info, options) + @info = info + @options = options + @counter = 0 + FileUtils.mkdir_p(DOT_PATH) + @diagram_cache = {} + end + + ## + # Draw the diagrams. We traverse the files, drawing a diagram for each. We + # also traverse each top-level class and module in that file drawing a + # diagram for these too. + + def draw + unless @options.quiet + $stderr.print "Diagrams: " + $stderr.flush + end + + @info.each_with_index do |i, file_count| + @done_modules = {} + @local_names = find_names(i) + @global_names = [] + @global_graph = graph = DOT::Digraph.new('name' => 'TopLevel', + 'fontname' => FONT, + 'fontsize' => '8', + 'bgcolor' => 'lightcyan1', + 'compound' => 'true') + + # it's a little hack %) i'm too lazy to create a separate class + # for default node + graph << DOT::Node.new('name' => 'node', + 'fontname' => FONT, + 'color' => 'black', + 'fontsize' => 8) + + i.modules.each do |mod| + draw_module(mod, graph, true, i.relative_name) + end + add_classes(i, graph, i.relative_name) + + i.diagram = convert_to_png("f_#{file_count}", graph) + + # now go through and document each top level class and + # module independently + i.modules.each_with_index do |mod, count| + @done_modules = {} + @local_names = find_names(mod) + @global_names = [] + + @global_graph = graph = DOT::Digraph.new('name' => 'TopLevel', + 'fontname' => FONT, + 'fontsize' => '8', + 'bgcolor' => 'lightcyan1', + 'compound' => 'true') + + graph << DOT::Node.new('name' => 'node', + 'fontname' => FONT, + 'color' => 'black', + 'fontsize' => 8) + draw_module(mod, graph, true) + mod.diagram = convert_to_png("m_#{file_count}_#{count}", + graph) + end + end + $stderr.puts unless @options.quiet + end + + private + + def find_names(mod) + return [mod.full_name] + mod.classes.collect{|cl| cl.full_name} + + mod.modules.collect{|m| find_names(m)}.flatten + end + + def find_full_name(name, mod) + full_name = name.dup + return full_name if @local_names.include?(full_name) + mod_path = mod.full_name.split('::')[0..-2] + unless mod_path.nil? + until mod_path.empty? + full_name = mod_path.pop + '::' + full_name + return full_name if @local_names.include?(full_name) + end + end + return name + end + + def draw_module(mod, graph, top_level = false, file = nil) + return if @done_modules[mod.full_name] and not top_level + + @counter += 1 + url = mod.http_url("classes") + m = DOT::Subgraph.new('name' => "cluster_#{mod.full_name.gsub( /:/,'_' )}", + 'label' => mod.name, + 'fontname' => FONT, + 'color' => 'blue', + 'style' => 'filled', + 'URL' => %{"#{url}"}, + 'fillcolor' => top_level ? 'palegreen1' : 'palegreen3') + + @done_modules[mod.full_name] = m + add_classes(mod, m, file) + graph << m + + unless mod.includes.empty? + mod.includes.each do |inc| + m_full_name = find_full_name(inc.name, mod) + if @local_names.include?(m_full_name) + @global_graph << DOT::Edge.new('from' => "#{m_full_name.gsub( /:/,'_' )}", + 'to' => "#{mod.full_name.gsub( /:/,'_' )}", + 'ltail' => "cluster_#{m_full_name.gsub( /:/,'_' )}", + 'lhead' => "cluster_#{mod.full_name.gsub( /:/,'_' )}") + else + unless @global_names.include?(m_full_name) + path = m_full_name.split("::") + url = File.join('classes', *path) + ".html" + @global_graph << DOT::Node.new('name' => "#{m_full_name.gsub( /:/,'_' )}", + 'shape' => 'box', + 'label' => "#{m_full_name}", + 'URL' => %{"#{url}"}) + @global_names << m_full_name + end + @global_graph << DOT::Edge.new('from' => "#{m_full_name.gsub( /:/,'_' )}", + 'to' => "#{mod.full_name.gsub( /:/,'_' )}", + 'lhead' => "cluster_#{mod.full_name.gsub( /:/,'_' )}") + end + end + end + end + + def add_classes(container, graph, file = nil ) + + use_fileboxes = @options.fileboxes + + files = {} + + # create dummy node (needed if empty and for module includes) + if container.full_name + graph << DOT::Node.new('name' => "#{container.full_name.gsub( /:/,'_' )}", + 'label' => "", + 'width' => (container.classes.empty? and + container.modules.empty?) ? + '0.75' : '0.01', + 'height' => '0.01', + 'shape' => 'plaintext') + end + + container.classes.each_with_index do |cl, cl_index| + last_file = cl.in_files[-1].relative_name + + if use_fileboxes && !files.include?(last_file) + @counter += 1 + files[last_file] = + DOT::Subgraph.new('name' => "cluster_#{@counter}", + 'label' => "#{last_file}", + 'fontname' => FONT, + 'color'=> + last_file == file ? 'red' : 'black') + end + + next if cl.name == 'Object' || cl.name[0,2] == "<<" + + url = cl.http_url("classes") + + label = cl.name.dup + if use_fileboxes && cl.in_files.length > 1 + label << '\n[' + + cl.in_files.collect {|i| + i.relative_name + }.sort.join( '\n' ) + + ']' + end + + attrs = { + 'name' => "#{cl.full_name.gsub( /:/, '_' )}", + 'fontcolor' => 'black', + 'style'=>'filled', + 'color'=>'palegoldenrod', + 'label' => label, + 'shape' => 'ellipse', + 'URL' => %{"#{url}"} + } + + c = DOT::Node.new(attrs) + + if use_fileboxes + files[last_file].push c + else + graph << c + end + end + + if use_fileboxes + files.each_value do |val| + graph << val + end + end + + unless container.classes.empty? + container.classes.each_with_index do |cl, cl_index| + cl.includes.each do |m| + m_full_name = find_full_name(m.name, cl) + if @local_names.include?(m_full_name) + @global_graph << DOT::Edge.new('from' => "#{m_full_name.gsub( /:/,'_' )}", + 'to' => "#{cl.full_name.gsub( /:/,'_' )}", + 'ltail' => "cluster_#{m_full_name.gsub( /:/,'_' )}") + else + unless @global_names.include?(m_full_name) + path = m_full_name.split("::") + url = File.join('classes', *path) + ".html" + @global_graph << DOT::Node.new('name' => "#{m_full_name.gsub( /:/,'_' )}", + 'shape' => 'box', + 'label' => "#{m_full_name}", + 'URL' => %{"#{url}"}) + @global_names << m_full_name + end + @global_graph << DOT::Edge.new('from' => "#{m_full_name.gsub( /:/,'_' )}", + 'to' => "#{cl.full_name.gsub( /:/, '_')}") + end + end + + sclass = cl.superclass + next if sclass.nil? || sclass == 'Object' + sclass_full_name = find_full_name(sclass,cl) + unless @local_names.include?(sclass_full_name) or @global_names.include?(sclass_full_name) + path = sclass_full_name.split("::") + url = File.join('classes', *path) + ".html" + @global_graph << DOT::Node.new('name' => "#{sclass_full_name.gsub( /:/, '_' )}", + 'label' => sclass_full_name, + 'URL' => %{"#{url}"}) + @global_names << sclass_full_name + end + @global_graph << DOT::Edge.new('from' => "#{sclass_full_name.gsub( /:/,'_' )}", + 'to' => "#{cl.full_name.gsub( /:/, '_')}") + end + end + + container.modules.each do |submod| + draw_module(submod, graph) + end + + end + + def convert_to_png(file_base, graph) + str = graph.to_s + return @diagram_cache[str] if @diagram_cache[str] + op_type = @options.image_format + dotfile = File.join(DOT_PATH, file_base) + src = dotfile + ".dot" + dot = dotfile + "." + op_type + + unless @options.quiet + $stderr.print "." + $stderr.flush + end + + File.open(src, 'w+' ) do |f| + f << str << "\n" + end + + system "dot", "-T#{op_type}", src, "-o", dot + + # Now construct the imagemap wrapper around + # that png + + ret = wrap_in_image_map(src, dot) + @diagram_cache[str] = ret + return ret + end + + ## + # Extract the client-side image map from dot, and use it to generate the + # imagemap proper. Return the whole <map>..<img> combination, suitable for + # inclusion on the page + + def wrap_in_image_map(src, dot) + res = "" + dot_map = `dot -Tismap #{src}` + + if(!dot_map.empty?) + res << %{<map id="map" name="map">\n} + dot_map.split($/).each do |area| + unless area =~ /^rectangle \((\d+),(\d+)\) \((\d+),(\d+)\) ([\/\w.]+)\s*(.*)/ + $stderr.puts "Unexpected output from dot:\n#{area}" + return nil + end + + xs, ys = [$1.to_i, $3.to_i], [$2.to_i, $4.to_i] + url, area_name = $5, $6 + + res << %{ <area shape="rect" coords="#{xs.min},#{ys.min},#{xs.max},#{ys.max}" } + res << %{ href="#{url}" alt="#{area_name}" />\n} + end + res << "</map>\n" + end + + res << %{<img src="#{dot}" usemap="#map" alt="#{dot}" />} + return res + end + + end + +end diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/dot.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/dot.rb new file mode 100644 index 000000000..fbd2cfba0 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/dot.rb @@ -0,0 +1,249 @@ +module RDoc; end + +module RDoc::DOT + + TAB = ' ' + TAB2 = TAB * 2 + + # options for node declaration + NODE_OPTS = [ + 'bgcolor', + 'color', + 'fontcolor', + 'fontname', + 'fontsize', + 'height', + 'width', + 'label', + 'layer', + 'rank', + 'shape', + 'shapefile', + 'style', + 'URL', + ] + + # options for edge declaration + EDGE_OPTS = [ + 'color', + 'decorate', + 'dir', + 'fontcolor', + 'fontname', + 'fontsize', + 'id', + 'label', + 'layer', + 'lhead', + 'ltail', + 'minlen', + 'style', + 'weight' + ] + + # options for graph declaration + GRAPH_OPTS = [ + 'bgcolor', + 'center', + 'clusterrank', + 'color', + 'compound', + 'concentrate', + 'fillcolor', + 'fontcolor', + 'fontname', + 'fontsize', + 'label', + 'layerseq', + 'margin', + 'mclimit', + 'nodesep', + 'nslimit', + 'ordering', + 'orientation', + 'page', + 'rank', + 'rankdir', + 'ranksep', + 'ratio', + 'size', + 'style', + 'URL' + ] + + # a root class for any element in dot notation + class SimpleElement + attr_accessor :name + + def initialize( params = {} ) + @label = params['name'] ? params['name'] : '' + end + + def to_s + @name + end + end + + # an element that has options ( node, edge or graph ) + class Element < SimpleElement + #attr_reader :parent + attr_accessor :name, :options + + def initialize( params = {}, option_list = [] ) + super( params ) + @name = params['name'] ? params['name'] : nil + @parent = params['parent'] ? params['parent'] : nil + @options = {} + option_list.each{ |i| + @options[i] = params[i] if params[i] + } + @options['label'] ||= @name if @name != 'node' + end + + def each_option + @options.each{ |i| yield i } + end + + def each_option_pair + @options.each_pair{ |key, val| yield key, val } + end + + #def parent=( thing ) + # @parent.delete( self ) if defined?( @parent ) and @parent + # @parent = thing + #end + end + + + # this is used when we build nodes that have shape=record + # ports don't have options :) + class Port < SimpleElement + attr_accessor :label + + def initialize( params = {} ) + super( params ) + @name = params['label'] ? params['label'] : '' + end + def to_s + ( @name && @name != "" ? "<#{@name}>" : "" ) + "#{@label}" + end + end + + # node element + class Node < Element + + def initialize( params = {}, option_list = NODE_OPTS ) + super( params, option_list ) + @ports = params['ports'] ? params['ports'] : [] + end + + def each_port + @ports.each{ |i| yield i } + end + + def << ( thing ) + @ports << thing + end + + def push ( thing ) + @ports.push( thing ) + end + + def pop + @ports.pop + end + + def to_s( t = '' ) + + label = @options['shape'] != 'record' && @ports.length == 0 ? + @options['label'] ? + t + TAB + "label = \"#{@options['label']}\"\n" : + '' : + t + TAB + 'label = "' + " \\\n" + + t + TAB2 + "#{@options['label']}| \\\n" + + @ports.collect{ |i| + t + TAB2 + i.to_s + }.join( "| \\\n" ) + " \\\n" + + t + TAB + '"' + "\n" + + t + "#{@name} [\n" + + @options.to_a.collect{ |i| + i[1] && i[0] != 'label' ? + t + TAB + "#{i[0]} = #{i[1]}" : nil + }.compact.join( ",\n" ) + ( label != '' ? ",\n" : "\n" ) + + label + + t + "]\n" + end + end + + # subgraph element is the same to graph, but has another header in dot + # notation + class Subgraph < Element + + def initialize( params = {}, option_list = GRAPH_OPTS ) + super( params, option_list ) + @nodes = params['nodes'] ? params['nodes'] : [] + @dot_string = 'subgraph' + end + + def each_node + @nodes.each{ |i| yield i } + end + + def << ( thing ) + @nodes << thing + end + + def push( thing ) + @nodes.push( thing ) + end + + def pop + @nodes.pop + end + + def to_s( t = '' ) + hdr = t + "#{@dot_string} #{@name} {\n" + + options = @options.to_a.collect{ |name, val| + val && name != 'label' ? + t + TAB + "#{name} = #{val}" : + name ? t + TAB + "#{name} = \"#{val}\"" : nil + }.compact.join( "\n" ) + "\n" + + nodes = @nodes.collect{ |i| + i.to_s( t + TAB ) + }.join( "\n" ) + "\n" + hdr + options + nodes + t + "}\n" + end + end + + # this is graph + class Digraph < Subgraph + def initialize( params = {}, option_list = GRAPH_OPTS ) + super( params, option_list ) + @dot_string = 'digraph' + end + end + + # this is edge + class Edge < Element + attr_accessor :from, :to + def initialize( params = {}, option_list = EDGE_OPTS ) + super( params, option_list ) + @from = params['from'] ? params['from'] : nil + @to = params['to'] ? params['to'] : nil + end + + def to_s( t = '' ) + t + "#{@from} -> #{to} [\n" + + @options.to_a.collect{ |i| + i[1] && i[0] != 'label' ? + t + TAB + "#{i[0]} = #{i[1]}" : + i[1] ? t + TAB + "#{i[0]} = \"#{i[1]}\"" : nil + }.compact.join( "\n" ) + "\n" + t + "]\n" + end + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator.rb new file mode 100644 index 000000000..b65002977 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator.rb @@ -0,0 +1,8 @@ +require 'rdoc' + +## +# Namespace for generators + +module RDoc::Generator +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/darkfish.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/darkfish.rb new file mode 100644 index 000000000..4e5791cd3 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/darkfish.rb @@ -0,0 +1,455 @@ +#!ruby +# vim: noet ts=2 sts=8 sw=2 + +require 'rubygems' +gem 'rdoc', '>= 2.4' unless defined? $rdoc_rakefile + +require 'pp' +require 'pathname' +require 'fileutils' +require 'erb' +require 'yaml' + +require 'rdoc/rdoc' +require 'rdoc/generator' +require 'rdoc/generator/markup' + +# +# Darkfish RDoc HTML Generator +# +# $Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $ +# +# == Author/s +# * Michael Granger (ged@FaerieMUD.org) +# +# == Contributors +# * Mahlon E. Smith (mahlon@martini.nu) +# * Eric Hodel (drbrain@segment7.net) +# +# == License +# +# Copyright (c) 2007, 2008, Michael Granger. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the author/s, nor the names of the project's +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +class RDoc::Generator::Darkfish + + RDoc::RDoc.add_generator( self ) + + include ERB::Util + + # Subversion rev + SVNRev = %$Rev: 52 $ + + # Subversion ID + SVNId = %$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $ + + # Path to this file's parent directory. Used to find templates and other + # resources. + GENERATOR_DIR = File.join 'rdoc', 'generator' + + # Release Version + VERSION = '1.1.6' + + # Directory where generated classes live relative to the root + CLASS_DIR = nil + + # Directory where generated files live relative to the root + FILE_DIR = nil + + + ################################################################# + ### C L A S S M E T H O D S + ################################################################# + + ### Standard generator factory method + def self::for( options ) + new( options ) + end + + + ################################################################# + ### I N S T A N C E M E T H O D S + ################################################################# + + ### Initialize a few instance variables before we start + def initialize( options ) + @options = options + @options.diagram = false + + template = @options.template || 'darkfish' + + template_dir = $LOAD_PATH.map do |path| + File.join path, GENERATOR_DIR, 'template', template + end.find do |dir| + File.directory? dir + end + + raise RDoc::Error, "could not find template #{template.inspect}" unless + template_dir + + @template_dir = Pathname.new File.expand_path(template_dir) + + @files = nil + @classes = nil + + @basedir = Pathname.pwd.expand_path + end + + ###### + public + ###### + + # The output directory + attr_reader :outputdir + + + ### Output progress information if debugging is enabled + def debug_msg( *msg ) + return unless $DEBUG_RDOC + $stderr.puts( *msg ) + end + + def class_dir + CLASS_DIR + end + + def file_dir + FILE_DIR + end + + ### Create the directories the generated docs will live in if + ### they don't already exist. + def gen_sub_directories + @outputdir.mkpath + end + + ### Copy over the stylesheet into the appropriate place in the output + ### directory. + def write_style_sheet + debug_msg "Copying static files" + options = { :verbose => $DEBUG_RDOC, :noop => $dryrun } + + FileUtils.cp @template_dir + 'rdoc.css', '.', options + + Dir[(@template_dir + "{js,images}/**/*").to_s].each do |path| + next if File.directory? path + next if path =~ /#{File::SEPARATOR}\./ + + dst = Pathname.new(path).relative_path_from @template_dir + + # I suck at glob + dst_dir = dst.dirname + FileUtils.mkdir_p dst_dir, options unless File.exist? dst_dir + + FileUtils.cp @template_dir + path, dst, options + end + end + + ### Build the initial indices and output objects + ### based on an array of TopLevel objects containing + ### the extracted information. + def generate( top_levels ) + @outputdir = Pathname.new( @options.op_dir ).expand_path( @basedir ) + + @files = top_levels.sort + @classes = RDoc::TopLevel.all_classes_and_modules.sort + @methods = @classes.map { |m| m.method_list }.flatten.sort + @modsort = get_sorted_module_list( @classes ) + + # Now actually write the output + write_style_sheet + generate_index + generate_class_files + generate_file_files + + rescue StandardError => err + debug_msg "%s: %s\n %s" % [ err.class.name, err.message, err.backtrace.join("\n ") ] + raise + end + + ######### + protected + ######### + + ### Return a list of the documented modules sorted by salience first, then + ### by name. + def get_sorted_module_list( classes ) + nscounts = classes.inject({}) do |counthash, klass| + top_level = klass.full_name.gsub( /::.*/, '' ) + counthash[top_level] ||= 0 + counthash[top_level] += 1 + + counthash + end + + # Sort based on how often the top level namespace occurs, and then on the + # name of the module -- this works for projects that put their stuff into + # a namespace, of course, but doesn't hurt if they don't. + classes.sort_by do |klass| + top_level = klass.full_name.gsub( /::.*/, '' ) + [ + nscounts[ top_level ] * -1, + klass.full_name + ] + end.select do |klass| + klass.document_self + end + end + + ### Generate an index page which lists all the classes which + ### are documented. + def generate_index + debug_msg "Rendering the index page..." + + templatefile = @template_dir + 'index.rhtml' + template_src = templatefile.read + template = ERB.new( template_src, nil, '<>' ) + template.filename = templatefile.to_s + context = binding() + + output = nil + + begin + output = template.result( context ) + rescue NoMethodError => err + raise RDoc::Error, "Error while evaluating %s: %s (at %p)" % [ + templatefile, + err.message, + eval( "_erbout[-50,50]", context ) + ], err.backtrace + end + + outfile = @basedir + @options.op_dir + 'index.html' + unless $dryrun + debug_msg "Outputting to %s" % [outfile.expand_path] + outfile.open( 'w', 0644 ) do |fh| + fh.print( output ) + end + else + debug_msg "Would have output to %s" % [outfile.expand_path] + end + end + + ### Generate a documentation file for each class + def generate_class_files + debug_msg "Generating class documentation in #@outputdir" + templatefile = @template_dir + 'classpage.rhtml' + + @classes.each do |klass| + debug_msg " working on %s (%s)" % [ klass.full_name, klass.path ] + outfile = @outputdir + klass.path + rel_prefix = @outputdir.relative_path_from( outfile.dirname ) + svninfo = self.get_svninfo( klass ) + + debug_msg " rendering #{outfile}" + self.render_template( templatefile, binding(), outfile ) + end + end + + ### Generate a documentation file for each file + def generate_file_files + debug_msg "Generating file documentation in #@outputdir" + templatefile = @template_dir + 'filepage.rhtml' + + @files.each do |file| + outfile = @outputdir + file.path + debug_msg " working on %s (%s)" % [ file.full_name, outfile ] + rel_prefix = @outputdir.relative_path_from( outfile.dirname ) + context = binding() + + debug_msg " rendering #{outfile}" + self.render_template( templatefile, binding(), outfile ) + end + end + + + ### Return a string describing the amount of time in the given number of + ### seconds in terms a human can understand easily. + def time_delta_string( seconds ) + return 'less than a minute' if seconds < 1.minute + return (seconds / 1.minute).to_s + ' minute' + (seconds/60 == 1 ? '' : 's') if seconds < 50.minutes + return 'about one hour' if seconds < 90.minutes + return (seconds / 1.hour).to_s + ' hours' if seconds < 18.hours + return 'one day' if seconds < 1.day + return 'about one day' if seconds < 2.days + return (seconds / 1.day).to_s + ' days' if seconds < 1.week + return 'about one week' if seconds < 2.week + return (seconds / 1.week).to_s + ' weeks' if seconds < 3.months + return (seconds / 1.month).to_s + ' months' if seconds < 1.year + return (seconds / 1.year).to_s + ' years' + end + + + # %q$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $" + SVNID_PATTERN = / + \$Id:\s + (\S+)\s # filename + (\d+)\s # rev + (\d{4}-\d{2}-\d{2})\s # Date (YYYY-MM-DD) + (\d{2}:\d{2}:\d{2}Z)\s # Time (HH:MM:SSZ) + (\w+)\s # committer + \$$ + /x + + ### Try to extract Subversion information out of the first constant whose value looks like + ### a subversion Id tag. If no matching constant is found, and empty hash is returned. + def get_svninfo( klass ) + constants = klass.constants or return {} + + constants.find {|c| c.value =~ SVNID_PATTERN } or return {} + + filename, rev, date, time, committer = $~.captures + commitdate = Time.parse( date + ' ' + time ) + + return { + :filename => filename, + :rev => Integer( rev ), + :commitdate => commitdate, + :commitdelta => time_delta_string( Time.now.to_i - commitdate.to_i ), + :committer => committer, + } + end + + + ### Load and render the erb template in the given +templatefile+ within the + ### specified +context+ (a Binding object) and write it out to +outfile+. + ### Both +templatefile+ and +outfile+ should be Pathname-like objects. + + def render_template( templatefile, context, outfile ) + template_src = templatefile.read + template = ERB.new( template_src, nil, '<>' ) + template.filename = templatefile.to_s + + output = begin + template.result( context ) + rescue NoMethodError => err + raise RDoc::Error, "Error while evaluating %s: %s (at %p)" % [ + templatefile.to_s, + err.message, + eval( "_erbout[-50,50]", context ) + ], err.backtrace + end + + unless $dryrun + outfile.dirname.mkpath + outfile.open( 'w', 0644 ) do |ofh| + ofh.print( output ) + end + else + debug_msg " would have written %d bytes to %s" % + [ output.length, outfile ] + end + end + +end # Roc::Generator::Darkfish + +# :stopdoc: + +### Time constants +module TimeConstantMethods # :nodoc: + + ### Number of seconds (returns receiver unmodified) + def seconds + return self + end + alias_method :second, :seconds + + ### Returns number of seconds in <receiver> minutes + def minutes + return self * 60 + end + alias_method :minute, :minutes + + ### Returns the number of seconds in <receiver> hours + def hours + return self * 60.minutes + end + alias_method :hour, :hours + + ### Returns the number of seconds in <receiver> days + def days + return self * 24.hours + end + alias_method :day, :days + + ### Return the number of seconds in <receiver> weeks + def weeks + return self * 7.days + end + alias_method :week, :weeks + + ### Returns the number of seconds in <receiver> fortnights + def fortnights + return self * 2.weeks + end + alias_method :fortnight, :fortnights + + ### Returns the number of seconds in <receiver> months (approximate) + def months + return self * 30.days + end + alias_method :month, :months + + ### Returns the number of seconds in <receiver> years (approximate) + def years + return (self * 365.25.days).to_i + end + alias_method :year, :years + + + ### Returns the Time <receiver> number of seconds before the + ### specified +time+. E.g., 2.hours.before( header.expiration ) + def before( time ) + return time - self + end + + + ### Returns the Time <receiver> number of seconds ago. (e.g., + ### expiration > 2.hours.ago ) + def ago + return self.before( ::Time.now ) + end + + + ### Returns the Time <receiver> number of seconds after the given +time+. + ### E.g., 10.minutes.after( header.expiration ) + def after( time ) + return time + self + end + + # Reads best without arguments: 10.minutes.from_now + def from_now + return self.after( ::Time.now ) + end +end # module TimeConstantMethods + + +# Extend Numeric with time constants +class Numeric # :nodoc: + include TimeConstantMethods +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/markup.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/markup.rb new file mode 100644 index 000000000..c492483b3 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/markup.rb @@ -0,0 +1,194 @@ +require 'rdoc/code_objects' +require 'rdoc/generator' +require 'rdoc/markup/to_html_crossref' + +## +# Handle common HTML markup tasks for various CodeObjects + +module RDoc::Generator::Markup + + ## + # Generates a relative URL from this object's path to +target_path+ + + def aref_to(target_path) + RDoc::Markup::ToHtml.gen_relative_url path, target_path + end + + ## + # Generates a relative URL from +from_path+ to this object's path + + def as_href(from_path) + RDoc::Markup::ToHtml.gen_relative_url from_path, path + end + + ## + # Handy wrapper for marking up this object's comment + + def description + markup @comment + end + + ## + # RDoc::Markup formatter object + + def formatter + return @formatter if defined? @formatter + + show_hash = RDoc::RDoc.current.options.show_hash + this = RDoc::Context === self ? self : @parent + @formatter = RDoc::Markup::ToHtmlCrossref.new this.path, this, show_hash + end + + ## + # Convert a string in markup format into HTML. + + def markup(str, remove_para = false) + return '' unless str + + # Convert leading comment markers to spaces, but only if all non-blank + # lines have them + if str =~ /^(?>\s*)[^\#]/ then + content = str + else + content = str.gsub(/^\s*(#+)/) { $1.tr '#', ' ' } + end + + res = formatter.convert content + + if remove_para then + res.sub!(/^<p>/, '') + res.sub!(/<\/p>$/, '') + end + + res + end + + ## + # Build a webcvs URL starting for the given +url+ with +full_path+ appended + # as the destination path. If +url+ contains '%s' +full_path+ will be + # sprintf'd into +url+ instead. + + def cvs_url(url, full_path) + if /%s/ =~ url then + sprintf url, full_path + else + url + full_path + end + end + +end + +class RDoc::AnyMethod + + include RDoc::Generator::Markup + + ## + # Prepend +src+ with line numbers. Relies on the first line of a source + # code listing having: + # + # # File xxxxx, line dddd + + def add_line_numbers(src) + if src =~ /\A.*, line (\d+)/ then + first = $1.to_i - 1 + last = first + src.count("\n") + size = last.to_s.length + + line = first + src.gsub!(/^/) do + res = if line == first then + " " * (size + 2) + else + "%#{size}d: " % line + end + + line += 1 + res + end + end + end + + ## + # Turns the method's token stream into HTML + + def markup_code + return '' unless @token_stream + + src = "" + + @token_stream.each do |t| + next unless t + # style = STYLE_MAP[t.class] + style = case t + when RDoc::RubyToken::TkCONSTANT then "ruby-constant" + when RDoc::RubyToken::TkKW then "ruby-keyword kw" + when RDoc::RubyToken::TkIVAR then "ruby-ivar" + when RDoc::RubyToken::TkOp then "ruby-operator" + when RDoc::RubyToken::TkId then "ruby-identifier" + when RDoc::RubyToken::TkNode then "ruby-node" + when RDoc::RubyToken::TkCOMMENT then "ruby-comment cmt" + when RDoc::RubyToken::TkREGEXP then "ruby-regexp re" + when RDoc::RubyToken::TkSTRING then "ruby-value str" + when RDoc::RubyToken::TkVal then "ruby-value" + else + nil + end + + text = CGI.escapeHTML(t.text) + + if style + src << "<span class=\"#{style}\">#{text}</span>" + else + src << text + end + end + + add_line_numbers src if RDoc::RDoc.current.options.include_line_numbers + + src + end + +end + +class RDoc::Attr + + include RDoc::Generator::Markup + +end + +class RDoc::Constant + + include RDoc::Generator::Markup + +end + +class RDoc::Context + + include RDoc::Generator::Markup + +end + +class RDoc::Context::Section + + include RDoc::Generator::Markup + +end + +class RDoc::TopLevel + + ## + # Returns a URL for this source file on some web repository. Use the -W + # command line option to set. + + def cvs_url + url = RDoc::RDoc.current.options.webcvs + + if /%s/ =~ url then + url % @absolute_name + else + url + @absolute_name + end + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/ri.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/ri.rb new file mode 100644 index 000000000..44fc97d72 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/ri.rb @@ -0,0 +1,230 @@ +require 'rdoc/generator' +require 'rdoc/markup/to_flow' + +require 'rdoc/ri/cache' +require 'rdoc/ri/reader' +require 'rdoc/ri/writer' +require 'rdoc/ri/descriptions' + +class RDoc::Generator::RI + + RDoc::RDoc.add_generator self + + ## + # Generator may need to return specific subclasses depending on the + # options they are passed. Because of this we create them using a factory + + def self.for(options) + new(options) + end + + ## + # Set up a new ri generator + + def initialize(options) #:not-new: + @options = options + @ri_writer = RDoc::RI::Writer.new "." + @markup = RDoc::Markup.new + @to_flow = RDoc::Markup::ToFlow.new + + @generated = {} + end + + ## + # Build the initial indices and output objects based on an array of + # TopLevel objects containing the extracted information. + + def generate(top_levels) + RDoc::TopLevel.all_classes_and_modules.each do |cls| + process_class cls + end + end + + def process_class(from_class) + generate_class_info(from_class) + + # now recurse into this class' constituent classes + from_class.each_classmodule do |mod| + process_class(mod) + end + end + + def generate_class_info(cls) + case cls + when RDoc::NormalModule then + cls_desc = RDoc::RI::ModuleDescription.new + else + cls_desc = RDoc::RI::ClassDescription.new + superclass = cls.superclass + superclass = superclass.full_name unless String === superclass + cls_desc.superclass = superclass + end + + cls_desc.name = cls.name + cls_desc.full_name = cls.full_name + cls_desc.comment = markup(cls.comment) + + cls_desc.attributes = cls.attributes.sort.map do |a| + RDoc::RI::Attribute.new(a.name, a.rw, markup(a.comment)) + end + + cls_desc.constants = cls.constants.map do |c| + RDoc::RI::Constant.new(c.name, c.value, markup(c.comment)) + end + + cls_desc.includes = cls.includes.map do |i| + RDoc::RI::IncludedModule.new(i.name) + end + + class_methods, instance_methods = method_list(cls) + + cls_desc.class_methods = class_methods.map do |m| + RDoc::RI::MethodSummary.new(m.name) + end + + cls_desc.instance_methods = instance_methods.map do |m| + RDoc::RI::MethodSummary.new(m.name) + end + + update_or_replace(cls_desc) + + class_methods.each do |m| + generate_method_info(cls_desc, m) + end + + instance_methods.each do |m| + generate_method_info(cls_desc, m) + end + end + + def generate_method_info(cls_desc, method) + meth_desc = RDoc::RI::MethodDescription.new + meth_desc.name = method.name + meth_desc.full_name = cls_desc.full_name + if method.singleton + meth_desc.full_name += "::" + else + meth_desc.full_name += "#" + end + meth_desc.full_name << method.name + + meth_desc.comment = markup(method.comment) + meth_desc.params = params_of(method) + meth_desc.visibility = method.visibility.to_s + meth_desc.is_singleton = method.singleton + meth_desc.block_params = method.block_params + + meth_desc.aliases = method.aliases.map do |a| + RDoc::RI::AliasName.new(a.name) + end + + @ri_writer.add_method(cls_desc, meth_desc) + end + + private + + ## + # Returns a list of class and instance methods that we'll be documenting + + def method_list(cls) + list = cls.method_list + unless @options.show_all + list = list.find_all do |m| + m.visibility == :public || m.visibility == :protected || m.force_documentation + end + end + + c = [] + i = [] + list.sort.each do |m| + if m.singleton + c << m + else + i << m + end + end + return c,i + end + + def params_of(method) + if method.call_seq + method.call_seq + else + params = method.params || "" + + p = params.gsub(/\s*\#.*/, '') + p = p.tr("\n", " ").squeeze(" ") + p = "(" + p + ")" unless p[0] == ?( + + if (block = method.block_params) + block.gsub!(/\s*\#.*/, '') + block = block.tr("\n", " ").squeeze(" ") + if block[0] == ?( + block.sub!(/^\(/, '').sub!(/\)/, '') + end + p << " {|#{block.strip}| ...}" + end + p + end + end + + def markup(comment) + return nil if !comment || comment.empty? + + # Convert leading comment markers to spaces, but only + # if all non-blank lines have them + + if comment =~ /^(?>\s*)[^\#]/ + content = comment + else + content = comment.gsub(/^\s*(#+)/) { $1.tr('#',' ') } + end + @markup.convert(content, @to_flow) + end + + ## + # By default we replace existing classes with the same name. If the + # --merge option was given, we instead merge this definition into an + # existing class. We add our methods, aliases, etc to that class, but do + # not change the class's description. + + def update_or_replace(cls_desc) + old_cls = nil + + if @options.merge + rdr = RDoc::RI::Reader.new RDoc::RI::Cache.new(@options.op_dir) + + namespace = rdr.top_level_namespace + namespace = rdr.lookup_namespace_in(cls_desc.name, namespace) + if namespace.empty? + $stderr.puts "You asked me to merge this source into existing " + $stderr.puts "documentation. This file references a class or " + $stderr.puts "module called #{cls_desc.name} which I don't" + $stderr.puts "have existing documentation for." + $stderr.puts + $stderr.puts "Perhaps you need to generate its documentation first" + exit 1 + else + old_cls = namespace[0] + end + end + + prev_cls = @generated[cls_desc.full_name] + + if old_cls and not prev_cls then + old_desc = rdr.get_class old_cls + cls_desc.merge_in old_desc + end + + if prev_cls then + cls_desc.merge_in prev_cls + end + + @generated[cls_desc.full_name] = cls_desc + + @ri_writer.remove_class cls_desc + @ri_writer.add_class cls_desc + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/.document b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/.document new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/.document diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/classpage.rhtml b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/classpage.rhtml new file mode 100644 index 000000000..921fcef71 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/classpage.rhtml @@ -0,0 +1,281 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" /> + + <title><%= klass.type.capitalize %>: <%= klass.full_name %></title> + + <link rel="stylesheet" href="<%= rel_prefix %>/rdoc.css" type="text/css" media="screen" /> + + <script src="<%= rel_prefix %>/js/jquery.js" type="text/javascript" + charset="utf-8"></script> + <script src="<%= rel_prefix %>/js/thickbox-compressed.js" type="text/javascript" + charset="utf-8"></script> + <script src="<%= rel_prefix %>/js/quicksearch.js" type="text/javascript" + charset="utf-8"></script> + <script src="<%= rel_prefix %>/js/darkfish.js" type="text/javascript" + charset="utf-8"></script> + +</head> +<body class="<%= klass.type %>"> + + <div id="metadata"> + <div id="file-metadata"> + <div id="file-list-section" class="section"> + <h3 class="section-header">In Files</h3> + <div class="section-body"> + <ul> + <% klass.in_files.each do |tl| %> + <li><a href="<%= rel_prefix %>/<%= h tl.path %>?TB_iframe=true&height=550&width=785" + class="thickbox" title="<%= h tl.absolute_name %>"><%= h tl.absolute_name %></a></li> + <% end %> + </ul> + </div> + </div> + + <% if !svninfo.empty? %> + <div id="file-svninfo-section" class="section"> + <h3 class="section-header">Subversion Info</h3> + <div class="section-body"> + <dl class="svninfo"> + <dt>Rev</dt> + <dd><%= svninfo[:rev] %></dd> + + <dt>Last Checked In</dt> + <dd><%= svninfo[:commitdate].strftime('%Y-%m-%d %H:%M:%S') %> + (<%= svninfo[:commitdelta] %> ago)</dd> + + <dt>Checked in by</dt> + <dd><%= svninfo[:committer] %></dd> + </dl> + </div> + </div> + <% end %> + </div> + + <div id="class-metadata"> + + <!-- Parent Class --> + <% if klass.type == 'class' %> + <div id="parent-class-section" class="section"> + <h3 class="section-header">Parent</h3> + <% unless String === klass.superclass %> + <p class="link"><a href="<%= klass.aref_to klass.superclass.path %>"><%= klass.superclass.full_name %></a></p> + <% else %> + <p class="link"><%= klass.superclass %></p> + <% end %> + </div> + <% end %> + + <!-- Namespace Contents --> + <% unless klass.classes_and_modules.empty? %> + <div id="namespace-list-section" class="section"> + <h3 class="section-header">Namespace</h3> + <ul class="link-list"> + <% (klass.modules.sort + klass.classes.sort).each do |mod| %> + <li><span class="type"><%= mod.type.upcase %></span> <a href="<%= klass.aref_to mod.path %>"><%= mod.full_name %></a></li> + <% end %> + </ul> + </div> + <% end %> + + <!-- Method Quickref --> + <% unless klass.method_list.empty? %> + <div id="method-list-section" class="section"> + <h3 class="section-header">Methods</h3> + <ul class="link-list"> + <% klass.each_method do |meth| %> + <li><a href="#<%= meth.aref %>"><%= meth.singleton ? '::' : '#' %><%= meth.name %></a></li> + <% end %> + </ul> + </div> + <% end %> + + <!-- Included Modules --> + <% unless klass.includes.empty? %> + <div id="includes-section" class="section"> + <h3 class="section-header">Included Modules</h3> + <ul class="link-list"> + <% klass.each_include do |inc| %> + <% unless String === inc.module %> + <li><a class="include" href="<%= klass.aref_to inc.module.path %>"><%= inc.module.full_name %></a></li> + <% else %> + <li><span class="include"><%= inc.name %></span></li> + <% end %> + <% end %> + </ul> + </div> + <% end %> + </div> + + <div id="project-metadata"> + <% simple_files = @files.select {|tl| tl.parser == RDoc::Parser::Simple } %> + <% unless simple_files.empty? then %> + <div id="fileindex-section" class="section project-section"> + <h3 class="section-header">Files</h3> + <ul> + <% simple_files.each do |file| %> + <li class="file"><a href="<%= rel_prefix %>/<%= file.path %>"><%= h file.base_name %></a></li> + <% end %> + </ul> + </div> + <% end %> + + <div id="classindex-section" class="section project-section"> + <h3 class="section-header">Class Index + <span class="search-toggle"><img src="<%= rel_prefix %>/images/find.png" + height="16" width="16" alt="[+]" + title="show/hide quicksearch" /></span></h3> + <form action="#" method="get" accept-charset="utf-8" class="initially-hidden"> + <fieldset> + <legend>Quicksearch</legend> + <input type="text" name="quicksearch" value="" + class="quicksearch-field" /> + </fieldset> + </form> + + <ul class="link-list"> + <% @modsort.each do |index_klass| %> + <li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a></li> + <% end %> + </ul> + <div id="no-class-search-results" style="display: none;">No matching classes.</div> + </div> + + <% if $DEBUG_RDOC %> + <div id="debugging-toggle"><img src="<%= rel_prefix %>/images/bug.png" + alt="toggle debugging" height="16" width="16" /></div> + <% end %> + </div> + </div> + + <div id="documentation"> + <h1 class="<%= klass.type %>"><%= klass.full_name %></h1> + + <div id="description"> + <%= klass.description %> + </div> + + <!-- Constants --> + <% unless klass.constants.empty? %> + <div id="constants-list" class="section"> + <h3 class="section-header">Constants</h3> + <dl> + <% klass.each_constant do |const| %> + <dt><a name="<%= const.name %>"><%= const.name %></a></dt> + <% if const.comment %> + <dd class="description"><%= const.description.strip %></dd> + <% else %> + <dd class="description missing-docs">(Not documented)</dd> + <% end %> + <% end %> + </dl> + </div> + <% end %> + + <!-- Attributes --> + <% unless klass.attributes.empty? %> + <div id="attribute-method-details" class="method-section section"> + <h3 class="section-header">Attributes</h3> + + <% klass.each_attribute do |attrib| %> + <div id="<%= attrib.html_name %>-attribute-method" class="method-detail"> + <a name="<%= h attrib.name %>"></a> + <% if attrib.rw =~ /w/i %> + <a name="<%= h attrib.name %>="></a> + <% end %> + <div class="method-heading attribute-method-heading"> + <span class="method-name"><%= h attrib.name %></span><span + class="attribute-access-type">[<%= attrib.rw %>]</span> + </div> + + <div class="method-description"> + <% if attrib.comment %> + <%= attrib.description.strip %> + <% else %> + <p class="missing-docs">(Not documented)</p> + <% end %> + </div> + </div> + <% end %> + </div> + <% end %> + + <!-- Methods --> + <% klass.methods_by_type.each do |type, visibilities| + next if visibilities.empty? + visibilities.each do |visibility, methods| + next if methods.empty? %> + <div id="<%= visibility %>-<%= type %>-method-details" class="method-section section"> + <h3 class="section-header"><%= visibility.to_s.capitalize %> <%= type.capitalize %> Methods</h3> + + <% methods.each do |method| %> + <div id="<%= method.html_name %>-method" class="method-detail <%= method.is_alias_for ? "method-alias" : '' %>"> + <a name="<%= h method.aref %>"></a> + + <div class="method-heading"> + <% if method.call_seq %> + <span class="method-callseq"><%= method.call_seq.strip.gsub(/->/, '→').gsub( /^\w.*?\./m, '') %></span> + <span class="method-click-advice">click to toggle source</span> + <% else %> + <span class="method-name"><%= h method.name %></span><span + class="method-args"><%= method.params %></span> + <span class="method-click-advice">click to toggle source</span> + <% end %> + </div> + + <div class="method-description"> + <% if method.comment %> + <%= method.description.strip %> + <% else %> + <p class="missing-docs">(Not documented)</p> + <% end %> + + <% if method.token_stream %> + <div class="method-source-code" + id="<%= method.html_name %>-source"> +<pre> +<%= method.markup_code %> +</pre> + </div> + <% end %> + </div> + + <% unless method.aliases.empty? %> + <div class="aliases"> + Also aliased as: <%= method.aliases.map do |aka| + %{<a href="#{ klass.aref_to aka.path}">#{h aka.name}</a>} + end.join(", ") %> + </div> + <% end %> + </div> + + <% end %> + </div> + <% end + end %> + + </div> + + + <div id="rdoc-debugging-section-dump" class="debugging-section"> + <% if $DEBUG_RDOC + require 'pp' %> +<pre><%= h PP.pp(klass, _erbout) %></pre> + </div> + <% else %> + <p>Disabled; run with --debug to generate this.</p> + <% end %> + </div> + + <div id="validator-badges"> + <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p> + <p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish + Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p> + </div> + +</body> +</html> + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/filepage.rhtml b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/filepage.rhtml new file mode 100644 index 000000000..2627e8966 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/filepage.rhtml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" /> + + <title>File: <%= file.base_name %> [<%= @options.title %>]</title> + + <link type="text/css" media="screen" href="<%= rel_prefix %>/rdoc.css" rel="stylesheet" /> + + <script src="<%= rel_prefix %>/js/jquery.js" type="text/javascript" + charset="utf-8"></script> + <script src="<%= rel_prefix %>/js/thickbox-compressed.js" type="text/javascript" + charset="utf-8"></script> + <script src="<%= rel_prefix %>/js/quicksearch.js" type="text/javascript" + charset="utf-8"></script> + <script src="<%= rel_prefix %>/js/darkfish.js" type="text/javascript" + charset="utf-8"></script> +</head> + +<% if file.parser == RDoc::Parser::Simple %> +<body class="file"> + <div id="metadata"> + <div id="project-metadata"> + <% simple_files = @files.select { |f| f.parser == RDoc::Parser::Simple } %> + <% unless simple_files.empty? then %> + <div id="fileindex-section" class="section project-section"> + <h3 class="section-header">Files</h3> + <ul> + <% simple_files.each do |f| %> + <li class="file"><a href="<%= rel_prefix %>/<%= f.path %>"><%= h f.base_name %></a></li> + <% end %> + </ul> + </div> + <% end %> + + <div id="classindex-section" class="section project-section"> + <h3 class="section-header">Class Index + <span class="search-toggle"><img src="<%= rel_prefix %>/images/find.png" + height="16" width="16" alt="[+]" + title="show/hide quicksearch" /></span></h3> + <form action="#" method="get" accept-charset="utf-8" class="initially-hidden"> + <fieldset> + <legend>Quicksearch</legend> + <input type="text" name="quicksearch" value="" + class="quicksearch-field" /> + </fieldset> + </form> + + <ul class="link-list"> + <% @modsort.each do |index_klass| %> + <li><a href="<%= rel_prefix %>/<%= index_klass.path %>"><%= index_klass.full_name %></a></li> + <% end %> + </ul> + <div id="no-class-search-results" style="display: none;">No matching classes.</div> + </div> + + <% if $DEBUG_RDOC %> + <div id="debugging-toggle"><img src="<%= rel_prefix %>/images/bug.png" + alt="toggle debugging" height="16" width="16" /></div> + <% end %> + </div> + </div> + + <div id="documentation"> + <%= file.description %> + </div> + + <div id="validator-badges"> + <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p> + <p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish + Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p> + </div> +</body> +<% else %> +<body class="file file-popup"> + <div id="metadata"> + <dl> + <dt class="modified-date">Last Modified</dt> + <dd class="modified-date"><%= file.last_modified %></dd> + + <% if file.requires %> + <dt class="requires">Requires</dt> + <dd class="requires"> + <ul> + <% file.requires.each do |require| %> + <li><%= require.name %></li> + <% end %> + </ul> + </dd> + <% end %> + + <% if @options.webcvs %> + <dt class="scs-url">Trac URL</dt> + <dd class="scs-url"><a target="_top" + href="<%= file.cvs_url %>"><%= file.cvs_url %></a></dd> + <% end %> + </dl> + </div> + + <div id="documentation"> + <% if file.comment %> + <div class="description"> + <h2>Description</h2> + <%= file.description %> + </div> + <% end %> + </div> +</body> +<% end %> +</html> + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/brick.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/brick.png Binary files differnew file mode 100755 index 000000000..7851cf34c --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/brick.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/brick_link.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/brick_link.png Binary files differnew file mode 100755 index 000000000..9ebf013a2 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/brick_link.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/bug.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/bug.png Binary files differnew file mode 100644 index 000000000..2d5fb90ec --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/bug.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/bullet_black.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/bullet_black.png Binary files differnew file mode 100755 index 000000000..57619706d --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/bullet_black.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png Binary files differnew file mode 100755 index 000000000..b47ce55f6 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png Binary files differnew file mode 100755 index 000000000..9ab4a8966 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/date.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/date.png Binary files differnew file mode 100755 index 000000000..783c83357 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/date.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/find.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/find.png Binary files differnew file mode 100755 index 000000000..154747964 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/find.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif Binary files differnew file mode 100644 index 000000000..82290f483 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/macFFBgHack.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/macFFBgHack.png Binary files differnew file mode 100644 index 000000000..c6473b324 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/macFFBgHack.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/package.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/package.png Binary files differnew file mode 100755 index 000000000..da3c2a2d7 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/package.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/page_green.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/page_green.png Binary files differnew file mode 100755 index 000000000..de8e003f9 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/page_green.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/page_white_text.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/page_white_text.png Binary files differnew file mode 100755 index 000000000..813f712f7 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/page_white_text.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/page_white_width.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/page_white_width.png Binary files differnew file mode 100755 index 000000000..1eb880947 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/page_white_width.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/plugin.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/plugin.png Binary files differnew file mode 100755 index 000000000..6187b15ae --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/plugin.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/ruby.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/ruby.png Binary files differnew file mode 100755 index 000000000..f763a1688 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/ruby.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/tag_green.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/tag_green.png Binary files differnew file mode 100755 index 000000000..83ec984bd --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/tag_green.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/wrench.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/wrench.png Binary files differnew file mode 100755 index 000000000..5c8213fef --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/wrench.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/wrench_orange.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/wrench_orange.png Binary files differnew file mode 100755 index 000000000..565a9330e --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/wrench_orange.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/zoom.png b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/zoom.png Binary files differnew file mode 100755 index 000000000..908612e39 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/images/zoom.png diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/index.rhtml b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/index.rhtml new file mode 100644 index 000000000..21c067606 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/index.rhtml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> + +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> + <meta content="text/html; charset=<%= @options.charset %>" http-equiv="Content-Type" /> + + <title><%= h @options.title %></title> + + <link type="text/css" media="screen" href="rdoc.css" rel="stylesheet" /> + + <script src="js/jquery.js" type="text/javascript" charset="utf-8"></script> + <script src="js/thickbox-compressed.js" type="text/javascript" charset="utf-8"></script> + <script src="js/quicksearch.js" type="text/javascript" charset="utf-8"></script> + <script src="js/darkfish.js" type="text/javascript" charset="utf-8"></script> + +</head> +<body class="indexpage"> + + <% $stderr.sync = true %> + <h1><%= h @options.title %></h1> + + <% if @options.main_page && main_page = @files.find { |f| f.full_name == @options.main_page } %> + <div id="main"> + <%= main_page.description.sub(%r{^\s*<h1.*?/h1>}i, '') %> + </div> + <% else %> + <p>This is the API documentation for '<%= @options.title %>'.</p> + <% end %> + + <% simple_files = @files.select {|tl| tl.parser == RDoc::Parser::Simple } %> + <% unless simple_files.empty? then %> + <h2>Files</h2> + <ul> + <% simple_files.sort.each do |file| %> + <li class="file"><a href="<%= file.path %>"><%= h file.base_name %></a></li> + <% end %> + </ul> + <% end %> + + <h2>Classes/Modules</h2> + <ul> + <% @modsort.each do |klass| %> + <li class="<%= klass.type %>"><a href="<%= klass.path %>"><%= klass.full_name %></a></li> + <% end %> + </ul> + + <h2>Methods</h2> + <ul> + <% RDoc::TopLevel.all_classes_and_modules.map do |mod| + mod.method_list + end.flatten.sort.each do |method| %> + <li><a href="<%= method.path %>"><%= method.pretty_name %> — <%= method.parent.full_name %></a></li> + <% end %> + </ul> + + <div id="validator-badges"> + <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p> + <p><small>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish + Rdoc Generator</a> <%= RDoc::Generator::Darkfish::VERSION %></small>.</p> + </div> +</body> +</html> diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/js/darkfish.js b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/js/darkfish.js new file mode 100644 index 000000000..43528fdde --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/js/darkfish.js @@ -0,0 +1,116 @@ +/** + * + * Darkfish Page Functions + * $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $ + * + * Author: Michael Granger <mgranger@laika.com> + * + */ + +/* Provide console simulation for firebug-less environments */ +if (!("console" in window) || !("firebug" in console)) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", + "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; + + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +}; + + +/** + * Unwrap the first element that matches the given @expr@ from the targets and return them. + */ +$.fn.unwrap = function( expr ) { + return this.each( function() { + $(this).parents( expr ).eq( 0 ).after( this ).remove(); + }); +}; + + +function showSource( e ) { + var target = e.target; + var codeSections = $(target). + parents('.method-detail'). + find('.method-source-code'); + + $(target). + parents('.method-detail'). + find('.method-source-code'). + slideToggle(); +}; + +function hookSourceViews() { + $('.method-description,.method-heading').click( showSource ); +}; + +function toggleDebuggingSection() { + $('.debugging-section').slideToggle(); +}; + +function hookDebuggingToggle() { + $('#debugging-toggle img').click( toggleDebuggingSection ); +}; + +function hookQuickSearch() { + $('.quicksearch-field').each( function() { + var searchElems = $(this).parents('.section').find( 'li' ); + var toggle = $(this).parents('.section').find('h3 .search-toggle'); + // console.debug( "Toggle is: %o", toggle ); + var qsbox = $(this).parents('form').get( 0 ); + + $(this).quicksearch( this, searchElems, { + noSearchResultsIndicator: 'no-class-search-results', + focusOnLoad: false + }); + $(toggle).click( function() { + // console.debug( "Toggling qsbox: %o", qsbox ); + $(qsbox).toggle(); + }); + }); +}; + +function highlightTarget( anchor ) { + console.debug( "Highlighting target '%s'.", anchor ); + + $("a[name=" + anchor + "]").each( function() { + if ( !$(this).parent().parent().hasClass('target-section') ) { + console.debug( "Wrapping the target-section" ); + $('div.method-detail').unwrap( 'div.target-section' ); + $(this).parent().wrap( '<div class="target-section"></div>' ); + } else { + console.debug( "Already wrapped." ); + } + }); +}; + +function highlightLocationTarget() { + console.debug( "Location hash: %s", window.location.hash ); + if ( ! window.location.hash || window.location.hash.length == 0 ) return; + + var anchor = window.location.hash.substring(1); + console.debug( "Found anchor: %s; matching %s", anchor, "a[name=" + anchor + "]" ); + + highlightTarget( anchor ); +}; + +function highlightClickTarget( event ) { + console.debug( "Highlighting click target for event %o", event.target ); + try { + var anchor = $(event.target).attr( 'href' ).substring(1); + console.debug( "Found target anchor: %s", anchor ); + highlightTarget( anchor ); + } catch ( err ) { + console.error( "Exception while highlighting: %o", err ); + }; +}; + + +$(document).ready( function() { + hookSourceViews(); + hookDebuggingToggle(); + hookQuickSearch(); + highlightLocationTarget(); + + $('ul.link-list a').bind( "click", highlightClickTarget ); +}); diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/js/jquery.js b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/js/jquery.js new file mode 100644 index 000000000..afe9e74c9 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/js/jquery.js @@ -0,0 +1,32 @@ +/* + * jQuery 1.2.6 - New Wave Javascript + * + * Copyright (c) 2008 John Resig (jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Date: 2008-09-25 09:50:52 -0700 (Thu, 25 Sep 2008) $ + * $Rev: 38 $ + */ +(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3])return jQuery().find(selector);return jQuery(elem);}selector=[];}}else +return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else +return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else +selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else +return(this[0].value||"").replace(/\r/g,"");}return undefined;}if(value.constructor==Number)value+='';return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else +this.value=value;});},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&parts[1]?this.data(parts[0]):data;}else +return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script"))scripts=scripts.add(elem);else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else +jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}function now(){return+new Date;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&©&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else +script.appendChild(document.createTextNode(data));head.insertBefore(script,head.firstChild);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!==undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===false)break;}else +for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else +for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else +jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem+='';if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else +ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&¬xml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&¬xml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&¬xml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else +while(i)ret[--i]=array[i];}return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]===elem)return i;return-1;},merge:function(first,second){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else +while(elem=second[i++])first[pos++]=elem;return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv!=!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null)ret[ret.length]=value;}return ret.concat.apply([],ret);}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false,re=quickChild,m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem)r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else +for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||handler.type==namespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false;}));},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else +jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!='string')return this._load(url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{url:location.href,global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else +xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else +jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else +for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else +s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt.complete.call(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else +e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.call(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(elem){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));}return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].call(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.call(this.elem,this.now,this);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=now();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done)this.options.complete.call(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}}});jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l,10)||0;top+=parseInt(t,10)||0;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})();
\ No newline at end of file diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/js/quicksearch.js b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/js/quicksearch.js new file mode 100644 index 000000000..332772ac7 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/js/quicksearch.js @@ -0,0 +1,114 @@ +/** + * + * JQuery QuickSearch - Hook up a form field to hide non-matching elements. + * $Id: quicksearch.js 53 2009-01-07 02:52:03Z deveiant $ + * + * Author: Michael Granger <mgranger@laika.com> + * + */ +jQuery.fn.quicksearch = function( target, searchElems, options ) { + // console.debug( "Quicksearch fn" ); + + var settings = { + delay: 250, + clearButton: false, + highlightMatches: false, + focusOnLoad: false, + noSearchResultsIndicator: null + }; + if ( options ) $.extend( settings, options ); + + return jQuery(this).each( function() { + // console.debug( "Creating a new quicksearch on %o for %o", this, searchElems ); + new jQuery.quicksearch( this, searchElems, settings ); + }); +}; + + +jQuery.quicksearch = function( searchBox, searchElems, settings ) { + var timeout; + var boxdiv = $(searchBox).parents('div').eq(0); + + function init() { + setupKeyEventHandlers(); + focusOnLoad(); + }; + + function setupKeyEventHandlers() { + // console.debug( "Hooking up the 'keypress' event to %o", searchBox ); + $(searchBox). + unbind( 'keyup' ). + keyup( function(e) { return onSearchKey( e.keyCode ); }); + $(searchBox). + unbind( 'keypress' ). + keypress( function(e) { + switch( e.which ) { + // Execute the search on Enter, Tab, or Newline + case 9: + case 13: + case 10: + clearTimeout( timeout ); + e.preventDefault(); + doQuickSearch(); + break; + + // Allow backspace + case 8: + return true; + break; + + // Only allow valid search characters + default: + return validQSChar( e.charCode ); + } + }); + }; + + function focusOnLoad() { + if ( !settings.focusOnLoad ) return false; + $(searchBox).focus(); + }; + + function onSearchKey ( code ) { + clearTimeout( timeout ); + // console.debug( "...scheduling search." ); + timeout = setTimeout( doQuickSearch, settings.delay ); + }; + + function validQSChar( code ) { + var c = String.fromCharCode( code ); + return ( + (c == ':') || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') + ); + }; + + function doQuickSearch() { + var searchText = searchBox.value; + var pat = new RegExp( searchText, "im" ); + var shownCount = 0; + + if ( settings.noSearchResultsIndicator ) { + $('#' + settings.noSearchResultsIndicator).hide(); + } + + // All elements start out hidden + $(searchElems).each( function(index) { + var str = $(this).text(); + + if ( pat.test(str) ) { + shownCount += 1; + $(this).fadeIn(); + } else { + $(this).hide(); + } + }); + + if ( shownCount == 0 && settings.noSearchResultsIndicator ) { + $('#' + settings.noSearchResultsIndicator).slideDown(); + } + }; + + init(); +}; diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js new file mode 100644 index 000000000..3a3fdae1f --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/js/thickbox-compressed.js @@ -0,0 +1,10 @@ +/* + * Thickbox 3 - One Box To Rule Them All. + * By Cody Lindley (http://www.codylindley.com) + * Copyright (c) 2007 cody lindley + * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php +*/ + +var tb_pathToImage = "../images/loadingAnimation.gif"; + +eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('$(o).2S(9(){1u(\'a.18, 3n.18, 3i.18\');1w=1p 1t();1w.L=2H});9 1u(b){$(b).s(9(){6 t=X.Q||X.1v||M;6 a=X.u||X.23;6 g=X.1N||P;19(t,a,g);X.2E();H P})}9 19(d,f,g){3m{3(2t o.v.J.2i==="2g"){$("v","11").r({A:"28%",z:"28%"});$("11").r("22","2Z");3(o.1Y("1F")===M){$("v").q("<U 5=\'1F\'></U><4 5=\'B\'></4><4 5=\'8\'></4>");$("#B").s(G)}}n{3(o.1Y("B")===M){$("v").q("<4 5=\'B\'></4><4 5=\'8\'></4>");$("#B").s(G)}}3(1K()){$("#B").1J("2B")}n{$("#B").1J("2z")}3(d===M){d=""}$("v").q("<4 5=\'K\'><1I L=\'"+1w.L+"\' /></4>");$(\'#K\').2y();6 h;3(f.O("?")!==-1){h=f.3l(0,f.O("?"))}n{h=f}6 i=/\\.2s$|\\.2q$|\\.2m$|\\.2l$|\\.2k$/;6 j=h.1C().2h(i);3(j==\'.2s\'||j==\'.2q\'||j==\'.2m\'||j==\'.2l\'||j==\'.2k\'){1D="";1G="";14="";1z="";1x="";R="";1n="";1r=P;3(g){E=$("a[@1N="+g+"]").36();25(D=0;((D<E.1c)&&(R===""));D++){6 k=E[D].u.1C().2h(i);3(!(E[D].u==f)){3(1r){1z=E[D].Q;1x=E[D].u;R="<1e 5=\'1X\'>&1d;&1d;<a u=\'#\'>2T &2R;</a></1e>"}n{1D=E[D].Q;1G=E[D].u;14="<1e 5=\'1U\'>&1d;&1d;<a u=\'#\'>&2O; 2N</a></1e>"}}n{1r=1b;1n="1t "+(D+1)+" 2L "+(E.1c)}}}S=1p 1t();S.1g=9(){S.1g=M;6 a=2x();6 x=a[0]-1M;6 y=a[1]-1M;6 b=S.z;6 c=S.A;3(b>x){c=c*(x/b);b=x;3(c>y){b=b*(y/c);c=y}}n 3(c>y){b=b*(y/c);c=y;3(b>x){c=c*(x/b);b=x}}13=b+30;1a=c+2G;$("#8").q("<a u=\'\' 5=\'1L\' Q=\'1o\'><1I 5=\'2F\' L=\'"+f+"\' z=\'"+b+"\' A=\'"+c+"\' 23=\'"+d+"\'/></a>"+"<4 5=\'2D\'>"+d+"<4 5=\'2C\'>"+1n+14+R+"</4></4><4 5=\'2A\'><a u=\'#\' 5=\'Z\' Q=\'1o\'>1l</a> 1k 1j 1s</4>");$("#Z").s(G);3(!(14==="")){9 12(){3($(o).N("s",12)){$(o).N("s",12)}$("#8").C();$("v").q("<4 5=\'8\'></4>");19(1D,1G,g);H P}$("#1U").s(12)}3(!(R==="")){9 1i(){$("#8").C();$("v").q("<4 5=\'8\'></4>");19(1z,1x,g);H P}$("#1X").s(1i)}o.1h=9(e){3(e==M){I=2w.2v}n{I=e.2u}3(I==27){G()}n 3(I==3k){3(!(R=="")){o.1h="";1i()}}n 3(I==3j){3(!(14=="")){o.1h="";12()}}};16();$("#K").C();$("#1L").s(G);$("#8").r({Y:"T"})};S.L=f}n{6 l=f.2r(/^[^\\?]+\\??/,\'\');6 m=2p(l);13=(m[\'z\']*1)+30||3h;1a=(m[\'A\']*1)+3g||3f;W=13-30;V=1a-3e;3(f.O(\'2j\')!=-1){1E=f.1B(\'3d\');$("#15").C();3(m[\'1A\']!="1b"){$("#8").q("<4 5=\'2f\'><4 5=\'1H\'>"+d+"</4><4 5=\'2e\'><a u=\'#\' 5=\'Z\' Q=\'1o\'>1l</a> 1k 1j 1s</4></4><U 1W=\'0\' 2d=\'0\' L=\'"+1E[0]+"\' 5=\'15\' 1v=\'15"+1f.2c(1f.1y()*2b)+"\' 1g=\'1m()\' J=\'z:"+(W+29)+"p;A:"+(V+17)+"p;\' > </U>")}n{$("#B").N();$("#8").q("<U 1W=\'0\' 2d=\'0\' L=\'"+1E[0]+"\' 5=\'15\' 1v=\'15"+1f.2c(1f.1y()*2b)+"\' 1g=\'1m()\' J=\'z:"+(W+29)+"p;A:"+(V+17)+"p;\'> </U>")}}n{3($("#8").r("Y")!="T"){3(m[\'1A\']!="1b"){$("#8").q("<4 5=\'2f\'><4 5=\'1H\'>"+d+"</4><4 5=\'2e\'><a u=\'#\' 5=\'Z\'>1l</a> 1k 1j 1s</4></4><4 5=\'F\' J=\'z:"+W+"p;A:"+V+"p\'></4>")}n{$("#B").N();$("#8").q("<4 5=\'F\' 3c=\'3b\' J=\'z:"+W+"p;A:"+V+"p;\'></4>")}}n{$("#F")[0].J.z=W+"p";$("#F")[0].J.A=V+"p";$("#F")[0].3a=0;$("#1H").11(d)}}$("#Z").s(G);3(f.O(\'37\')!=-1){$("#F").q($(\'#\'+m[\'26\']).1T());$("#8").24(9(){$(\'#\'+m[\'26\']).q($("#F").1T())});16();$("#K").C();$("#8").r({Y:"T"})}n 3(f.O(\'2j\')!=-1){16();3($.1q.35){$("#K").C();$("#8").r({Y:"T"})}}n{$("#F").34(f+="&1y="+(1p 33().32()),9(){16();$("#K").C();1u("#F a.18");$("#8").r({Y:"T"})})}}3(!m[\'1A\']){o.21=9(e){3(e==M){I=2w.2v}n{I=e.2u}3(I==27){G()}}}}31(e){}}9 1m(){$("#K").C();$("#8").r({Y:"T"})}9 G(){$("#2Y").N("s");$("#Z").N("s");$("#8").2X("2W",9(){$(\'#8,#B,#1F\').2V("24").N().C()});$("#K").C();3(2t o.v.J.2i=="2g"){$("v","11").r({A:"1Z",z:"1Z"});$("11").r("22","")}o.1h="";o.21="";H P}9 16(){$("#8").r({2U:\'-\'+20((13/2),10)+\'p\',z:13+\'p\'});3(!(1V.1q.2Q&&1V.1q.2P<7)){$("#8").r({38:\'-\'+20((1a/2),10)+\'p\'})}}9 2p(a){6 b={};3(!a){H b}6 c=a.1B(/[;&]/);25(6 i=0;i<c.1c;i++){6 d=c[i].1B(\'=\');3(!d||d.1c!=2){39}6 e=2a(d[0]);6 f=2a(d[1]);f=f.2r(/\\+/g,\' \');b[e]=f}H b}9 2x(){6 a=o.2M;6 w=1S.2o||1R.2o||(a&&a.1Q)||o.v.1Q;6 h=1S.1P||1R.1P||(a&&a.2n)||o.v.2n;1O=[w,h];H 1O}9 1K(){6 a=2K.2J.1C();3(a.O(\'2I\')!=-1&&a.O(\'3o\')!=-1){H 1b}}',62,211,'|||if|div|id|var||TB_window|function||||||||||||||else|document|px|append|css|click||href|body||||width|height|TB_overlay|remove|TB_Counter|TB_TempArray|TB_ajaxContent|tb_remove|return|keycode|style|TB_load|src|null|unbind|indexOf|false|title|TB_NextHTML|imgPreloader|block|iframe|ajaxContentH|ajaxContentW|this|display|TB_closeWindowButton||html|goPrev|TB_WIDTH|TB_PrevHTML|TB_iframeContent|tb_position||thickbox|tb_show|TB_HEIGHT|true|length|nbsp|span|Math|onload|onkeydown|goNext|Esc|or|close|tb_showIframe|TB_imageCount|Close|new|browser|TB_FoundURL|Key|Image|tb_init|name|imgLoader|TB_NextURL|random|TB_NextCaption|modal|split|toLowerCase|TB_PrevCaption|urlNoQuery|TB_HideSelect|TB_PrevURL|TB_ajaxWindowTitle|img|addClass|tb_detectMacXFF|TB_ImageOff|150|rel|arrayPageSize|innerHeight|clientWidth|self|window|children|TB_prev|jQuery|frameborder|TB_next|getElementById|auto|parseInt|onkeyup|overflow|alt|unload|for|inlineId||100||unescape|1000|round|hspace|TB_closeAjaxWindow|TB_title|undefined|match|maxHeight|TB_iframe|bmp|gif|png|clientHeight|innerWidth|tb_parseQuery|jpeg|replace|jpg|typeof|which|keyCode|event|tb_getPageSize|show|TB_overlayBG|TB_closeWindow|TB_overlayMacFFBGHack|TB_secondLine|TB_caption|blur|TB_Image|60|tb_pathToImage|mac|userAgent|navigator|of|documentElement|Prev|lt|version|msie|gt|ready|Next|marginLeft|trigger|fast|fadeOut|TB_imageOff|hidden||catch|getTime|Date|load|safari|get|TB_inline|marginTop|continue|scrollTop|TB_modal|class|TB_|45|440|40|630|input|188|190|substr|try|area|firefox'.split('|'),0,{}))
\ No newline at end of file diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/rdoc.css b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/rdoc.css new file mode 100644 index 000000000..bca0a021c --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/generator/template/darkfish/rdoc.css @@ -0,0 +1,696 @@ +/* + * "Darkfish" Rdoc CSS + * $Id: rdoc.css 54 2009-01-27 01:09:48Z deveiant $ + * + * Author: Michael Granger <ged@FaerieMUD.org> + * + */ + +/* Base Green is: #6C8C22 */ + +*{ padding: 0; margin: 0; } + +body { + background: #efefef; + font: 14px "Helvetica Neue", Helvetica, Tahoma, sans-serif; +} +body.class, body.module, body.file { + margin-left: 40px; +} +body.file-popup { + font-size: 90%; + margin-left: 0; +} + +h1 { + font-size: 300%; + text-shadow: rgba(135,145,135,0.65) 2px 2px 3px; + color: #6C8C22; +} +h2,h3,h4 { margin-top: 1.5em; } + +a { + color: #6C8C22; + text-decoration: none; +} +a:hover { + border-bottom: 1px dotted #6C8C22; +} + +pre { + background: #ddd; + padding: 0.5em 0; +} + + +/* @group Generic Classes */ + +.initially-hidden { + display: none; +} + +.quicksearch-field { + width: 98%; + background: #ddd; + border: 1px solid #aaa; + height: 1.5em; + -webkit-border-radius: 4px; +} +.quicksearch-field:focus { + background: #f1edba; +} + +.missing-docs { + font-size: 120%; + background: white url(images/wrench_orange.png) no-repeat 4px center; + color: #ccc; + line-height: 2em; + border: 1px solid #d00; + opacity: 1; + padding-left: 20px; + text-indent: 24px; + letter-spacing: 3px; + font-weight: bold; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; +} + +.target-section { + border: 2px solid #dcce90; + border-left-width: 8px; + padding: 0 1em; + background: #fff3c2; +} + +/* @end */ + + +/* @group Index Page, Standalone file pages */ +body.indexpage { + margin: 1em 3em; +} +body.indexpage p, +body.indexpage div, +body.file p { + margin: 1em 0; +} + +.indexpage ul, +.file #documentation ul { + line-height: 160%; + list-style: none; +} +.indexpage ul a, +.file #documentation ul a { + font-size: 16px; +} + +.indexpage li, +.file #documentation li { + padding-left: 20px; + background: url(images/bullet_black.png) no-repeat left 4px; +} +.indexpage li.module { + background: url(images/package.png) no-repeat left 4px; +} +.indexpage li.class { + background: url(images/ruby.png) no-repeat left 4px; +} +.indexpage li.file { + background: url(images/page_white_text.png) no-repeat left 4px; +} + +/* @end */ + +/* @group Top-Level Structure */ + +.class #metadata, +.file #metadata, +.module #metadata { + float: left; + width: 260px; +} + +.class #documentation, +.file #documentation, +.module #documentation { + margin: 2em 1em 5em 300px; + min-width: 340px; +} + +.file #metadata { + margin: 0.8em; +} + +#validator-badges { + clear: both; + margin: 1em 1em 2em; +} + +/* @end */ + +/* @group Metadata Section */ +#metadata .section { + background-color: #dedede; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + border: 1px solid #aaa; + margin: 0 8px 16px; + font-size: 90%; + overflow: hidden; +} +#metadata h3.section-header { + margin: 0; + padding: 2px 8px; + background: #ccc; + color: #666; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-bottom: 1px solid #aaa; +} +#metadata ul, +#metadata dl, +#metadata p { + padding: 8px; + list-style: none; +} + +#file-metadata ul { + padding-left: 28px; + list-style-image: url(images/page_green.png); +} + +dl.svninfo { + color: #666; + margin: 0; +} +dl.svninfo dt { + font-weight: bold; +} + +ul.link-list li { + white-space: nowrap; +} +ul.link-list .type { + font-size: 8px; + text-transform: uppercase; + color: white; + background: #969696; + padding: 2px 4px; + -webkit-border-radius: 5px; +} + +/* @end */ + + +/* @group Project Metadata Section */ +#project-metadata { + margin-top: 3em; +} + +.file #project-metadata { + margin-top: 0em; +} + +#project-metadata .section { + border: 1px solid #aaa; +} +#project-metadata h3.section-header { + border-bottom: 1px solid #aaa; + position: relative; +} +#project-metadata h3.section-header .search-toggle { + position: absolute; + right: 5px; +} + + +#project-metadata form { + color: #777; + background: #ccc; + padding: 8px 8px 16px; + border-bottom: 1px solid #bbb; +} +#project-metadata fieldset { + border: 0; +} + +#no-class-search-results { + margin: 0 auto 1em; + text-align: center; + font-size: 14px; + font-weight: bold; + color: #aaa; +} + +/* @end */ + + +/* @group Documentation Section */ +#description { + font-size: 100%; + color: #333; +} + +#description p { + margin: 1em 0.4em; +} + +#description ul { + margin-left: 2em; +} +#description ul li { + line-height: 1.4em; +} + +#description dl, +#documentation dl { + margin: 8px 1.5em; + border: 1px solid #ccc; +} +#description dl { + font-size: 14px; +} + +#description dt, +#documentation dt { + padding: 2px 4px; + font-weight: bold; + background: #ddd; +} +#description dd, +#documentation dd { + padding: 2px 12px; +} +#description dd + dt, +#documentation dd + dt { + margin-top: 0.7em; +} + +#documentation .section { + font-size: 90%; +} +#documentation h3.section-header { + margin-top: 2em; + padding: 0.75em 0.5em; + background-color: #dedede; + color: #333; + font-size: 150%; + border: 1px solid #bbb; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +#constants-list > dl, +#attributes-list > dl { + margin: 1em 0 2em; + border: 0; +} +#constants-list > dl dt, +#attributes-list > dl dt { + padding-left: 0; + font-weight: bold; + font-family: Monaco, "Andale Mono"; + background: inherit; +} +#constants-list > dl dt a, +#attributes-list > dl dt a { + color: inherit; +} +#constants-list > dl dd, +#attributes-list > dl dd { + margin: 0 0 1em 0; + padding: 0; + color: #666; +} + +/* @group Method Details */ + +#documentation .method-source-code { + display: none; +} + +#documentation .method-detail { + margin: 0.5em 0; + padding: 0.5em 0; + cursor: pointer; +} +#documentation .method-detail:hover { + background-color: #f1edba; +} +#documentation .method-alias { + font-style: oblique; +} +#documentation .method-heading { + position: relative; + padding: 2px 4px 0 20px; + font-size: 125%; + font-weight: bold; + color: #333; + background: url(images/brick.png) no-repeat left bottom; +} +#documentation .method-heading a { + color: inherit; +} +#documentation .method-click-advice { + position: absolute; + top: 2px; + right: 5px; + font-size: 10px; + color: #9b9877; + visibility: hidden; + padding-right: 20px; + line-height: 20px; + background: url(images/zoom.png) no-repeat right top; +} +#documentation .method-detail:hover .method-click-advice { + visibility: visible; +} + +#documentation .method-alias .method-heading { + color: #666; + background: url(images/brick_link.png) no-repeat left bottom; +} + +#documentation .method-description, +#documentation .aliases { + margin: 0 20px; + line-height: 1.2em; + color: #666; +} +#documentation .aliases { + padding-top: 4px; + font-style: italic; + cursor: default; +} +#documentation .method-description p { + padding: 0; +} +#documentation .method-description p + p { + margin-bottom: 0.5em; +} + +#documentation .attribute-method-heading { + background: url(images/tag_green.png) no-repeat left bottom; +} +#documentation #attribute-method-details .method-detail:hover { + background-color: transparent; + cursor: default; +} +#documentation .attribute-access-type { + font-size: 60%; + text-transform: uppercase; + vertical-align: super; + padding: 0 2px; +} +/* @end */ + +/* @end */ + + + +/* @group Source Code */ + +a.source-toggle { + font-size: 90%; +} +a.source-toggle img { + +} + +div.method-source-code { + background: #262626; + color: #efefef; + margin: 1em; + padding: 0.5em; + border: 1px dashed #999; + overflow: hidden; +} + +div.method-source-code pre { + background: inherit; + padding: 0; + color: white; + overflow: hidden; +} + +/* @group Ruby keyword styles */ + +.standalone-code { background: #221111; color: #ffdead; overflow: hidden; } + +.ruby-constant { color: #7fffd4; background: transparent; } +.ruby-keyword { color: #00ffff; background: transparent; } +.ruby-ivar { color: #eedd82; background: transparent; } +.ruby-operator { color: #00ffee; background: transparent; } +.ruby-identifier { color: #ffdead; background: transparent; } +.ruby-node { color: #ffa07a; background: transparent; } +.ruby-comment { color: #b22222; font-weight: bold; background: transparent; } +.ruby-regexp { color: #ffa07a; background: transparent; } +.ruby-value { color: #7fffd4; background: transparent; } + +/* @end */ +/* @end */ + + +/* @group File Popup Contents */ + +.file #metadata, +.file-popup #metadata { +} + +.file-popup dl { + font-size: 80%; + padding: 0.75em; + background-color: #dedede; + color: #333; + border: 1px solid #bbb; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} +.file dt { + font-weight: bold; + padding-left: 22px; + line-height: 20px; + background: url(images/page_white_width.png) no-repeat left top; +} +.file dt.modified-date { + background: url(images/date.png) no-repeat left top; +} +.file dt.requires { + background: url(images/plugin.png) no-repeat left top; +} +.file dt.scs-url { + background: url(images/wrench.png) no-repeat left top; +} + +.file dl dd { + margin: 0 0 1em 0; +} +.file #metadata dl dd ul { + list-style: circle; + margin-left: 20px; + padding-top: 0; +} +.file #metadata dl dd ul li { +} + + +.file h2 { + margin-top: 2em; + padding: 0.75em 0.5em; + background-color: #dedede; + color: #333; + font-size: 120%; + border: 1px solid #bbb; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +/* @end */ + + + + +/* @group ThickBox Styles */ +#TB_window { + font: 12px Arial, Helvetica, sans-serif; + color: #333333; +} + +#TB_secondLine { + font: 10px Arial, Helvetica, sans-serif; + color:#666666; +} + +#TB_window a:link {color: #666666;} +#TB_window a:visited {color: #666666;} +#TB_window a:hover {color: #000;} +#TB_window a:active {color: #666666;} +#TB_window a:focus{color: #666666;} + +#TB_overlay { + position: fixed; + z-index:100; + top: 0px; + left: 0px; + height:100%; + width:100%; +} + +.TB_overlayMacFFBGHack {background: url(images/macFFBgHack.png) repeat;} +.TB_overlayBG { + background-color:#000; + filter:alpha(opacity=75); + -moz-opacity: 0.75; + opacity: 0.75; +} + +* html #TB_overlay { /* ie6 hack */ + position: absolute; + height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); +} + +#TB_window { + position: fixed; + background: #ffffff; + z-index: 102; + color:#000000; + display:none; + border: 4px solid #525252; + text-align:left; + top:50%; + left:50%; +} + +* html #TB_window { /* ie6 hack */ +position: absolute; +margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px'); +} + +#TB_window img#TB_Image { + display:block; + margin: 15px 0 0 15px; + border-right: 1px solid #ccc; + border-bottom: 1px solid #ccc; + border-top: 1px solid #666; + border-left: 1px solid #666; +} + +#TB_caption{ + height:25px; + padding:7px 30px 10px 25px; + float:left; +} + +#TB_closeWindow{ + height:25px; + padding:11px 25px 10px 0; + float:right; +} + +#TB_closeAjaxWindow{ + padding:7px 10px 5px 0; + margin-bottom:1px; + text-align:right; + float:right; +} + +#TB_ajaxWindowTitle{ + float:left; + padding:7px 0 5px 10px; + margin-bottom:1px; + font-size: 22px; +} + +#TB_title{ + background-color: #6C8C22; + color: #dedede; + height:40px; +} +#TB_title a { + color: white !important; + border-bottom: 1px dotted #dedede; +} + +#TB_ajaxContent{ + clear:both; + padding:2px 15px 15px 15px; + overflow:auto; + text-align:left; + line-height:1.4em; +} + +#TB_ajaxContent.TB_modal{ + padding:15px; +} + +#TB_ajaxContent p{ + padding:5px 0px 5px 0px; +} + +#TB_load{ + position: fixed; + display:none; + height:13px; + width:208px; + z-index:103; + top: 50%; + left: 50%; + margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */ +} + +* html #TB_load { /* ie6 hack */ +position: absolute; +margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px'); +} + +#TB_HideSelect{ + z-index:99; + position:fixed; + top: 0; + left: 0; + background-color:#fff; + border:none; + filter:alpha(opacity=0); + -moz-opacity: 0; + opacity: 0; + height:100%; + width:100%; +} + +* html #TB_HideSelect { /* ie6 hack */ + position: absolute; + height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); +} + +#TB_iframeContent{ + clear:both; + border:none; + margin-bottom:-1px; + margin-top:1px; + _margin-bottom:1px; +} + +/* @end */ + +/* @group Debugging Section */ + +#debugging-toggle { + text-align: center; +} +#debugging-toggle img { + cursor: pointer; +} + +#rdoc-debugging-section-dump { + display: none; + margin: 0 2em 2em; + background: #ccc; + border: 1px solid #999; +} + + + +/* @end */ diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ghost_method.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ghost_method.rb new file mode 100644 index 000000000..192b46f51 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ghost_method.rb @@ -0,0 +1,8 @@ +require 'rdoc/any_method' + +## +# GhostMethod represents a method referenced only by a comment + +class RDoc::GhostMethod < RDoc::AnyMethod +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/include.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/include.rb new file mode 100644 index 000000000..9be906158 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/include.rb @@ -0,0 +1,39 @@ +require 'rdoc/code_object' + +## +# A Module include in a class with \#include + +class RDoc::Include < RDoc::CodeObject + + ## + # Name of included module + + attr_accessor :name + + ## + # Creates a new Include for +name+ with +comment+ + + def initialize(name, comment) + super() + @name = name + self.comment = comment + end + + def inspect # :nodoc: + "#<%s:0x%x %s.include %s>" % [ + self.class, + object_id, + parent_name, @name, + ] + end + + ## + # Attempts to locate the included module object. Returns the name if not + # known. + + def module + RDoc::TopLevel.find_module_named(@name) || @name + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/known_classes.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/known_classes.rb new file mode 100644 index 000000000..dbb1802f5 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/known_classes.rb @@ -0,0 +1,68 @@ +module RDoc + + ## + # Ruby's built-in classes, modules and exceptions + + KNOWN_CLASSES = { + "rb_cArray" => "Array", + "rb_cBignum" => "Bignum", + "rb_cClass" => "Class", + "rb_cData" => "Data", + "rb_cDir" => "Dir", + "rb_cFalseClass" => "FalseClass", + "rb_cFile" => "File", + "rb_cFixnum" => "Fixnum", + "rb_cFloat" => "Float", + "rb_cHash" => "Hash", + "rb_cIO" => "IO", + "rb_cInteger" => "Integer", + "rb_cModule" => "Module", + "rb_cNilClass" => "NilClass", + "rb_cNumeric" => "Numeric", + "rb_cObject" => "Object", + "rb_cProc" => "Proc", + "rb_cRange" => "Range", + "rb_cRegexp" => "Regexp", + "rb_cRubyVM" => "RubyVM", + "rb_cString" => "String", + "rb_cStruct" => "Struct", + "rb_cSymbol" => "Symbol", + "rb_cThread" => "Thread", + "rb_cTime" => "Time", + "rb_cTrueClass" => "TrueClass", + + "rb_eArgError" => "ArgError", + "rb_eEOFError" => "EOFError", + "rb_eException" => "Exception", + "rb_eFatal" => "Fatal", + "rb_eFloatDomainError" => "FloatDomainError", + "rb_eIOError" => "IOError", + "rb_eIndexError" => "IndexError", + "rb_eInterrupt" => "Interrupt", + "rb_eLoadError" => "LoadError", + "rb_eNameError" => "NameError", + "rb_eNoMemError" => "NoMemError", + "rb_eNotImpError" => "NotImpError", + "rb_eRangeError" => "RangeError", + "rb_eRuntimeError" => "RuntimeError", + "rb_eScriptError" => "ScriptError", + "rb_eSecurityError" => "SecurityError", + "rb_eSignal" => "Signal", + "rb_eStandardError" => "StandardError", + "rb_eSyntaxError" => "SyntaxError", + "rb_eSystemCallError" => "SystemCallError", + "rb_eSystemExit" => "SystemExit", + "rb_eTypeError" => "TypeError", + "rb_eZeroDivError" => "ZeroDivError", + + "rb_mComparable" => "Comparable", + "rb_mEnumerable" => "Enumerable", + "rb_mErrno" => "Errno", + "rb_mFileTest" => "FileTest", + "rb_mGC" => "GC", + "rb_mKernel" => "Kernel", + "rb_mMath" => "Math", + "rb_mProcess" => "Process" + } + +end diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup.rb new file mode 100644 index 000000000..9d22b3894 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup.rb @@ -0,0 +1,378 @@ +require 'rdoc' + +## +# RDoc::Markup 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. +# +# RDoc::Markup itself does no output formatting: this is left to a different +# set of classes. +# +# RDoc::Markup is extendable at runtime: you can add \new markup elements to +# be recognised in the documents that RDoc::Markup parses. +# +# RDoc::Markup 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 +# RDoc::Markup could be the basis for formatting RDoc style comment blocks, +# Wiki entries, and online FAQs. +# +# == Synopsis +# +# This code converts +input_string+ to HTML. The conversion takes place in +# the +convert+ method, so you can use the same RDoc::Markup converter to +# convert multiple input strings. +# +# require 'rdoc/markup/to_html' +# +# h = RDoc::Markup::ToHtml.new +# +# puts h.convert(input_string) +# +# You can extend the RDoc::Markup parser to recognise new markup +# sequences, and to add special processing for text that matches a +# regular expression. Here we make WikiWords significant to the parser, +# and also make the sequences {word} and \<no>text...</no> signify +# strike-through text. When then subclass the HTML output class to deal +# with these: +# +# require 'rdoc/markup' +# require 'rdoc/markup/to_html' +# +# class WikiHtml < RDoc::Markup::ToHtml +# def handle_special_WIKIWORD(special) +# "<font color=red>" + special.text + "</font>" +# end +# end +# +# m = RDoc::Markup.new +# m.add_word_pair("{", "}", :STRIKE) +# m.add_html("no", :STRIKE) +# +# m.add_special(/\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD) +# +# wh = WikiHtml.new +# wh.add_tag(:STRIKE, "<strike>", "</strike>") +# +# puts "<body>#{wh.convert ARGF.read}</body>" +# +#-- +# Author:: Dave Thomas, dave@pragmaticprogrammer.com +# License:: Ruby license + +class RDoc::Markup + + 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 = RDoc::Markup::AttributeManager.new + @output = nil + end + + ## + # Add to the sequences used to add formatting to an individual word (such + # as *bold*). Matching entries will generate attributes 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 = str.split(/\r?\n/).map { |line| Line.new line } + @lines = Lines.new lines + + return "" if @lines.empty? + @lines.normalize + assign_types_to_lines + group = group_lines + # call the output formatter to handle the result + #group.each { |line| p line } + 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.blank? then + line.stamp :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 :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 :BULLET + when /^\d/ then :NUMBER + when /^[A-Z]/ then :UPPERALPHA + when /^[a-z]/ then :LOWERALPHA + else raise "Invalid List Type: #{self.inspect}" + end + + line.stamp :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 :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 :VERBATIM, level + else + line.stamp :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 be 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 /^\[/ then + flag = :LABELED + prefix = prefix[1, prefix.length-2] + when /:$/ then + flag = :NOTE + prefix.chop! + else + raise "Invalid List Type: #{self.inspect}" + end + + # body is on the next line + if text.length <= offset then + 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 then + @lines.unget + return false + else + offset = i + prefix_length = 0 + + if text[offset..-1] =~ SIMPLE_LIST_RE then + @lines.unget + line = original_line + line.text = '' + else + @lines.delete original_line + end + end + end + + line.stamp :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 + + in_list = false + wanted_type = wanted_level = nil + + block = LineCollection.new + group = nil + + while line = @lines.next + if line.level == wanted_level and line.type == wanted_type + group.add_text(line.text) + else + group = block.fragment_for(line) + block.add(group) + + if line.type == :LIST + wanted_type = :PARAGRAPH + else + wanted_type = line.type + end + + wanted_level = line.type == :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 + +require 'rdoc/markup/fragments' +require 'rdoc/markup/inline' +require 'rdoc/markup/lines' diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/attribute_manager.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/attribute_manager.rb new file mode 100644 index 000000000..5c253b10c --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/attribute_manager.rb @@ -0,0 +1,311 @@ +require 'rdoc/markup/inline' + +## +# 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 + 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) + RDoc::Markup::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 do |name| + current |= RDoc::Markup::Attribute.bitmap_for(name) + end + + new_set.each do |name| + new |= RDoc::Markup::Attribute.bitmap_for(name) + end + + 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 <b>text</b>to the sequence + # \001\002<char>\001\003<char>, where <char> 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) + unless SPECIAL.empty? + SPECIAL.each do |regexp, attr| + str.scan(regexp) do + attrs.set_attrs($`.length, $&.length, + attr | RDoc::Markup::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 = %w[<\\] + + ## + # Escapes special sequences of text to prevent conversion to RDoc + + def mask_protected_sequences + protect_pattern = Regexp.new("\\\\([#{Regexp.escape(PROTECTABLE.join(''))}])") + @str.gsub!(protect_pattern, "\\1#{PROTECT_ATTR}") + end + + ## + # Unescapes special sequences of text + + def unmask_protected_sequences + @str.gsub!(/(.)#{PROTECT_ATTR}/, "\\1\000") + end + + ## + # Creates a new attribute manager that understands bold, emphasized and + # teletype text. + + 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) + 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 = RDoc::Markup::Attribute.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] = RDoc::Markup::Attribute.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] = RDoc::Markup::Attribute.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 + + def split_into_flow + res = [] + current_attr = 0 + str = "" + + 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 & RDoc::Markup::Attribute::SPECIAL) != 0 then + i += 1 while + i < str_len and (@attrs[i] & RDoc::Markup::Attribute::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 + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/formatter.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/formatter.rb new file mode 100644 index 000000000..a499d12ea --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/formatter.rb @@ -0,0 +1,25 @@ +require 'rdoc/markup' + +## +# Base class for RDoc markup formatters +# +# Formatters use a visitor pattern to convert content into output. + +class RDoc::Markup::Formatter + + ## + # Creates a new Formatter + + def initialize + @markup = RDoc::Markup.new + end + + ## + # Marks up +content+ + + def convert(content) + @markup.convert content, self + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/fragments.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/fragments.rb new file mode 100644 index 000000000..bbe0bced0 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/fragments.rb @@ -0,0 +1,377 @@ +require 'rdoc/markup' +require 'rdoc/markup/lines' + +class RDoc::Markup + + ## + # 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 + + ## + # This is a simple factory system that lets us associate fragement + # types (a string) with a subclass of fragment + + TYPE_MAP = {} + + def self.type_name(name) + TYPE_MAP[name] = self + end + + def self.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 + + 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 + + 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 :PARAGRAPH + end + + ## + # An empty line + + class BlankLine < Paragraph + type_name :BLANK + end + + ## + # A heading + + class Heading < Paragraph + type_name :HEADING + + ## + # Level of heading, smaller is more important + + def head_level + @param.to_i + end + + end + + ## + # A List is a fragment with some kind of label + + class ListBase < Paragraph + LIST_TYPES = [ + :BULLET, + :NUMBER, + :UPPERALPHA, + :LOWERALPHA, + :LABELED, + :NOTE, + ] + end + + ## + # An item in a list + + class ListItem < ListBase + type_name :LIST + + def to_s # :nodoc: + text = if [:NOTE, :LABELED].include? type then + "#{@param}: #{@txt}" + else + @txt + end + + "L#@level: #{type} #{self.class.name.split('::')[-1]}\n#{text}" + end + + end + + ## + # Start of a list + + class ListStart < ListBase + + ## + # Creates a ListStart with nesting +level+ + + def initialize(level, param, type) + super(level, param, type, nil) + end + end + + ## + # End of a list + + class ListEnd < ListBase + + ## + # Creates a ListEnd with nesting +level+ + + def initialize(level, type) + super(level, "", type, nil) + end + end + + ## + # Verbatim code contains lines that don't get wrapped. + + class Verbatim < Fragment + type_name :VERBATIM + + ## + # Adds +txt+ to this verbatim + + def add_text(txt) + @txt << txt.chomp << "\n" + end + + end + + ## + # A horizontal rule + + class Rule < Fragment + type_name :RULE + end + + ## + # Collect groups of lines together. Each group will end up containing a flow + # of text. + + class LineCollection + + ## + # Creates a new collection of lines + + def initialize + @fragments = [] + end + + ## + # Adds +fragment+ to the collection + + def add(fragment) + @fragments << fragment + end + + ## + # Iterates over the lines in the collection + + def each(&b) + @fragments.each(&b) + end + + def to_a # :nodoc: + @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 # :nodoc: + @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 indentation. 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 + + ## + # Inserts 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 + + ## + # 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 BlankLine === @fragments[i] and ListEnd === @fragments[i+1] then + @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 + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/inline.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/inline.rb new file mode 100644 index 000000000..ce091aabc --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/inline.rb @@ -0,0 +1,126 @@ +require 'rdoc/markup' + +class RDoc::Markup + + ## + # 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 self.bitmap_for(name) + bitmap = @@name_to_bitmap[name] + unless bitmap then + bitmap = @@next_bitmap + @@next_bitmap <<= 1 + @@name_to_bitmap[name] = bitmap + end + bitmap + end + + def self.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 self.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 + + AttrChanger = Struct.new :turn_on, :turn_off + + ## + # 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 AttrChanger + def to_s # :nodoc: + "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 + + ## + # 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 + + ## + # Acccesses flags for character +n+ + + def [](n) + @attrs[n] + end + + end + + ## + # Hold details of a special sequence + + class 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: + "#<RDoc::Markup::Special:0x%x @type=%p, name=%p @text=%p>" % [ + object_id, @type, RDoc::Markup::Attribute.as_string(type), text.dump] + end + + def to_s # :nodoc: + "Special: type=#{type}, name=#{RDoc::Markup::Attribute.as_string type}, text=#{text.dump}" + end + + end + +end + +require 'rdoc/markup/attribute_manager' diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/lines.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/lines.rb new file mode 100644 index 000000000..6ec8e0937 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/lines.rb @@ -0,0 +1,156 @@ +class RDoc::Markup + + ## + # 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. + + class Line + + ## + # Not really + + INFINITY = 9999 + + LINE_TYPES = [ + :BLANK, + :HEADING, + :LIST, + :PARAGRAPH, + :RULE, + :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 blank? + @text.empty? + 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 # :nodoc: + + 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 == :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 + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/preprocess.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/preprocess.rb new file mode 100644 index 000000000..a175d179c --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/preprocess.rb @@ -0,0 +1,80 @@ +require 'rdoc/markup' + +## +# Handle common directives that can occur in a block of text: +# +# : include : filename + +class RDoc::Markup::PreProcess + + ## + # 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 + end + + ## + # Look for common options in a chunk of text. Options that we don't handle + # are yielded to the caller. + + def handle(text) + text.gsub!(/^([ \t]*#?[ \t]*):(\w+):([ \t]*)(.+)?\n/) do + next $& if $3.empty? and $4 and $4[0, 1] == ':' + + prefix = $1 + directive = $2.downcase + param = $4 + + case directive + when 'include' then + filename = param.split[0] + include_file filename, prefix + + else + result = yield directive, param + result = "#{prefix}:#{directive}: #{param}\n" unless result + result + end + end + end + + private + + ## + # Include a file, indenting it correctly. + + def include_file(name, indent) + if full_name = find_include_file(name) then + content = File.read full_name + + # strip leading '#'s, but only if all lines start with them + if content =~ /^[^#]/ then + content.gsub(/^/, indent) + else + content.gsub(/^#?/, indent) + end + else + $stderr.puts "Couldn't find file to include '#{name}' from #{@input_file_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 + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_flow.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_flow.rb new file mode 100644 index 000000000..3556a4fa0 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_flow.rb @@ -0,0 +1,211 @@ +require 'rdoc/markup/formatter' +require 'rdoc/markup/fragments' +require 'rdoc/markup/inline' +require 'cgi' + +class RDoc::Markup + + module Flow + + ## + # Paragraph + + P = Struct.new(:body) + + ## + # Verbatim + + VERB = Struct.new(:body) + + ## + # Horizontal rule + + RULE = Struct.new(:width) + + ## + # List + + class LIST + attr_reader :type, :contents + def initialize(type) + @type = type + @contents = [] + end + def <<(stuff) + @contents << stuff + end + end + + ## + # List item + + LI = Struct.new(:label, :body) + + ## + # Heading + + H = Struct.new(:level, :text) + + end + + class ToFlow < RDoc::Markup::Formatter + + LIST_TYPE_TO_HTML = { + :BULLET => [ "<ul>", "</ul>" ], + :NUMBER => [ "<ol>", "</ol>" ], + :UPPERALPHA => [ "<ol>", "</ol>" ], + :LOWERALPHA => [ "<ol>", "</ol>" ], + :LABELED => [ "<dl>", "</dl>" ], + :NOTE => [ "<table>", "</table>" ], + } + + InlineTag = Struct.new(:bit, :on, :off) + + def initialize + super + + init_tags + end + + ## + # Set up the standard mapping of attributes to HTML tags + + def init_tags + @attr_tags = [ + InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"), + InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"), + InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), "<em>", "</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(RDoc::Markup::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 + + ## + # :section: Visitor + + 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("<p />") << "\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 + + 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 + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_html.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_html.rb new file mode 100644 index 000000000..9e431502c --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_html.rb @@ -0,0 +1,406 @@ +require 'rdoc/markup/formatter' +require 'rdoc/markup/fragments' +require 'rdoc/markup/inline' + +require 'cgi' + +class RDoc::Markup::ToHtml < RDoc::Markup::Formatter + + LIST_TYPE_TO_HTML = { + :BULLET => %w[<ul> </ul>], + :NUMBER => %w[<ol> </ol>], + :UPPERALPHA => %w[<ol> </ol>], + :LOWERALPHA => %w[<ol> </ol>], + :LABELED => %w[<dl> </dl>], + :NOTE => %w[<table> </table>], + } + + InlineTag = Struct.new(:bit, :on, :off) + + def initialize + super + + # @in_tt - tt nested levels count + # @tt_bit - cache + @in_tt = 0 + @tt_bit = RDoc::Markup::Attribute.bitmap_for :TT + + # external hyperlinks + @markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK) + + # and links of the form <text>[<url>] + @markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\.\S+?\])/, :TIDYLINK) + + init_tags + end + + ## + # 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 + + ## + # Generate a hyperlink for url, labeled with text. Handle the + # special cases for img: and link: described under handle_special_HYPERLINK + + def gen_url(url, text) + if url =~ /([A-Za-z]+):(.*)/ then + type = $1 + path = $2 + else + type = "http" + path = url + url = "http://#{url}" + end + + if type == "link" then + url = if path[0, 1] == '#' then # is this meaningful? + path + else + self.class.gen_relative_url @from_path, path + end + end + + if (type == "http" or type == "link") and + url =~ /\.(gif|png|jpg|jpeg|bmp)$/ then + "<img src=\"#{url}\" />" + else + "<a href=\"#{url}\">#{text.sub(%r{^#{type}:/*}, '')}</a>" + end + end + + ## + # And we're invoked with a potential external hyperlink mailto: + # just gets inserted. http: links are checked to see if they + # reference an image. If so, that image gets inserted using an + # <img> tag. Otherwise a conventional <a href> is used. We also + # support a special type of hyperlink, link:, which is a reference + # to a local file whose path is relative to the --op directory. + + def handle_special_HYPERLINK(special) + url = special.text + gen_url url, url + end + + ## + # Here's a hypedlink where the label is different to 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 + gen_url url, label + end + + ## + # are we currently inside tt tags? + + def in_tt? + @in_tt > 0 + end + + ## + # is +tag+ a tt tag? + + def tt?(tag) + tag.bit == @tt_bit + end + + ## + # Set up the standard mapping of attributes to HTML tags + + def init_tags + @attr_tags = [ + InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"), + InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"), + InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), "<em>", "</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(RDoc::Markup::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 + + ## + # 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 + + ## + # :section: Visitor + + def start_accepting + @res = "" + @in_list_entry = [] + end + + def end_accepting + @res + end + + def accept_paragraph(am, fragment) + @res << annotate("<p>") + "\n" + @res << wrap(convert_flow(am.flow(fragment.txt))) + @res << annotate("</p>") + "\n" + end + + def accept_verbatim(am, fragment) + @res << annotate("<pre>") + "\n" + @res << CGI.escapeHTML(fragment.txt) + @res << annotate("</pre>") << "\n" + end + + def accept_rule(am, fragment) + size = fragment.param + size = 10 if size > 10 + @res << "<hr size=\"#{size}\"></hr>" + 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("<p />") << "\n" + end + + def accept_heading(am, fragment) + @res << convert_heading(fragment.head_level, 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) + @in_tt += 1 if tt?(tag) + 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 + @in_tt -= 1 if tt?(tag) + 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 RDoc::Markup::AttrChanger + off_tags(res, item) + on_tags(res, item) + when RDoc::Markup::Special + res << convert_special(item) + else + raise "Unknown flow element: #{item.inspect}" + end + end + + res + end + + def convert_string(item) + in_tt? ? convert_string_simple(item) : convert_string_fancy(item) + end + + def convert_string_simple(item) + CGI.escapeHTML item + end + + ## + # some of these patterns are taken from SmartyPants... + + def convert_string_fancy(item) + # convert ampersand before doing anything else + item.gsub(/&/, '&'). + + # convert -- to em-dash, (-- to en-dash) + gsub(/---?/, '—'). #gsub(/--/, '–'). + + # convert ... to elipsis (and make sure .... becomes .<elipsis>) + 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 registered trademark + gsub(/\(r\)/, '®') + end + + def convert_special(special) + handled = false + RDoc::Markup::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("<h#{level}>") + + convert_flow(flow) + + annotate("</h#{level}>\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 :BULLET, :NUMBER then + annotate("<li>") + + when :UPPERALPHA then + annotate("<li type=\"A\">") + + when :LOWERALPHA then + annotate("<li type=\"a\">") + + when :LABELED then + annotate("<dt>") + + convert_flow(am.flow(fragment.param)) + + annotate("</dt>") + + annotate("<dd>") + + when :NOTE then + annotate("<tr>") + + annotate("<td valign=\"top\">") + + convert_flow(am.flow(fragment.param)) + + annotate("</td>") + + annotate("<td>") + else + raise "Invalid list type" + end + end + + def list_end_for(fragment_type) + case fragment_type + when :BULLET, :NUMBER, :UPPERALPHA, :LOWERALPHA then + "</li>" + when :LABELED then + "</dd>" + when :NOTE then + "</td></tr>" + else + raise "Invalid list type" + end + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_html_crossref.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_html_crossref.rb new file mode 100644 index 000000000..e6c6f6a77 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_html_crossref.rb @@ -0,0 +1,140 @@ +require 'rdoc/markup/to_html' + +## +# Subclass of the RDoc::Markup::ToHtml class that supports looking up words +# from a context. Those that are found will be hyperlinked. + +class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml + + ## + # Regular expressions to match class and method references. + # + # 1) There can be a '\' in front of text to suppress any cross-references + # 2) There can be a '::' in front of class names to reference from the + # top-level namespace. + # 3) The method can be followed by parenthesis which may + + CLASS_REGEXP_STR = '\\\\?((?:\:{2})?[A-Z]\w*(?:\:\:\w+)*)' + METHOD_REGEXP_STR = '(\w+[!?=]?)(?:\([\.\w+\*\/\+\-\=\<\>]*\))?' + + ## + # Regular expressions matching text that should potentially have + # cross-reference links generated are passed to add_special. Note that + # these expressions are meant to pick up text for which cross-references + # have been suppressed, since the suppression characters are removed by the + # code that is triggered. + + CROSSREF_REGEXP = /( + # A::B::C.meth + #{CLASS_REGEXP_STR}[\.\#]#{METHOD_REGEXP_STR} + + # Stand-alone method (proceeded by a #) + | \\?\##{METHOD_REGEXP_STR} + + # A::B::C + # The stuff after CLASS_REGEXP_STR is a + # nasty hack. CLASS_REGEXP_STR unfortunately matches + # words like dog and cat (these are legal "class" + # names in Fortran 95). When a word is flagged as a + # potential cross-reference, limitations in the markup + # engine suppress other processing, such as typesetting. + # This is particularly noticeable for contractions. + # In order that words like "can't" not + # be flagged as potential cross-references, only + # flag potential class cross-references if the character + # after the cross-referece is a space or sentence + # punctuation. + | #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;]|\z) + + # Things that look like filenames + # The key thing is that there must be at least + # one special character (period, slash, or + # underscore). + | [\/\w]+[_\/\.][\w\/\.]+ + + # Things that have markup suppressed + | \\[^\s] + )/x + + ## + # RDoc::CodeObject for generating references + + attr_accessor :context + + ## + # 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. + + def initialize(from_path, context, show_hash) + raise ArgumentError, 'from_path cannot be nil' if from_path.nil? + super() + + @markup.add_special(CROSSREF_REGEXP, :CROSSREF) + + @from_path = from_path + @context = context + @show_hash = show_hash + + @seen = {} + end + + ## + # We're invoked when any text matches the CROSSREF pattern (defined in + # MarkUp). If we find the corresponding reference, generate a hyperlink. + # If the name we're looking for contains no punctuation, we look for it up + # the module/class chain. For example, HyperlinkHtml is found, even without + # the Generator:: prefix, because we look for it in module Generator first. + + def handle_special_CROSSREF(special) + name = special.text + + # 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/ + + return @seen[name] if @seen.include? name + + if name[0, 1] == '#' then + lookup = name[1..-1] + name = lookup unless @show_hash + else + lookup = name + end + + # Find class, module, or method in class or module. + # + # Do not, however, use an if/elsif/else chain to do so. Instead, test + # each possible pattern until one matches. The reason for this is that a + # string like "YAML.txt" could be the txt() class method of class YAML (in + # which case it would match the first pattern, which splits the string + # into container and method components and looks up both) or a filename + # (in which case it would match the last pattern, which just checks + # whether the string as a whole is a known symbol). + + if /#{CLASS_REGEXP_STR}[\.\#]#{METHOD_REGEXP_STR}/ =~ lookup then + container = $1 + method = $2 + ref = @context.find_symbol container, method + end + + ref = @context.find_symbol lookup unless ref + + out = if lookup == '\\' then + lookup + elsif lookup =~ /^\\/ then + $' + elsif ref and ref.document_self then + "<a href=\"#{ref.as_href(@from_path)}\">#{name}</a>" + else + name + end + + @seen[name] = out + + out + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_latex.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_latex.rb new file mode 100644 index 000000000..aac5c495e --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_latex.rb @@ -0,0 +1,328 @@ +require 'rdoc/markup/formatter' +require 'rdoc/markup/fragments' +require 'rdoc/markup/inline' + +require 'cgi' + +## +# Convert SimpleMarkup to basic LaTeX report format. + +class RDoc::Markup::ToLaTeX < RDoc::Markup::Formatter + + 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) + RDoc::Markup::ToLaTeX.l(arg) + end + + LIST_TYPE_TO_LATEX = { + :BULLET => [ l("\\begin{itemize}"), l("\\end{itemize}") ], + :NUMBER => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\arabic" ], + :UPPERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\Alph" ], + :LOWERALPHA => [ l("\\begin{enumerate}"), l("\\end{enumerate}"), "\\alph" ], + :LABELED => [ l("\\begin{description}"), l("\\end{description}") ], + :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(RDoc::Markup::Attribute.bitmap_for(:BOLD), l("\\textbf{"), l("}")), + InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:TT), l("\\texttt{"), l("}")), + InlineTag.new(RDoc::Markup::Attribute.bitmap_for(:EM), l("\\emph{"), l("}")), + ] + end + + ## + # Escape a LaTeX string + + def escape(str) + $stderr.print "FE: ", str if $DEBUG_RDOC + s = str. + sub(/\s+$/, ''). + gsub(/([_\${}&%#])/, "#{BS}\\1"). + gsub(/\\/, BACKSLASH). + gsub(/\^/, HAT). + gsub(/~/, TILDE). + gsub(/</, LESSTHAN). + gsub(/>/, GREATERTHAN). + gsub(/,,/, ",{},"). + gsub(/\`/, BACKQUOTE) + $stderr.print "-> ", s, "\n" if $DEBUG_RDOC + 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(RDoc::Markup::Attribute.bitmap_for(name), start, stop) + 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 + + ## + # :section: Visitor + + 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 + + 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}'" if $DEBUG_RDOC + 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 .<elipsis>) + 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 :BULLET, :NUMBER, :UPPERALPHA, :LOWERALPHA then + "\\item " + + when :LABELED then + "\\item[" + convert_flow(am.flow(fragment.param)) + "] " + + when :NOTE then + convert_flow(am.flow(fragment.param)) + " & " + else + raise "Invalid list type" + end + end + + def list_end_for(fragment_type) + case fragment_type + when :BULLET, :NUMBER, :UPPERALPHA, :LOWERALPHA, :LABELED then + "" + when :NOTE + "\\\\\n" + else + raise "Invalid list type" + end + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_test.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_test.rb new file mode 100644 index 000000000..b55a0ccef --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_test.rb @@ -0,0 +1,53 @@ +require 'rdoc/markup' +require 'rdoc/markup/formatter' + +## +# This Markup outputter is used for testing purposes. + +class RDoc::Markup::ToTest < RDoc::Markup::Formatter + + ## + # :section: Visitor + + 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 + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_texinfo.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_texinfo.rb new file mode 100644 index 000000000..2b75e00b2 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/markup/to_texinfo.rb @@ -0,0 +1,73 @@ +require 'rdoc/markup/formatter' +require 'rdoc/markup/fragments' +require 'rdoc/markup/inline' + +require 'rdoc/markup' +require 'rdoc/markup/formatter' + +## +# Convert SimpleMarkup to basic TexInfo format +# +# TODO: WTF is AttributeManager for? + +class RDoc::Markup::ToTexInfo < RDoc::Markup::Formatter + + def format(text) + text.txt. + gsub(/@/, "@@"). + gsub(/\{/, "@{"). + gsub(/\}/, "@}"). + # gsub(/,/, "@,"). # technically only required in cross-refs + gsub(/\+([\w]+)\+/, "@code{\\1}"). + gsub(/\<tt\>([^<]+)\<\/tt\>/, "@code{\\1}"). + gsub(/\*([\w]+)\*/, "@strong{\\1}"). + gsub(/\<b\>([^<]+)\<\/b\>/, "@strong{\\1}"). + gsub(/_([\w]+)_/, "@emph{\\1}"). + gsub(/\<em\>([^<]+)\<\/em\>/, "@emph{\\1}") + end + + # :section: Visitor + + def start_accepting + @text = [] + end + + def end_accepting + @text.join("\n") + end + + def accept_paragraph(attributes, text) + @text << format(text) + end + + def accept_verbatim(attributes, text) + @text << "@verb{|#{format(text)}|}" + end + + def accept_heading(attributes, text) + heading = ['@majorheading', '@chapheading'][text.head_level - 1] || '@heading' + @text << "#{heading} #{format(text)}" + end + + def accept_list_start(attributes, text) + @text << '@itemize @bullet' + end + + def accept_list_end(attributes, text) + @text << '@end itemize' + end + + def accept_list_item(attributes, text) + @text << "@item\n#{format(text)}" + end + + def accept_blank_line(attributes, text) + @text << "\n" + end + + def accept_rule(attributes, text) + @text << '-----' + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/meta_method.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/meta_method.rb new file mode 100644 index 000000000..e0c065c2b --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/meta_method.rb @@ -0,0 +1,8 @@ +require 'rdoc/any_method' + +## +# MetaMethod represents a meta-programmed method + +class RDoc::MetaMethod < RDoc::AnyMethod +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/normal_class.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/normal_class.rb new file mode 100644 index 000000000..9a5c5e33a --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/normal_class.rb @@ -0,0 +1,18 @@ +require 'rdoc/class_module' + +## +# A normal class, neither singleton nor anonymous + +class RDoc::NormalClass < RDoc::ClassModule + + def inspect # :nodoc: + superclass = @superclass ? " < #{@superclass}" : nil + "<%s:0x%x class %s%s includes: %p attributes: %p methods: %p aliases: %p>" % [ + self.class, object_id, + full_name, superclass, @includes, @attributes, @method_list, @aliases + ] + end + +end + + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/normal_module.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/normal_module.rb new file mode 100644 index 000000000..6f561c7b6 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/normal_module.rb @@ -0,0 +1,34 @@ +require 'rdoc/class_module' + +## +# A normal module, like NormalClass + +class RDoc::NormalModule < RDoc::ClassModule + + ## + # Appends +comment+ to the current comment, but separated by a rule + + def comment=(comment) + return if comment.empty? + comment = @comment << "\n# ---\n" << comment unless @comment.empty? + + super + end + + def inspect # :nodoc: + "#<%s:0x%x module %s includes: %p attributes: %p methods: %p aliases: %p>" % [ + self.class, object_id, + full_name, @includes, @attributes, @method_list, @aliases + ] + end + + ## + # This is a module, returns true + + def module? + true + end + +end + + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/options.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/options.rb new file mode 100644 index 000000000..40f1bfccd --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/options.rb @@ -0,0 +1,542 @@ +require 'optparse' + +require 'rdoc/ri/paths' + +## +# RDoc::Options handles the parsing and storage of options + +class RDoc::Options + + ## + # Character-set + + attr_reader :charset + + ## + # Should diagrams be drawn? + + attr_accessor :diagram + + ## + # Files matching this pattern will be excluded + + attr_accessor :exclude + + ## + # Should we draw fileboxes in diagrams? + + attr_reader :fileboxes + + ## + # The list of files to be processed + + attr_accessor :files + + ## + # Scan newer sources than the flag file if true. + + attr_reader :force_update + + ## + # Description of the output generator (set with the <tt>-fmt</tt> option) + + attr_accessor :generator + + ## + # Formatter to mark up text with + + attr_accessor :formatter + + ## + # Image format for diagrams + + attr_reader :image_format + + ## + # Include line numbers in the source listings? + + attr_reader :include_line_numbers + + ## + # Name of the file, class or module to display in the initial index page (if + # not specified the first file we encounter is used) + + attr_accessor :main_page + + ## + # Merge into classes of the same name when generating ri + + attr_reader :merge + + ## + # The name of the output directory + + attr_accessor :op_dir + + ## + # Is RDoc in pipe mode? + + attr_accessor :pipe + + ## + # Array of directories to search for files to satisfy an :include: + + attr_reader :rdoc_include + + ## + # Include private and protected methods in the output? + + attr_accessor :show_all + + ## + # Include the '#' at the front of hyperlinked instance method names + + attr_reader :show_hash + + ## + # The number of columns in a tab + + attr_reader :tab_width + + ## + # Template to be used when generating output + + attr_reader :template + + ## + # Number of threads to parse with + + attr_accessor :threads + + ## + # Documentation title + + attr_reader :title + + ## + # Verbosity, zero means quiet + + attr_accessor :verbosity + + ## + # URL of web cvs frontend + + attr_reader :webcvs + + def initialize # :nodoc: + require 'rdoc/rdoc' + @op_dir = 'doc' + @show_all = false + @main_page = nil + @merge = false + @exclude = [] + @generators = RDoc::RDoc::GENERATORS + @generator = RDoc::Generator::Darkfish + @generator_name = nil + @rdoc_include = [] + @title = nil + @template = nil + @threads = if RUBY_PLATFORM == 'java' then + Java::java::lang::Runtime.getRuntime.availableProcessors * 2 + else + 2 + end + @diagram = false + @fileboxes = false + @show_hash = false + @image_format = 'png' + @tab_width = 8 + @include_line_numbers = false + @force_update = true + @verbosity = 1 + @pipe = false + + @webcvs = nil + + @charset = 'utf-8' + end + + ## + # Parse command line options. + + def parse(argv) + opts = OptionParser.new do |opt| + opt.program_name = File.basename $0 + opt.version = RDoc::VERSION + opt.release = nil + opt.summary_indent = ' ' * 4 + opt.banner = <<-EOF +Usage: #{opt.program_name} [options] [names...] + + Files are parsed, and the information they contain collected, before any + output is produced. This allows cross references between all files to be + resolved. If a name is a directory, it is traversed. If no names are + specified, all Ruby files in the current directory (and subdirectories) are + processed. + + How RDoc generates output depends on the output formatter being used, and on + the options you give. + + - Darkfish creates frameless HTML output by Michael Granger. + + - ri creates ri data files + EOF + + opt.separator nil + opt.separator "Parsing Options:" + opt.separator nil + + opt.on("--all", "-a", + "Include all methods (not just public) in", + "the output.") do |value| + @show_all = value + end + + opt.separator nil + + opt.on("--exclude=PATTERN", "-x", Regexp, + "Do not process files or directories", + "matching PATTERN.") do |value| + @exclude << value + end + + opt.separator nil + + opt.on("--extension=NEW=OLD", "-E", + "Treat files ending with .new as if they", + "ended with .old. Using '-E cgi=rb' will", + "cause xxx.cgi to be parsed as a Ruby file.") do |value| + new, old = value.split(/=/, 2) + + unless new and old then + raise OptionParser::InvalidArgument, "Invalid parameter to '-E'" + end + + unless RDoc::ParserFactory.alias_extension old, new then + raise OptionParser::InvalidArgument, "Unknown extension .#{old} to -E" + end + end + + opt.separator nil + + opt.on("--force-update", "-U", + "Forces rdoc to scan all sources even if", + "newer than the flag file.") do |value| + @force_update = value + end + + opt.separator nil + + opt.on("--pipe", + "Convert RDoc on stdin to HTML") do + @pipe = true + end + + opt.separator nil + + opt.on("--threads=THREADS", Integer, + "Number of threads to parse with.") do |threads| + @threads = threads + end + + opt.separator nil + opt.separator "Generator Options:" + opt.separator nil + + opt.on("--charset=CHARSET", "-c", + "Specifies the output HTML character-set.") do |value| + @charset = value + end + + opt.separator nil + + generator_text = @generators.keys.map { |name| " #{name}" }.sort + + opt.on("--fmt=FORMAT", "--format=FORMAT", "-f", @generators.keys, + "Set the output formatter. One of:", *generator_text) do |value| + @generator_name = value.downcase + setup_generator + end + + opt.separator nil + + opt.on("--include=DIRECTORIES", "-i", Array, + "Set (or add to) the list of directories to", + "be searched when satisfying :include:", + "requests. Can be used more than once.") do |value| + @rdoc_include.concat value.map { |dir| dir.strip } + end + + opt.separator nil + + opt.on("--line-numbers", "-N", + "Include line numbers in the source code.") do |value| + @include_line_numbers = value + end + + opt.separator nil + + opt.on("--main=NAME", "-m", + "NAME will be the initial page displayed.") do |value| + @main_page = value + end + + opt.separator nil + + opt.on("--output=DIR", "--op", "-o", + "Set the output directory.") do |value| + @op_dir = value + end + + opt.separator nil + + opt.on("--show-hash", "-H", + "A name of the form #name in a comment is a", + "possible hyperlink to an instance method", + "name. When displayed, the '#' is removed", + "unless this option is specified.") do |value| + @show_hash = value + end + + opt.separator nil + + opt.on("--tab-width=WIDTH", "-w", OptionParser::DecimalInteger, + "Set the width of tab characters.") do |value| + @tab_width = value + end + + opt.separator nil + + opt.on("--template=NAME", "-T", + "Set the template used when generating", + "output.") do |value| + @template = value + end + + opt.separator nil + + opt.on("--title=TITLE", "-t", + "Set TITLE as the title for HTML output.") do |value| + @title = value + end + + opt.separator nil + + opt.on("--webcvs=URL", "-W", + "Specify a URL for linking to a web frontend", + "to CVS. If the URL contains a '\%s', the", + "name of the current file will be", + "substituted; if the URL doesn't contain a", + "'\%s', the filename will be appended to it.") do |value| + @webcvs = value + end + + opt.separator nil + opt.separator "Diagram Options:" + opt.separator nil + + image_formats = %w[gif png jpg jpeg] + opt.on("--image-format=FORMAT", "-I", image_formats, + "Sets output image format for diagrams. Can", + "be #{image_formats.join ', '}. If this option", + "is omitted, png is used. Requires", + "diagrams.") do |value| + @image_format = value + end + + opt.separator nil + + opt.on("--diagram", "-d", + "Generate diagrams showing modules and", + "classes. You need dot V1.8.6 or later to", + "use the --diagram option correctly. Dot is", + "available from http://graphviz.org") do |value| + check_diagram + @diagram = true + end + + opt.separator nil + + opt.on("--fileboxes", "-F", + "Classes are put in boxes which represents", + "files, where these classes reside. Classes", + "shared between more than one file are", + "shown with list of files that are sharing", + "them. Silently discarded if --diagram is", + "not given.") do |value| + @fileboxes = value + end + + opt.separator nil + opt.separator "ri Generator Options:" + opt.separator nil + + opt.on("--ri", "-r", + "Generate output for use by `ri`. The files", + "are stored in the '.rdoc' directory under", + "your home directory unless overridden by a", + "subsequent --op parameter, so no special", + "privileges are needed.") do |value| + @generator_name = "ri" + @op_dir = RDoc::RI::Paths::HOMEDIR + setup_generator + end + + opt.separator nil + + opt.on("--ri-site", "-R", + "Generate output for use by `ri`. The files", + "are stored in a site-wide directory,", + "making them accessible to others, so", + "special privileges are needed.") do |value| + @generator_name = "ri" + @op_dir = RDoc::RI::Paths::SITEDIR + setup_generator + end + + opt.separator nil + + opt.on("--merge", "-M", + "When creating ri output, merge previously", + "processed classes into previously", + "documented classes of the same name.") do |value| + @merge = value + end + + opt.separator nil + opt.separator "Generic Options:" + opt.separator nil + + opt.on("--debug", "-D", + "Displays lots on internal stuff.") do |value| + $DEBUG_RDOC = value + end + + opt.on("--quiet", "-q", + "Don't show progress as we parse.") do |value| + @verbosity = 0 + end + + opt.on("--verbose", "-v", + "Display extra progress as we parse.") do |value| + @verbosity = 2 + end + + opt.separator nil + opt.separator 'Deprecated options - these warn when set' + opt.separator nil + + opt.on("--inline-source", "-S") do |value| + warn "--inline-source will be removed from RDoc on or after August 2009" + end + + opt.on("--promiscuous", "-p") do |value| + warn "--promiscuous will be removed from RDoc on or after August 2009" + end + + opt.separator nil + end + + argv.insert(0, *ENV['RDOCOPT'].split) if ENV['RDOCOPT'] + + opts.parse! argv + + @files = argv.dup + + @rdoc_include << "." if @rdoc_include.empty? + + if @exclude.empty? then + @exclude = nil + else + @exclude = Regexp.new(@exclude.join("|")) + end + + check_files + + # If no template was specified, use the default template for the output + # formatter + + @template ||= @generator_name + + rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e + puts opts + puts + puts e + exit 1 + end + + ## + # Set the title, but only if not already set. This means that a title set + # from the command line trumps one set in a source file + + def title=(string) + @title ||= string + end + + ## + # Don't display progress as we process the files + + def quiet + @verbosity.zero? + end + + def quiet=(bool) + @verbosity = bool ? 0 : 1 + end + + private + + ## + # Set up an output generator for the format in @generator_name + + def setup_generator + @generator = @generators[@generator_name] + + unless @generator then + raise OptionParser::InvalidArgument, "Invalid output formatter" + end + end + + # Check that the right version of 'dot' is available. Unfortunately this + # doesn't work correctly under Windows NT, so we'll bypass the test under + # Windows. + + def check_diagram + return if RUBY_PLATFORM =~ /mswin|cygwin|mingw|bccwin/ + + ok = false + ver = nil + + IO.popen "dot -V 2>&1" do |io| + ver = io.read + if ver =~ /dot.+version(?:\s+gviz)?\s+(\d+)\.(\d+)/ then + ok = ($1.to_i > 1) || ($1.to_i == 1 && $2.to_i >= 8) + end + end + + unless ok then + if ver =~ /^dot.+version/ then + $stderr.puts "Warning: You may need dot V1.8.6 or later to use\n", + "the --diagram option correctly. You have:\n\n ", + ver, + "\nDiagrams might have strange background colors.\n\n" + else + $stderr.puts "You need the 'dot' program to produce diagrams.", + "(see http://www.research.att.com/sw/tools/graphviz/)\n\n" + exit + end + end + end + + ## + # Check that the files on the command line exist + + def check_files + @files.each do |f| + stat = File.stat f rescue next + raise RDoc::Error, "file '#{f}' not readable" unless stat.readable? + end + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/parser.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/parser.rb new file mode 100644 index 000000000..df3becd0a --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/parser.rb @@ -0,0 +1,138 @@ +require 'rdoc' +require 'rdoc/code_objects' +require 'rdoc/markup/preprocess' +require 'rdoc/stats' + +## +# A parser is simple a class that implements +# +# #initialize(file_name, body, options) +# +# and +# +# #scan +# +# The initialize method takes a file name to be used, the body of the file, +# and an RDoc::Options object. The scan method is then called to return an +# appropriately parsed TopLevel code object. +# +# The ParseFactory is used to redirect to the correct parser given a +# filename extension. This magic works because individual parsers have to +# register themselves with us as they are loaded in. The do this using the +# following incantation +# +# require "rdoc/parser" +# +# class RDoc::Parser::Xyz < RDoc::Parser +# parse_files_matching /\.xyz$/ # <<<< +# +# def initialize(file_name, body, options) +# ... +# end +# +# def scan +# ... +# end +# end +# +# Just to make life interesting, if we suspect a plain text file, we also +# look for a shebang line just in case it's a potential shell script + +class RDoc::Parser + + @parsers = [] + + class << self + attr_reader :parsers + end + + ## + # Alias an extension to another extension. After this call, files ending + # "new_ext" will be parsed using the same parser as "old_ext" + + def self.alias_extension(old_ext, new_ext) + old_ext = old_ext.sub(/^\.(.*)/, '\1') + new_ext = new_ext.sub(/^\.(.*)/, '\1') + + parser = can_parse "xxx.#{old_ext}" + return false unless parser + + RDoc::Parser.parsers.unshift [/\.#{new_ext}$/, parser] + + true + end + + ## + # Shamelessly stolen from the ptools gem (since RDoc cannot depend on + # the gem). + + def self.binary?(file) + s = (File.read(file, File.stat(file).blksize) || "").split(//) + + if s.size > 0 then + ((s.size - s.grep(" ".."~").size) / s.size.to_f) > 0.30 + else + false + end + end + private_class_method :binary? + + ## + # Return a parser that can handle a particular extension + + def self.can_parse(file_name) + parser = RDoc::Parser.parsers.find { |regexp,| regexp =~ file_name }.last + + # + # The default parser should *NOT* parse binary files. + # + if parser == RDoc::Parser::Simple && file_name !~ /\.(txt|rdoc)$/ then + if binary? file_name then + return nil + end + end + + return parser + end + + ## + # Find the correct parser for a particular file name. Return a SimpleParser + # for ones that we don't know + + def self.for(top_level, file_name, body, options, stats) + # If no extension, look for shebang + if file_name !~ /\.\w+$/ && body =~ %r{\A#!(.+)} then + shebang = $1 + case shebang + when %r{env\s+ruby}, %r{/ruby} + file_name = "dummy.rb" + end + end + + parser = can_parse file_name + + # This method must return a parser. + parser ||= RDoc::Parser::Simple + + parser.new top_level, file_name, body, options, stats + end + + ## + # Record which file types this parser can understand. + + def self.parse_files_matching(regexp) + RDoc::Parser.parsers.unshift [regexp, self] + end + + def initialize(top_level, file_name, content, options, stats) + @top_level = top_level + @file_name = file_name + @content = content + @options = options + @stats = stats + end + +end + +require 'rdoc/parser/simple' + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/parser/c.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/parser/c.rb new file mode 100644 index 000000000..5a11889b3 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/parser/c.rb @@ -0,0 +1,678 @@ +require 'rdoc/parser' +require 'rdoc/parser/ruby' +require 'rdoc/known_classes' + +## +# We attempt to parse C extension files. Basically we look for +# the standard patterns that you find in extensions: <tt>rb_define_class, +# rb_define_method</tt> and so on. We also try to find the corresponding +# C source for the methods and extract comments, but if we fail +# we don't worry too much. +# +# The comments associated with a Ruby method are extracted from the C +# comment block associated with the routine that _implements_ that +# method, that is to say the method whose name is given in the +# <tt>rb_define_method</tt> call. For example, you might write: +# +# /* +# * Returns a new array that is a one-dimensional flattening of this +# * array (recursively). That is, for every element that is an array, +# * extract its elements into the new array. +# * +# * s = [ 1, 2, 3 ] #=> [1, 2, 3] +# * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]] +# * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10] +# * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +# */ +# static VALUE +# rb_ary_flatten(ary) +# VALUE ary; +# { +# ary = rb_obj_dup(ary); +# rb_ary_flatten_bang(ary); +# return ary; +# } +# +# ... +# +# void +# Init_Array() +# { +# ... +# rb_define_method(rb_cArray, "flatten", rb_ary_flatten, 0); +# +# Here RDoc will determine from the rb_define_method line that there's a +# method called "flatten" in class Array, and will look for the implementation +# in the method rb_ary_flatten. It will then use the comment from that +# method in the HTML output. This method must be in the same source file +# as the rb_define_method. +# +# C classes can be diagrammed (see /tc/dl/ruby/ruby/error.c), and RDoc +# integrates C and Ruby source into one tree +# +# The comment blocks may include special directives: +# +# [Document-class: <i>name</i>] +# This comment block is documentation for the given class. Use this +# when the <tt>Init_xxx</tt> method is not named after the class. +# +# [Document-method: <i>name</i>] +# This comment documents the named method. Use when RDoc cannot +# automatically find the method from it's declaration +# +# [call-seq: <i>text up to an empty line</i>] +# Because C source doesn't give descripive names to Ruby-level parameters, +# you need to document the calling sequence explicitly +# +# In addition, RDoc assumes by default that the C method implementing a +# Ruby function is in the same source file as the rb_define_method call. +# If this isn't the case, add the comment: +# +# rb_define_method(....); // in: filename +# +# As an example, we might have an extension that defines multiple classes +# in its Init_xxx method. We could document them using +# +# /* +# * Document-class: MyClass +# * +# * Encapsulate the writing and reading of the configuration +# * file. ... +# */ +# +# /* +# * Document-method: read_value +# * +# * call-seq: +# * cfg.read_value(key) -> value +# * cfg.read_value(key} { |key| } -> value +# * +# * Return the value corresponding to +key+ from the configuration. +# * In the second form, if the key isn't found, invoke the +# * block and return its value. +# */ + +class RDoc::Parser::C < RDoc::Parser + + parse_files_matching(/\.(?:([CcHh])\1?|c([+xp])\2|y)\z/) + + ## + # C file the parser is parsing + + attr_accessor :content + + ## + # Resets cross-file state. Call when parsing different projects that need + # separate documentation. + + def self.reset + @@enclosure_classes = {} + @@known_bodies = {} + end + + reset + + ## + # Prepare to parse a C file + + def initialize(top_level, file_name, content, options, stats) + super + + @known_classes = RDoc::KNOWN_CLASSES.dup + @content = handle_tab_width handle_ifdefs_in(@content) + @classes = Hash.new + @file_dir = File.dirname(@file_name) + end + + def do_aliases + @content.scan(%r{rb_define_alias\s*\(\s*(\w+),\s*"([^"]+)",\s*"([^"]+)"\s*\)}m) do + |var_name, new_name, old_name| + class_name = @known_classes[var_name] || var_name + class_obj = find_class(var_name, class_name) + + as = class_obj.add_alias RDoc::Alias.new("", old_name, new_name, "") + + @stats.add_alias as + end + end + + def do_classes + @content.scan(/(\w+)\s* = \s*rb_define_module\s*\(\s*"(\w+)"\s*\)/mx) do + |var_name, class_name| + handle_class_module(var_name, "module", class_name, nil, nil) + end + + # The '.' lets us handle SWIG-generated files + @content.scan(/([\w\.]+)\s* = \s*rb_define_class\s* + \( + \s*"(\w+)", + \s*(\w+)\s* + \)/mx) do |var_name, class_name, parent| + handle_class_module(var_name, "class", class_name, parent, nil) + end + + @content.scan(/(\w+)\s*=\s*boot_defclass\s*\(\s*"(\w+?)",\s*(\w+?)\s*\)/) do + |var_name, class_name, parent| + parent = nil if parent == "0" + handle_class_module(var_name, "class", class_name, parent, nil) + end + + @content.scan(/(\w+)\s* = \s*rb_define_module_under\s* + \( + \s*(\w+), + \s*"(\w+)" + \s*\)/mx) do |var_name, in_module, class_name| + handle_class_module(var_name, "module", class_name, nil, in_module) + end + + @content.scan(/([\w\.]+)\s* = \s*rb_define_class_under\s* + \( + \s*(\w+), + \s*"(\w+)", + \s*([\w\*\s\(\)\.\->]+)\s* # for SWIG + \s*\)/mx) do |var_name, in_module, class_name, parent| + handle_class_module(var_name, "class", class_name, parent, in_module) + end + end + + def do_constants + @content.scan(%r{\Wrb_define_ + ( + variable | + readonly_variable | + const | + global_const | + ) + \s*\( + (?:\s*(\w+),)? + \s*"(\w+)", + \s*(.*?)\s*\)\s*; + }xm) do |type, var_name, const_name, definition| + var_name = "rb_cObject" if !var_name or var_name == "rb_mKernel" + handle_constants(type, var_name, const_name, definition) + end + end + + ## + # Look for includes of the form: + # + # rb_include_module(rb_cArray, rb_mEnumerable); + + def do_includes + @content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m| + if cls = @classes[c] + m = @known_classes[m] || m + cls.add_include RDoc::Include.new(m, "") + end + end + end + + def do_methods + @content.scan(%r{rb_define_ + ( + singleton_method | + method | + module_function | + private_method + ) + \s*\(\s*([\w\.]+), + \s*"([^"]+)", + \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, + \s*(-?\w+)\s*\) + (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))? + }xm) do + |type, var_name, meth_name, meth_body, param_count, source_file| + + # Ignore top-object and weird struct.c dynamic stuff + next if var_name == "ruby_top_self" + next if var_name == "nstr" + next if var_name == "envtbl" + next if var_name == "argf" # it'd be nice to handle this one + + var_name = "rb_cObject" if var_name == "rb_mKernel" + handle_method(type, var_name, meth_name, + meth_body, param_count, source_file) + end + + @content.scan(%r{rb_define_attr\( + \s*([\w\.]+), + \s*"([^"]+)", + \s*(\d+), + \s*(\d+)\s*\); + }xm) do |var_name, attr_name, attr_reader, attr_writer| + #var_name = "rb_cObject" if var_name == "rb_mKernel" + handle_attr(var_name, attr_name, + attr_reader.to_i != 0, + attr_writer.to_i != 0) + end + + @content.scan(%r{rb_define_global_function\s*\( + \s*"([^"]+)", + \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, + \s*(-?\w+)\s*\) + (?:;\s*/[*/]\s+in\s+(\w+?\.[cy]))? + }xm) do |meth_name, meth_body, param_count, source_file| + handle_method("method", "rb_mKernel", meth_name, + meth_body, param_count, source_file) + end + + @content.scan(/define_filetest_function\s*\( + \s*"([^"]+)", + \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, + \s*(-?\w+)\s*\)/xm) do + |meth_name, meth_body, param_count| + + handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count) + handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count) + end + end + + def find_attr_comment(attr_name) + if @content =~ %r{((?>/\*.*?\*/\s+)) + rb_define_attr\((?:\s*(\w+),)?\s*"#{attr_name}"\s*,.*?\)\s*;}xmi + $1 + elsif @content =~ %r{Document-attr:\s#{attr_name}\s*?\n((?>.*?\*/))}m + $1 + else + '' + end + end + + ## + # Find the C code corresponding to a Ruby method + + def find_body(class_name, meth_name, meth_obj, body, quiet = false) + case body + when %r"((?>/\*.*?\*/\s*))((?:(?:static|SWIGINTERN)\s+)?(?:intern\s+)?VALUE\s+#{meth_name} + \s*(\([^)]*\))([^;]|$))"xm + comment = $1 + body_text = $2 + params = $3 + + remove_private_comments comment if comment + + # see if we can find the whole body + + re = Regexp.escape(body_text) + '[^(]*^\{.*?^\}' + body_text = $& if /#{re}/m =~ body + + # The comment block may have been overridden with a 'Document-method' + # block. This happens in the interpreter when multiple methods are + # vectored through to the same C method but those methods are logically + # distinct (for example Kernel.hash and Kernel.object_id share the same + # implementation + + override_comment = find_override_comment class_name, meth_obj.name + comment = override_comment if override_comment + + find_modifiers comment, meth_obj if comment + +# meth_obj.params = params + meth_obj.start_collecting_tokens + meth_obj.add_token RDoc::RubyToken::Token.new(1,1).set_text(body_text) + meth_obj.comment = mangle_comment comment + when %r{((?>/\*.*?\*/\s*))^\s*(\#\s*define\s+#{meth_name}\s+(\w+))}m + comment = $1 + body_text = $2 + find_body class_name, $3, meth_obj, body, true + find_modifiers comment, meth_obj + + meth_obj.start_collecting_tokens + meth_obj.add_token RDoc::RubyToken::Token.new(1,1).set_text(body_text) + meth_obj.comment = mangle_comment(comment) + meth_obj.comment.to_s + when %r{^\s*\#\s*define\s+#{meth_name}\s+(\w+)}m + unless find_body(class_name, $1, meth_obj, body, true) + warn "No definition for #{meth_name}" unless @options.quiet + return false + end + else + # No body, but might still have an override comment + comment = find_override_comment(class_name, meth_obj.name) + + if comment + find_modifiers(comment, meth_obj) + meth_obj.comment = mangle_comment(comment) + else + warn "No definition for #{meth_name}" unless @options.quiet + return false + end + end + true + end + + def find_class(raw_name, name) + unless @classes[raw_name] + if raw_name =~ /^rb_m/ + container = @top_level.add_module RDoc::NormalModule, name + else + container = @top_level.add_class RDoc::NormalClass, name + end + + container.record_location @top_level + @classes[raw_name] = container + end + @classes[raw_name] + end + + ## + # Look for class or module documentation above Init_+class_name+(void), + # in a Document-class +class_name+ (or module) comment or above an + # rb_define_class (or module). If a comment is supplied above a matching + # Init_ and a rb_define_class the Init_ comment is used. + # + # /* + # * This is a comment for Foo + # */ + # Init_Foo(void) { + # VALUE cFoo = rb_define_class("Foo", rb_cObject); + # } + # + # /* + # * Document-class: Foo + # * This is a comment for Foo + # */ + # Init_foo(void) { + # VALUE cFoo = rb_define_class("Foo", rb_cObject); + # } + # + # /* + # * This is a comment for Foo + # */ + # VALUE cFoo = rb_define_class("Foo", rb_cObject); + + def find_class_comment(class_name, class_meth) + comment = nil + + if @content =~ %r{((?>/\*.*?\*/\s+)) + (static\s+)?void\s+Init_#{class_name}\s*(?:_\(\s*)?\(\s*(?:void\s*)\)}xmi then + comment = $1 + elsif @content =~ %r{Document-(?:class|module):\s+#{class_name}\s*?(?:<\s+[:,\w]+)?\n((?>.*?\*/))}m then + comment = $1 + elsif @content =~ %r{((?>/\*.*?\*/\s+)) + ([\w\.\s]+\s* = \s+)?rb_define_(class|module).*?"(#{class_name})"}xm then + comment = $1 + end + + class_meth.comment = mangle_comment comment if comment + end + + ## + # Finds a comment matching +type+ and +const_name+ either above the + # comment or in the matching Document- section. + + def find_const_comment(type, const_name) + if @content =~ %r{((?>^\s*/\*.*?\*/\s+)) + rb_define_#{type}\((?:\s*(\w+),)?\s*"#{const_name}"\s*,.*?\)\s*;}xmi + $1 + elsif @content =~ %r{Document-(?:const|global|variable):\s#{const_name}\s*?\n((?>.*?\*/))}m + $1 + else + '' + end + end + + ## + # If the comment block contains a section that looks like: + # + # call-seq: + # Array.new + # Array.new(10) + # + # use it for the parameters. + + def find_modifiers(comment, meth_obj) + if comment.sub!(/:nodoc:\s*^\s*\*?\s*$/m, '') or + comment.sub!(/\A\/\*\s*:nodoc:\s*\*\/\Z/, '') + meth_obj.document_self = false + end + if comment.sub!(/call-seq:(.*?)^\s*\*?\s*$/m, '') or + comment.sub!(/\A\/\*\s*call-seq:(.*?)\*\/\Z/, '') + seq = $1 + seq.gsub!(/^\s*\*\s*/, '') + meth_obj.call_seq = seq + end + end + + def find_override_comment(class_name, meth_name) + name = Regexp.escape(meth_name) + if @content =~ %r{Document-method:\s+#{class_name}(?:\.|::|#)#{name}\s*?\n((?>.*?\*/))}m then + $1 + elsif @content =~ %r{Document-method:\s#{name}\s*?\n((?>.*?\*/))}m then + $1 + end + end + + def handle_attr(var_name, attr_name, reader, writer) + rw = '' + if reader + #@stats.num_methods += 1 + rw << 'R' + end + if writer + #@stats.num_methods += 1 + rw << 'W' + end + + class_name = @known_classes[var_name] + + return unless class_name + + class_obj = find_class(var_name, class_name) + + if class_obj + comment = find_attr_comment(attr_name) + unless comment.empty? + comment = mangle_comment(comment) + end + att = RDoc::Attr.new '', attr_name, rw, comment + class_obj.add_attribute(att) + end + end + + def handle_class_module(var_name, class_mod, class_name, parent, in_module) + parent_name = @known_classes[parent] || parent + + if in_module + enclosure = @classes[in_module] || @@enclosure_classes[in_module] + unless enclosure + if enclosure = @known_classes[in_module] + handle_class_module(in_module, (/^rb_m/ =~ in_module ? "module" : "class"), + enclosure, nil, nil) + enclosure = @classes[in_module] + end + end + unless enclosure + warn("Enclosing class/module '#{in_module}' for " + + "#{class_mod} #{class_name} not known") + return + end + else + enclosure = @top_level + end + + if class_mod == "class" then + full_name = if RDoc::ClassModule === enclosure then + enclosure.full_name + "::#{class_name}" + else + class_name + end + + if @content =~ %r{Document-class:\s+#{full_name}\s*<\s+([:,\w]+)} then + parent_name = $1 + end + cm = enclosure.add_class RDoc::NormalClass, class_name, parent_name + @stats.add_class cm + else + cm = enclosure.add_module RDoc::NormalModule, class_name + @stats.add_module cm + end + + cm.record_location enclosure.top_level + + find_class_comment cm.full_name, cm + + @classes[var_name] = cm + @@enclosure_classes[var_name] = cm + @known_classes[var_name] = cm.full_name + end + + ## + # Adds constant comments. By providing some_value: at the start ofthe + # comment you can override the C value of the comment to give a friendly + # definition. + # + # /* 300: The perfect score in bowling */ + # rb_define_const(cFoo, "PERFECT", INT2FIX(300); + # + # Will override +INT2FIX(300)+ with the value +300+ in the output RDoc. + # Values may include quotes and escaped colons (\:). + + def handle_constants(type, var_name, const_name, definition) + #@stats.num_constants += 1 + class_name = @known_classes[var_name] + + return unless class_name + + class_obj = find_class(var_name, class_name) + + unless class_obj + warn("Enclosing class/module '#{const_name}' for not known") + return + end + + comment = find_const_comment(type, const_name) + + # In the case of rb_define_const, the definition and comment are in + # "/* definition: comment */" form. The literal ':' and '\' characters + # can be escaped with a backslash. + if type.downcase == 'const' then + elements = mangle_comment(comment).split(':') + if elements.nil? or elements.empty? then + con = RDoc::Constant.new(const_name, definition, + mangle_comment(comment)) + else + new_definition = elements[0..-2].join(':') + if new_definition.empty? then # Default to literal C definition + new_definition = definition + else + new_definition.gsub!("\:", ":") + new_definition.gsub!("\\", '\\') + end + new_definition.sub!(/\A(\s+)/, '') + new_comment = $1.nil? ? elements.last : "#{$1}#{elements.last.lstrip}" + con = RDoc::Constant.new(const_name, new_definition, + mangle_comment(new_comment)) + end + else + con = RDoc::Constant.new const_name, definition, mangle_comment(comment) + end + + class_obj.add_constant(con) + end + + ## + # Removes #ifdefs that would otherwise confuse us + + def handle_ifdefs_in(body) + body.gsub(/^#ifdef HAVE_PROTOTYPES.*?#else.*?\n(.*?)#endif.*?\n/m, '\1') + end + + def handle_method(type, var_name, meth_name, meth_body, param_count, + source_file = nil) + class_name = @known_classes[var_name] + + return unless class_name + + class_obj = find_class var_name, class_name + + if class_obj then + if meth_name == "initialize" then + meth_name = "new" + type = "singleton_method" + end + + meth_obj = RDoc::AnyMethod.new '', meth_name + meth_obj.singleton = %w[singleton_method module_function].include? type + + p_count = (Integer(param_count) rescue -1) + + if p_count < 0 + meth_obj.params = "(...)" + elsif p_count == 0 + meth_obj.params = "()" + else + meth_obj.params = "(" + (1..p_count).map{|i| "p#{i}"}.join(", ") + ")" + end + + if source_file then + file_name = File.join(@file_dir, source_file) + body = (@@known_bodies[source_file] ||= File.read(file_name)) + else + body = @content + end + + if find_body(class_name, meth_body, meth_obj, body) and meth_obj.document_self then + class_obj.add_method meth_obj + @stats.add_method meth_obj + meth_obj.visibility = :private if 'private_method' == type + end + end + end + + def handle_tab_width(body) + if /\t/ =~ body + tab_width = @options.tab_width + body.split(/\n/).map do |line| + 1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)} && $~ #` + line + end .join("\n") + else + body + end + end + + ## + # Remove the /*'s and leading asterisks from C comments + + def mangle_comment(comment) + comment.sub!(%r{/\*+}) { " " * $&.length } + comment.sub!(%r{\*+/}) { " " * $&.length } + comment.gsub!(/^[ \t]*\*/m) { " " * $&.length } + comment + end + + ## + # Removes lines that are commented out that might otherwise get picked up + # when scanning for classes and methods + + def remove_commented_out_lines + @content.gsub!(%r{//.*rb_define_}, '//') + end + + def remove_private_comments(comment) + comment.gsub!(/\/?\*--\n(.*?)\/?\*\+\+/m, '') + comment.sub!(/\/?\*--\n.*/m, '') + end + + ## + # Extract the classes/modules and methods from a C file and return the + # corresponding top-level object + + def scan + remove_commented_out_lines + do_classes + do_constants + do_methods + do_includes + do_aliases + @top_level + end + + def warn(msg) + $stderr.puts + $stderr.puts msg + $stderr.flush + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/parser/perl.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/parser/perl.rb new file mode 100644 index 000000000..43d1e9ff6 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/parser/perl.rb @@ -0,0 +1,165 @@ +require 'rdoc/parser' + +## +# +# This is an attamept to write a basic parser for Perl's +# POD (Plain old Documentation) format. Ruby code must +# co-exist with Perl, and some tasks are easier in Perl +# than Ruby because of existing libraries. +# +# One difficult is that Perl POD has no means of identifying +# the classes (packages) and methods (subs) with which it +# is associated, it is more like literate programming in so +# far as it just happens to be in the same place as the code, +# but need not be. +# +# We would like to support all the markup the POD provides +# so that it will convert happily to HTML. At the moment +# I don't think I can do that: time constraints. +# + +class RDoc::Parser::PerlPOD < RDoc::Parser + + parse_files_matching(/.p[lm]$/) + + ## + # Prepare to parse a perl file + + def initialize(top_level, file_name, content, options, stats) + super + + preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include + + preprocess.handle @content do |directive, param| + warn "Unrecognized directive '#{directive}' in #{@file_name}" + end + end + + ## + # Extract the Pod(-like) comments from the code. + # At its most basic there will ne no need to distinguish + # between the different types of header, etc. + # + # This uses a simple finite state machine, in a very + # procedural pattern. I could "replace case with polymorphism" + # but I think it would obscure the intent, scatter the + # code all over tha place. This machine is necessary + # because POD requires that directives be preceded by + # blank lines, so reading line by line is necessary, + # and preserving state about what is seen is necesary. + + def scan + + @top_level.comment ||= "" + state=:code_blank + line_number = 0 + line = nil + + # This started out as a really long nested case statement, + # which also led to repetitive code. I'd like to avoid that + # so I'm using a "table" instead. + + # Firstly we need some procs to do the transition and processing + # work. Because these are procs they are closures, and they can + # use variables in the local scope. + # + # First, the "nothing to see here" stuff. + code_noop = lambda do + if line =~ /^\s+$/ + state = :code_blank + end + end + + pod_noop = lambda do + if line =~ /^\s+$/ + state = :pod_blank + end + @top_level.comment += filter(line) + end + + begin_noop = lambda do + if line =~ /^\s+$/ + state = :begin_blank + end + @top_level.comment += filter(line) + end + + # Now for the blocks that process code and comments... + + transit_to_pod = lambda do + case line + when /^=(?:pod|head\d+)/ + state = :pod_no_blank + @top_level.comment += filter(line) + when /^=over/ + state = :over_no_blank + @top_level.comment += filter(line) + when /^=(?:begin|for)/ + state = :begin_no_blank + end + end + + process_pod = lambda do + case line + when /^\s*$/ + state = :pod_blank + @top_level.comment += filter(line) + when /^=cut/ + state = :code_no_blank + when /^=end/ + $stderr.puts "'=end' unexpected at #{line_number} in #{@file_name}" + else + @top_level.comment += filter(line) + end + end + + + process_begin = lambda do + case line + when /^\s*$/ + state = :begin_blank + @top_level.comment += filter(line) + when /^=end/ + state = :code_no_blank + when /^=cut/ + $stderr.puts "'=cut' unexpected at #{line_number} in #{@file_name}" + else + @top_level.comment += filter(line) + end + + end + + + transitions = { :code_no_blank => code_noop, + :code_blank => transit_to_pod, + :pod_no_blank => pod_noop, + :pod_blank => process_pod, + :begin_no_blank => begin_noop, + :begin_blank => process_begin} + @content.each_line do |l| + line = l + line_number += 1 + transitions[state].call + end # each line + + @top_level + end + + # Filter the perl markup that does the same as the rdoc + # filtering. Only basic for now. Will probably need a + # proper parser to cope with C<<...>> etc + def filter(comment) + return '' if comment =~ /^=pod\s*$/ + comment.gsub!(/^=pod/, '==') + comment.gsub!(/^=head(\d+)/) do + "=" * $1.to_i + end + comment.gsub!(/=item/, ''); + comment.gsub!(/C<(.*?)>/, '<tt>\1</tt>'); + comment.gsub!(/I<(.*?)>/, '<i>\1</i>'); + comment.gsub!(/B<(.*?)>/, '<b>\1</b>'); + comment + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/parser/ruby.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/parser/ruby.rb new file mode 100644 index 000000000..84e292d47 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/parser/ruby.rb @@ -0,0 +1,2904 @@ +## +# This file contains stuff stolen outright from: +# +# rtags.rb - +# ruby-lex.rb - ruby lexcal analyzer +# ruby-token.rb - ruby tokens +# by Keiju ISHITSUKA (Nippon Rational Inc.) +# + +require 'e2mmap' +require 'irb/slex' + +require 'rdoc/code_objects' +require 'rdoc/tokenstream' +require 'rdoc/markup/preprocess' +require 'rdoc/parser' + +$TOKEN_DEBUG ||= nil +#$TOKEN_DEBUG = $DEBUG_RDOC + +## +# Definitions of all tokens involved in the lexical analysis + +module RDoc::RubyToken + + EXPR_BEG = :EXPR_BEG + EXPR_MID = :EXPR_MID + EXPR_END = :EXPR_END + EXPR_ARG = :EXPR_ARG + EXPR_FNAME = :EXPR_FNAME + EXPR_DOT = :EXPR_DOT + EXPR_CLASS = :EXPR_CLASS + + class Token + NO_TEXT = "??".freeze + + attr_accessor :text + attr_reader :line_no + attr_reader :char_no + + def initialize(line_no, char_no) + @line_no = line_no + @char_no = char_no + @text = NO_TEXT + end + + def ==(other) + self.class == other.class and + other.line_no == @line_no and + other.char_no == @char_no and + other.text == @text + end + + ## + # Because we're used in contexts that expect to return a token, we set the + # text string and then return ourselves + + def set_text(text) + @text = text + self + end + + end + + class TkNode < Token + attr :node + end + + class TkId < Token + def initialize(line_no, char_no, name) + super(line_no, char_no) + @name = name + end + attr :name + end + + class TkKW < TkId + end + + class TkVal < Token + def initialize(line_no, char_no, value = nil) + super(line_no, char_no) + set_text(value) + end + end + + class TkOp < Token + def name + self.class.op_name + end + end + + class TkOPASGN < TkOp + def initialize(line_no, char_no, op) + super(line_no, char_no) + op = TkReading2Token[op] unless Symbol === op + @op = op + end + attr :op + end + + class TkUnknownChar < Token + def initialize(line_no, char_no, id) + super(line_no, char_no) + @name = char_no.chr + end + attr :name + end + + class TkError < Token + end + + def set_token_position(line, char) + @prev_line_no = line + @prev_char_no = char + end + + def Token(token, value = nil) + tk = nil + case token + when String, Symbol + source = String === token ? TkReading2Token : TkSymbol2Token + raise TkReading2TokenNoKey, token if (tk = source[token]).nil? + tk = Token(tk[0], value) + else + tk = if (token.ancestors & [TkId, TkVal, TkOPASGN, TkUnknownChar]).empty? + token.new(@prev_line_no, @prev_char_no) + else + token.new(@prev_line_no, @prev_char_no, value) + end + end + tk + end + + TokenDefinitions = [ + [:TkCLASS, TkKW, "class", EXPR_CLASS], + [:TkMODULE, TkKW, "module", EXPR_CLASS], + [:TkDEF, TkKW, "def", EXPR_FNAME], + [:TkUNDEF, TkKW, "undef", EXPR_FNAME], + [:TkBEGIN, TkKW, "begin", EXPR_BEG], + [:TkRESCUE, TkKW, "rescue", EXPR_MID], + [:TkENSURE, TkKW, "ensure", EXPR_BEG], + [:TkEND, TkKW, "end", EXPR_END], + [:TkIF, TkKW, "if", EXPR_BEG, :TkIF_MOD], + [:TkUNLESS, TkKW, "unless", EXPR_BEG, :TkUNLESS_MOD], + [:TkTHEN, TkKW, "then", EXPR_BEG], + [:TkELSIF, TkKW, "elsif", EXPR_BEG], + [:TkELSE, TkKW, "else", EXPR_BEG], + [:TkCASE, TkKW, "case", EXPR_BEG], + [:TkWHEN, TkKW, "when", EXPR_BEG], + [:TkWHILE, TkKW, "while", EXPR_BEG, :TkWHILE_MOD], + [:TkUNTIL, TkKW, "until", EXPR_BEG, :TkUNTIL_MOD], + [:TkFOR, TkKW, "for", EXPR_BEG], + [:TkBREAK, TkKW, "break", EXPR_END], + [:TkNEXT, TkKW, "next", EXPR_END], + [:TkREDO, TkKW, "redo", EXPR_END], + [:TkRETRY, TkKW, "retry", EXPR_END], + [:TkIN, TkKW, "in", EXPR_BEG], + [:TkDO, TkKW, "do", EXPR_BEG], + [:TkRETURN, TkKW, "return", EXPR_MID], + [:TkYIELD, TkKW, "yield", EXPR_END], + [:TkSUPER, TkKW, "super", EXPR_END], + [:TkSELF, TkKW, "self", EXPR_END], + [:TkNIL, TkKW, "nil", EXPR_END], + [:TkTRUE, TkKW, "true", EXPR_END], + [:TkFALSE, TkKW, "false", EXPR_END], + [:TkAND, TkKW, "and", EXPR_BEG], + [:TkOR, TkKW, "or", EXPR_BEG], + [:TkNOT, TkKW, "not", EXPR_BEG], + [:TkIF_MOD, TkKW], + [:TkUNLESS_MOD, TkKW], + [:TkWHILE_MOD, TkKW], + [:TkUNTIL_MOD, TkKW], + [:TkALIAS, TkKW, "alias", EXPR_FNAME], + [:TkDEFINED, TkKW, "defined?", EXPR_END], + [:TklBEGIN, TkKW, "BEGIN", EXPR_END], + [:TklEND, TkKW, "END", EXPR_END], + [:Tk__LINE__, TkKW, "__LINE__", EXPR_END], + [:Tk__FILE__, TkKW, "__FILE__", EXPR_END], + + [:TkIDENTIFIER, TkId], + [:TkFID, TkId], + [:TkGVAR, TkId], + [:TkIVAR, TkId], + [:TkCONSTANT, TkId], + + [:TkINTEGER, TkVal], + [:TkFLOAT, TkVal], + [:TkSTRING, TkVal], + [:TkXSTRING, TkVal], + [:TkREGEXP, TkVal], + [:TkCOMMENT, TkVal], + + [:TkDSTRING, TkNode], + [:TkDXSTRING, TkNode], + [:TkDREGEXP, TkNode], + [:TkNTH_REF, TkId], + [:TkBACK_REF, TkId], + + [:TkUPLUS, TkOp, "+@"], + [:TkUMINUS, TkOp, "-@"], + [:TkPOW, TkOp, "**"], + [:TkCMP, TkOp, "<=>"], + [:TkEQ, TkOp, "=="], + [:TkEQQ, TkOp, "==="], + [:TkNEQ, TkOp, "!="], + [:TkGEQ, TkOp, ">="], + [:TkLEQ, TkOp, "<="], + [:TkANDOP, TkOp, "&&"], + [:TkOROP, TkOp, "||"], + [:TkMATCH, TkOp, "=~"], + [:TkNMATCH, TkOp, "!~"], + [:TkDOT2, TkOp, ".."], + [:TkDOT3, TkOp, "..."], + [:TkAREF, TkOp, "[]"], + [:TkASET, TkOp, "[]="], + [:TkLSHFT, TkOp, "<<"], + [:TkRSHFT, TkOp, ">>"], + [:TkCOLON2, TkOp], + [:TkCOLON3, TkOp], +# [:OPASGN, TkOp], # +=, -= etc. # + [:TkASSOC, TkOp, "=>"], + [:TkQUESTION, TkOp, "?"], #? + [:TkCOLON, TkOp, ":"], #: + + [:TkfLPAREN], # func( # + [:TkfLBRACK], # func[ # + [:TkfLBRACE], # func{ # + [:TkSTAR], # *arg + [:TkAMPER], # &arg # + [:TkSYMBOL, TkId], # :SYMBOL + [:TkSYMBEG, TkId], + [:TkGT, TkOp, ">"], + [:TkLT, TkOp, "<"], + [:TkPLUS, TkOp, "+"], + [:TkMINUS, TkOp, "-"], + [:TkMULT, TkOp, "*"], + [:TkDIV, TkOp, "/"], + [:TkMOD, TkOp, "%"], + [:TkBITOR, TkOp, "|"], + [:TkBITXOR, TkOp, "^"], + [:TkBITAND, TkOp, "&"], + [:TkBITNOT, TkOp, "~"], + [:TkNOTOP, TkOp, "!"], + + [:TkBACKQUOTE, TkOp, "`"], + + [:TkASSIGN, Token, "="], + [:TkDOT, Token, "."], + [:TkLPAREN, Token, "("], #(exp) + [:TkLBRACK, Token, "["], #[arry] + [:TkLBRACE, Token, "{"], #{hash} + [:TkRPAREN, Token, ")"], + [:TkRBRACK, Token, "]"], + [:TkRBRACE, Token, "}"], + [:TkCOMMA, Token, ","], + [:TkSEMICOLON, Token, ";"], + + [:TkRD_COMMENT], + [:TkSPACE], + [:TkNL], + [:TkEND_OF_SCRIPT], + + [:TkBACKSLASH, TkUnknownChar, "\\"], + [:TkAT, TkUnknownChar, "@"], + [:TkDOLLAR, TkUnknownChar, "\$"], #" + ] + + # {reading => token_class} + # {reading => [token_class, *opt]} + TkReading2Token = {} + TkSymbol2Token = {} + + def self.def_token(token_n, super_token = Token, reading = nil, *opts) + token_n = token_n.id2name unless String === token_n + + fail AlreadyDefinedToken, token_n if const_defined?(token_n) + + token_c = Class.new super_token + const_set token_n, token_c +# token_c.inspect + + if reading + if TkReading2Token[reading] + fail TkReading2TokenDuplicateError, token_n, reading + end + if opts.empty? + TkReading2Token[reading] = [token_c] + else + TkReading2Token[reading] = [token_c].concat(opts) + end + end + TkSymbol2Token[token_n.intern] = token_c + + if token_c <= TkOp + token_c.class_eval %{ + def self.op_name; "#{reading}"; end + } + end + end + + for defs in TokenDefinitions + def_token(*defs) + end + + NEWLINE_TOKEN = TkNL.new(0,0) + NEWLINE_TOKEN.set_text("\n") + +end + +## +# Lexical analyzer for Ruby source + +class RDoc::RubyLex + + ## + # Read an input stream character by character. We allow for unlimited + # ungetting of characters just read. + # + # We simplify the implementation greatly by reading the entire input + # into a buffer initially, and then simply traversing it using + # pointers. + # + # We also have to allow for the <i>here document diversion</i>. This + # little gem comes about when the lexer encounters a here + # document. At this point we effectively need to split the input + # stream into two parts: one to read the body of the here document, + # the other to read the rest of the input line where the here + # document was initially encountered. For example, we might have + # + # do_something(<<-A, <<-B) + # stuff + # for + # A + # stuff + # for + # B + # + # When the lexer encounters the <<A, it reads until the end of the + # line, and keeps it around for later. It then reads the body of the + # here document. Once complete, it needs to read the rest of the + # original line, but then skip the here document body. + # + + class BufferedReader + + attr_reader :line_num + + def initialize(content, options) + @options = options + + if /\t/ =~ content + tab_width = @options.tab_width + content = content.split(/\n/).map do |line| + 1 while line.gsub!(/\t+/) { ' ' * (tab_width*$&.length - $`.length % tab_width)} && $~ #` + line + end .join("\n") + end + @content = content + @content << "\n" unless @content[-1,1] == "\n" + @size = @content.size + @offset = 0 + @hwm = 0 + @line_num = 1 + @read_back_offset = 0 + @last_newline = 0 + @newline_pending = false + end + + def column + @offset - @last_newline + end + + def getc + return nil if @offset >= @size + ch = @content[@offset, 1] + + @offset += 1 + @hwm = @offset if @hwm < @offset + + if @newline_pending + @line_num += 1 + @last_newline = @offset - 1 + @newline_pending = false + end + + if ch == "\n" + @newline_pending = true + end + ch + end + + def getc_already_read + getc + end + + def ungetc(ch) + raise "unget past beginning of file" if @offset <= 0 + @offset -= 1 + if @content[@offset] == ?\n + @newline_pending = false + end + end + + def get_read + res = @content[@read_back_offset...@offset] + @read_back_offset = @offset + res + end + + def peek(at) + pos = @offset + at + if pos >= @size + nil + else + @content[pos, 1] + end + end + + def peek_equal(str) + @content[@offset, str.length] == str + end + + def divert_read_from(reserve) + @content[@offset, 0] = reserve + @size = @content.size + end + end + + # end of nested class BufferedReader + + extend Exception2MessageMapper + def_exception(:AlreadyDefinedToken, "Already defined token(%s)") + def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')") + def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')") + def_exception(:TkReading2TokenDuplicateError, + "key duplicate(token_n='%s', key='%s')") + def_exception(:SyntaxError, "%s") + + include RDoc::RubyToken + include IRB + + attr_reader :continue + attr_reader :lex_state + + def self.debug? + false + end + + def initialize(content, options) + lex_init + + @options = options + + @reader = BufferedReader.new content, @options + + @exp_line_no = @line_no = 1 + @base_char_no = 0 + @indent = 0 + + @ltype = nil + @quoted = nil + @lex_state = EXPR_BEG + @space_seen = false + + @continue = false + @line = "" + + @skip_space = false + @read_auto_clean_up = false + @exception_on_syntax_error = true + end + + attr_accessor :skip_space + attr_accessor :read_auto_clean_up + attr_accessor :exception_on_syntax_error + attr_reader :indent + + # io functions + def line_no + @reader.line_num + end + + def char_no + @reader.column + end + + def get_read + @reader.get_read + end + + def getc + @reader.getc + end + + def getc_of_rests + @reader.getc_already_read + end + + def gets + c = getc or return + l = "" + begin + l.concat c unless c == "\r" + break if c == "\n" + end while c = getc + l + end + + + def ungetc(c = nil) + @reader.ungetc(c) + end + + def peek_equal?(str) + @reader.peek_equal(str) + end + + def peek(i = 0) + @reader.peek(i) + end + + def lex + until (TkNL === (tk = token) or TkEND_OF_SCRIPT === tk) and + not @continue or tk.nil? + end + + line = get_read + + if line == "" and TkEND_OF_SCRIPT === tk or tk.nil? then + nil + else + line + end + end + + def token + set_token_position(line_no, char_no) + begin + begin + tk = @OP.match(self) + @space_seen = TkSPACE === tk + rescue SyntaxError => e + raise RDoc::Error, "syntax error: #{e.message}" if + @exception_on_syntax_error + + tk = TkError.new(line_no, char_no) + end + end while @skip_space and TkSPACE === tk + if @read_auto_clean_up + get_read + end +# throw :eof unless tk + tk + end + + ENINDENT_CLAUSE = [ + "case", "class", "def", "do", "for", "if", + "module", "unless", "until", "while", "begin" #, "when" + ] + DEINDENT_CLAUSE = ["end" #, "when" + ] + + PERCENT_LTYPE = { + "q" => "\'", + "Q" => "\"", + "x" => "\`", + "r" => "/", + "w" => "]" + } + + PERCENT_PAREN = { + "{" => "}", + "[" => "]", + "<" => ">", + "(" => ")" + } + + Ltype2Token = { + "\'" => TkSTRING, + "\"" => TkSTRING, + "\`" => TkXSTRING, + "/" => TkREGEXP, + "]" => TkDSTRING + } + Ltype2Token.default = TkSTRING + + DLtype2Token = { + "\"" => TkDSTRING, + "\`" => TkDXSTRING, + "/" => TkDREGEXP, + } + + def lex_init() + @OP = IRB::SLex.new + @OP.def_rules("\0", "\004", "\032") do |chars, io| + Token(TkEND_OF_SCRIPT).set_text(chars) + end + + @OP.def_rules(" ", "\t", "\f", "\r", "\13") do |chars, io| + @space_seen = TRUE + while (ch = getc) =~ /[ \t\f\r\13]/ + chars << ch + end + ungetc + Token(TkSPACE).set_text(chars) + end + + @OP.def_rule("#") do + |op, io| + identify_comment + end + + @OP.def_rule("=begin", proc{@prev_char_no == 0 && peek(0) =~ /\s/}) do + |op, io| + str = op + @ltype = "=" + + + begin + line = "" + begin + ch = getc + line << ch + end until ch == "\n" + str << line + end until line =~ /^=end/ + + ungetc + + @ltype = nil + + if str =~ /\A=begin\s+rdoc/i + str.sub!(/\A=begin.*\n/, '') + str.sub!(/^=end.*/m, '') + Token(TkCOMMENT).set_text(str) + else + Token(TkRD_COMMENT)#.set_text(str) + end + end + + @OP.def_rule("\n") do + print "\\n\n" if RDoc::RubyLex.debug? + case @lex_state + when EXPR_BEG, EXPR_FNAME, EXPR_DOT + @continue = TRUE + else + @continue = FALSE + @lex_state = EXPR_BEG + end + Token(TkNL).set_text("\n") + end + + @OP.def_rules("*", "**", + "!", "!=", "!~", + "=", "==", "===", + "=~", "<=>", + "<", "<=", + ">", ">=", ">>") do + |op, io| + @lex_state = EXPR_BEG + Token(op).set_text(op) + end + + @OP.def_rules("<<") do + |op, io| + tk = nil + if @lex_state != EXPR_END && @lex_state != EXPR_CLASS && + (@lex_state != EXPR_ARG || @space_seen) + c = peek(0) + if /[-\w_\"\'\`]/ =~ c + tk = identify_here_document + end + end + if !tk + @lex_state = EXPR_BEG + tk = Token(op).set_text(op) + end + tk + end + + @OP.def_rules("'", '"') do + |op, io| + identify_string(op) + end + + @OP.def_rules("`") do + |op, io| + if @lex_state == EXPR_FNAME + Token(op).set_text(op) + else + identify_string(op) + end + end + + @OP.def_rules('?') do + |op, io| + if @lex_state == EXPR_END + @lex_state = EXPR_BEG + Token(TkQUESTION).set_text(op) + else + ch = getc + if @lex_state == EXPR_ARG && ch !~ /\s/ + ungetc + @lex_state = EXPR_BEG + Token(TkQUESTION).set_text(op) + else + str = op + str << ch + if (ch == '\\') #' + str << read_escape + end + @lex_state = EXPR_END + Token(TkINTEGER).set_text(str) + end + end + end + + @OP.def_rules("&", "&&", "|", "||") do + |op, io| + @lex_state = EXPR_BEG + Token(op).set_text(op) + end + + @OP.def_rules("+=", "-=", "*=", "**=", + "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do + |op, io| + @lex_state = EXPR_BEG + op =~ /^(.*)=$/ + Token(TkOPASGN, $1).set_text(op) + end + + @OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) do |op, io| + Token(TkUPLUS).set_text(op) + end + + @OP.def_rule("-@", proc{@lex_state == EXPR_FNAME}) do |op, io| + Token(TkUMINUS).set_text(op) + end + + @OP.def_rules("+", "-") do + |op, io| + catch(:RET) do + if @lex_state == EXPR_ARG + if @space_seen and peek(0) =~ /[0-9]/ + throw :RET, identify_number(op) + else + @lex_state = EXPR_BEG + end + elsif @lex_state != EXPR_END and peek(0) =~ /[0-9]/ + throw :RET, identify_number(op) + else + @lex_state = EXPR_BEG + end + Token(op).set_text(op) + end + end + + @OP.def_rule(".") do + @lex_state = EXPR_BEG + if peek(0) =~ /[0-9]/ + ungetc + identify_number("") + else + # for obj.if + @lex_state = EXPR_DOT + Token(TkDOT).set_text(".") + end + end + + @OP.def_rules("..", "...") do + |op, io| + @lex_state = EXPR_BEG + Token(op).set_text(op) + end + + lex_int2 + end + + def lex_int2 + @OP.def_rules("]", "}", ")") do + |op, io| + @lex_state = EXPR_END + @indent -= 1 + Token(op).set_text(op) + end + + @OP.def_rule(":") do + if @lex_state == EXPR_END || peek(0) =~ /\s/ + @lex_state = EXPR_BEG + tk = Token(TkCOLON) + else + @lex_state = EXPR_FNAME + tk = Token(TkSYMBEG) + end + tk.set_text(":") + end + + @OP.def_rule("::") do + if @lex_state == EXPR_BEG or @lex_state == EXPR_ARG && @space_seen + @lex_state = EXPR_BEG + tk = Token(TkCOLON3) + else + @lex_state = EXPR_DOT + tk = Token(TkCOLON2) + end + tk.set_text("::") + end + + @OP.def_rule("/") do + |op, io| + if @lex_state == EXPR_BEG || @lex_state == EXPR_MID + identify_string(op) + elsif peek(0) == '=' + getc + @lex_state = EXPR_BEG + Token(TkOPASGN, :/).set_text("/=") #") + elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ + identify_string(op) + else + @lex_state = EXPR_BEG + Token("/").set_text(op) + end + end + + @OP.def_rules("^") do + @lex_state = EXPR_BEG + Token("^").set_text("^") + end + + @OP.def_rules(",", ";") do + |op, io| + @lex_state = EXPR_BEG + Token(op).set_text(op) + end + + @OP.def_rule("~") do + @lex_state = EXPR_BEG + Token("~").set_text("~") + end + + @OP.def_rule("~@", proc{@lex_state = EXPR_FNAME}) do + @lex_state = EXPR_BEG + Token("~").set_text("~@") + end + + @OP.def_rule("(") do + @indent += 1 + if @lex_state == EXPR_BEG || @lex_state == EXPR_MID + @lex_state = EXPR_BEG + tk = Token(TkfLPAREN) + else + @lex_state = EXPR_BEG + tk = Token(TkLPAREN) + end + tk.set_text("(") + end + + @OP.def_rule("[]", proc{@lex_state == EXPR_FNAME}) do + Token("[]").set_text("[]") + end + + @OP.def_rule("[]=", proc{@lex_state == EXPR_FNAME}) do + Token("[]=").set_text("[]=") + end + + @OP.def_rule("[") do + @indent += 1 + if @lex_state == EXPR_FNAME + t = Token(TkfLBRACK) + else + if @lex_state == EXPR_BEG || @lex_state == EXPR_MID + t = Token(TkLBRACK) + elsif @lex_state == EXPR_ARG && @space_seen + t = Token(TkLBRACK) + else + t = Token(TkfLBRACK) + end + @lex_state = EXPR_BEG + end + t.set_text("[") + end + + @OP.def_rule("{") do + @indent += 1 + if @lex_state != EXPR_END && @lex_state != EXPR_ARG + t = Token(TkLBRACE) + else + t = Token(TkfLBRACE) + end + @lex_state = EXPR_BEG + t.set_text("{") + end + + @OP.def_rule('\\') do #' + if getc == "\n" + @space_seen = true + @continue = true + Token(TkSPACE).set_text("\\\n") + else + ungetc + Token("\\").set_text("\\") #" + end + end + + @OP.def_rule('%') do + |op, io| + if @lex_state == EXPR_BEG || @lex_state == EXPR_MID + identify_quotation('%') + elsif peek(0) == '=' + getc + Token(TkOPASGN, "%").set_text("%=") + elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ + identify_quotation('%') + else + @lex_state = EXPR_BEG + Token("%").set_text("%") + end + end + + @OP.def_rule('$') do #' + identify_gvar + end + + @OP.def_rule('@') do + if peek(0) =~ /[@\w_]/ + ungetc + identify_identifier + else + Token("@").set_text("@") + end + end + + @OP.def_rule("__END__", proc{@prev_char_no == 0 && peek(0) =~ /[\r\n]/}) do + throw :eof + end + + @OP.def_rule("") do + |op, io| + printf "MATCH: start %s: %s\n", op, io.inspect if RDoc::RubyLex.debug? + if peek(0) =~ /[0-9]/ + t = identify_number("") + elsif peek(0) =~ /[\w_]/ + t = identify_identifier + end + printf "MATCH: end %s: %s\n", op, io.inspect if RDoc::RubyLex.debug? + t + end + end + + def identify_gvar + @lex_state = EXPR_END + str = "$" + + tk = case ch = getc + when /[~_*$?!@\/\\;,=:<>".]/ #" + str << ch + Token(TkGVAR, str) + + when "-" + str << "-" << getc + Token(TkGVAR, str) + + when "&", "`", "'", "+" + str << ch + Token(TkBACK_REF, str) + + when /[1-9]/ + str << ch + while (ch = getc) =~ /[0-9]/ + str << ch + end + ungetc + Token(TkNTH_REF) + when /\w/ + ungetc + ungetc + return identify_identifier + else + ungetc + Token("$") + end + tk.set_text(str) + end + + def identify_identifier + token = "" + token.concat getc if peek(0) =~ /[$@]/ + token.concat getc if peek(0) == "@" + + while (ch = getc) =~ /\w|_/ + print ":", ch, ":" if RDoc::RubyLex.debug? + token.concat ch + end + ungetc + + if ch == "!" or ch == "?" + token.concat getc + end + # fix token + + # $stderr.puts "identifier - #{token}, state = #@lex_state" + + case token + when /^\$/ + return Token(TkGVAR, token).set_text(token) + when /^\@/ + @lex_state = EXPR_END + return Token(TkIVAR, token).set_text(token) + end + + if @lex_state != EXPR_DOT + print token, "\n" if RDoc::RubyLex.debug? + + token_c, *trans = TkReading2Token[token] + if token_c + # reserved word? + + if (@lex_state != EXPR_BEG && + @lex_state != EXPR_FNAME && + trans[1]) + # modifiers + token_c = TkSymbol2Token[trans[1]] + @lex_state = trans[0] + else + if @lex_state != EXPR_FNAME + if ENINDENT_CLAUSE.include?(token) + @indent += 1 + elsif DEINDENT_CLAUSE.include?(token) + @indent -= 1 + end + @lex_state = trans[0] + else + @lex_state = EXPR_END + end + end + return Token(token_c, token).set_text(token) + end + end + + if @lex_state == EXPR_FNAME + @lex_state = EXPR_END + if peek(0) == '=' + token.concat getc + end + elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT + @lex_state = EXPR_ARG + else + @lex_state = EXPR_END + end + + if token[0, 1] =~ /[A-Z]/ + return Token(TkCONSTANT, token).set_text(token) + elsif token[token.size - 1, 1] =~ /[!?]/ + return Token(TkFID, token).set_text(token) + else + return Token(TkIDENTIFIER, token).set_text(token) + end + end + + def identify_here_document + ch = getc + if ch == "-" + ch = getc + indent = true + end + if /['"`]/ =~ ch # ' + lt = ch + quoted = "" + while (c = getc) && c != lt + quoted.concat c + end + else + lt = '"' + quoted = ch.dup + while (c = getc) && c =~ /\w/ + quoted.concat c + end + ungetc + end + + ltback, @ltype = @ltype, lt + reserve = "" + + while ch = getc + reserve << ch + if ch == "\\" #" + ch = getc + reserve << ch + elsif ch == "\n" + break + end + end + + str = "" + while (l = gets) + l.chomp! + l.strip! if indent + break if l == quoted + str << l.chomp << "\n" + end + + @reader.divert_read_from(reserve) + + @ltype = ltback + @lex_state = EXPR_END + Token(Ltype2Token[lt], str).set_text(str.dump) + end + + def identify_quotation(initial_char) + ch = getc + if lt = PERCENT_LTYPE[ch] + initial_char += ch + ch = getc + elsif ch =~ /\W/ + lt = "\"" + else + fail SyntaxError, "unknown type of %string ('#{ch}')" + end +# if ch !~ /\W/ +# ungetc +# next +# end + #@ltype = lt + @quoted = ch unless @quoted = PERCENT_PAREN[ch] + identify_string(lt, @quoted, ch, initial_char) + end + + def identify_number(start) + str = start.dup + + if start == "+" or start == "-" or start == "" + start = getc + str << start + end + + @lex_state = EXPR_END + + if start == "0" + if peek(0) == "x" + ch = getc + str << ch + match = /[0-9a-f_]/ + else + match = /[0-7_]/ + end + while ch = getc + if ch !~ match + ungetc + break + else + str << ch + end + end + return Token(TkINTEGER).set_text(str) + end + + type = TkINTEGER + allow_point = TRUE + allow_e = TRUE + while ch = getc + case ch + when /[0-9_]/ + str << ch + + when allow_point && "." + type = TkFLOAT + if peek(0) !~ /[0-9]/ + ungetc + break + end + str << ch + allow_point = false + + when allow_e && "e", allow_e && "E" + str << ch + type = TkFLOAT + if peek(0) =~ /[+-]/ + str << getc + end + allow_e = false + allow_point = false + else + ungetc + break + end + end + Token(type).set_text(str) + end + + def identify_string(ltype, quoted = ltype, opener=nil, initial_char = nil) + @ltype = ltype + @quoted = quoted + subtype = nil + + str = "" + str << initial_char if initial_char + str << (opener||quoted) + + nest = 0 + begin + while ch = getc + str << ch + if @quoted == ch + if nest == 0 + break + else + nest -= 1 + end + elsif opener == ch + nest += 1 + elsif @ltype != "'" && @ltype != "]" and ch == "#" + ch = getc + if ch == "{" + subtype = true + str << ch << skip_inner_expression + else + ungetc(ch) + end + elsif ch == '\\' #' + str << read_escape + end + end + if @ltype == "/" + if peek(0) =~ /i|o|n|e|s/ + str << getc + end + end + if subtype + Token(DLtype2Token[ltype], str) + else + Token(Ltype2Token[ltype], str) + end.set_text(str) + ensure + @ltype = nil + @quoted = nil + @lex_state = EXPR_END + end + end + + def skip_inner_expression + res = "" + nest = 0 + while (ch = getc) + res << ch + if ch == '}' + break if nest.zero? + nest -= 1 + elsif ch == '{' + nest += 1 + end + end + res + end + + def identify_comment + @ltype = "#" + comment = "#" + while ch = getc + if ch == "\\" + ch = getc + if ch == "\n" + ch = " " + else + comment << "\\" + end + else + if ch == "\n" + @ltype = nil + ungetc + break + end + end + comment << ch + end + return Token(TkCOMMENT).set_text(comment) + end + + def read_escape + res = "" + case ch = getc + when /[0-7]/ + ungetc ch + 3.times do + case ch = getc + when /[0-7]/ + when nil + break + else + ungetc + break + end + res << ch + end + + when "x" + res << ch + 2.times do + case ch = getc + when /[0-9a-fA-F]/ + when nil + break + else + ungetc + break + end + res << ch + end + + when "M" + res << ch + if (ch = getc) != '-' + ungetc + else + res << ch + if (ch = getc) == "\\" #" + res << ch + res << read_escape + else + res << ch + end + end + + when "C", "c" #, "^" + res << ch + if ch == "C" and (ch = getc) != "-" + ungetc + else + res << ch + if (ch = getc) == "\\" #" + res << ch + res << read_escape + else + res << ch + end + end + else + res << ch + end + res + end +end + +## +# Extracts code elements from a source file returning a TopLevel object +# containing the constituent file elements. +# +# This file is based on rtags +# +# RubyParser understands how to document: +# * classes +# * modules +# * methods +# * constants +# * aliases +# * private, public, protected +# * private_class_function, public_class_function +# * module_function +# * attr, attr_reader, attr_writer, attr_accessor +# * extra accessors given on the command line +# * metaprogrammed methods +# * require +# * include +# +# == Method Arguments +# +#-- +# NOTE: I don't think this works, needs tests, remove the paragraph following +# this block when known to work +# +# The parser extracts the arguments from the method definition. You can +# override this with a custom argument definition using the :args: directive: +# +# ## +# # This method tries over and over until it is tired +# +# def go_go_go(thing_to_try, tries = 10) # :args: thing_to_try +# puts thing_to_try +# go_go_go thing_to_try, tries - 1 +# end +# +# If you have a more-complex set of overrides you can use the :call-seq: +# directive: +#++ +# +# The parser extracts the arguments from the method definition. You can +# override this with a custom argument definition using the :call-seq: +# directive: +# +# ## +# # This method can be called with a range or an offset and length +# # +# # :call-seq: +# # my_method(Range) +# # my_method(offset, length) +# +# def my_method(*args) +# end +# +# The parser extracts +yield+ expressions from method bodies to gather the +# yielded argument names. If your method manually calls a block instead of +# yielding or you want to override the discovered argument names use +# the :yields: directive: +# +# ## +# # My method is awesome +# +# def my_method(&block) # :yields: happy, times +# block.call 1, 2 +# end +# +# == Metaprogrammed Methods +# +# To pick up a metaprogrammed method, the parser looks for a comment starting +# with '##' before an identifier: +# +# ## +# # This is a meta-programmed method! +# +# add_my_method :meta_method, :arg1, :arg2 +# +# The parser looks at the token after the identifier to determine the name, in +# this example, :meta_method. If a name cannot be found, a warning is printed +# and 'unknown is used. +# +# You can force the name of a method using the :method: directive: +# +# ## +# # :method: woo_hoo! +# +# By default, meta-methods are instance methods. To indicate that a method is +# a singleton method instead use the :singleton-method: directive: +# +# ## +# # :singleton-method: +# +# You can also use the :singleton-method: directive with a name: +# +# ## +# # :singleton-method: woo_hoo! +# +# Additionally you can mark a method as an attribute by +# using :attr:, :attr_reader:, :attr_writer: or :attr_accessor:. Just like +# for :method:, the name is optional. +# +# ## +# # :attr_reader: my_attr_name +# +# == Hidden methods and attributes +# +# You can provide documentation for methods that don't appear using +# the :method:, :singleton-method: and :attr: directives: +# +# ## +# # :attr_writer: ghost_writer +# # There is an attribute here, but you can't see it! +# +# ## +# # :method: ghost_method +# # There is a method here, but you can't see it! +# +# ## +# # this is a comment for a regular method +# +# def regular_method() end +# +# Note that by default, the :method: directive will be ignored if there is a +# standard rdocable item following it. + +class RDoc::Parser::Ruby < RDoc::Parser + + parse_files_matching(/\.rbw?$/) + + include RDoc::RubyToken + include RDoc::TokenStream + + NORMAL = "::" + SINGLE = "<<" + + def initialize(top_level, file_name, content, options, stats) + super + + @size = 0 + @token_listeners = nil + @scanner = RDoc::RubyLex.new content, @options + @scanner.exception_on_syntax_error = false + + reset + end + + def add_token_listener(obj) + @token_listeners ||= [] + @token_listeners << obj + end + + ## + # Look for the first comment in a file that isn't a shebang line. + + def collect_first_comment + skip_tkspace + res = '' + first_line = true + + tk = get_tk + + while TkCOMMENT === tk + if first_line and tk.text =~ /\A#!/ then + skip_tkspace + tk = get_tk + elsif first_line and tk.text =~ /\A#\s*-\*-/ then + first_line = false + skip_tkspace + tk = get_tk + else + first_line = false + res << tk.text << "\n" + tk = get_tk + + if TkNL === tk then + skip_tkspace false + tk = get_tk + end + end + end + + unget_tk tk + + res + end + + def error(msg) + msg = make_message msg + $stderr.puts msg + exit(1) + end + + ## + # Look for a 'call-seq' in the comment, and override the normal parameter + # stuff + + def extract_call_seq(comment, meth) + if comment.sub!(/:?call-seq:(.*?)^\s*\#?\s*$/m, '') then + seq = $1 + seq.gsub!(/^\s*\#\s*/, '') + meth.call_seq = seq + end + + meth + end + + def get_bool + skip_tkspace + tk = get_tk + case tk + when TkTRUE + true + when TkFALSE, TkNIL + false + else + unget_tk tk + true + end + end + + ## + # Look for the name of a class of module (optionally with a leading :: or + # with :: separated named) and return the ultimate name and container + + def get_class_or_module(container) + skip_tkspace + name_t = get_tk + + # class ::A -> A is in the top level + if TkCOLON2 === name_t then + name_t = get_tk + container = @top_level + end + + skip_tkspace(false) + + while TkCOLON2 === peek_tk do + prev_container = container + container = container.find_module_named(name_t.name) + if !container +# warn("Couldn't find module #{name_t.name}") + container = prev_container.add_module RDoc::NormalModule, name_t.name + end + get_tk + name_t = get_tk + end + skip_tkspace(false) + return [container, name_t] + end + + ## + # Return a superclass, which can be either a constant of an expression + + def get_class_specification + tk = get_tk + return "self" if TkSELF === tk + + res = "" + while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do + res += tk.text + tk = get_tk + end + + unget_tk(tk) + skip_tkspace(false) + + get_tkread # empty out read buffer + + tk = get_tk + + case tk + when TkNL, TkCOMMENT, TkSEMICOLON then + unget_tk(tk) + return res + end + + res += parse_call_parameters(tk) + res + end + + ## + # Parse a constant, which might be qualified by one or more class or module + # names + + def get_constant + res = "" + skip_tkspace(false) + tk = get_tk + + while TkCOLON2 === tk or TkCOLON3 === tk or TkCONSTANT === tk do + res += tk.text + tk = get_tk + end + +# if res.empty? +# warn("Unexpected token #{tk} in constant") +# end + unget_tk(tk) + res + end + + ## + # Get a constant that may be surrounded by parens + + def get_constant_with_optional_parens + skip_tkspace(false) + nest = 0 + while TkLPAREN === (tk = peek_tk) or TkfLPAREN === tk do + get_tk + skip_tkspace(true) + nest += 1 + end + + name = get_constant + + while nest > 0 + skip_tkspace(true) + tk = get_tk + nest -= 1 if TkRPAREN === tk + end + name + end + + def get_symbol_or_name + tk = get_tk + case tk + when TkSYMBOL + tk.text.sub(/^:/, '') + when TkId, TkOp + tk.name + when TkSTRING + tk.text + else + raise "Name or symbol expected (got #{tk})" + end + end + + def get_tk + tk = nil + if @tokens.empty? + tk = @scanner.token + @read.push @scanner.get_read + puts "get_tk1 => #{tk.inspect}" if $TOKEN_DEBUG + else + @read.push @unget_read.shift + tk = @tokens.shift + puts "get_tk2 => #{tk.inspect}" if $TOKEN_DEBUG + end + + if TkSYMBEG === tk then + set_token_position(tk.line_no, tk.char_no) + tk1 = get_tk + if TkId === tk1 or TkOp === tk1 or TkSTRING === tk1 or TkDSTRING === tk1 then + if tk1.respond_to?(:name) + tk = Token(TkSYMBOL).set_text(":" + tk1.name) + else + tk = Token(TkSYMBOL).set_text(":" + tk1.text) + end + # remove the identifier we just read (we're about to + # replace it with a symbol) + @token_listeners.each do |obj| + obj.pop_token + end if @token_listeners + else + warn("':' not followed by identifier or operator") + tk = tk1 + end + end + + # inform any listeners of our shiny new token + @token_listeners.each do |obj| + obj.add_token(tk) + end if @token_listeners + + tk + end + + def get_tkread + read = @read.join("") + @read = [] + read + end + + ## + # Look for directives in a normal comment block: + # + # #-- - don't display comment from this point forward + # + # This routine modifies it's parameter + + def look_for_directives_in(context, comment) + preprocess = RDoc::Markup::PreProcess.new(@file_name, + @options.rdoc_include) + + preprocess.handle(comment) do |directive, param| + case directive + when 'enddoc' then + throw :enddoc + when 'main' then + @options.main_page = param + '' + when 'method', 'singleton-method' then + false # ignore + when 'section' then + context.set_current_section(param, comment) + comment.replace '' + break + when 'startdoc' then + context.start_doc + context.force_documentation = true + '' + when 'stopdoc' then + context.stop_doc + '' + when 'title' then + @options.title = param + '' + else + warn "Unrecognized directive '#{directive}'" + false + end + end + + remove_private_comments(comment) + end + + def make_message(msg) + prefix = "\n" + @file_name + ":" + if @scanner + prefix << "#{@scanner.line_no}:#{@scanner.char_no}: " + end + return prefix + msg + end + + ## + # Creates an RDoc::Attr for the name following +tk+, setting the comment to + # +comment+. + + def parse_attr(context, single, tk, comment) + args = parse_symbol_arg 1 + if args.size > 0 + name = args[0] + rw = "R" + skip_tkspace(false) + tk = get_tk + if TkCOMMA === tk then + rw = "RW" if get_bool + else + unget_tk tk + end + att = RDoc::Attr.new get_tkread, name, rw, comment + read_documentation_modifiers att, RDoc::ATTR_MODIFIERS + if att.document_self + context.add_attribute(att) + end + else + warn("'attr' ignored - looks like a variable") + end + end + + ## + # Creates an RDoc::Attr for each attribute listed after +tk+, setting the + # comment for each to +comment+. + + def parse_attr_accessor(context, single, tk, comment) + args = parse_symbol_arg + read = get_tkread + rw = "?" + + # TODO If nodoc is given, don't document any of them + + tmp = RDoc::CodeObject.new + read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS + return unless tmp.document_self + + case tk.name + when "attr_reader" then rw = "R" + when "attr_writer" then rw = "W" + when "attr_accessor" then rw = "RW" + else + rw = '?' + end + + for name in args + att = RDoc::Attr.new get_tkread, name, rw, comment + context.add_attribute att + end + end + + def parse_alias(context, single, tk, comment) + skip_tkspace + if TkLPAREN === peek_tk then + get_tk + skip_tkspace + end + new_name = get_symbol_or_name + @scanner.instance_eval{@lex_state = EXPR_FNAME} + skip_tkspace + if TkCOMMA === peek_tk then + get_tk + skip_tkspace + end + old_name = get_symbol_or_name + + al = RDoc::Alias.new get_tkread, old_name, new_name, comment + read_documentation_modifiers al, RDoc::ATTR_MODIFIERS + if al.document_self + context.add_alias(al) + end + end + + def parse_call_parameters(tk) + end_token = case tk + when TkLPAREN, TkfLPAREN + TkRPAREN + when TkRPAREN + return "" + else + TkNL + end + nest = 0 + + loop do + case tk + when TkSEMICOLON + break + when TkLPAREN, TkfLPAREN + nest += 1 + when end_token + if end_token == TkRPAREN + nest -= 1 + break if @scanner.lex_state == EXPR_END and nest <= 0 + else + break unless @scanner.continue + end + when TkCOMMENT + unget_tk(tk) + break + end + tk = get_tk + end + res = get_tkread.tr("\n", " ").strip + res = "" if res == ";" + res + end + + def parse_class(container, single, tk, comment) + container, name_t = get_class_or_module container + + case name_t + when TkCONSTANT + name = name_t.name + superclass = "Object" + + if TkLT === peek_tk then + get_tk + skip_tkspace(true) + superclass = get_class_specification + superclass = "<unknown>" if superclass.empty? + end + + cls_type = single == SINGLE ? RDoc::SingleClass : RDoc::NormalClass + cls = container.add_class cls_type, name, superclass + + @stats.add_class cls + + read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS + cls.record_location @top_level + + parse_statements cls + cls.comment = comment + + when TkLSHFT + case name = get_class_specification + when "self", container.name + parse_statements(container, SINGLE) + else + other = RDoc::TopLevel.find_class_named(name) + unless other +# other = @top_level.add_class(NormalClass, name, nil) +# other.record_location(@top_level) +# other.comment = comment + other = RDoc::NormalClass.new "Dummy", nil + end + + @stats.add_class other + + read_documentation_modifiers other, RDoc::CLASS_MODIFIERS + parse_statements(other, SINGLE) + end + + else + warn("Expected class name or '<<'. Got #{name_t.class}: #{name_t.text.inspect}") + end + end + + def parse_constant(container, single, tk, comment) + name = tk.name + skip_tkspace(false) + eq_tk = get_tk + + unless TkASSIGN === eq_tk then + unget_tk(eq_tk) + return + end + + nest = 0 + get_tkread + + tk = get_tk + if TkGT === tk then + unget_tk(tk) + unget_tk(eq_tk) + return + end + + loop do + case tk + when TkSEMICOLON then + break + when TkLPAREN, TkfLPAREN, TkLBRACE, TkLBRACK, TkDO, TkIF, TkUNLESS, + TkCASE then + nest += 1 + when TkRPAREN, TkRBRACE, TkRBRACK, TkEND then + nest -= 1 + when TkCOMMENT then + if nest <= 0 && @scanner.lex_state == EXPR_END + unget_tk tk + break + end + when TkNL then + if nest <= 0 && + (@scanner.lex_state == EXPR_END || !@scanner.continue) then + unget_tk tk + break + end + end + tk = get_tk + end + + res = get_tkread.tr("\n", " ").strip + res = "" if res == ";" + + con = RDoc::Constant.new name, res, comment + read_documentation_modifiers con, RDoc::CONSTANT_MODIFIERS + + container.add_constant con if con.document_self + end + + ## + # Generates an RDoc::Method or RDoc::Attr from +comment+ by looking for + # :method: or :attr: directives in +comment+. + + def parse_comment(container, tk, comment) + line_no = tk.line_no + column = tk.char_no + + singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3') + + # REFACTOR + if comment.sub!(/^# +:?method: *(\S*).*?\n/i, '') then + name = $1 unless $1.empty? + + meth = RDoc::GhostMethod.new get_tkread, name + meth.singleton = singleton + + @stats.add_method meth + + meth.start_collecting_tokens + indent = TkSPACE.new 1, 1 + indent.set_text " " * column + + position_comment = TkCOMMENT.new(line_no, 1, "# File #{@top_level.absolute_name}, line #{line_no}") + meth.add_tokens [position_comment, NEWLINE_TOKEN, indent] + + meth.params = '' + + extract_call_seq comment, meth + + container.add_method meth if meth.document_self + + meth.comment = comment + elsif comment.sub!(/# +:?(attr(_reader|_writer|_accessor)?:) *(\S*).*?\n/i, '') then + rw = case $1 + when 'attr_reader' then 'R' + when 'attr_writer' then 'W' + else 'RW' + end + + name = $3 unless $3.empty? + + att = RDoc::Attr.new get_tkread, name, rw, comment + container.add_attribute att + end + end + + def parse_include(context, comment) + loop do + skip_tkspace_comment + + name = get_constant_with_optional_parens + context.add_include RDoc::Include.new(name, comment) unless name.empty? + + return unless TkCOMMA === peek_tk + get_tk + end + end + + def parse_meta_attr(context, single, tk, comment) + args = parse_symbol_arg + read = get_tkread + rw = "?" + + # If nodoc is given, don't document any of them + + tmp = RDoc::CodeObject.new + read_documentation_modifiers tmp, RDoc::ATTR_MODIFIERS + return unless tmp.document_self + + if comment.sub!(/^# +:?(attr(_reader|_writer|_accessor)?): *(\S*).*?\n/i, '') then + rw = case $1 + when 'attr_reader' then 'R' + when 'attr_writer' then 'W' + else 'RW' + end + name = $3 unless $3.empty? + end + + for name in args + att = RDoc::Attr.new get_tkread, name, rw, comment + context.add_attribute att + end + end + + ## + # Parses a meta-programmed method + + def parse_meta_method(container, single, tk, comment) + line_no = tk.line_no + column = tk.char_no + + start_collecting_tokens + add_token tk + add_token_listener self + + skip_tkspace false + + singleton = !!comment.sub!(/(^# +:?)(singleton-)(method:)/, '\1\3') + + if comment.sub!(/^# +:?method: *(\S*).*?\n/i, '') then + name = $1 unless $1.empty? + end + + if name.nil? then + name_t = get_tk + case name_t + when TkSYMBOL then + name = name_t.text[1..-1] + when TkSTRING then + name = name_t.text[1..-2] + when TkASSIGN then # ignore + remove_token_listener self + return + else + warn "unknown name token #{name_t.inspect} for meta-method '#{tk.name}'" + name = 'unknown' + end + end + + meth = RDoc::MetaMethod.new get_tkread, name + meth.singleton = singleton + + @stats.add_method meth + + remove_token_listener self + + meth.start_collecting_tokens + indent = TkSPACE.new 1, 1 + indent.set_text " " * column + + position_comment = TkCOMMENT.new(line_no, 1, "# File #{@top_level.absolute_name}, line #{line_no}") + meth.add_tokens [position_comment, NEWLINE_TOKEN, indent] + meth.add_tokens @token_stream + + add_token_listener meth + + meth.params = '' + + extract_call_seq comment, meth + + container.add_method meth if meth.document_self + + last_tk = tk + + while tk = get_tk do + case tk + when TkSEMICOLON then + break + when TkNL then + break unless last_tk and TkCOMMA === last_tk + when TkSPACE then + # expression continues + else + last_tk = tk + end + end + + remove_token_listener meth + + meth.comment = comment + end + + ## + # Parses a method + + def parse_method(container, single, tk, comment) + line_no = tk.line_no + column = tk.char_no + + start_collecting_tokens + add_token(tk) + add_token_listener(self) + + @scanner.instance_eval do @lex_state = EXPR_FNAME end + + skip_tkspace(false) + name_t = get_tk + back_tk = skip_tkspace + meth = nil + added_container = false + + dot = get_tk + if TkDOT === dot or TkCOLON2 === dot then + @scanner.instance_eval do @lex_state = EXPR_FNAME end + skip_tkspace + name_t2 = get_tk + + case name_t + when TkSELF then + name = name_t2.name + when TkCONSTANT then + name = name_t2.name + prev_container = container + container = container.find_module_named(name_t.name) + unless container then + added_container = true + obj = name_t.name.split("::").inject(Object) do |state, item| + state.const_get(item) + end rescue nil + + type = obj.class == Class ? RDoc::NormalClass : RDoc::NormalModule + + unless [Class, Module].include?(obj.class) then + warn("Couldn't find #{name_t.name}. Assuming it's a module") + end + + if type == RDoc::NormalClass then + container = prev_container.add_class(type, name_t.name, obj.superclass.name) + else + container = prev_container.add_module(type, name_t.name) + end + + container.record_location @top_level + end + else + warn "unexpected method name token #{name_t2.inspect}" + # break + skip_method(container) + return + end + + meth = RDoc::AnyMethod.new(get_tkread, name) + meth.singleton = true + else + unget_tk dot + back_tk.reverse_each do |token| + unget_tk token + end + + unless name_t.respond_to? :name then + warn "unexpected method name token #{name_t.inspect}" + skip_method container + return + end + + name = name_t.name + + meth = RDoc::AnyMethod.new get_tkread, name + meth.singleton = (single == SINGLE) + end + + @stats.add_method meth + + remove_token_listener self + + meth.start_collecting_tokens + indent = TkSPACE.new 1, 1 + indent.set_text " " * column + + token = TkCOMMENT.new(line_no, 1, "# File #{@top_level.absolute_name}, line #{line_no}") + meth.add_tokens [token, NEWLINE_TOKEN, indent] + meth.add_tokens @token_stream + + add_token_listener meth + + @scanner.instance_eval do @continue = false end + parse_method_parameters meth + + if meth.document_self then + container.add_method meth + elsif added_container then + container.document_self = false + end + + # Having now read the method parameters and documentation modifiers, we + # now know whether we have to rename #initialize to ::new + + if name == "initialize" && !meth.singleton then + if meth.dont_rename_initialize then + meth.visibility = :protected + else + meth.singleton = true + meth.name = "new" + meth.visibility = :public + end + end + + parse_statements(container, single, meth) + + remove_token_listener(meth) + + extract_call_seq comment, meth + + meth.comment = comment + end + + def parse_method_or_yield_parameters(method = nil, + modifiers = RDoc::METHOD_MODIFIERS) + skip_tkspace(false) + tk = get_tk + + # Little hack going on here. In the statement + # f = 2*(1+yield) + # We see the RPAREN as the next token, so we need + # to exit early. This still won't catch all cases + # (such as "a = yield + 1" + end_token = case tk + when TkLPAREN, TkfLPAREN + TkRPAREN + when TkRPAREN + return "" + else + TkNL + end + nest = 0 + + loop do + case tk + when TkSEMICOLON then + break + when TkLBRACE then + nest += 1 + when TkRBRACE then + # we might have a.each {|i| yield i } + unget_tk(tk) if nest.zero? + nest -= 1 + break if nest <= 0 + when TkLPAREN, TkfLPAREN then + nest += 1 + when end_token then + if end_token == TkRPAREN + nest -= 1 + break if @scanner.lex_state == EXPR_END and nest <= 0 + else + break unless @scanner.continue + end + when method && method.block_params.nil? && TkCOMMENT then + unget_tk tk + read_documentation_modifiers method, modifiers + @read.pop + when TkCOMMENT then + @read.pop + end + tk = get_tk + end + + res = get_tkread.gsub(/\s+/, ' ').strip + res = '' if res == ';' + res + end + + ## + # Capture the method's parameters. Along the way, look for a comment + # containing: + # + # # yields: .... + # + # and add this as the block_params for the method + + def parse_method_parameters(method) + res = parse_method_or_yield_parameters method + + res = "(#{res})" unless res =~ /\A\(/ + method.params = res unless method.params + + if method.block_params.nil? then + skip_tkspace(false) + read_documentation_modifiers method, RDoc::METHOD_MODIFIERS + end + end + + def parse_module(container, single, tk, comment) + container, name_t = get_class_or_module(container) + + name = name_t.name + + mod = container.add_module RDoc::NormalModule, name + mod.record_location @top_level + + @stats.add_module mod + + read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS + parse_statements(mod) + mod.comment = comment + end + + def parse_require(context, comment) + skip_tkspace_comment + tk = get_tk + if TkLPAREN === tk then + skip_tkspace_comment + tk = get_tk + end + + name = nil + case tk + when TkSTRING + name = tk.text + # when TkCONSTANT, TkIDENTIFIER, TkIVAR, TkGVAR + # name = tk.name + when TkDSTRING + warn "Skipping require of dynamic string: #{tk.text}" + # else + # warn "'require' used as variable" + end + if name + context.add_require RDoc::Require.new(name, comment) + else + unget_tk(tk) + end + end + + def parse_statements(container, single = NORMAL, current_method = nil, + comment = '') + nest = 1 + save_visibility = container.visibility + + non_comment_seen = true + + while tk = get_tk do + keep_comment = false + + non_comment_seen = true unless TkCOMMENT === tk + + case tk + when TkNL then + skip_tkspace true # Skip blanks and newlines + tk = get_tk + + if TkCOMMENT === tk then + if non_comment_seen then + # Look for RDoc in a comment about to be thrown away + parse_comment container, tk, comment unless comment.empty? + + comment = '' + non_comment_seen = false + end + + while TkCOMMENT === tk do + comment << tk.text << "\n" + tk = get_tk # this is the newline + skip_tkspace(false) # leading spaces + tk = get_tk + end + + unless comment.empty? then + look_for_directives_in container, comment + + if container.done_documenting then + container.ongoing_visibility = save_visibility + end + end + + keep_comment = true + else + non_comment_seen = true + end + + unget_tk tk + keep_comment = true + + when TkCLASS then + if container.document_children then + parse_class container, single, tk, comment + else + nest += 1 + end + + when TkMODULE then + if container.document_children then + parse_module container, single, tk, comment + else + nest += 1 + end + + when TkDEF then + if container.document_self then + parse_method container, single, tk, comment + else + nest += 1 + end + + when TkCONSTANT then + if container.document_self then + parse_constant container, single, tk, comment + end + + when TkALIAS then + if container.document_self then + parse_alias container, single, tk, comment + end + + when TkYIELD then + if current_method.nil? then + warn "Warning: yield outside of method" if container.document_self + else + parse_yield container, single, tk, current_method + end + + # Until and While can have a 'do', which shouldn't increase the nesting. + # We can't solve the general case, but we can handle most occurrences by + # ignoring a do at the end of a line. + + when TkUNTIL, TkWHILE then + nest += 1 + skip_optional_do_after_expression + + # 'for' is trickier + when TkFOR then + nest += 1 + skip_for_variable + skip_optional_do_after_expression + + when TkCASE, TkDO, TkIF, TkUNLESS, TkBEGIN then + nest += 1 + + when TkIDENTIFIER then + if nest == 1 and current_method.nil? then + case tk.name + when 'private', 'protected', 'public', 'private_class_method', + 'public_class_method', 'module_function' then + parse_visibility container, single, tk + keep_comment = true + when 'attr' then + parse_attr container, single, tk, comment + when /^attr_(reader|writer|accessor)$/ then + parse_attr_accessor container, single, tk, comment + when 'alias_method' then + if container.document_self then + parse_alias container, single, tk, comment + end + else + if container.document_self and comment =~ /\A#\#$/ then + parse_meta_method container, single, tk, comment + end + end + end + + case tk.name + when "require" then + parse_require container, comment + when "include" then + parse_include container, comment + end + + when TkEND then + nest -= 1 + if nest == 0 then + read_documentation_modifiers container, RDoc::CLASS_MODIFIERS + container.ongoing_visibility = save_visibility + return + end + + end + + comment = '' unless keep_comment + + begin + get_tkread + skip_tkspace(false) + end while peek_tk == TkNL + end + end + + def parse_symbol_arg(no = nil) + args = [] + skip_tkspace_comment + case tk = get_tk + when TkLPAREN + loop do + skip_tkspace_comment + if tk1 = parse_symbol_in_arg + args.push tk1 + break if no and args.size >= no + end + + skip_tkspace_comment + case tk2 = get_tk + when TkRPAREN + break + when TkCOMMA + else + warn("unexpected token: '#{tk2.inspect}'") if $DEBUG_RDOC + break + end + end + else + unget_tk tk + if tk = parse_symbol_in_arg + args.push tk + return args if no and args.size >= no + end + + loop do + skip_tkspace(false) + + tk1 = get_tk + unless TkCOMMA === tk1 then + unget_tk tk1 + break + end + + skip_tkspace_comment + if tk = parse_symbol_in_arg + args.push tk + break if no and args.size >= no + end + end + end + args + end + + def parse_symbol_in_arg + case tk = get_tk + when TkSYMBOL + tk.text.sub(/^:/, '') + when TkSTRING + eval @read[-1] + else + warn("Expected symbol or string, got #{tk.inspect}") if $DEBUG_RDOC + nil + end + end + + def parse_top_level_statements(container) + comment = collect_first_comment + look_for_directives_in(container, comment) + container.comment = comment unless comment.empty? + parse_statements container, NORMAL, nil, comment + end + + def parse_visibility(container, single, tk) + singleton = (single == SINGLE) + + vis_type = tk.name + + vis = case vis_type + when 'private' then :private + when 'protected' then :protected + when 'public' then :public + when 'private_class_method' then + singleton = true + :private + when 'public_class_method' then + singleton = true + :public + when 'module_function' then + singleton = true + :public + else + raise "Invalid visibility: #{tk.name}" + end + + skip_tkspace_comment false + + case peek_tk + # Ryan Davis suggested the extension to ignore modifiers, because he + # often writes + # + # protected unless $TESTING + # + when TkNL, TkUNLESS_MOD, TkIF_MOD, TkSEMICOLON then + container.ongoing_visibility = vis + else + if vis_type == 'module_function' then + args = parse_symbol_arg + container.set_visibility_for args, :private, false + + module_functions = [] + + container.methods_matching args do |m| + s_m = m.dup + s_m.singleton = true if RDoc::AnyMethod === s_m + s_m.visibility = :public + module_functions << s_m + end + + module_functions.each do |s_m| + case s_m + when RDoc::AnyMethod then + container.add_method s_m + when RDoc::Attr then + container.add_attribute s_m + end + end + else + args = parse_symbol_arg + container.set_visibility_for args, vis, singleton + end + end + end + + def parse_yield_parameters + parse_method_or_yield_parameters + end + + def parse_yield(context, single, tk, method) + if method.block_params.nil? + get_tkread + @scanner.instance_eval{@continue = false} + method.block_params = parse_yield_parameters + end + end + + def peek_read + @read.join('') + end + + ## + # Peek at the next token, but don't remove it from the stream + + def peek_tk + unget_tk(tk = get_tk) + tk + end + + ## + # Directives are modifier comments that can appear after class, module, or + # method names. For example: + # + # def fred # :yields: a, b + # + # or: + # + # class MyClass # :nodoc: + # + # We return the directive name and any parameters as a two element array + + def read_directive(allowed) + tk = get_tk + result = nil + + if TkCOMMENT === tk then + if tk.text =~ /\s*:?(\w+):\s*(.*)/ then + directive = $1.downcase + if allowed.include? directive then + result = [directive, $2] + end + end + else + unget_tk tk + end + + result + end + + def read_documentation_modifiers(context, allow) + dir = read_directive(allow) + + case dir[0] + when "notnew", "not_new", "not-new" then + context.dont_rename_initialize = true + + when "nodoc" then + context.document_self = false + if dir[1].downcase == "all" + context.document_children = false + end + + when "doc" then + context.document_self = true + context.force_documentation = true + + when "yield", "yields" then + unless context.params.nil? + context.params.sub!(/(,|)\s*&\w+/,'') # remove parameter &proc + end + + context.block_params = dir[1] + + when "arg", "args" then + context.params = dir[1] + end if dir + end + + def remove_private_comments(comment) + comment.gsub!(/^#--\n.*?^#\+\+/m, '') + comment.sub!(/^#--\n.*/m, '') + end + + def remove_token_listener(obj) + @token_listeners.delete(obj) + end + + def reset + @tokens = [] + @unget_read = [] + @read = [] + end + + def scan + reset + + catch(:eof) do + catch(:enddoc) do + begin + parse_top_level_statements(@top_level) + rescue Exception => e + $stderr.puts <<-EOF + + +RDoc failure in #{@file_name} at or around line #{@scanner.line_no} column +#{@scanner.char_no} + +Before reporting this, could you check that the file you're documenting +compiles cleanly--RDoc is not a full Ruby parser, and gets confused easily if +fed invalid programs. + +The internal error was: + + EOF + + e.set_backtrace(e.backtrace[0,4]) + raise + end + end + end + + @top_level + end + + ## + # while, until, and for have an optional do + + def skip_optional_do_after_expression + skip_tkspace(false) + tk = get_tk + case tk + when TkLPAREN, TkfLPAREN + end_token = TkRPAREN + else + end_token = TkNL + end + + nest = 0 + @scanner.instance_eval{@continue = false} + + loop do + case tk + when TkSEMICOLON + break + when TkLPAREN, TkfLPAREN + nest += 1 + when TkDO + break if nest.zero? + when end_token + if end_token == TkRPAREN + nest -= 1 + break if @scanner.lex_state == EXPR_END and nest.zero? + else + break unless @scanner.continue + end + end + tk = get_tk + end + skip_tkspace(false) + + get_tk if TkDO === peek_tk + end + + ## + # skip the var [in] part of a 'for' statement + + def skip_for_variable + skip_tkspace(false) + tk = get_tk + skip_tkspace(false) + tk = get_tk + unget_tk(tk) unless TkIN === tk + end + + def skip_method(container) + meth = RDoc::AnyMethod.new "", "anon" + parse_method_parameters(meth) + parse_statements(container, false, meth) + end + + ## + # Skip spaces + + def skip_tkspace(skip_nl = true) + tokens = [] + + while TkSPACE === (tk = get_tk) or (skip_nl and TkNL === tk) do + tokens.push tk + end + + unget_tk(tk) + tokens + end + + ## + # Skip spaces until a comment is found + + def skip_tkspace_comment(skip_nl = true) + loop do + skip_tkspace(skip_nl) + return unless TkCOMMENT === peek_tk + get_tk + end + end + + def unget_tk(tk) + @tokens.unshift tk + @unget_read.unshift @read.pop + + # Remove this token from any listeners + @token_listeners.each do |obj| + obj.pop_token + end if @token_listeners + end + + def warn(msg) + return if @options.quiet + msg = make_message msg + $stderr.puts msg + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/parser/simple.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/parser/simple.rb new file mode 100644 index 000000000..e34ce70e5 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/parser/simple.rb @@ -0,0 +1,39 @@ +require 'rdoc/parser' + +## +# Parse a non-source file. We basically take the whole thing as one big +# comment. If the first character in the file is '#', we strip leading pound +# signs. + +class RDoc::Parser::Simple < RDoc::Parser + + parse_files_matching(//) + + ## + # Prepare to parse a plain file + + def initialize(top_level, file_name, content, options, stats) + super + + preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include + + preprocess.handle @content do |directive, param| + warn "Unrecognized directive '#{directive}' in #{@file_name}" + end + end + + ## + # Extract the file contents and attach them to the TopLevel as a comment + + def scan + @top_level.comment = remove_private_comments(@content) + @top_level.parser = self.class + @top_level + end + + def remove_private_comments(comment) + comment.gsub(/^--\n.*?^\+\+/m, '').sub(/^--\n.*/m, '') + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/rdoc.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/rdoc.rb new file mode 100644 index 000000000..b854988ac --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/rdoc.rb @@ -0,0 +1,375 @@ +require 'rdoc' + +require 'rdoc/parser' + +# Simple must come first +require 'rdoc/parser/simple' +require 'rdoc/parser/ruby' +require 'rdoc/parser/c' +require 'rdoc/parser/perl' + +require 'rdoc/stats' +require 'rdoc/options' + +require 'rdoc/diagram' + +require 'find' +require 'fileutils' +require 'time' +require 'thread' + +## +# Encapsulate the production of rdoc documentation. Basically you can use this +# as you would invoke rdoc from the command line: +# +# rdoc = RDoc::RDoc.new +# rdoc.document(args) +# +# Where +args+ is an array of strings, each corresponding to an argument you'd +# give rdoc on the command line. See rdoc/rdoc.rb for details. + +class RDoc::RDoc + + ## + # Generator instance used for creating output + + attr_accessor :generator + + ## + # RDoc options + + attr_reader :options + + ## + # Accessor for statistics. Available after each call to parse_files + + attr_reader :stats + + ## + # This is the list of supported output generators + + GENERATORS = {} + + ## + # Add +klass+ that can generate output after parsing + + def self.add_generator(klass) + name = klass.name.sub(/^RDoc::Generator::/, '').downcase + GENERATORS[name] = klass + end + + ## + # Active RDoc::RDoc instance + + def self.current + @current + end + + ## + # Sets the active RDoc::RDoc instance + + def self.current=(rdoc) + @current = rdoc + end + + def initialize + @generator = nil + @options = nil + @stats = nil + end + + ## + # Report an error message and exit + + def error(msg) + raise RDoc::Error, msg + end + + ## + # Turns RDoc from stdin into HTML + + def handle_pipe + @html = RDoc::Markup::ToHtml.new + + out = @html.convert $stdin.read + + $stdout.write out + end + + ## + # Create an output dir if it doesn't exist. If it does exist, but doesn't + # contain the flag file <tt>created.rid</tt> then we refuse to use it, as + # we may clobber some manually generated documentation + + def setup_output_dir(op_dir, force) + flag_file = output_flag_file op_dir + + if File.exist? op_dir then + unless File.directory? op_dir then + error "'#{op_dir}' exists, and is not a directory" + end + begin + created = File.read(flag_file) + rescue SystemCallError + error "\nDirectory #{op_dir} already exists, but it looks like it\n" + + "isn't an RDoc directory. Because RDoc doesn't want to risk\n" + + "destroying any of your existing files, you'll need to\n" + + "specify a different output directory name (using the\n" + + "--op <dir> option).\n\n" + else + last = (Time.parse(created) unless force rescue nil) + end + else + FileUtils.mkdir_p(op_dir) + end + last + end + + ## + # Update the flag file in an output directory. + + def update_output_dir(op_dir, time) + File.open(output_flag_file(op_dir), "w") { |f| f.puts time.rfc2822 } + end + + ## + # Return the path name of the flag file in an output directory. + + def output_flag_file(op_dir) + File.join op_dir, "created.rid" + end + + ## + # The .document file contains a list of file and directory name patterns, + # representing candidates for documentation. It may also contain comments + # (starting with '#') + + def parse_dot_doc_file(in_dir, filename, options) + # read and strip comments + patterns = File.read(filename).gsub(/#.*/, '') + + result = [] + + patterns.split.each do |patt| + candidates = Dir.glob(File.join(in_dir, patt)) + result.concat(normalized_file_list(options, candidates)) + end + + result + end + + ## + # Given a list of files and directories, create a list of all the Ruby + # files they contain. + # + # If +force_doc+ is true we always add the given files, if false, only + # add files that we guarantee we can parse. It is true when looking at + # files given on the command line, false when recursing through + # subdirectories. + # + # The effect of this is that if you want a file with a non-standard + # extension parsed, you must name it explicitly. + + def normalized_file_list(options, relative_files, force_doc = false, + exclude_pattern = nil) + file_list = [] + + relative_files.each do |rel_file_name| + next if exclude_pattern && exclude_pattern =~ rel_file_name + stat = File.stat rel_file_name rescue next + + case type = stat.ftype + when "file" + next if @last_created and stat.mtime < @last_created + + if force_doc or RDoc::Parser.can_parse(rel_file_name) then + file_list << rel_file_name.sub(/^\.\//, '') + end + when "directory" + next if rel_file_name == "CVS" || rel_file_name == ".svn" + dot_doc = File.join(rel_file_name, RDoc::DOT_DOC_FILENAME) + if File.file?(dot_doc) + file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options)) + else + file_list.concat(list_files_in_directory(rel_file_name, options)) + end + else + raise RDoc::Error, "I can't deal with a #{type} #{rel_file_name}" + end + end + + file_list + end + + ## + # Return a list of the files to be processed in a directory. We know that + # this directory doesn't have a .document file, so we're looking for real + # files. However we may well contain subdirectories which must be tested + # for .document files. + + def list_files_in_directory(dir, options) + files = Dir.glob File.join(dir, "*") + + normalized_file_list options, files, false, options.exclude + end + + ## + # Parse each file on the command line, recursively entering directories. + + def parse_files(options) + files = options.files + files = ["."] if files.empty? + + file_list = normalized_file_list(options, files, true, options.exclude) + + return [] if file_list.empty? + + jobs = SizedQueue.new(@options.threads * 3) + workers = [] + file_info = [] + file_info_lock = Mutex.new + + Thread.abort_on_exception = true + @stats = RDoc::Stats.new(file_list.size, options.verbosity) + @stats.begin_adding @options.threads + + # Create worker threads. + @options.threads.times do + thread = Thread.new do + while (filename = jobs.pop) + @stats.add_file(filename) + content = read_file_contents(filename) + top_level = RDoc::TopLevel.new filename + + parser = RDoc::Parser.for(top_level, filename, content, options, + @stats) + result = parser.scan + + file_info_lock.synchronize do + file_info << result + end + end + end + workers << thread + end + + # Feed filenames to the parser worker threads... + file_list.each do |filename| + jobs << filename + end + workers.size.times do + jobs << nil + end + + # ...and wait until they're done. + workers.each do |thread| + thread.join + end + + @stats.done_adding + + file_info + end + + ## + # Format up one or more files according to the given arguments. + # + # For simplicity, _argv_ is an array of strings, equivalent to the strings + # that would be passed on the command line. (This isn't a coincidence, as + # we _do_ pass in ARGV when running interactively). For a list of options, + # see rdoc/rdoc.rb. By default, output will be stored in a directory + # called +doc+ below the current directory, so make sure you're somewhere + # writable before invoking. + # + # Throws: RDoc::Error on error + + def document(argv) + RDoc::TopLevel.reset + + @options = RDoc::Options.new + @options.parse argv + + if @options.pipe then + handle_pipe + exit + end + + @last_created = setup_output_dir @options.op_dir, @options.force_update + + start_time = Time.now + + file_info = parse_files @options + + @options.title = "RDoc Documentation" + + if file_info.empty? + $stderr.puts "\nNo newer files." unless @options.quiet + else + gen_klass = @options.generator + + unless @options.quiet then + $stderr.puts "\nGenerating #{gen_klass.name.sub(/^.*::/, '')}..." + end + + @generator = gen_klass.for @options + + pwd = Dir.pwd + + Dir.chdir @options.op_dir + + begin + self.class.current = self + + RDoc::Diagram.new(file_info, @options).draw if @options.diagram + @generator.generate file_info + update_output_dir ".", start_time + ensure + self.class.current = nil + Dir.chdir pwd + end + end + + unless @options.quiet or not @stats then + puts + @stats.print + end + end + + private + + def read_file_contents(filename) + content = if RUBY_VERSION >= '1.9' then + File.open(filename, "r:ascii-8bit") { |f| f.read } + else + File.read filename + end + + if defined? Encoding then + if /coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/] + if enc = ::Encoding.find($1) + content.force_encoding(enc) + end + end + end + + content + end + +end + +if Gem.respond_to? :find_files then + rdoc_extensions = Gem.find_files 'rdoc/discover' + + rdoc_extensions.each do |extension| + begin + load extension + rescue => e + warn "error loading #{extension.inspect}: #{e.message} (#{e.class})" + end + end +end + +# require built-in generators after discovery in case they've been replaced +require 'rdoc/generator/darkfish' +require 'rdoc/generator/ri' + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/require.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/require.rb new file mode 100644 index 000000000..407b55af3 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/require.rb @@ -0,0 +1,32 @@ +require 'rdoc/code_object' + +## +# A file loaded by \#require + +class RDoc::Require < RDoc::CodeObject + + ## + # Name of the required file + + attr_accessor :name + + ## + # Creates a new Require that loads +name+ with +comment+ + + def initialize(name, comment) + super() + @name = name.gsub(/'|"/, "") #' + self.comment = comment + end + + def inspect # :nodoc: + "#<%s:0x%x require '%s' in %s>" % [ + self.class, + object_id, + @name, + parent_file_name, + ] + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri.rb new file mode 100644 index 000000000..a3a858e67 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri.rb @@ -0,0 +1,8 @@ +require 'rdoc' + +module RDoc::RI + + class Error < RDoc::Error; end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/cache.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/cache.rb new file mode 100644 index 000000000..15935abb1 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/cache.rb @@ -0,0 +1,187 @@ +require 'rdoc/ri' + +class RDoc::RI::ClassEntry + + attr_reader :name + attr_reader :path_names + + def initialize(path_name, name, in_class) + @path_names = [ path_name ] + @name = name + @in_class = in_class + @class_methods = [] + @instance_methods = [] + @inferior_classes = [] + end + + # We found this class in more than one place, so add + # in the name from there. + def add_path(path) + @path_names << path + end + + ## + # read in our methods and any classes and modules in our namespace. Methods + # are stored in files called name-c|i.yaml, where the 'name' portion is the + # external form of the method name and the c|i is a class|instance flag + + def load_from(dir) + return unless File.exist? dir + + Dir.foreach(dir) do |name| + next if name =~ /^\./ + + # convert from external to internal form, and + # extract the instance/class flag + + if name =~ /^(.*?)-(c|i).yaml$/ + external_name = $1 + is_class_method = $2 == "c" + internal_name = RDoc::RI::Writer.external_to_internal(external_name) + list = is_class_method ? @class_methods : @instance_methods + path = File.join(dir, name) + list << RDoc::RI::MethodEntry.new(path, internal_name, is_class_method, self) + else + full_name = File.join(dir, name) + if File.directory?(full_name) + inf_class = @inferior_classes.find {|c| c.name == name } + if inf_class + inf_class.add_path(full_name) + else + inf_class = RDoc::RI::ClassEntry.new(full_name, name, self) + @inferior_classes << inf_class + end + inf_class.load_from(full_name) + end + end + end + end + + # Return a list of any classes or modules that we contain + # that match a given string + + def contained_modules_matching(name) + @inferior_classes.find_all {|c| c.name[name]} + end + + def classes_and_modules + @inferior_classes + end + + # Return an exact match to a particular name + def contained_class_named(name) + @inferior_classes.find {|c| c.name == name} + end + + # return the list of local methods matching name + # We're split into two because we need distinct behavior + # when called from the _toplevel_ + def methods_matching(name, is_class_method) + local_methods_matching(name, is_class_method) + end + + # Find methods matching 'name' in ourselves and in + # any classes we contain + def recursively_find_methods_matching(name, is_class_method) + res = local_methods_matching(name, is_class_method) + @inferior_classes.each do |c| + res.concat(c.recursively_find_methods_matching(name, is_class_method)) + end + res + end + + + # Return our full name + def full_name + res = @in_class.full_name + res << "::" unless res.empty? + res << @name + end + + # Return a list of all out method names + def all_method_names + res = @class_methods.map {|m| m.full_name } + @instance_methods.each {|m| res << m.full_name} + res + end + + private + + # Return a list of all our methods matching a given string. + # Is +is_class_methods+ if 'nil', we don't care if the method + # is a class method or not, otherwise we only return + # those methods that match + def local_methods_matching(name, is_class_method) + + list = case is_class_method + when nil then @class_methods + @instance_methods + when true then @class_methods + when false then @instance_methods + else fail "Unknown is_class_method: #{is_class_method.inspect}" + end + + list.find_all {|m| m.name; m.name[name]} + end +end + +## +# A TopLevelEntry is like a class entry, but when asked to search for methods +# searches all classes, not just itself + +class RDoc::RI::TopLevelEntry < RDoc::RI::ClassEntry + def methods_matching(name, is_class_method) + res = recursively_find_methods_matching(name, is_class_method) + end + + def full_name + "" + end + + def module_named(name) + + end + +end + +class RDoc::RI::MethodEntry + attr_reader :name + attr_reader :path_name + + def initialize(path_name, name, is_class_method, in_class) + @path_name = path_name + @name = name + @is_class_method = is_class_method + @in_class = in_class + end + + def full_name + res = @in_class.full_name + unless res.empty? + if @is_class_method + res << "::" + else + res << "#" + end + end + res << @name + end +end + +## +# We represent everything known about all 'ri' files accessible to this program + +class RDoc::RI::Cache + + attr_reader :toplevel + + def initialize(dirs) + # At the top level we have a dummy module holding the + # overall namespace + @toplevel = RDoc::RI::TopLevelEntry.new('', '::', nil) + + dirs.each do |dir| + @toplevel.load_from(dir) + end + end + +end diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/descriptions.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/descriptions.rb new file mode 100644 index 000000000..99a7cb11f --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/descriptions.rb @@ -0,0 +1,156 @@ +require 'yaml' +require 'rdoc/markup/fragments' +require 'rdoc/ri' + +## +# Descriptions are created by RDoc (in ri_generator) and written out in +# serialized form into the documentation tree. ri then reads these to generate +# the documentation + +class RDoc::RI::NamedThing + attr_reader :name + def initialize(name) + @name = name + end + + def <=>(other) + @name <=> other.name + end + + def hash + @name.hash + end + + def eql?(other) + @name.eql?(other) + end +end + +class RDoc::RI::AliasName < RDoc::RI::NamedThing; end + +class RDoc::RI::Attribute < RDoc::RI::NamedThing + attr_reader :rw, :comment + + def initialize(name, rw, comment) + super(name) + @rw = rw + @comment = comment + end +end + +class RDoc::RI::Constant < RDoc::RI::NamedThing + attr_reader :value, :comment + + def initialize(name, value, comment) + super(name) + @value = value + @comment = comment + end +end + +class RDoc::RI::IncludedModule < RDoc::RI::NamedThing; end + +class RDoc::RI::MethodSummary < RDoc::RI::NamedThing + def initialize(name="") + super + end +end + +class RDoc::RI::Description + attr_accessor :name + attr_accessor :full_name + attr_accessor :comment + + def serialize + self.to_yaml + end + + def self.deserialize(from) + YAML.load(from) + end + + def <=>(other) + @name <=> other.name + end +end + +class RDoc::RI::ModuleDescription < RDoc::RI::Description + + attr_accessor :class_methods + attr_accessor :class_method_extensions + attr_accessor :instance_methods + attr_accessor :instance_method_extensions + attr_accessor :attributes + attr_accessor :constants + attr_accessor :includes + + # merge in another class description into this one + def merge_in(old) + merge(@class_methods, old.class_methods) + merge(@instance_methods, old.instance_methods) + merge(@attributes, old.attributes) + merge(@constants, old.constants) + merge(@includes, old.includes) + if @comment.nil? || @comment.empty? + @comment = old.comment + else + unless old.comment.nil? or old.comment.empty? then + if @comment.nil? or @comment.empty? then + @comment = old.comment + else + @comment << RDoc::Markup::Flow::RULE.new + @comment.concat old.comment + end + end + end + end + + def display_name + "Module" + end + + # the 'ClassDescription' subclass overrides this + # to format up the name of a parent + def superclass_string + nil + end + + private + + def merge(into, from) + names = {} + into.each {|i| names[i.name] = i } + from.each {|i| names[i.name] = i } + into.replace(names.keys.sort.map {|n| names[n]}) + end +end + +class RDoc::RI::ClassDescription < RDoc::RI::ModuleDescription + attr_accessor :superclass + + def display_name + "Class" + end + + def superclass_string + if @superclass && @superclass != "Object" + @superclass + else + nil + end + end +end + +class RDoc::RI::MethodDescription < RDoc::RI::Description + + attr_accessor :is_class_method + attr_accessor :visibility + attr_accessor :block_params + attr_accessor :is_singleton + attr_accessor :aliases + attr_accessor :is_alias_for + attr_accessor :params + attr_accessor :source_path + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/display.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/display.rb new file mode 100644 index 000000000..173995943 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/display.rb @@ -0,0 +1,340 @@ +require 'rdoc/ri' + +## +# This is a kind of 'flag' module. If you want to write your own 'ri' display +# module (perhaps because you're writing an IDE), you write a class which +# implements the various 'display' methods in RDoc::RI::DefaultDisplay, and +# include the RDoc::RI::Display module in that class. +# +# To access your class from the command line, you can do +# +# ruby -r <your source file> ../ri .... + +module RDoc::RI::Display + + @@display_class = nil + + def self.append_features(display_class) + @@display_class = display_class + end + + def self.new(*args) + @@display_class.new(*args) + end + +end + +## +# A paging display module. Uses the RDoc::RI::Formatter class to do the actual +# presentation. + +class RDoc::RI::DefaultDisplay + + include RDoc::RI::Display + + attr_reader :formatter + + def initialize(formatter, width, use_stdout, output = $stdout) + @use_stdout = use_stdout + @formatter = formatter.new output, width, " " + end + + ## + # Display information about +klass+. Fetches additional information from + # +ri_reader+ as necessary. + + def display_class_info(klass) + page do + superclass = klass.superclass + + if superclass + superclass = " < " + superclass + else + superclass = "" + end + + @formatter.draw_line(klass.display_name + ": " + + klass.full_name + superclass) + + display_flow(klass.comment) + @formatter.draw_line + + unless klass.includes.empty? + @formatter.blankline + @formatter.display_heading("Includes:", 2, "") + incs = [] + + klass.includes.each do |inc| + incs << inc.name + end + + @formatter.wrap(incs.sort.join(', ')) + end + + unless klass.constants.empty? + @formatter.blankline + @formatter.display_heading("Constants:", 2, "") + + constants = klass.constants.sort_by { |constant| constant.name } + + constants.each do |constant| + @formatter.wrap "#{constant.name} = #{constant.value}" + if constant.comment then + @formatter.indent do + @formatter.display_flow constant.comment + end + else + @formatter.break_to_newline + end + end + end + + unless klass.attributes.empty? then + @formatter.blankline + @formatter.display_heading 'Attributes:', 2, '' + + attributes = klass.attributes.sort_by { |attribute| attribute.name } + + attributes.each do |attribute| + if attribute.comment then + @formatter.wrap "#{attribute.name} (#{attribute.rw}):" + @formatter.indent do + @formatter.display_flow attribute.comment + end + else + @formatter.wrap "#{attribute.name} (#{attribute.rw})" + @formatter.break_to_newline + end + end + end + + return display_class_method_list(klass) + end + end + + ## + # Given a Hash mapping a class' methods to method types (returned by + # display_class_method_list), this method allows the user to choose one of + # the methods. + + def get_class_method_choice(method_map) + end + + ## + # Display methods on +klass+. Returns a hash mapping method name to method + # contents + + def display_class_method_list(klass) + method_map = {} + + class_data = [ + :class_methods, + :class_method_extensions, + :instance_methods, + :instance_method_extensions, + ] + + class_data.each do |data_type| + data = klass.send data_type + + unless data.nil? or data.empty? then + @formatter.blankline + + heading = data_type.to_s.split('_').join(' ').capitalize << ':' + @formatter.display_heading heading, 2, '' + + method_names = [] + data.each do |item| + method_names << item.name + + if(data_type == :class_methods || + data_type == :class_method_extensions) then + method_map["::#{item.name}"] = :class + method_map[item.name] = :class + else + # + # Since we iterate over instance methods after class methods, + # an instance method always will overwrite the unqualified + # class method entry for a class method of the same name. + # + method_map["##{item.name}"] = :instance + method_map[item.name] = :instance + end + end + method_names.sort! + + @formatter.wrap method_names.join(', ') + end + end + + method_map + end + private :display_class_method_list + + ## + # Display an Array of RDoc::Markup::Flow objects, +flow+. + + def display_flow(flow) + if flow and not flow.empty? then + @formatter.display_flow flow + else + @formatter.wrap '[no description]' + end + end + + ## + # Display information about +method+. + + def display_method_info(method) + page do + @formatter.draw_line(method.full_name) + display_params(method) + + @formatter.draw_line + display_flow(method.comment) + + if method.aliases and not method.aliases.empty? then + @formatter.blankline + aka = "(also known as #{method.aliases.map { |a| a.name }.join(', ')})" + @formatter.wrap aka + end + end + end + + ## + # Display the list of +methods+. + + def display_method_list(methods) + page do + @formatter.wrap "More than one method matched your request. You can refine your search by asking for information on one of:" + @formatter.blankline + + methods.each do |method| + @formatter.raw_print_line "#{method.full_name} [#{method.source_path}]\n" + end + end + end + + ## + # Display a list of +methods+ and allow the user to select one of them. + + def display_method_list_choice(methods) + page do + @formatter.wrap "More than one method matched your request. Please choose one of the possible matches." + @formatter.blankline + + methods.each_with_index do |method, index| + @formatter.raw_print_line "%3d %s [%s]\n" % [index + 1, method.full_name, method.source_path] + end + + @formatter.raw_print_line ">> " + + choice = $stdin.gets.strip! + + if(choice == '') + return + end + + choice = choice.to_i + + if ((choice == 0) || (choice > methods.size)) then + @formatter.raw_print_line "Invalid choice!\n" + else + method = methods[choice - 1] + display_method_info(method) + end + end + end + + ## + # Display the params for +method+. + + def display_params(method) + params = method.params + + if params[0,1] == "(" then + if method.is_singleton + params = method.full_name + params + else + params = method.name + params + end + end + + params.split(/\n/).each do |param| + @formatter.wrap param + @formatter.break_to_newline + end + + @formatter.blankline + @formatter.wrap("From #{method.source_path}") + end + + ## + # List the classes in +classes+. + + def list_known_classes(classes) + if classes.empty? then + warn_no_database + else + page do + @formatter.draw_line "Known classes and modules" + @formatter.blankline + + classes.sort.each do |klass| + @formatter.wrap klass + end + end + end + end + + ## + # Paginates output through a pager program. + + def page + if pager = setup_pager then + begin + orig_output = @formatter.output + @formatter.output = pager + yield + ensure + @formatter.output = orig_output + pager.close + end + else + yield + end + rescue Errno::EPIPE + end + + ## + # Sets up a pager program to pass output through. + + def setup_pager + unless @use_stdout then + for pager in [ ENV['PAGER'], "less", "more", 'pager' ].compact.uniq + return IO.popen(pager, "w") rescue nil + end + @use_stdout = true + nil + end + end + + ## + # Displays a message that describes how to build RI data. + + def warn_no_database + output = @formatter.output + + output.puts "No ri data found" + output.puts + output.puts "If you've installed Ruby yourself, you need to generate documentation using:" + output.puts + output.puts " make install-doc" + output.puts + output.puts "from the same place you ran `make` to build ruby." + output.puts + output.puts "If you installed Ruby from a packaging system, then you may need to" + output.puts "install an additional package, or ask the packager to enable ri generation." + end + +end diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/driver.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/driver.rb new file mode 100644 index 000000000..310ff8487 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/driver.rb @@ -0,0 +1,828 @@ +require 'abbrev' +require 'optparse' +require 'yaml' + +begin + require 'readline' +rescue LoadError +end + +require 'rdoc/ri' +require 'rdoc/ri/paths' +require 'rdoc/ri/formatter' +require 'rdoc/ri/display' +require 'fileutils' +require 'rdoc/markup' +require 'rdoc/markup/to_flow' + +class RDoc::RI::Driver + + ## + # This class offers both Hash and OpenStruct functionality. We convert from + # the Core Hash to this before calling any of the display methods, in order + # to give the display methods a cleaner API for accessing the data. + + class OpenStructHash < Hash + + ## + # This method converts from a Hash to an OpenStructHash. + + def self.convert(object) + case object + when Hash then + new_hash = new # Convert Hash -> OpenStructHash + + object.each do |key, value| + new_hash[key] = convert value + end + + new_hash + when Array then + object.map do |element| + convert element + end + else + object + end + end + + def merge_enums(other) + other.each do |k, v| + if self[k] then + case v + when Array then + # HACK dunno + if String === self[k] and self[k].empty? then + self[k] = v + else + self[k] += v + end + when Hash then + self[k].update v + else + # do nothing + end + else + self[k] = v + end + end + end + + def method_missing method, *args + self[method.to_s] + end + end + + class Error < RDoc::RI::Error; end + + class NotFoundError < Error + def message + "Nothing known about #{super}" + end + end + + attr_accessor :homepath # :nodoc: + + ## + # Default options for ri + + def self.default_options + options = {} + options[:use_stdout] = !$stdout.tty? + options[:width] = 72 + options[:formatter] = RDoc::RI::Formatter.for 'plain' + options[:interactive] = false + options[:use_cache] = true + + # By default all standard paths are used. + options[:use_system] = true + options[:use_site] = true + options[:use_home] = true + options[:use_gems] = true + options[:extra_doc_dirs] = [] + + return options + end + + ## + # Parses +argv+ and returns a Hash of options + + def self.process_args(argv) + options = default_options + + opts = OptionParser.new do |opt| + opt.program_name = File.basename $0 + opt.version = RDoc::VERSION + opt.release = nil + opt.summary_indent = ' ' * 4 + + directories = [ + RDoc::RI::Paths::SYSDIR, + RDoc::RI::Paths::SITEDIR, + RDoc::RI::Paths::HOMEDIR + ] + + if RDoc::RI::Paths::GEMDIRS then + Gem.path.each do |dir| + directories << "#{dir}/doc/*/ri" + end + end + + opt.banner = <<-EOT +Usage: #{opt.program_name} [options] [names...] + +Where name can be: + + Class | Class::method | Class#method | Class.method | method + +All class names may be abbreviated to their minimum unambiguous form. If a name +is ambiguous, all valid options will be listed. + +The form '.' method matches either class or instance methods, while #method +matches only instance and ::method matches only class methods. + +For example: + + #{opt.program_name} Fil + #{opt.program_name} File + #{opt.program_name} File.new + #{opt.program_name} zip + +Note that shell quoting may be required for method names containing +punctuation: + + #{opt.program_name} 'Array.[]' + #{opt.program_name} compact\\! + +By default ri searches for documentation in the following directories: + + #{directories.join "\n "} + +Specifying the --system, --site, --home, --gems or --doc-dir options will +limit ri to searching only the specified directories. + +Options may also be set in the 'RI' environment variable. + EOT + + opt.separator nil + opt.separator "Options:" + opt.separator nil + + opt.on("--fmt=FORMAT", "--format=FORMAT", "-f", + RDoc::RI::Formatter::FORMATTERS.keys, + "Format to use when displaying output:", + " #{RDoc::RI::Formatter.list}", + "Use 'bs' (backspace) with most pager", + "programs. To use ANSI, either disable the", + "pager or tell the pager to allow control", + "characters.") do |value| + options[:formatter] = RDoc::RI::Formatter.for value + end + + opt.separator nil + + opt.on("--doc-dir=DIRNAME", "-d", Array, + "List of directories from which to source", + "documentation in addition to the standard", + "directories. May be repeated.") do |value| + value.each do |dir| + unless File.directory? dir then + raise OptionParser::InvalidArgument, "#{dir} is not a directory" + end + + options[:extra_doc_dirs] << File.expand_path(dir) + end + end + + opt.separator nil + + opt.on("--[no-]use-cache", + "Whether or not to use ri's cache.", + "True by default.") do |value| + options[:use_cache] = value + end + + opt.separator nil + + opt.on("--no-standard-docs", + "Do not include documentation from", + "the Ruby standard library, site_lib,", + "installed gems, or ~/.rdoc.", + "Equivalent to specifying", + "the options --no-system, --no-site, --no-gems,", + "and --no-home") do + options[:use_system] = false + options[:use_site] = false + options[:use_gems] = false + options[:use_home] = false + end + + opt.separator nil + + opt.on("--[no-]system", + "Include documentation from Ruby's standard", + "library. Defaults to true.") do |value| + options[:use_system] = value + end + + opt.separator nil + + opt.on("--[no-]site", + "Include documentation from libraries", + "installed in site_lib.", + "Defaults to true.") do |value| + options[:use_site] = value + end + + opt.separator nil + + opt.on("--[no-]gems", + "Include documentation from RubyGems.", + "Defaults to true.") do |value| + options[:use_gems] = value + end + + opt.separator nil + + opt.on("--[no-]home", + "Include documentation stored in ~/.rdoc.", + "Defaults to true.") do |value| + options[:use_home] = value + end + + opt.separator nil + + opt.on("--list-doc-dirs", + "List the directories from which ri will", + "source documentation on stdout and exit.") do + options[:list_doc_dirs] = true + end + + opt.separator nil + + opt.on("--no-pager", "-T", + "Send output directly to stdout,", + "rather than to a pager.") do + options[:use_stdout] = true + end + + opt.on("--interactive", "-i", + "This makes ri go into interactive mode.", + "When ri is in interactive mode it will", + "allow the user to disambiguate lists of", + "methods in case multiple methods match", + "against a method search string. It also", + "will allow the user to enter in a method", + "name (with auto-completion, if readline", + "is supported) when viewing a class.") do + options[:interactive] = true + end + + opt.separator nil + + opt.on("--width=WIDTH", "-w", OptionParser::DecimalInteger, + "Set the width of the output.") do |value| + options[:width] = value + end + end + + argv = ENV['RI'].to_s.split.concat argv + + opts.parse! argv + + options[:names] = argv + + options[:formatter] ||= RDoc::RI::Formatter.for('plain') + options[:use_stdout] ||= !$stdout.tty? + options[:use_stdout] ||= options[:interactive] + options[:width] ||= 72 + + options + + rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e + puts opts + puts + puts e + exit 1 + end + + ## + # Runs the ri command line executable using +argv+ + + def self.run(argv = ARGV) + options = process_args argv + ri = new options + ri.run + end + + def initialize(initial_options={}) + options = self.class.default_options.update(initial_options) + + @names = options[:names] + @class_cache_name = 'classes' + + @doc_dirs = RDoc::RI::Paths.path(options[:use_system], + options[:use_site], + options[:use_home], + options[:use_gems], + options[:extra_doc_dirs]) + + @homepath = RDoc::RI::Paths.raw_path(false, false, true, false).first + @homepath = @homepath.sub(/\.rdoc/, '.ri') + @sys_dir = RDoc::RI::Paths.raw_path(true, false, false, false).first + @list_doc_dirs = options[:list_doc_dirs] + + FileUtils.mkdir_p cache_file_path unless File.directory? cache_file_path + @cache_doc_dirs_path = File.join cache_file_path, ".doc_dirs" + + @use_cache = options[:use_cache] + @class_cache = nil + + @interactive = options[:interactive] + @display = RDoc::RI::DefaultDisplay.new(options[:formatter], + options[:width], + options[:use_stdout]) + end + + ## + # Cache of classes ri knows about + + def class_cache + return @class_cache if @class_cache + + # Get the documentation directories used to make the cache in order to see + # whether the cache is valid for the current ri instantiation. + if(File.readable?(@cache_doc_dirs_path)) + cache_doc_dirs = IO.read(@cache_doc_dirs_path).split("\n") + else + cache_doc_dirs = [] + end + + newest = map_dirs('created.rid') do |f| + File.mtime f if test ?f, f + end.max + + # An up to date cache file must have been created more recently than + # the last modification of any of the documentation directories. It also + # must have been created with the same documentation directories + # as those from which ri currently is sourcing documentation. + up_to_date = (File.exist?(class_cache_file_path) and + newest and newest < File.mtime(class_cache_file_path) and + (cache_doc_dirs == @doc_dirs)) + + if up_to_date and @use_cache then + open class_cache_file_path, 'rb' do |fp| + begin + @class_cache = Marshal.load fp.read + rescue + # + # This shouldn't be necessary, since the up_to_date logic above + # should force the cache to be recreated when a new version of + # rdoc is installed. This seems like a worthwhile enhancement + # to ri's robustness, however. + # + $stderr.puts "Error reading the class cache; recreating the class cache!" + @class_cache = create_class_cache + end + end + else + @class_cache = create_class_cache + end + + @class_cache + end + + ## + # Creates the class cache if it is empty + + def create_class_cache + class_cache = OpenStructHash.new + + if(@use_cache) + # Dump the documentation directories to a file in the cache, so that + # we only will use the cache for future instantiations with identical + # documentation directories. + File.open @cache_doc_dirs_path, "wb" do |fp| + fp << @doc_dirs.join("\n") + end + end + + classes = map_dirs('**/cdesc*.yaml') { |f| Dir[f] } + warn "Updating ri class cache with #{classes.size} classes..." + populate_class_cache class_cache, classes + + write_cache class_cache, class_cache_file_path + + class_cache + end + + ## + # Populates +class_cache+ with +classes+, adding +extension+ data for found + # methods when asked + + def populate_class_cache(class_cache, classes, extension = false) + classes.each do |cdesc| + desc = read_yaml cdesc + klassname = desc["full_name"] + + unless class_cache.has_key? klassname then + desc["display_name"] = "Class" + desc["sources"] = [cdesc] + desc["instance_method_extensions"] = [] + desc["class_method_extensions"] = [] + class_cache[klassname] = desc + else + klass = class_cache[klassname] + + if extension then + desc["instance_method_extensions"] = desc.delete "instance_methods" + desc["class_method_extensions"] = desc.delete "class_methods" + end + + klass.merge_enums desc + klass["sources"] << cdesc + end + end + end + + ## + # Path to the class_cache + + def class_cache_file_path + File.join cache_file_path, @class_cache_name + end + + ## + # Path to the cache file for +klassname+ + + def cache_file_for(klassname) + File.join cache_file_path, klassname.gsub(/:+/, "-") + end + + ## + # Directory where cache files live + + def cache_file_path + File.join @homepath, 'cache' + end + + ## + # Displays the module, class or method +name+. For methods, locates the + # method in the ancestors list if it isn't in the named module. + + def display_name(name) + if class_cache.key? name then + method_map = display_class name + elsif name =~ /::|\#|\./ then + method = nil + klass, = parse_name name + + klass = expand_klass klass unless class_cache.key? klass + + orig_klass = klass + orig_name = name + + loop do + method = lookup_method name, klass + + break if method + + ancestor = lookup_ancestor klass, orig_klass + + break unless ancestor + + name = name.sub klass, ancestor + klass = ancestor + end + + raise NotFoundError, orig_name unless method + + display_method method + else + methods = select_methods(/#{name}/) + + if methods.size == 0 + raise NotFoundError, name + elsif methods.size == 1 + display_method methods[0] + else + @display.display_method_list methods + end + end + end + + ## + # Displays info for class or module +name+ + + def display_class(name) + klass = class_cache[name] + @display.display_class_info klass + end + + ## + # Displays info for method +method+ + + def display_method(method) + @display.display_method_info method + end + + ## + # Runs ri interactively using Readline if it is available. + + def interactive + formatter = @display.formatter + + if defined? Readline then + # prepare abbreviations for tab completion + klasses = class_cache.keys + + Readline.completion_proc = proc do |name| + case name + when /(#|\.|::)([^A-Z]|$)/ then + methods = [] + method_type = $1 == '.' ? '#|::' : $1 + + klass, method = if $2.empty? then + [$`, ''] + else + parse_name name + end + + cache = load_cache_for klass + + methods += cache.keys.select do |method_name| + method_name =~ /^#{klass}#{method_type}#{method}/ + end + + # TODO ancestor lookup + + if method_type == '::' and method.empty? then + methods += klasses.grep(/^#{klass}::/) + end + + methods + when /^[A-Z]\w*/ then + klasses.grep(/^#{name}/) + else + [] + end + end + end + + formatter.raw_print_line "\nEnter the method name you want to look up.\n" + + if defined? Readline then + formatter.raw_print_line "You can use tab to autocomplete.\n" + end + + formatter.raw_print_line "Enter a blank line to exit.\n\n" + + loop do + name = if defined? Readline then + Readline.readline ">> " + else + formatter.raw_print_line ">> " + $stdin.gets + end + + return if name.nil? or name.empty? + + name = name.strip + + begin + display_name name + rescue NotFoundError => e + formatter.raw_print_line "#{e.message}\n" + end + end + + rescue Interrupt + exit + end + + ## + # Expands abbreviated klass +klass+ into a fully-qualified klass. "Zl::Da" + # will be expanded to Zlib::DataError. + + def expand_klass(klass) + klass.split('::').inject '' do |expanded, klass_part| + expanded << '::' unless expanded.empty? + short = expanded << klass_part + + subset = class_cache.keys.select do |klass_name| + klass =~ /^#{expanded}[^:]*$/ + end + + abbrevs = Abbrev.abbrev subset + + expanded = abbrevs[short] + + raise NotFoundError, short unless expanded + + expanded.dup + end + end + + ## + # Loads the cache for +klassname+ + + def load_cache_for(klassname) + path = cache_file_for klassname + + cache = nil + + if File.exist? path and + File.mtime(path) >= File.mtime(class_cache_file_path) and + @use_cache then + open path, 'rb' do |fp| + begin + cache = Marshal.load fp.read + rescue + # + # The cache somehow is bad. Recreate the cache. + # + $stderr.puts "Error reading the cache for #{klassname}; recreating the cache!" + cache = create_cache_for klassname, path + end + end + else + cache = create_cache_for klassname, path + end + + cache + end + + ## + # Writes a cache file for +klassname+ to +path+ + + def create_cache_for(klassname, path) + klass = class_cache[klassname] + return nil unless klass + + method_files = klass["sources"] + cache = OpenStructHash.new + + method_files.each do |f| + system_file = f.index(@sys_dir) == 0 + Dir[File.join(File.dirname(f), "*")].each do |yaml| + next unless yaml =~ /yaml$/ + next if yaml =~ /cdesc-[^\/]+yaml$/ + + method = read_yaml yaml + + if system_file then + method["source_path"] = "Ruby #{RDoc::RI::Paths::VERSION}" + else + gem = Gem.path.any? do |gem_path| + pattern = File.join Regexp.escape(gem_path), 'doc', '(.*?)', '' + + f =~ /^#{pattern}/ + end + + method["source_path"] = if gem then + "gem #{$1}" + else + f + end + end + + name = method["full_name"] + cache[name] = method + end + end + + write_cache cache, path + end + + ## + # Finds the next ancestor of +orig_klass+ after +klass+. + + def lookup_ancestor(klass, orig_klass) + # This is a bit hacky, but ri will go into an infinite loop otherwise, + # since Object has an Object ancestor for some reason. Depending on the + # documentation state, I've seen Kernel as an ancestor of Object and not + # as an ancestor of Object. + if orig_klass == "Object" && (klass == "Kernel" || klass == "Object") then + return nil + end + + cache = class_cache[orig_klass] + + return nil unless cache + + ancestors = [orig_klass] + ancestors.push(*cache.includes.map { |inc| inc['name'] }) + ancestors << cache.superclass + + ancestor_index = ancestors.index klass + + if ancestor_index + ancestor = ancestors[ancestors.index(klass) + 1] + return ancestor if ancestor + end + + lookup_ancestor klass, cache.superclass + end + + ## + # Finds the method + + def lookup_method(name, klass) + cache = load_cache_for klass + return nil unless cache + + method = cache[name.gsub('.', '#')] + method = cache[name.gsub('.', '::')] unless method + method + end + + def map_dirs(file_name) + @doc_dirs.map { |dir| yield File.join(dir, file_name) }.flatten.compact + end + + ## + # Extract the class and method name parts from +name+ like Foo::Bar#baz + + def parse_name(name) + parts = name.split(/(::|\#|\.)/) + + if parts[-2] != '::' or parts.last !~ /^[A-Z]/ then + meth = parts.pop + parts.pop + end + + klass = parts.join + + [klass, meth] + end + + ## + # Reads ri YAML data from +path+, converting RDoc 1.x classes to RDoc 2.x + # classes + + def read_yaml(path) + data = File.read path + + # Necessary to be backward-compatible with documentation generated + # by earliar RDoc versions. + data = data.gsub(/ \!ruby\/(object|struct):(RDoc::RI|RI).*/, '') + data = data.gsub(/ \!ruby\/(object|struct):SM::(\S+)/, + ' !ruby/\1:RDoc::Markup::\2') + + OpenStructHash.convert YAML.load(data) + end + + ## + # Looks up and displays ri data according to the options given. + + def run + if @list_doc_dirs then + puts @doc_dirs + elsif @interactive then + interactive + elsif @names.empty? then + @display.list_known_classes class_cache.keys.sort + else + @names.each do |name| + display_name name + end + end + rescue NotFoundError => e + abort e.message + end + + ## + # Selects methods matching +pattern+ from all modules + + def select_methods(pattern) + methods = [] + class_cache.keys.sort.each do |klass| + class_cache[klass]["instance_methods"].map{|h|h["name"]}.grep(pattern) do |name| + method = load_cache_for(klass)[klass+'#'+name] + methods << method if method + end + class_cache[klass]["class_methods"].map{|h|h["name"]}.grep(pattern) do |name| + method = load_cache_for(klass)[klass+'::'+name] + methods << method if method + end + end + methods + end + + ## + # Writes +cache+ to +path+ + + def write_cache(cache, path) + if @use_cache then + File.open path, "wb" do |cache_file| + Marshal.dump cache, cache_file + end + end + + cache + rescue Errno::EISDIR # HACK toplevel, replace with main + cache + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/formatter.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/formatter.rb new file mode 100644 index 000000000..b2c9d07b3 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/formatter.rb @@ -0,0 +1,654 @@ +require 'rdoc/ri' +require 'rdoc/markup' + +class RDoc::RI::Formatter + + attr_writer :indent + attr_accessor :output + + FORMATTERS = { } + + def self.for(name) + FORMATTERS[name.downcase] + end + + def self.list + FORMATTERS.keys.sort.join ", " + end + + def initialize(output, width, indent) + @output = output + @width = width + @indent = indent + @original_indent = indent.dup + end + + def draw_line(label=nil) + len = @width + len -= (label.size + 1) if label + + if len > 0 then + @output.print '-' * len + if label + @output.print ' ' + bold_print label + end + + @output.puts + else + @output.print '-' * @width + @output.puts + + @output.puts label + end + end + + def indent + return @indent unless block_given? + + begin + indent = @indent.dup + @indent += @original_indent + yield + ensure + @indent = indent + end + end + + def wrap(txt, prefix=@indent, linelen=@width) + return unless txt && !txt.empty? + + work = conv_markup(txt) + textLen = linelen - prefix.length + patt = Regexp.new("^(.{0,#{textLen}})[ \n]") + next_prefix = prefix.tr("^ ", " ") + + res = [] + + while work.length > textLen + if work =~ patt + res << $1 + work.slice!(0, $&.length) + else + res << work.slice!(0, textLen) + end + end + res << work if work.length.nonzero? + @output.puts(prefix + res.join("\n" + next_prefix)) + end + + def blankline + @output.puts + end + + ## + # Called when we want to ensure a new 'wrap' starts on a newline. Only + # needed for HtmlFormatter, because the rest do their own line breaking. + + def break_to_newline + end + + def bold_print(txt) + @output.print txt + end + + def raw_print_line(txt) + @output.print txt + end + + ## + # Convert HTML entities back to ASCII + + def conv_html(txt) + txt = txt.gsub(/>/, '>') + txt.gsub!(/</, '<') + txt.gsub!(/"/, '"') + txt.gsub!(/&/, '&') + txt + end + + ## + # Convert markup into display form + + def conv_markup(txt) + txt = txt.gsub(%r{<tt>(.*?)</tt>}, '+\1+') + txt.gsub!(%r{<code>(.*?)</code>}, '+\1+') + txt.gsub!(%r{<b>(.*?)</b>}, '*\1*') + txt.gsub!(%r{<em>(.*?)</em>}, '_\1_') + txt + end + + def display_list(list) + case list.type + when :BULLET + prefixer = proc { |ignored| @indent + "* " } + + when :NUMBER, :UPPERALPHA, :LOWERALPHA then + start = case list.type + when :NUMBER then 1 + when :UPPERALPHA then 'A' + when :LOWERALPHA then 'a' + end + + prefixer = proc do |ignored| + res = @indent + "#{start}.".ljust(4) + start = start.succ + res + end + + when :LABELED, :NOTE then + longest = 0 + + list.contents.each do |item| + if RDoc::Markup::Flow::LI === item and item.label.length > longest then + longest = item.label.length + end + end + + longest += 1 + + prefixer = proc { |li| @indent + li.label.ljust(longest) } + + else + raise ArgumentError, "unknown list type #{list.type}" + end + + list.contents.each do |item| + if RDoc::Markup::Flow::LI === item then + prefix = prefixer.call item + display_flow_item item, prefix + else + display_flow_item item + end + end + end + + def display_flow_item(item, prefix = @indent) + case item + when RDoc::Markup::Flow::P, RDoc::Markup::Flow::LI + wrap(conv_html(item.body), prefix) + blankline + + when RDoc::Markup::Flow::LIST + display_list(item) + + when RDoc::Markup::Flow::VERB + display_verbatim_flow_item(item, @indent) + + when RDoc::Markup::Flow::H + display_heading(conv_html(item.text), item.level, @indent) + + when RDoc::Markup::Flow::RULE + draw_line + + else + raise RDoc::Error, "Unknown flow element: #{item.class}" + end + end + + def display_verbatim_flow_item(item, prefix=@indent) + item.body.split(/\n/).each do |line| + @output.print @indent, conv_html(line), "\n" + end + blankline + end + + def display_heading(text, level, indent) + text = strip_attributes text + + case level + when 1 then + ul = "=" * text.length + @output.puts + @output.puts text.upcase + @output.puts ul + + when 2 then + ul = "-" * text.length + @output.puts + @output.puts text + @output.puts ul + else + @output.print indent, text, "\n" + end + + @output.puts + end + + def display_flow(flow) + flow.each do |f| + display_flow_item(f) + end + end + + def strip_attributes(text) + text.gsub(/(<\/?(?:b|code|em|i|tt)>)/, '') + end + +end + +## +# Handle text with attributes. We're a base class: there are different +# presentation classes (one, for example, uses overstrikes to handle bold and +# underlining, while another using ANSI escape sequences. + +class RDoc::RI::AttributeFormatter < RDoc::RI::Formatter + + BOLD = 1 + ITALIC = 2 + CODE = 4 + + ATTR_MAP = { + "b" => BOLD, + "code" => CODE, + "em" => ITALIC, + "i" => ITALIC, + "tt" => CODE + } + + AttrChar = Struct.new :char, :attr + + class AttributeString + attr_reader :txt + + def initialize + @txt = [] + @optr = 0 + end + + def <<(char) + @txt << char + end + + def empty? + @optr >= @txt.length + end + + # accept non space, then all following spaces + def next_word + start = @optr + len = @txt.length + + while @optr < len && @txt[@optr].char != " " + @optr += 1 + end + + while @optr < len && @txt[@optr].char == " " + @optr += 1 + end + + @txt[start...@optr] + end + end + + ## + # Overrides base class. Looks for <tt>...</tt> etc sequences and generates + # an array of AttrChars. This array is then used as the basis for the + # split. + + def wrap(txt, prefix=@indent, linelen=@width) + return unless txt && !txt.empty? + + txt = add_attributes_to(txt) + next_prefix = prefix.tr("^ ", " ") + linelen -= prefix.size + + line = [] + + until txt.empty? + word = txt.next_word + if word.size + line.size > linelen + write_attribute_text(prefix, line) + prefix = next_prefix + line = [] + end + line.concat(word) + end + + write_attribute_text(prefix, line) if line.length > 0 + end + + protected + + def write_attribute_text(prefix, line) + @output.print prefix + line.each do |achar| + @output.print achar.char + end + @output.puts + end + + def bold_print(txt) + @output.print txt + end + + private + + def add_attributes_to(txt) + tokens = txt.split(%r{(</?(?:b|code|em|i|tt)>)}) + text = AttributeString.new + attributes = 0 + tokens.each do |tok| + case tok + when %r{^</(\w+)>$} then attributes &= ~(ATTR_MAP[$1]||0) + when %r{^<(\w+)>$} then attributes |= (ATTR_MAP[$1]||0) + else + tok.split(//).each {|ch| text << AttrChar.new(ch, attributes)} + end + end + text + end + +end + +## +# This formatter generates overstrike-style formatting, which works with +# pagers such as man and less. + +class RDoc::RI::OverstrikeFormatter < RDoc::RI::AttributeFormatter + + BS = "\C-h" + + def write_attribute_text(prefix, line) + @output.print prefix + + line.each do |achar| + attr = achar.attr + @output.print "_", BS if (attr & (ITALIC + CODE)) != 0 + @output.print achar.char, BS if (attr & BOLD) != 0 + @output.print achar.char + end + + @output.puts + end + + ## + # Draw a string in bold + + def bold_print(text) + text.split(//).each do |ch| + @output.print ch, BS, ch + end + end + +end + +## +# This formatter uses ANSI escape sequences to colorize stuff works with +# pagers such as man and less. + +class RDoc::RI::AnsiFormatter < RDoc::RI::AttributeFormatter + + def initialize(*args) + super + @output.print "\033[0m" + end + + def write_attribute_text(prefix, line) + @output.print prefix + curr_attr = 0 + line.each do |achar| + attr = achar.attr + if achar.attr != curr_attr + update_attributes(achar.attr) + curr_attr = achar.attr + end + @output.print achar.char + end + update_attributes(0) unless curr_attr.zero? + @output.puts + end + + def bold_print(txt) + @output.print "\033[1m#{txt}\033[m" + end + + HEADINGS = { + 1 => ["\033[1;32m", "\033[m"], + 2 => ["\033[4;32m", "\033[m"], + 3 => ["\033[32m", "\033[m"], + } + + def display_heading(text, level, indent) + level = 3 if level > 3 + heading = HEADINGS[level] + @output.print indent + @output.print heading[0] + @output.print strip_attributes(text) + @output.puts heading[1] + end + + private + + ATTR_MAP = { + BOLD => "1", + ITALIC => "33", + CODE => "36" + } + + def update_attributes(attr) + str = "\033[" + for quality in [ BOLD, ITALIC, CODE] + unless (attr & quality).zero? + str << ATTR_MAP[quality] + end + end + @output.print str, "m" + end + +end + +## +# This formatter uses HTML. + +class RDoc::RI::HtmlFormatter < RDoc::RI::AttributeFormatter + + ## + # We depend on HTML4-conforming user agents to ignore an empty p element + + def blankline + @output.puts '<p />' + end + + ## + # Emboldens +text+ + + def bold_print(text) + tag("b") { text } + end + + ## + # Outputs a forced line break element + + def break_to_newline + @output.puts '<br />' + end + + ## + # Outputs heading elements for +text+ with +level+ up to 4. Ignores + # +indent+. + + def display_heading(text, level, indent) + level = 4 if level > 4 + tag("h#{level}") { text } + @output.puts + end + + ## + # Outputs +list+ which is displayed as follows: + # + # BULLET:: unordered list + # NUMBER:: ordered list + # LABELED:: definition list + # NOTE:: table + + def display_list(list) + case list.type + when :BULLET then + list_type = "ul" + prefixer = proc { |ignored| '<li>' } + suffix = '</li>' + + when :NUMBER, :UPPERALPHA, :LOWERALPHA then + list_type = "ol" + prefixer = proc { |ignored| '<li>' } + suffix = '</li>' + + when :LABELED then + list_type = "dl" + prefixer = proc do |li| + "<dt><b>#{escape li.label}</b></dt><dd>" + end + suffix = '</dd>' + + when :NOTE then + list_type = "table" + prefixer = proc do |li| + %{<tr valign="top"><td>#{li.label.gsub(/ /, ' ')}</td><td>} + end + suffix = '</td></tr>' + else + fail "unknown list type" + end + + @output.print "<#{list_type}>" + + list.contents.each do |item| + if item.kind_of? RDoc::Markup::Flow::LI + prefix = prefixer.call item + @output.print prefix + display_flow_item item, prefix + @output.print suffix + else + display_flow_item item + end + end + + @output.print "</#{list_type}>" + end + + ## + # Outputs a preformatted section for +item+. +prefix+ is ignored. + + def display_verbatim_flow_item(item, prefix=@indent) + @output.print '<pre>' + + item.body.split(/\n/).each do |line| + @output.puts escape(line) + end + + @output.puts '</pre>' + end + + ## + # Outputs a horizontal rule element, optionally labeled above with +label+ in + # bold. + + def draw_line(label = nil) + bold_print label if label + + @output.puts "<hr />" + end + + def write_attribute_text(prefix, line) + curr_attr = 0 + + line.each do |achar| + attr = achar.attr + if achar.attr != curr_attr then + update_attributes curr_attr, achar.attr + curr_attr = achar.attr + end + @output.print escape(achar.char) + end + + update_attributes curr_attr, 0 unless curr_attr.zero? + end + + private + + ATTR_MAP = { + BOLD => "b>", + ITALIC => "i>", + CODE => "tt>" + } + + def update_attributes(current, wanted) + str = "" + # first turn off unwanted ones + off = current & ~wanted + for quality in [ BOLD, ITALIC, CODE] + if (off & quality) > 0 + str << "</" + ATTR_MAP[quality] + end + end + + # now turn on wanted + for quality in [ BOLD, ITALIC, CODE] + unless (wanted & quality).zero? + str << "<" << ATTR_MAP[quality] + end + end + @output.print str + end + + def tag(code) + @output.print("<#{code}>") + @output.print(yield) + @output.print("</#{code}>") + end + + def escape(str) + str = str.gsub(/&/n, '&') + str.gsub!(/\"/n, '"') + str.gsub!(/>/n, '>') + str.gsub!(/</n, '<') + str + end + +end + +## +# This formatter reduces extra lines for a simpler output. It improves way +# output looks for tools like IRC bots. + +class RDoc::RI::SimpleFormatter < RDoc::RI::Formatter + + ## + # No extra blank lines + + def blankline + end + + ## + # Display labels only, no lines + + def draw_line(label=nil) + unless label.nil? then + bold_print(label) + @output.puts + end + end + + ## + # Place heading level indicators inline with heading. + + def display_heading(text, level, indent) + text = strip_attributes(text) + case level + when 1 + @output.puts "= " + text.upcase + when 2 + @output.puts "-- " + text + else + @output.print indent, text, "\n" + end + end + +end + +RDoc::RI::Formatter::FORMATTERS['plain'] = RDoc::RI::Formatter +RDoc::RI::Formatter::FORMATTERS['simple'] = RDoc::RI::SimpleFormatter +RDoc::RI::Formatter::FORMATTERS['bs'] = RDoc::RI::OverstrikeFormatter +RDoc::RI::Formatter::FORMATTERS['ansi'] = RDoc::RI::AnsiFormatter +RDoc::RI::Formatter::FORMATTERS['html'] = RDoc::RI::HtmlFormatter diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/paths.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/paths.rb new file mode 100644 index 000000000..2f72b9dfd --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/paths.rb @@ -0,0 +1,93 @@ +require 'rdoc/ri' + +## +# Encapsulate all the strangeness to do with finding out where to find RDoc +# files +# +# We basically deal with three directories: +# +# 1. The 'system' documentation directory, which holds the documentation +# distributed with Ruby, and which is managed by the Ruby install process +# 2. The 'site' directory, which contains site-wide documentation added +# locally. +# 3. The 'user' documentation directory, stored under the user's own home +# directory. +# +# There's contention about all this, but for now: +# +# system:: $datadir/ri/<ver>/system/... +# site:: $datadir/ri/<ver>/site/... +# user:: ~/.rdoc + +module RDoc::RI::Paths + + #:stopdoc: + require 'rbconfig' + + DOC_DIR = "doc/rdoc" + + VERSION = RbConfig::CONFIG['ruby_version'] + + base = File.join(RbConfig::CONFIG['datadir'], "ri", VERSION) + SYSDIR = File.join(base, "system") + SITEDIR = File.join(base, "site") + homedir = ENV['HOME'] || ENV['USERPROFILE'] || ENV['HOMEPATH'] + + if homedir then + HOMEDIR = File.join(homedir, ".rdoc") + else + HOMEDIR = nil + end + + begin + require 'rubygems' unless defined?(Gem) and defined?(Gem::Enable) and + Gem::Enable + + # HACK dup'd from Gem.latest_partials and friends + all_paths = [] + + all_paths = Gem.path.map do |dir| + Dir[File.join(dir, 'doc', '*', 'ri')] + end.flatten + + ri_paths = {} + + all_paths.each do |dir| + base = File.basename File.dirname(dir) + if base =~ /(.*)-((\d+\.)*\d+)/ then + name, version = $1, $2 + ver = Gem::Version.new version + if ri_paths[name].nil? or ver > ri_paths[name][0] then + ri_paths[name] = [ver, dir] + end + end + end + + GEMDIRS = ri_paths.map { |k,v| v.last }.sort + rescue LoadError + GEMDIRS = [] + end + + # Returns the selected documentation directories as an Array, or PATH if no + # overriding directories were given. + + def self.path(use_system, use_site, use_home, use_gems, *extra_dirs) + path = raw_path(use_system, use_site, use_home, use_gems, *extra_dirs) + return path.select { |directory| File.directory? directory } + end + + # Returns the selected documentation directories including nonexistent + # directories. Used to print out what paths were searched if no ri was + # found. + + def self.raw_path(use_system, use_site, use_home, use_gems, *extra_dirs) + path = [] + path << extra_dirs unless extra_dirs.empty? + path << SYSDIR if use_system + path << SITEDIR if use_site + path << HOMEDIR if use_home + path << GEMDIRS if use_gems + + return path.flatten.compact + end +end diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/reader.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/reader.rb new file mode 100644 index 000000000..de3c8d9af --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/reader.rb @@ -0,0 +1,106 @@ +require 'rdoc/ri' +require 'rdoc/ri/descriptions' +require 'rdoc/ri/writer' +require 'rdoc/markup/to_flow' + +class RDoc::RI::Reader + + def initialize(ri_cache) + @cache = ri_cache + end + + def top_level_namespace + [ @cache.toplevel ] + end + + def lookup_namespace_in(target, namespaces) + result = [] + for n in namespaces + result.concat(n.contained_modules_matching(target)) + end + result + end + + def find_class_by_name(full_name) + names = full_name.split(/::/) + ns = @cache.toplevel + for name in names + ns = ns.contained_class_named(name) + return nil if ns.nil? + end + get_class(ns) + end + + def find_methods(name, is_class_method, namespaces) + result = [] + namespaces.each do |ns| + result.concat ns.methods_matching(name, is_class_method) + end + result + end + + ## + # Return the MethodDescription for a given MethodEntry by deserializing the + # YAML + + def get_method(method_entry) + path = method_entry.path_name + File.open(path) { |f| RDoc::RI::Description.deserialize(f) } + end + + ## + # Return a class description + + def get_class(class_entry) + result = nil + for path in class_entry.path_names + path = RDoc::RI::Writer.class_desc_path(path, class_entry) + desc = File.open(path) {|f| RDoc::RI::Description.deserialize(f) } + if result + result.merge_in(desc) + else + result = desc + end + end + result + end + + ## + # Return the names of all classes and modules + + def full_class_names + res = [] + find_classes_in(res, @cache.toplevel) + end + + ## + # Return a list of all classes, modules, and methods + + def all_names + res = [] + find_names_in(res, @cache.toplevel) + end + + private + + def find_classes_in(res, klass) + classes = klass.classes_and_modules + for c in classes + res << c.full_name + find_classes_in(res, c) + end + res + end + + def find_names_in(res, klass) + classes = klass.classes_and_modules + for c in classes + res << c.full_name + res.concat c.all_method_names + find_names_in(res, c) + end + res + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/util.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/util.rb new file mode 100644 index 000000000..4e91eb978 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/util.rb @@ -0,0 +1,79 @@ +require 'rdoc/ri' + +## +# Break argument into its constituent class or module names, an +# optional method type, and a method name + +class RDoc::RI::NameDescriptor + + attr_reader :class_names + attr_reader :method_name + + ## + # true and false have the obvious meaning. nil means we don't care + + attr_reader :is_class_method + + ## + # +arg+ may be + # + # 1. A class or module name (optionally qualified with other class or module + # names (Kernel, File::Stat etc) + # 2. A method name + # 3. A method name qualified by a optionally fully qualified class or module + # name + # + # We're fairly casual about delimiters: folks can say Kernel::puts, + # Kernel.puts, or Kernel\#puts for example. There's one exception: if you + # say IO::read, we look for a class method, but if you say IO.read, we look + # for an instance method + + def initialize(arg) + @class_names = [] + separator = nil + + tokens = arg.split(/(\.|::|#)/) + + # Skip leading '::', '#' or '.', but remember it might + # be a method name qualifier + separator = tokens.shift if tokens[0] =~ /^(\.|::|#)/ + + # Skip leading '::', but remember we potentially have an inst + + # leading stuff must be class names + + while tokens[0] =~ /^[A-Z]/ + @class_names << tokens.shift + unless tokens.empty? + separator = tokens.shift + break unless separator == "::" + end + end + + # Now must have a single token, the method name, or an empty array + unless tokens.empty? + @method_name = tokens.shift + # We may now have a trailing !, ?, or = to roll into + # the method name + if !tokens.empty? && tokens[0] =~ /^[!?=]$/ + @method_name << tokens.shift + end + + if @method_name =~ /::|\.|#/ or !tokens.empty? + raise RDoc::RI::Error.new("Bad argument: #{arg}") + end + if separator && separator != '.' + @is_class_method = separator == "::" + end + end + end + + # Return the full class name (with '::' between the components) or "" if + # there's no class name + + def full_class_name + @class_names.join("::") + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/writer.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/writer.rb new file mode 100644 index 000000000..92aaa1c2d --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/ri/writer.rb @@ -0,0 +1,68 @@ +require 'fileutils' +require 'rdoc/ri' + +class RDoc::RI::Writer + + def self.class_desc_path(dir, class_desc) + File.join(dir, "cdesc-" + class_desc.name + ".yaml") + end + + ## + # Convert a name from internal form (containing punctuation) to an external + # form (where punctuation is replaced by %xx) + + def self.internal_to_external(name) + if ''.respond_to? :ord then + name.gsub(/\W/) { "%%%02x" % $&[0].ord } + else + name.gsub(/\W/) { "%%%02x" % $&[0] } + end + end + + ## + # And the reverse operation + + def self.external_to_internal(name) + name.gsub(/%([0-9a-f]{2,2})/) { $1.to_i(16).chr } + end + + def initialize(base_dir) + @base_dir = base_dir + end + + def remove_class(class_desc) + FileUtils.rm_rf(path_to_dir(class_desc.full_name)) + end + + def add_class(class_desc) + dir = path_to_dir(class_desc.full_name) + FileUtils.mkdir_p(dir) + class_file_name = self.class.class_desc_path(dir, class_desc) + File.open(class_file_name, "w") do |f| + f.write(class_desc.serialize) + end + end + + def add_method(class_desc, method_desc) + dir = path_to_dir(class_desc.full_name) + file_name = self.class.internal_to_external(method_desc.name) + meth_file_name = File.join(dir, file_name) + if method_desc.is_singleton + meth_file_name += "-c.yaml" + else + meth_file_name += "-i.yaml" + end + + File.open(meth_file_name, "w") do |f| + f.write(method_desc.serialize) + end + end + + private + + def path_to_dir(class_name) + File.join(@base_dir, *class_name.split('::')) + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/single_class.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/single_class.rb new file mode 100644 index 000000000..de96a6a36 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/single_class.rb @@ -0,0 +1,8 @@ +require 'rdoc/class_module' + +## +# A singleton class + +class RDoc::SingleClass < RDoc::ClassModule +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/stats.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/stats.rb new file mode 100644 index 000000000..ff5255f9c --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/stats.rb @@ -0,0 +1,178 @@ +require 'rdoc' +require 'thread' + +## +# Simple stats collector + +class RDoc::Stats + + attr_reader :num_classes + attr_reader :num_files + attr_reader :num_methods + attr_reader :num_modules + attr_reader :total_files + + def initialize(total_files, verbosity = 1) + @lock = Mutex.new + + @num_classes = 0 + @num_files = 0 + @num_methods = 0 + @num_modules = 0 + @total_files = total_files + + @start = Time.now + + @display = case verbosity + when 0 then Quiet.new + when 1 then Normal.new(total_files) + else Verbose.new + end + end + + def begin_adding(number_of_workers) + @display.begin_adding(number_of_workers) + end + + def add_alias(as) + @lock.synchronize do + @display.print_alias as + @num_methods += 1 + end + end + + def add_class(klass) + @lock.synchronize do + @display.print_class klass + @num_classes += 1 + end + end + + def add_file(file) + @lock.synchronize do + @display.print_file @num_files, file + @num_files += 1 + end + end + + def add_method(method) + @lock.synchronize do + @display.print_method method + @num_methods += 1 + end + end + + def add_module(mod) + @lock.synchronize do + @display.print_module mod + @num_modules += 1 + end + end + + def done_adding + @lock.synchronize do + @display.done_adding + end + end + + def print + puts "Files: #@num_files" + puts "Classes: #@num_classes" + puts "Modules: #@num_modules" + puts "Methods: #@num_methods" + puts "Elapsed: " + sprintf("%0.1fs", Time.now - @start) + end + + class Quiet + def begin_adding(*) end + def print_alias(*) end + def print_class(*) end + def print_file(*) end + def print_method(*) end + def print_module(*) end + def done_adding(*) end + end + + class Normal + def initialize(total_files) + @total_files = total_files + end + + def begin_adding(number_of_workers) + puts "Parsing sources with #{number_of_workers} thread(s)..." + end + + def print_file(files_so_far, filename) + progress_bar = sprintf("%3d%% [%2d/%2d] ", + 100 * (files_so_far + 1) / @total_files, + files_so_far + 1, + @total_files) + + if $stdout.tty? + # Print a progress bar, but make sure it fits on a single line. Filename + # will be truncated if necessary. + terminal_width = (ENV['COLUMNS'] || 80).to_i + max_filename_size = terminal_width - progress_bar.size + if filename.size > max_filename_size + # Turn "some_long_filename.rb" to "...ong_filename.rb" + filename = filename[(filename.size - max_filename_size) .. -1] + filename[0..2] = "..." + end + + # Pad the line with whitespaces so that leftover output from the + # previous line doesn't show up. + line = "#{progress_bar}#{filename}" + padding = terminal_width - line.size + if padding > 0 + line << (" " * padding) + end + + $stdout.print("#{line}\r") + $stdout.flush + else + puts "#{progress_bar} #{filename}" + end + end + + def done_adding + puts "\n" + end + + def print_alias(*) end + def print_class(*) end + def print_method(*) end + def print_module(*) end + end + + class Verbose + def begin_adding(number_of_workers) + puts "Parsing sources with #{number_of_workers} thread(s)..." + end + + def print_alias(as) + puts "\t\talias #{as.new_name} #{as.old_name}" + end + + def print_class(klass) + puts "\tclass #{klass.full_name}" + end + + def print_file(files_so_far, file) + puts file + end + + def print_method(method) + puts "\t\t#{method.singleton ? '::' : '#'}#{method.name}" + end + + def print_module(mod) + puts "\tmodule #{mod.full_name}" + end + + def done_adding + end + end + +end + + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/task.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/task.rb new file mode 100644 index 000000000..67657be77 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/task.rb @@ -0,0 +1,276 @@ +# Copyright (c) 2003, 2004 Jim Weirich, 2009 Eric Hodel +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +require 'rubygems' +begin + gem 'rdoc' +rescue Gem::LoadError +end + +begin + gem 'rake' +rescue Gem::LoadError +end + +require 'rdoc' +require 'rake' +require 'rake/tasklib' + +## +# Create a documentation task that will generate the RDoc files for a project. +# +# The RDoc::Task will create the following targets: +# +# [<b><em>rdoc</em></b>] +# Main task for this RDoc task. +# +# [<b>:clobber_<em>rdoc</em></b>] +# Delete all the rdoc files. This target is automatically added to the main +# clobber target. +# +# [<b>:re<em>rdoc</em></b>] +# Rebuild the rdoc files from scratch, even if they are not out of date. +# +# Simple Example: +# +# RDoc::Task.new do |rd| +# rd.main = "README.rdoc" +# rd.rdoc_files.include("README.rdoc", "lib/**/*.rb") +# end +# +# The +rd+ object passed to the block is an RDoc::Task object. See the +# attributes list for the RDoc::Task class for available customization options. +# +# == Specifying different task names +# +# You may wish to give the task a different name, such as if you are +# generating two sets of documentation. For instance, if you want to have a +# development set of documentation including private methods: +# +# RDoc::Task.new :rdoc_dev do |rd| +# rd.main = "README.doc" +# rd.rdoc_files.include("README.rdoc", "lib/**/*.rb") +# rd.options << "--all" +# end +# +# The tasks would then be named :<em>rdoc_dev</em>, +# :clobber_<em>rdoc_dev</em>, and :re<em>rdoc_dev</em>. +# +# If you wish to have completely different task names, then pass a Hash as +# first argument. With the <tt>:rdoc</tt>, <tt>:clobber_rdoc</tt> and +# <tt>:rerdoc</tt> options, you can customize the task names to your liking. +# +# For example: +# +# RDoc::Task.new(:rdoc => "rdoc", :clobber_rdoc => "rdoc:clean", +# :rerdoc => "rdoc:force") +# +# This will create the tasks <tt>:rdoc</tt>, <tt>:rdoc_clean</tt> and +# <tt>:rdoc:force</tt>. + +class RDoc::Task < Rake::TaskLib + + ## + # Name of the main, top level task. (default is :rdoc) + + attr_accessor :name + + ## + # Name of directory to receive the html output files. (default is "html") + + attr_accessor :rdoc_dir + + ## + # Title of RDoc documentation. (defaults to rdoc's default) + + attr_accessor :title + + ## + # Name of file to be used as the main, top level file of the RDoc. (default + # is none) + + attr_accessor :main + + ## + # Name of template to be used by rdoc. (defaults to rdoc's default) + + attr_accessor :template + + ## + # List of files to be included in the rdoc generation. (default is []) + + attr_accessor :rdoc_files + + ## + # Additional list of options to be passed rdoc. (default is []) + + attr_accessor :options + + ## + # Whether to run the rdoc process as an external shell (default is false) + + attr_accessor :external + + ## + # Create an RDoc task with the given name. See the RDoc::Task class overview + # for documentation. + + def initialize(name = :rdoc) # :yield: self + if name.is_a? Hash then + invalid_options = name.keys.map { |k| k.to_sym } - + [:rdoc, :clobber_rdoc, :rerdoc] + + unless invalid_options.empty? then + raise ArgumentError, "invalid options: #{invalid_options.join(", ")}" + end + end + + @name = name + @rdoc_files = Rake::FileList.new + @rdoc_dir = 'html' + @main = nil + @title = nil + @template = nil + @external = false + @options = [] + yield self if block_given? + define + end + + ## + # Create the tasks defined by this task lib. + + def define + if rdoc_task_name != "rdoc" then + desc "Build the RDoc HTML Files" + else + desc "Build the #{rdoc_task_name} HTML Files" + end + task rdoc_task_name + + desc "Force a rebuild of the RDoc files" + task rerdoc_task_name => [clobber_task_name, rdoc_task_name] + + desc "Remove RDoc products" + task clobber_task_name do + rm_r rdoc_dir rescue nil + end + + task :clobber => [clobber_task_name] + + directory @rdoc_dir + task rdoc_task_name => [rdoc_target] + file rdoc_target => @rdoc_files + [Rake.application.rakefile] do + rm_r @rdoc_dir rescue nil + @before_running_rdoc.call if @before_running_rdoc + args = option_list + @rdoc_files + + if @external then + argstring = args.join(' ') + sh %{ruby -Ivendor vendor/rd #{argstring}} + else + if Rake.application.options.trace then + $stderr.puts "rdoc #{args.join ' '}" + end + require 'rdoc/rdoc' + RDoc::RDoc.new.document(args) + end + end + + self + end + + def option_list + result = @options.dup + result << "-o" << @rdoc_dir + result << "--main" << quote(main) if main + result << "--title" << quote(title) if title + result << "-T" << quote(template) if template + result + end + + def quote(str) + if @external + "'#{str}'" + else + str + end + end + + def option_string + option_list.join(' ') + end + + ## + # The block passed to this method will be called just before running the + # RDoc generator. It is allowed to modify RDoc::Task attributes inside the + # block. + + def before_running_rdoc(&block) + @before_running_rdoc = block + end + + private + + def rdoc_target + "#{rdoc_dir}/index.html" + end + + def rdoc_task_name + case name + when Hash + (name[:rdoc] || "rdoc").to_s + else + name.to_s + end + end + + def clobber_task_name + case name + when Hash + (name[:clobber_rdoc] || "clobber_rdoc").to_s + else + "clobber_#{name}" + end + end + + def rerdoc_task_name + case name + when Hash + (name[:rerdoc] || "rerdoc").to_s + else + "re#{name}" + end + end + +end + +# :stopdoc: +module Rake + + ## + # For backwards compatibility + + RDocTask = RDoc::Task + +end +# :startdoc: + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/tokenstream.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/tokenstream.rb new file mode 100644 index 000000000..0a1eb9130 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/tokenstream.rb @@ -0,0 +1,33 @@ +module RDoc; end + +## +# A TokenStream is a list of tokens, gathered during the parse of some entity +# (say a method). Entities populate these streams by being registered with the +# lexer. Any class can collect tokens by including TokenStream. From the +# outside, you use such an object by calling the start_collecting_tokens +# method, followed by calls to add_token and pop_token. + +module RDoc::TokenStream + + def token_stream + @token_stream + end + + def start_collecting_tokens + @token_stream = [] + end + + def add_token(tk) + @token_stream << tk + end + + def add_tokens(tks) + tks.each {|tk| add_token(tk)} + end + + def pop_token + @token_stream.pop + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/lib/rdoc/top_level.rb b/vendor/gems/rdoc-2.4.3/lib/rdoc/top_level.rb new file mode 100644 index 000000000..5db404cc2 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/lib/rdoc/top_level.rb @@ -0,0 +1,242 @@ +require 'thread' +require 'rdoc/context' + +## +# A TopLevel context is a representation of the contents of a single file + +class RDoc::TopLevel < RDoc::Context + + ## + # This TopLevel's File::Stat struct + + attr_accessor :file_stat + + ## + # Relative name of this file + + attr_accessor :relative_name + + ## + # Absolute name of this file + + attr_accessor :absolute_name + + attr_accessor :diagram + + ## + # The parser that processed this file + + attr_accessor :parser + + ## + # Returns all classes and modules discovered by RDoc + + def self.all_classes_and_modules + classes_hash.values + modules_hash.values + end + + ## + # Returns all classes discovered by RDoc + + def self.classes + classes_hash.values + end + + ## + # Hash of all classes known to RDoc + + def self.classes_hash + @all_classes + end + + ## + # All TopLevels known to RDoc + + def self.files + @all_files.values + end + + ## + # Hash of all files known to RDoc + + def self.files_hash + @all_files + end + + ## + # Finds the class with +name+ in all discovered classes + + def self.find_class_named(name) + @lock.synchronize do + classes_hash.values.find do |c| + c.find_class_named name + end + end + end + + ## + # Finds the file with +name+ in all discovered files + + def self.find_file_named(name) + @lock.synchronize do + @all_files[name] + end + end + + ## + # Finds the module with +name+ in all discovered modules + + def self.find_module_named(name) + @lock.synchronize do + modules_hash.values.find do |c| + c.find_module_named name + end + end + end + + @lock = Mutex.new + + ## + # Lock for global class, module and file stores + + def self.lock + @lock + end + + ## + # Returns all modules discovered by RDoc + + def self.modules + modules_hash.values + end + + ## + # Hash of all modules known to RDoc + + def self.modules_hash + @all_modules + end + + ## + # Empties RDoc of stored class, module and file information + + def self.reset + @lock.synchronize do + @all_classes = {} + @all_modules = {} + @all_files = {} + end + end + + reset + + ## + # Creates a new TopLevel for +file_name+ + + def initialize(file_name) + super() + @name = nil + @relative_name = file_name + @absolute_name = file_name + @file_stat = File.stat(file_name) rescue nil # HACK for testing + @diagram = nil + @parser = nil + + RDoc::TopLevel.lock.synchronize do + RDoc::TopLevel.files_hash[file_name] = self + end + end + + ## + # Adds +method+ to Object instead of RDoc::TopLevel + + def add_method(method) + object = self.class.find_class_named 'Object' + object = add_class RDoc::NormalClass, 'Object' unless object + + object.add_method method + end + + ## + # Base name of this file + + def base_name + File.basename @absolute_name + end + + ## + # Find class or module named +symbol+ in all discovered classes and + # modules + + def find_class_or_module_named(symbol) + RDoc::TopLevel.classes_hash.each_value do |c| + return c if c.full_name == symbol + end + + RDoc::TopLevel.modules_hash.each_value do |m| + return m if m.full_name == symbol + end + + nil + end + + ## + # Finds a class or module named +symbol+ + + def find_local_symbol(symbol) + find_class_or_module_named(symbol) || super + end + + ## + # Finds a module or class with +name+ + + def find_module_named(name) + find_class_or_module_named(name) || find_enclosing_module_named(name) + end + + ## + # The name of this file + + def full_name + @relative_name + end + + ## + # URL for this with a +prefix+ + + def http_url(prefix) + path = [prefix, @relative_name.tr('.', '_')] + + File.join(*path.compact) + '.html' + end + + def inspect # :nodoc: + "#<%s:0x%x %p modules: %p classes: %p>" % [ + self.class, object_id, + base_name, + @modules.map { |n,m| m }, + @classes.map { |n,c| c } + ] + end + + ## + # Date this file was last modified, if known + + def last_modified + @file_stat ? file_stat.mtime.to_s : 'Unknown' + end + + ## + # Base name of this file + + alias name base_name + + ## + # Path to this file + + def path + http_url RDoc::RDoc.current.generator.file_dir + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/test/binary.dat b/vendor/gems/rdoc-2.4.3/test/binary.dat Binary files differnew file mode 100644 index 000000000..371950efe --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/binary.dat diff --git a/vendor/gems/rdoc-2.4.3/test/test.ja.rdoc b/vendor/gems/rdoc-2.4.3/test/test.ja.rdoc new file mode 100644 index 000000000..96e1db93d --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test.ja.rdoc @@ -0,0 +1,8 @@ +こんにちは! + +初めまして。アーロンと申します。 + +どんな食べ物が好きですか?私はフランスの料理が大好きです。 +日本の料理も大好きです。 + +食べ物を食べるのが大好きだけど、お皿を洗うのが大嫌いです。 diff --git a/vendor/gems/rdoc-2.4.3/test/test.ja.txt b/vendor/gems/rdoc-2.4.3/test/test.ja.txt new file mode 100644 index 000000000..96e1db93d --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test.ja.txt @@ -0,0 +1,8 @@ +こんにちは! + +初めまして。アーロンと申します。 + +どんな食べ物が好きですか?私はフランスの料理が大好きです。 +日本の料理も大好きです。 + +食べ物を食べるのが大好きだけど、お皿を洗うのが大嫌いです。 diff --git a/vendor/gems/rdoc-2.4.3/test/test_attribute_manager.rb b/vendor/gems/rdoc-2.4.3/test/test_attribute_manager.rb new file mode 100644 index 000000000..ee45c0596 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_attribute_manager.rb @@ -0,0 +1,76 @@ +require 'rubygems' +require 'minitest/unit' +require 'rdoc/markup/attribute_manager' + +class TestAttributeManager < MiniTest::Unit::TestCase + + def setup + @am = RDoc::Markup::AttributeManager.new + @klass = RDoc::Markup::AttributeManager + end + + def teardown + silently do + @klass.const_set(:MATCHING_WORD_PAIRS, {}) + @klass.const_set(:WORD_PAIR_MAP, {}) + @klass.const_set(:HTML_TAGS, {}) + end + end + + def test_initial_word_pairs + word_pairs = @klass::MATCHING_WORD_PAIRS + assert word_pairs.is_a?(Hash) + assert_equal(3, word_pairs.size) + end + + def test_initial_html + html_tags = @klass::HTML_TAGS + assert html_tags.is_a?(Hash) + assert_equal(5, html_tags.size) + end + + def test_add_matching_word_pair + @am.add_word_pair("x","x", :TEST) + word_pairs = @klass::MATCHING_WORD_PAIRS + assert_equal(4,word_pairs.size) + assert(word_pairs.has_key?("x")) + end + + def test_add_invalid_word_pair + assert_raises ArgumentError do + @am.add_word_pair("<", "<", :TEST) + end + end + + def test_add_word_pair_map + @am.add_word_pair("x", "y", :TEST) + word_pair_map = @klass::WORD_PAIR_MAP + assert_equal(1,word_pair_map.size) + assert_equal(word_pair_map. keys.first.source, "(x)(\\S+)(y)") + end + + def test_add_html_tag + @am.add_html("Test", :TEST) + tags = @klass::HTML_TAGS + assert_equal(6, tags.size) + assert(tags.has_key?("test")) + end + + def test_add_special + @am.add_special("WikiWord", :WIKIWORD) + specials = @klass::SPECIAL + assert_equal(1,specials.size) + assert(specials.has_key?("WikiWord")) + end + + def silently(&block) + warn_level = $VERBOSE + $VERBOSE = nil + result = block.call + $VERBOSE = warn_level + result + end + +end + +MiniTest::Unit.autorun diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_any_method.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_any_method.rb new file mode 100644 index 000000000..a4e30c42b --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_any_method.rb @@ -0,0 +1,10 @@ +require 'test/xref_test_case' + +class RDocAnyMethodTest < XrefTestCase + + def test_full_name + assert_equal 'C1::m', @c1.method_list.first.full_name + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_code_object.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_code_object.rb new file mode 100644 index 000000000..282ca1ecc --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_code_object.rb @@ -0,0 +1,80 @@ +require 'rubygems' +require 'minitest/unit' +require 'test/xref_test_case' +require 'rdoc/code_object' + +class TestRDocCodeObject < XrefTestCase + + def setup + super + + @co = RDoc::CodeObject.new + end + + def test_initialize + assert @co.document_self, 'document_self' + assert @co.document_children, 'document_children' + refute @co.force_documentation, 'force_documentation' + refute @co.done_documenting, 'done_documenting' + assert_equal nil, @co.comment, 'comment is nil' + end + + def test_comment_equals + @co.comment = '' + + assert_equal nil, @co.comment + + @co.comment = 'I am a comment' + + assert_equal 'I am a comment', @co.comment + end + + def test_document_children_equals + @co.document_children = false + refute @co.document_children + + @c2.document_children = false + assert_empty @c2.classes + end + + def test_document_self_equals + @co.document_self = false + refute @co.document_self + + @c1.document_self = false + assert_empty @c1.method_list + end + + def test_parent_file_name + assert_equal '(unknown)', @co.parent_file_name + assert_equal 'xref_data.rb', @c1.parent_file_name + end + + def test_parent_name + assert_equal '(unknown)', @co.parent_name + assert_equal 'xref_data.rb', @c1.parent_name + assert_equal 'C2', @c2_c3.parent_name + end + + def test_start_doc + @co.document_self = false + @co.document_children = false + + @co.start_doc + + assert @co.document_self + assert @co.document_children + end + + def test_stop_doc + @co.document_self = true + @co.document_children = true + + @co.stop_doc + + refute @co.document_self + refute @co.document_children + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_constant.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_constant.rb new file mode 100644 index 000000000..9ec697224 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_constant.rb @@ -0,0 +1,15 @@ +require 'test/xref_test_case' + +class TestRDocConstant < XrefTestCase + + def setup + super + + @const = @c1.constants.first + end + + def test_path + assert_equal 'C1.html#CONST', @const.path + end + +end diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_context.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_context.rb new file mode 100644 index 000000000..6360c5837 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_context.rb @@ -0,0 +1,250 @@ +require 'rubygems' +require 'minitest/unit' +require 'test/xref_test_case' + +class TestRDocContext < XrefTestCase + + def setup + super + + @context = RDoc::Context.new + end + + def test_initialize + assert_empty @context.in_files + assert_equal 'unknown', @context.name + assert_equal '', @context.comment + assert_equal nil, @context.parent + assert_equal :public, @context.visibility + assert_equal 1, @context.sections.length + + assert_empty @context.classes_hash + assert_empty @context.modules_hash + + assert_empty @context.method_list + assert_empty @context.attributes + assert_empty @context.aliases + assert_empty @context.requires + assert_empty @context.includes + assert_empty @context.constants + end + + def test_add_alias + as = RDoc::Alias.new nil, 'old_name', 'new_name', 'comment' + + @context.add_alias as + + assert_equal [as], @context.aliases + assert_equal [as], @context.unmatched_alias_lists['old_name'] + end + + def test_add_alias_method + meth = RDoc::AnyMethod.new nil, 'old_name' + as = RDoc::Alias.new nil, 'old_name', 'new_name', 'comment' + as.parent = @context + + @context.add_method meth + @context.add_alias as + + assert_empty @context.aliases + assert_empty @context.unmatched_alias_lists + assert_equal %w[old_name new_name], @context.method_list.map { |m| m.name } + end + + def test_add_class + @c1.add_class RDoc::NormalClass, 'Klass', 'Object' + + assert_includes @c1.classes.map { |k| k.full_name }, 'C1::Klass' + assert_includes RDoc::TopLevel.classes.map { |k| k.full_name }, 'C1::Klass' + end + + def test_add_class_upgrade + @c1.add_module RDoc::NormalModule, 'Klass' + @c1.add_class RDoc::NormalClass, 'Klass', nil + + assert_includes @c1.classes.map { |k| k.full_name }, 'C1::Klass', + 'c1 classes' + refute_includes @c1.modules.map { |k| k.full_name }, 'C1::Klass', + 'c1 modules' + + assert_includes RDoc::TopLevel.classes.map { |k| k.full_name }, 'C1::Klass', + 'TopLevel classes' + refute_includes RDoc::TopLevel.modules.map { |k| k.full_name }, 'C1::Klass', + 'TopLevel modules' + end + + def test_add_constant + const = RDoc::Constant.new 'NAME', 'value', 'comment' + @context.add_constant const + + assert_equal [const], @context.constants + end + + def test_add_include + incl = RDoc::Include.new 'Name', 'comment' + @context.add_include incl + + assert_equal [incl], @context.includes + end + + def test_add_method + meth = RDoc::AnyMethod.new nil, 'old_name' + meth.visibility = nil + + @context.add_method meth + + assert_equal [meth], @context.method_list + assert_equal :public, meth.visibility + end + + def test_add_method_alias + as = RDoc::Alias.new nil, 'old_name', 'new_name', 'comment' + meth = RDoc::AnyMethod.new nil, 'old_name' + + @context.add_alias as + refute_empty @context.aliases + + @context.add_method meth + + assert_empty @context.aliases + assert_empty @context.unmatched_alias_lists + assert_equal %w[old_name new_name], @context.method_list.map { |m| m.name } + end + + def test_add_module + @c1.add_module RDoc::NormalModule, 'Mod' + + assert_includes @c1.modules.map { |m| m.full_name }, 'C1::Mod' + end + + def test_add_module_class + k = @c1.add_class RDoc::NormalClass, 'Klass', nil + m = @c1.add_module RDoc::NormalModule, 'Klass' + + assert_equal k, m, 'returns class' + assert_empty @c1.modules + end + + def test_add_require + req = RDoc::Require.new 'require', 'comment' + @c1.add_require req + + assert_empty @c1.requires + assert_includes @c1.top_level.requires, req + end + + def test_add_to + incl = RDoc::Include.new 'Name', 'comment' + arr = [] + @context.add_to arr, incl + + assert_includes arr, incl + assert_equal @context, incl.parent + assert_equal @context.current_section, incl.section + end + + def test_add_to_no_document_self + incl = RDoc::Include.new 'Name', 'comment' + arr = [] + @context.document_self = false + @context.add_to arr, incl + + refute_includes arr, incl + end + + def test_add_to_done_documenting + incl = RDoc::Include.new 'Name', 'comment' + arr = [] + @context.done_documenting = true + @context.add_to arr, incl + + refute_includes arr, incl + end + + def test_classes + assert_equal %w[C2::C3], @c2.classes.map { |k| k.full_name } + assert_equal %w[C3::H1 C3::H2], @c3.classes.map { |k| k.full_name } + end + + def test_defined_in_eh + assert @c1.defined_in?(@c1.top_level) + + refute @c1.defined_in?(RDoc::TopLevel.new('name.rb')) + end + + def test_equals2 + assert_equal @c3, @c3 + refute_equal @c2, @c3 + refute_equal @c2_c3, @c3 + end + + def test_find_attribute_named + assert_equal nil, @c1.find_attribute_named('none') + assert_equal 'R', @c1.find_attribute_named('attr').rw + assert_equal 'R', @c1.find_attribute_named('attr_reader').rw + assert_equal 'W', @c1.find_attribute_named('attr_writer').rw + assert_equal 'RW', @c1.find_attribute_named('attr_accessor').rw + end + + def test_find_constant_named + assert_equal nil, @c1.find_constant_named('NONE') + assert_equal ':const', @c1.find_constant_named('CONST').value + end + + def test_find_enclosing_module_named + assert_equal nil, @c2_c3.find_enclosing_module_named('NONE') + assert_equal @c1, @c2_c3.find_enclosing_module_named('C1') + assert_equal @c2, @c2_c3.find_enclosing_module_named('C2') + end + + def test_find_file_named + assert_equal nil, @c1.find_file_named('nonexistent.rb') + assert_equal @xref_data, @c1.find_file_named(@file_name) + end + + def test_find_instance_method_named + assert_equal nil, @c1.find_instance_method_named('none') + + m = @c1.find_instance_method_named('m') + assert_instance_of RDoc::AnyMethod, m + assert_equal false, m.singleton + end + + def test_find_local_symbol + assert_equal true, @c1.find_local_symbol('m').singleton + assert_equal ':const', @c1.find_local_symbol('CONST').value + assert_equal 'R', @c1.find_local_symbol('attr').rw + assert_equal @xref_data, @c1.find_local_symbol(@file_name) + assert_equal @c2_c3, @c2.find_local_symbol('C3') + end + + def test_find_method_named + assert_equal true, @c1.find_method_named('m').singleton + end + + def test_find_module_named + assert_equal @c2_c3, @c2.find_module_named('C3') + assert_equal @c2, @c2.find_module_named('C2') + assert_equal @c1, @c2.find_module_named('C1') + + assert_equal 'C2::C3', @c2.find_module_named('C3').full_name + end + + def test_find_symbol + c3 = @xref_data.find_module_named('C3') + assert_equal c3, @xref_data.find_symbol('C3') + assert_equal c3, @c2.find_symbol('::C3') + assert_equal @c2_c3, @c2.find_symbol('C3') + end + + def test_spaceship + assert_equal(-1, @c2.<=>(@c3)) + assert_equal 0, @c2.<=>(@c2) + assert_equal 1, @c3.<=>(@c2) + + assert_equal 1, @c2_c3.<=>(@c2) + assert_equal(-1, @c2_c3.<=>(@c3)) + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_include.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_include.rb new file mode 100644 index 000000000..6e305dd13 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_include.rb @@ -0,0 +1,17 @@ +require 'test/xref_test_case' + +class TestRDocInclude < XrefTestCase + + def setup + super + + @inc = RDoc::Include.new 'M1', 'comment' + end + + def test_module + assert_equal @m1, @inc.module + assert_equal 'Unknown', RDoc::Include.new('Unknown', 'comment').module + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_markup.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_markup.rb new file mode 100644 index 000000000..ce962a2c5 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_markup.rb @@ -0,0 +1,626 @@ +require 'rubygems' +require 'minitest/unit' +require 'rdoc/markup' +require 'rdoc/markup/to_test' + +class TestRDocMarkup < MiniTest::Unit::TestCase + + def basic_conv(str) + sm = RDoc::Markup.new + mock = RDoc::Markup::ToTest.new + sm.convert(str, mock) + sm.content + end + + def line_groups(str, expected) + m = RDoc::Markup.new + mock = RDoc::Markup::ToTest.new + + block = m.convert(str, mock) + + unless block == expected then + 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 line_types(str, expected) + m = RDoc::Markup.new + mock = RDoc::Markup::ToTest.new + m.convert(str, mock) + assert_equal(expected, m.get_line_types.map{|type| type.to_s[0,1]}.join('')) + 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: BULLET ListItem\nl1", + "L1: BULLET 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: BULLET ListItem\nl1 l1+", + "L1: BULLET 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: BULLET ListItem\nl1", + "L2: ListStart\n", + "L2: BULLET ListItem\nl1.1", + "L2: ListEnd\n", + "L1: BULLET 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: BULLET ListItem\nl1", + "L2: ListStart\n", + "L2: BULLET ListItem\nl1.1 text", + "L2: Verbatim\n code\n code\n", + "L2: Paragraph\ntext", + "L2: ListEnd\n", + "L1: BULLET 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: NUMBER ListItem\nl1", + "L2: ListStart\n", + "L2: BULLET ListItem\nl1.1", + "L2: ListEnd\n", + "L1: NUMBER 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: LABELED ListItem\ncat: l1", + "L2: ListStart\n", + "L2: BULLET ListItem\nl1.1", + "L2: ListEnd\n", + "L1: LABELED ListItem\ndog: l2", + "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: LABELED ListItem\ncat: l1 continuation", + "L1: LABELED ListItem\ndog: l2", + "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 + + def test_list_alpha + str = "a. alpha\nb. baker\nB. ALPHA\nA. BAKER" + + line_groups(str, + [ "L1: ListStart\n", + "L1: LOWERALPHA ListItem\nalpha", + "L1: LOWERALPHA ListItem\nbaker", + "L1: ListEnd\n", + "L1: ListStart\n", + "L1: UPPERALPHA ListItem\nALPHA", + "L1: UPPERALPHA ListItem\nBAKER", + "L1: ListEnd\n" ]) + end + + def test_list_bullet_dash + str = "- one\n- two\n" + + line_groups(str, + [ "L1: ListStart\n", + "L1: BULLET ListItem\none", + "L1: BULLET ListItem\ntwo", + "L1: ListEnd\n" ]) + end + + def test_list_bullet_star + str = "* one\n* two\n" + + line_groups(str, + [ "L1: ListStart\n", + "L1: BULLET ListItem\none", + "L1: BULLET ListItem\ntwo", + "L1: ListEnd\n" ]) + end + + def test_list_labeled_bracket + str = "[one] item one\n[two] item two" + + line_groups(str, + [ "L1: ListStart\n", + "L1: LABELED ListItem\none: item one", + "L1: LABELED ListItem\ntwo: item two", + "L1: ListEnd\n" ]) + end + + def test_list_labeled_bracket_continued + str = "[one]\n item one\n[two]\n item two" + + line_groups(str, + [ "L1: ListStart\n", + "L1: LABELED ListItem\none: item one", + "L1: LABELED ListItem\ntwo: item two", + "L1: ListEnd\n" ]) + end + + def test_list_labeled_colon + str = "one:: item one\ntwo:: item two" + + line_groups(str, + [ "L1: ListStart\n", + "L1: NOTE ListItem\none:: item one", + "L1: NOTE ListItem\ntwo:: item two", + "L1: ListEnd\n" ]) + end + + def test_list_labeled_colon_continued + str = "one::\n item one\ntwo::\n item two" + + line_groups(str, + [ "L1: ListStart\n", + "L1: NOTE ListItem\none:: item one", + "L1: NOTE ListItem\ntwo:: item two", + "L1: ListEnd\n" ]) + end + + def test_list_nested_bullet_bullet + str = "* one\n* two\n * cat\n * dog" + + line_groups(str, + [ "L1: ListStart\n", + "L1: BULLET ListItem\none", + "L1: BULLET ListItem\ntwo", + "L2: ListStart\n", + "L2: BULLET ListItem\ncat", + "L2: BULLET ListItem\ndog", + "L2: ListEnd\n", + "L1: ListEnd\n" ]) + end + + def test_list_nested_labeled_bullet + str = "[one]\n * cat\n * dog" + + line_groups(str, + [ "L1: ListStart\n", + "L1: LABELED ListItem\none: ", + "L2: ListStart\n", + "L2: BULLET ListItem\ncat", + "L2: BULLET ListItem\ndog", + "L2: ListEnd\n", + "L1: ListEnd\n" ]) + end + + def test_list_nested_labeled_bullet_bullet + str = "[one]\n * cat\n * dog" + + line_groups(str, + [ "L1: ListStart\n", + "L1: LABELED ListItem\none: ", + "L2: ListStart\n", + "L2: BULLET ListItem\ncat", + "L3: ListStart\n", + "L3: BULLET ListItem\ndog", + "L3: ListEnd\n", + "L2: ListEnd\n", + "L1: ListEnd\n" ]) + end + + def test_list_nested_number_number + str = "1. one\n1. two\n 1. cat\n 1. dog" + + line_groups(str, + [ "L1: ListStart\n", + "L1: NUMBER ListItem\none", + "L1: NUMBER ListItem\ntwo", + "L2: ListStart\n", + "L2: NUMBER ListItem\ncat", + "L2: NUMBER ListItem\ndog", + "L2: ListEnd\n", + "L1: ListEnd\n" ]) + end + + def test_list_number + str = "1. one\n2. two\n1. three" + + line_groups(str, + [ "L1: ListStart\n", + "L1: NUMBER ListItem\none", + "L1: NUMBER ListItem\ntwo", + "L1: NUMBER ListItem\nthree", + "L1: ListEnd\n" ]) + 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: BULLET ListItem\nl1", + "L1: ListEnd\n", + "L1: ListStart\n", + "L1: NUMBER ListItem\nn1", + "L1: NUMBER ListItem\nn2", + "L1: ListEnd\n", + "L1: ListStart\n", + "L1: BULLET ListItem\nl2", + "L1: ListEnd\n", + "L0: Paragraph\nthe time" + ]) + + end + + def test_list_verbatim + str = "* one\n verb1\n verb2\n* two\n" + + line_groups(str, + [ "L1: ListStart\n", + "L1: BULLET ListItem\none", + "L1: Verbatim\n verb1\n verb2\n", + "L1: BULLET ListItem\ntwo", + "L1: ListEnd\n" ]) + end + + def test_paragraph + str = "paragraph\n\n*bold* paragraph\n" + + line_groups str, [ + "L0: Paragraph\nparagraph", + "L0: BlankLine\n", + "L0: Paragraph\n*bold* paragraph" + ] + 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_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_verbatim + str = "paragraph\n *bold* verbatim\n" + + line_groups str, [ + "L0: Paragraph\nparagraph", + "L0: Verbatim\n *bold* verbatim\n" + ] + 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_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 + +end + +MiniTest::Unit.autorun diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_markup_attribute_manager.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_markup_attribute_manager.rb new file mode 100644 index 000000000..0864523a0 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_markup_attribute_manager.rb @@ -0,0 +1,243 @@ +require "rubygems" +require "minitest/unit" +require "rdoc/markup/inline" +require "rdoc/markup/to_html_crossref" + +class TestRDocMarkupAttributeManager < MiniTest::Unit::TestCase + + def setup + @orig_special = RDoc::Markup::AttributeManager::SPECIAL + RDoc::Markup::AttributeManager::SPECIAL.replace Hash.new + + @am = RDoc::Markup::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 teardown + RDoc::Markup::AttributeManager::SPECIAL.replace @orig_special + end + + def crossref(text) + crossref_bitmap = RDoc::Markup::Attribute.bitmap_for(:_SPECIAL_) | + RDoc::Markup::Attribute.bitmap_for(:CROSSREF) + + [ @am.changed_attribute_by_name([], [:CROSSREF, :_SPECIAL_]), + RDoc::Markup::Special.new(crossref_bitmap, text), + @am.changed_attribute_by_name([:CROSSREF, :_SPECIAL_], []) + ] + 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 + + def test_add_word_pair + @am.add_word_pair '%', '&', 'percent and' + + assert RDoc::Markup::AttributeManager::WORD_PAIR_MAP.include?(/(%)(\S+)(&)/) + assert RDoc::Markup::AttributeManager::PROTECTABLE.include?('%') + assert !RDoc::Markup::AttributeManager::PROTECTABLE.include?('&') + end + + def test_add_word_pair_angle + e = assert_raises ArgumentError do + @am.add_word_pair '<', '>', 'angles' + end + + assert_equal "Word flags may not start with '<'", e.message + end + + def test_add_word_pair_matching + @am.add_word_pair '^', '^', 'caret' + + assert RDoc::Markup::AttributeManager::MATCHING_WORD_PAIRS.include?('^') + assert RDoc::Markup::AttributeManager::PROTECTABLE.include?('^') + 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_bold + assert_equal [@bold_on, 'bold', @bold_off], + @am.flow("*bold*") + + assert_equal [@bold_on, 'Bold:', @bold_off], + @am.flow("*Bold:*") + + assert_equal [@bold_on, '\\bold', @bold_off], + @am.flow("*\\bold*") + end + + def test_bold_html_escaped + assert_equal ['cat <b>dog</b>'], @am.flow('cat \<b>dog</b>') + 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_convert_attrs + str = '+foo+' + attrs = RDoc::Markup::AttrSpan.new str.length + + @am.convert_attrs str, attrs + + assert_equal "\000foo\000", str + + str = '+:foo:+' + attrs = RDoc::Markup::AttrSpan.new str.length + + @am.convert_attrs str, attrs + + assert_equal "\000:foo:\000", str + + str = '+x-y+' + attrs = RDoc::Markup::AttrSpan.new str.length + + @am.convert_attrs str, attrs + + assert_equal "\000x-y\000", str + end + + def test_html_like_em_bold + assert_equal ["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off], + @am.flow("cat <i>and </i><b>dog</b>") + end + + def test_html_like_em_bold_SGML + assert_equal ["cat ", @em_on, "and ", @em_to_bold, "dog", @bold_off], + @am.flow("cat <i>and <b></i>dog</b>") + end + + def test_html_like_em_bold_nested_1 + assert_equal(["cat ", @bold_em_on, "and", @bold_em_off, " dog"], + @am.flow("cat <i><b>and</b></i> dog")) + end + + def test_html_like_em_bold_nested_2 + assert_equal ["cat ", @em_on, "and ", @em_then_bold, "dog", @bold_em_off], + @am.flow("cat <i>and <b>dog</b></i>") + end + + def test_html_like_em_bold_nested_mixed_case + assert_equal ["cat ", @em_on, "and ", @em_then_bold, "dog", @bold_em_off], + @am.flow("cat <i>and <B>dog</B></I>") + end + + def test_html_like_em_bold_mixed_case + assert_equal ["cat ", @em_on, "and", @em_off, " ", @bold_on, "dog", @bold_off], + @am.flow("cat <i>and</i> <B>dog</b>") + end + + def test_html_like_teletype + assert_equal ["cat ", @tt_on, "dog", @tt_off], + @am.flow("cat <tt>dog</Tt>") + end + + def test_html_like_teletype_em_bold_SGML + assert_equal [@tt_on, "cat", @tt_off, " ", @em_on, "and ", @em_to_bold, "dog", @bold_off], + @am.flow("<tt>cat</tt> <i>and <b></i>dog</b>") + end + + def test_protect + assert_equal(['cat \\ dog'], @am.flow('cat \\ dog')) + + assert_equal(["cat <tt>dog</Tt>"], @am.flow("cat \\<tt>dog</Tt>")) + + assert_equal(["cat ", @em_on, "and", @em_off, " <B>dog</b>"], + @am.flow("cat <i>and</i> \\<B>dog</b>")) + + assert_equal(["*word* or <b>text</b>"], @am.flow("\\*word* or \\<b>text</b>")) + + assert_equal(["_cat_", @em_on, "dog", @em_off], + @am.flow("\\_cat_<i>dog</i>")) + end + + def test_special + @am.add_special(RDoc::Markup::ToHtmlCrossref::CROSSREF_REGEXP, :CROSSREF) + + # + # The apostrophes in "cats'" and "dogs'" suppress the flagging of these + # words as potential cross-references, which is necessary for the unit + # tests. Unfortunately, the markup engine right now does not actually + # check whether a cross-reference is valid before flagging it. + # + assert_equal(["cats'"], @am.flow("cats'")) + + assert_equal(["cats' ", crossref("#fred"), " dogs'"].flatten, + @am.flow("cats' #fred dogs'")) + + assert_equal([crossref("#fred"), " dogs'"].flatten, + @am.flow("#fred dogs'")) + + assert_equal(["cats' ", crossref("#fred")].flatten, @am.flow("cats' #fred")) + end + + def test_tt_html + assert_equal [@tt_on, '"\n"', @tt_off], + @am.flow('<tt>"\n"</tt>') + end + +end + +MiniTest::Unit.autorun diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_markup_to_html.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_markup_to_html.rb new file mode 100644 index 000000000..5b8c09ccf --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_markup_to_html.rb @@ -0,0 +1,81 @@ +require 'rubygems' +require 'minitest/unit' +require 'rdoc/markup' +require 'rdoc/markup/to_html' + +class TestRDocMarkupToHtml < MiniTest::Unit::TestCase + + def setup + @m = RDoc::Markup.new + @am = RDoc::Markup::AttributeManager.new + @th = RDoc::Markup::ToHtml.new + end + + def test_class_gen_relative_url + def gen(from, to) + RDoc::Markup::ToHtml.gen_relative_url from, to + end + + assert_equal 'a.html', gen('a.html', 'a.html') + assert_equal 'b.html', gen('a.html', 'b.html') + + assert_equal 'd.html', gen('a/c.html', 'a/d.html') + assert_equal '../a.html', gen('a/c.html', 'a.html') + assert_equal 'a/c.html', gen('a.html', 'a/c.html') + end + + def test_list_verbatim + str = "* one\n verb1\n verb2\n* two\n" + + expected = <<-EXPECTED +<ul> +<li>one + +<pre> + verb1 + verb2 +</pre> +</li> +<li>two + +</li> +</ul> + EXPECTED + + assert_equal expected, @m.convert(str, @th) + end + + def test_tt_formatting + assert_equal "<p>\n<tt>--</tt> — <tt>cats'</tt> cats’\n</p>\n", + util_format("<tt>--</tt> -- <tt>cats'</tt> cats'") + + assert_equal "<p>\n<b>—</b>\n</p>\n", util_format("<b>--</b>") + end + + def test_convert_string_fancy + # + # The HTML typesetting is broken in a number of ways, but I have fixed + # the most glaring issues for single and double quotes. Note that + # "strange" symbols (periods or dashes) need to be at the end of the + # test case strings in order to suppress cross-references. + # + assert_equal "<p>\n“cats”.\n</p>\n", util_format("\"cats\".") + assert_equal "<p>\n‘cats’.\n</p>\n", util_format("\'cats\'.") + assert_equal "<p>\ncat’s-\n</p>\n", util_format("cat\'s-") + end + + def util_fragment(text) + RDoc::Markup::Fragment.new 0, nil, nil, text + end + + def util_format(text) + fragment = util_fragment text + + @th.start_accepting + @th.accept_paragraph @am, fragment + @th.end_accepting + end + +end + +MiniTest::Unit.autorun diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_markup_to_html_crossref.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_markup_to_html_crossref.rb new file mode 100644 index 000000000..9e77c4bdc --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_markup_to_html_crossref.rb @@ -0,0 +1,161 @@ +require 'rubygems' +require 'minitest/unit' +require 'rdoc/rdoc' +require 'rdoc/code_objects' +require 'rdoc/markup/to_html_crossref' +require 'test/xref_test_case' + +class TestRDocMarkupToHtmlCrossref < XrefTestCase + + def setup + super + + @xref = RDoc::Markup::ToHtmlCrossref.new 'index.html', @c1, true + end + + def assert_ref(path, ref) + assert_equal "<p>\n<a href=\"#{path}\">#{ref}</a>\n</p>\n", + @xref.convert(ref) + end + + def refute_ref(body, ref) + assert_equal "<p>\n#{body}\n</p>\n", @xref.convert(ref) + end + + def test_handle_special_CROSSREF_C2 + @xref = RDoc::Markup::ToHtmlCrossref.new 'classes/C2.html', @c2, true + + refute_ref '#m', '#m' + + assert_ref '../C2/C3.html', 'C2::C3' + assert_ref '../C2/C3.html#M000002', 'C2::C3#m' + assert_ref '../C2/C3/H1.html', 'C3::H1' + assert_ref '../C4.html', 'C4' + + # TODO there is a C3::H2 in the top-level namespace and RDoc should follow + # constant scoping rules + refute_ref 'C3::H2', 'C3::H2' + refute_ref 'H1', 'H1' + end + + def test_handle_special_CROSSREF_C2_C3 + @xref = RDoc::Markup::ToHtmlCrossref.new 'classes/C2/C3.html', @c2_c3, true + + assert_ref '../../C2/C3.html#M000002', '#m' + + assert_ref '../../C2/C3.html', 'C3' + assert_ref '../../C2/C3.html#M000002', 'C3#m' + + assert_ref '../../C2/C3/H1.html', 'H1' + assert_ref '../../C2/C3/H1.html', 'C3::H1' + + assert_ref '../../C4.html', 'C4' + + refute_ref 'C3::H2', 'C3::H2' + end + + def test_handle_special_CROSSREF_C3 + @xref = RDoc::Markup::ToHtmlCrossref.new 'classes/C3.html', @c3, true + + assert_ref '../C3.html', 'C3' + + refute_ref '#m', '#m' + refute_ref 'C3#m', 'C3#m' + + assert_ref '../C3/H1.html', 'H1' + + assert_ref '../C3/H1.html', 'C3::H1' + assert_ref '../C3/H2.html', 'C3::H2' + + assert_ref '../C4.html', 'C4' + end + + def test_handle_special_CROSSREF_C4 + @xref = RDoc::Markup::ToHtmlCrossref.new 'classes/C4.html', @c4, true + + # C4 ref inside a C4 containing a C4 should resolve to the contained class + assert_ref '../C4/C4.html', 'C4' + end + + def test_handle_special_CROSSREF_C4_C4 + @xref = RDoc::Markup::ToHtmlCrossref.new 'classes/C4/C4.html', @c4_c4, true + + # A C4 reference inside a C4 class contained within a C4 class should + # resolve to the inner C4 class. + assert_ref '../../C4/C4.html', 'C4' + end + + def test_handle_special_CROSSREF_class + assert_ref 'C1.html', 'C1' + refute_ref 'H1', 'H1' + + assert_ref 'C2.html', 'C2' + assert_ref 'C2/C3.html', 'C2::C3' + assert_ref 'C2/C3/H1.html', 'C2::C3::H1' + + assert_ref 'C3.html', '::C3' + assert_ref 'C3/H1.html', '::C3::H1' + + assert_ref 'C4/C4.html', 'C4::C4' + end + + def test_handle_special_CROSSREF_file + assert_ref 'xref_data_rb.html', 'xref_data.rb' + end + + def test_handle_special_CROSSREF_method + refute_ref 'm', 'm' + assert_ref 'C1.html#M000000', '#m' + + assert_ref 'C1.html#M000000', 'C1#m' + assert_ref 'C1.html#M000000', 'C1#m()' + assert_ref 'C1.html#M000000', 'C1#m(*)' + + assert_ref 'C1.html#M000000', 'C1.m' + assert_ref 'C1.html#M000000', 'C1.m()' + assert_ref 'C1.html#M000000', 'C1.m(*)' + + # HACK should this work + #assert_ref 'classes/C1.html#M000001', 'C1::m' + #assert_ref 'classes/C1.html#M000001', 'C1::m()' + #assert_ref 'classes/C1.html#M000001', 'C1::m(*)' + + assert_ref 'C2/C3.html#M000002', 'C2::C3#m' + + assert_ref 'C2/C3.html#M000002', 'C2::C3.m' + + assert_ref 'C2/C3/H1.html#M000003', 'C2::C3::H1#m?' + + assert_ref 'C2/C3.html#M000002', '::C2::C3#m' + assert_ref 'C2/C3.html#M000002', '::C2::C3#m()' + assert_ref 'C2/C3.html#M000002', '::C2::C3#m(*)' + end + + def test_handle_special_CROSSREF_no_ref + assert_equal '', @xref.convert('') + + refute_ref 'bogus', 'bogus' + refute_ref 'bogus', '\bogus' + refute_ref '\bogus', '\\\bogus' + + refute_ref '#n', '\#n' + refute_ref '#n()', '\#n()' + refute_ref '#n(*)', '\#n(*)' + + refute_ref 'C1', '\C1' + refute_ref '::C3', '\::C3' + + refute_ref '::C3::H1#n', '::C3::H1#n' + refute_ref '::C3::H1#n(*)', '::C3::H1#n(*)' + refute_ref '::C3::H1#n', '\::C3::H1#n' + end + + def test_handle_special_CROSSREF_special + assert_equal "<p>\n<a href=\"C2/C3.html\">C2::C3</a>;method(*)\n</p>\n", + @xref.convert('C2::C3;method(*)') + end + +end + +MiniTest::Unit.autorun + diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_normal_module.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_normal_module.rb new file mode 100644 index 000000000..9bd681954 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_normal_module.rb @@ -0,0 +1,26 @@ +require 'test/xref_test_case' + +class TestRDocNormalModule < XrefTestCase + + def setup + super + + @mod = RDoc::NormalModule.new 'Mod' + end + + def test_comment_equals + @mod.comment = '# comment 1' + + assert_equal '# comment 1', @mod.comment + + @mod.comment = '# comment 2' + + assert_equal "# comment 1\n# ---\n# comment 2", @mod.comment + end + + def test_module_eh + assert @mod.module? + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_parser.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_parser.rb new file mode 100644 index 000000000..ae4801c42 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_parser.rb @@ -0,0 +1,29 @@ +require 'rubygems' +require 'minitest/unit' +require 'rdoc/parser' +require 'rdoc/parser/ruby' + +class TestRDocParser < MiniTest::Unit::TestCase + def test_can_parse + assert_equal(RDoc::Parser.can_parse(__FILE__), RDoc::Parser::Ruby) + + readme_file_name = File.join(File.dirname(__FILE__), "..", "README.txt") + + unless File.exist? readme_file_name then # HACK for tests in trunk :/ + readme_file_name = File.join File.dirname(__FILE__), '..', '..', 'README' + end + + assert_equal(RDoc::Parser.can_parse(readme_file_name), RDoc::Parser::Simple) + + binary_file_name = File.join(File.dirname(__FILE__), "binary.dat") + assert_equal(RDoc::Parser.can_parse(binary_file_name), nil) + + jtest_file_name = File.join(File.dirname(__FILE__), "test.ja.txt") + assert_equal(RDoc::Parser::Simple, RDoc::Parser.can_parse(jtest_file_name)) + + jtest_rdoc_file_name = File.join(File.dirname(__FILE__), "test.ja.rdoc") + assert_equal(RDoc::Parser::Simple, RDoc::Parser.can_parse(jtest_rdoc_file_name)) + end +end + +MiniTest::Unit.autorun diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_parser_c.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_parser_c.rb new file mode 100644 index 000000000..6d129cebe --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_parser_c.rb @@ -0,0 +1,401 @@ +require 'stringio' +require 'tempfile' +require 'rubygems' +require 'minitest/unit' +require 'rdoc/options' +require 'rdoc/parser/c' + +class RDoc::Parser::C + attr_accessor :classes + + public :do_classes, :do_constants +end + +class TestRDocParserC < MiniTest::Unit::TestCase + + def setup + @tempfile = Tempfile.new self.class.name + filename = @tempfile.path + + @top_level = RDoc::TopLevel.new filename + @fn = filename + @options = RDoc::Options.new + @stats = RDoc::Stats.new 0 + + RDoc::Parser::C.reset + RDoc::TopLevel.reset + end + + def teardown + @tempfile.close + end + + def test_do_classes_boot_class + content = <<-EOF +/* Document-class: Foo + * this is the Foo boot class + */ +VALUE cFoo = boot_defclass("Foo", 0); + EOF + + klass = util_get_class content, 'cFoo' + assert_equal " this is the Foo boot class\n ", klass.comment + end + + def test_do_classes_class + content = <<-EOF +/* Document-class: Foo + * this is the Foo class + */ +VALUE cFoo = rb_define_class("Foo", rb_cObject); + EOF + + klass = util_get_class content, 'cFoo' + assert_equal " this is the Foo class\n ", klass.comment + end + + def test_do_classes_class_under + content = <<-EOF +/* Document-class: Kernel::Foo + * this is the Foo class under Kernel + */ +VALUE cFoo = rb_define_class_under(rb_mKernel, "Foo", rb_cObject); + EOF + + klass = util_get_class content, 'cFoo' + assert_equal " this is the Foo class under Kernel\n ", klass.comment + end + + def test_do_classes_module + content = <<-EOF +/* Document-module: Foo + * this is the Foo module + */ +VALUE mFoo = rb_define_module("Foo"); + EOF + + klass = util_get_class content, 'mFoo' + assert_equal " this is the Foo module\n ", klass.comment + end + + def test_do_classes_module_under + content = <<-EOF +/* Document-module: Kernel::Foo + * this is the Foo module under Kernel + */ +VALUE mFoo = rb_define_module_under(rb_mKernel, "Foo"); + EOF + + klass = util_get_class content, 'mFoo' + assert_equal " this is the Foo module under Kernel\n ", klass.comment + end + + def test_do_constants + content = <<-EOF +#include <ruby.h> + +void Init_foo(){ + VALUE cFoo = rb_define_class("Foo", rb_cObject); + + /* 300: The highest possible score in bowling */ + rb_define_const(cFoo, "PERFECT", INT2FIX(300)); + + /* Huzzah!: What you cheer when you roll a perfect game */ + rb_define_const(cFoo, "CHEER", rb_str_new2("Huzzah!")); + + /* TEST\:TEST: Checking to see if escaped semicolon works */ + rb_define_const(cFoo, "TEST", rb_str_new2("TEST:TEST")); + + /* \\: The file separator on MS Windows */ + rb_define_const(cFoo, "MSEPARATOR", rb_str_new2("\\")); + + /* /: The file separator on Unix */ + rb_define_const(cFoo, "SEPARATOR", rb_str_new2("/")); + + /* C:\\Program Files\\Stuff: A directory on MS Windows */ + rb_define_const(cFoo, "STUFF", rb_str_new2("C:\\Program Files\\Stuff")); + + /* Default definition */ + rb_define_const(cFoo, "NOSEMI", INT2FIX(99)); + + rb_define_const(cFoo, "NOCOMMENT", rb_str_new2("No comment")); + + /* + * Multiline comment goes here because this comment spans multiple lines. + * Multiline comment goes here because this comment spans multiple lines. + */ + rb_define_const(cFoo, "MULTILINE", INT2FIX(1)); + + /* + * 1: Multiline comment goes here because this comment spans multiple lines. + * Multiline comment goes here because this comment spans multiple lines. + */ + rb_define_const(cFoo, "MULTILINE_VALUE", INT2FIX(1)); + + /* Multiline comment goes here because this comment spans multiple lines. + * Multiline comment goes here because this comment spans multiple lines. + */ + rb_define_const(cFoo, "MULTILINE_NOT_EMPTY", INT2FIX(1)); + +} + EOF + + @parser = util_parser content + + @parser.do_classes + @parser.do_constants + + klass = @parser.classes['cFoo'] + assert klass + + constants = klass.constants + assert !klass.constants.empty? + + constants = constants.map { |c| [c.name, c.value, c.comment] } + + assert_equal ['PERFECT', '300', + "\n The highest possible score in bowling \n "], + constants.shift + assert_equal ['CHEER', 'Huzzah!', + "\n What you cheer when you roll a perfect game \n "], + constants.shift + assert_equal ['TEST', 'TEST:TEST', + "\n Checking to see if escaped semicolon works \n "], + constants.shift + assert_equal ['MSEPARATOR', '\\', + "\n The file separator on MS Windows \n "], + constants.shift + assert_equal ['SEPARATOR', '/', + "\n The file separator on Unix \n "], + constants.shift + assert_equal ['STUFF', 'C:\\Program Files\\Stuff', + "\n A directory on MS Windows \n "], + constants.shift + assert_equal ['NOSEMI', 'INT2FIX(99)', + "\n Default definition \n "], + constants.shift + assert_equal ['NOCOMMENT', 'rb_str_new2("No comment")', nil], + constants.shift + + comment = <<-EOF.chomp + + + Multiline comment goes here because this comment spans multiple lines. + Multiline comment goes here because this comment spans multiple lines. + + + EOF + assert_equal ['MULTILINE', 'INT2FIX(1)', comment], constants.shift + assert_equal ['MULTILINE_VALUE', '1', comment], constants.shift + + comment = <<-EOF.chomp + + Multiline comment goes here because this comment spans multiple lines. + Multiline comment goes here because this comment spans multiple lines. + + + EOF + assert_equal ['MULTILINE_NOT_EMPTY', 'INT2FIX(1)', comment], constants.shift + + assert constants.empty?, constants.inspect + end + + def test_find_class_comment_init + content = <<-EOF +/* + * a comment for class Foo + */ +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); +} + EOF + + klass = util_get_class content, 'foo' + + assert_equal " \n a comment for class Foo\n \n", klass.comment + end + + def test_find_class_comment_define_class + content = <<-EOF +/* + * a comment for class Foo + */ +VALUE foo = rb_define_class("Foo", rb_cObject); + EOF + + klass = util_get_class content, 'foo' + + assert_equal " \n a comment for class Foo\n \n", klass.comment + end + + def test_find_class_comment_define_class_Init_Foo + content = <<-EOF +/* + * a comment for class Foo on Init + */ +void +Init_Foo(void) { + /* + * a comment for class Foo on rb_define_class + */ + VALUE foo = rb_define_class("Foo", rb_cObject); +} + EOF + + klass = util_get_class content, 'foo' + + assert_equal " \n a comment for class Foo on Init\n \n", klass.comment + end + + def test_find_class_comment_define_class_bogus_comment + content = <<-EOF +/* + * a comment for other_function + */ +void +other_function() { +} + +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); +} + EOF + + klass = util_get_class content, 'foo' + + assert_equal '', klass.comment + end + + def test_find_body + content = <<-EOF +/* + * a comment for other_function + */ +VALUE +other_function() { +} + +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); + + rb_define_method(foo, "my_method", other_function, 0); +} + EOF + + klass = util_get_class content, 'foo' + other_function = klass.method_list.first + + assert_equal 'my_method', other_function.name + assert_equal " \n a comment for other_function\n \n", + other_function.comment + assert_equal '()', other_function.params + + code = other_function.token_stream.first.text + + assert_equal "VALUE\nother_function() ", code + end + + def test_find_body_define + content = <<-EOF +/* + * a comment for other_function + */ +#define other_function rb_other_function + +/* */ +VALUE +rb_other_function() { +} + +void +Init_Foo(void) { + VALUE foo = rb_define_class("Foo", rb_cObject); + + rb_define_method(foo, "my_method", other_function, 0); +} + EOF + + klass = util_get_class content, 'foo' + other_function = klass.method_list.first + + assert_equal 'my_method', other_function.name + assert_equal " \n a comment for other_function\n \n \n", + other_function.comment + assert_equal '()', other_function.params + + code = other_function.token_stream.first.text + + assert_equal "#define other_function rb_other_function", code + end + + def test_define_method + content = <<-EOF +/*Method Comment! */ +static VALUE +rb_io_s_read(argc, argv, io) + int argc; + VALUE *argv; + VALUE io; +{ +} + +void +Init_IO(void) { + /* + * a comment for class Foo on rb_define_class + */ + VALUE rb_cIO = rb_define_class("IO", rb_cObject); + rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1); +} + EOF + + klass = util_get_class content, 'rb_cIO' + read_method = klass.method_list.first + assert_equal "read", read_method.name + assert_equal " Method Comment! \n", read_method.comment + end + + def test_define_method_private + content = <<-EOF +/*Method Comment! */ +static VALUE +rb_io_s_read(argc, argv, io) + int argc; + VALUE *argv; + VALUE io; +{ +} + +void +Init_IO(void) { + /* + * a comment for class Foo on rb_define_class + */ + VALUE rb_cIO = rb_define_class("IO", rb_cObject); + rb_define_private_method(rb_cIO, "read", rb_io_s_read, -1); +} + EOF + + klass = util_get_class content, 'rb_cIO' + read_method = klass.method_list.first + assert_equal 'IO#read', read_method.full_name + assert_equal :private, read_method.visibility + assert_equal " Method Comment! \n", read_method.comment + end + + def util_get_class(content, name) + @parser = util_parser content + @parser.scan + @parser.classes[name] + end + + def util_parser(content) + RDoc::Parser::C.new @top_level, @fn, content, @options, @stats + end + +end + +MiniTest::Unit.autorun diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_parser_perl.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_parser_perl.rb new file mode 100644 index 000000000..165cadaa5 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_parser_perl.rb @@ -0,0 +1,74 @@ +require 'stringio' +require 'tempfile' +require 'rubygems' +require 'minitest/unit' +require 'rdoc/options' +require 'rdoc/parser/perl' + +class TestRdocParserPerlPOD < MiniTest::Unit::TestCase + + def setup + @tempfile = Tempfile.new self.class.name + filename = @tempfile.path + + @top_level = RDoc::TopLevel.new filename + @fn = filename + @options = RDoc::Options.new + @stats = RDoc::Stats.new 0 + end + + def teardown + @tempfile.close + end + + def test_uncommented_perl + content = <<-EOF +while (<>) { + tr/a-z/A-Z; + print +} + EOF + + comment = util_get_comment content + assert_equal "", comment + end + + def test_perl_without_pod + content = <<-EOF +#!/usr/local/bin/perl +# +#This is a pointless perl program because it does -p. +# +while(<>) {print;}: + EOF + + comment = util_get_comment content + assert_equal "", comment + end + + def test_simple_pod_no_structure + content = <<-EOF +=begin pod + +This just contains plain old documentation + +=end + EOF + comment = util_get_comment content + assert_equal "\nThis just contains plain old documentation\n\n", comment + end + + # Get the comment of the @top_level when it has processed the input. + def util_get_comment(content) + parser = util_parser content + parser.scan.comment + end + + # create a new parser with the supplied content. + def util_parser(content) + RDoc::Parser::PerlPOD.new @top_level, @fn, content, @options, @stats + end + +end + +MiniTest::Unit.autorun diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_parser_ruby.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_parser_ruby.rb new file mode 100644 index 000000000..5fb880cb3 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_parser_ruby.rb @@ -0,0 +1,1040 @@ +require 'stringio' +require 'tempfile' +require 'rubygems' +require 'minitest/autorun' + +require 'rdoc/options' +require 'rdoc/parser/ruby' +require 'rdoc/stats' + +class TestRDocParserRuby < MiniTest::Unit::TestCase + + def setup + @tempfile = Tempfile.new self.class.name + @filename = @tempfile.path + + # Some tests need two paths. + @tempfile2 = Tempfile.new self.class.name + @filename2 = @tempfile2.path + + util_top_level + @options = RDoc::Options.new + @options.quiet = true + @stats = RDoc::Stats.new 0 + end + + def teardown + @tempfile.close + @tempfile2.close + end + + def test_look_for_directives_in_attr + util_parser "" + + comment = "# :attr: my_attr\n" + + @parser.look_for_directives_in @top_level, comment + + assert_equal "# :attr: my_attr\n", comment + + comment = "# :attr_reader: my_method\n" + + @parser.look_for_directives_in @top_level, comment + + assert_equal "# :attr_reader: my_method\n", comment + + comment = "# :attr_writer: my_method\n" + + @parser.look_for_directives_in @top_level, comment + + assert_equal "# :attr_writer: my_method\n", comment + end + + def test_look_for_directives_in_commented + util_parser "" + + comment = "# how to make a section:\n# # :section: new section\n" + + @parser.look_for_directives_in @top_level, comment + + section = @top_level.current_section + assert_equal nil, section.title + assert_equal nil, section.comment + + assert_equal "# how to make a section:\n# # :section: new section\n", + comment + end + + def test_look_for_directives_in_enddoc + util_parser "" + + assert_throws :enddoc do + @parser.look_for_directives_in @top_level, "# :enddoc:\n" + end + end + + def test_look_for_directives_in_main + util_parser "" + + @parser.look_for_directives_in @top_level, "# :main: new main page\n" + + assert_equal 'new main page', @options.main_page + end + + def test_look_for_directives_in_method + util_parser "" + + comment = "# :method: my_method\n" + + @parser.look_for_directives_in @top_level, comment + + assert_equal "# :method: my_method\n", comment + + comment = "# :singleton-method: my_method\n" + + @parser.look_for_directives_in @top_level, comment + + assert_equal "# :singleton-method: my_method\n", comment + end + + def test_look_for_directives_in_startdoc + util_parser "" + + @top_level.stop_doc + assert !@top_level.document_self + assert !@top_level.document_children + assert !@top_level.force_documentation + + @parser.look_for_directives_in @top_level, "# :startdoc:\n" + + assert @top_level.document_self + assert @top_level.document_children + assert @top_level.force_documentation + end + + def test_look_for_directives_in_stopdoc + util_parser "" + + assert @top_level.document_self + assert @top_level.document_children + + @parser.look_for_directives_in @top_level, "# :stopdoc:\n" + + assert !@top_level.document_self + assert !@top_level.document_children + end + + def test_look_for_directives_in_section + util_parser "" + + comment = "# :section: new section\n# woo stuff\n" + + @parser.look_for_directives_in @top_level, comment + + section = @top_level.current_section + assert_equal 'new section', section.title + assert_equal "# woo stuff\n", section.comment + + assert_equal '', comment + end + + def test_look_for_directives_in_title + util_parser "" + + @parser.look_for_directives_in @top_level, "# :title: new title\n" + + assert_equal 'new title', @options.title + end + + def test_look_for_directives_in_unhandled + util_parser "" + + comment = "# :unhandled: \n# :title: hi\n" + + @parser.look_for_directives_in @top_level, comment + + assert_equal "# :unhandled: \n", comment + + assert_equal 'hi', @options.title + end + + def test_parse_attr + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# my attr\n" + + util_parser "attr :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_equal 1, klass.attributes.length + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal "##\n# my attr\n", foo.comment + end + + def test_parse_attr_accessor + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# my attr\n" + + util_parser "attr_accessor :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_attr_accessor klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_equal 2, klass.attributes.length + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'RW', foo.rw + assert_equal "##\n# my attr\n", foo.comment + + bar = klass.attributes.last + assert_equal 'bar', bar.name + assert_equal 'RW', bar.rw + assert_equal "##\n# my attr\n", bar.comment + end + + def test_parse_attr_accessor_writer + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# my attr\n" + + util_parser "attr_writer :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_attr_accessor klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert_equal 2, klass.attributes.length + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'W', foo.rw + assert_equal "##\n# my attr\n", foo.comment + + bar = klass.attributes.last + assert_equal 'bar', bar.name + assert_equal 'W', bar.rw + assert_equal "##\n# my attr\n", bar.comment + end + + def test_parse_meta_attr + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# :attr: \n# my method\n" + + util_parser "add_my_method :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'RW', foo.rw + assert_equal "##\n# my method\n", foo.comment + end + + def test_parse_meta_attr_accessor + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# :attr_accessor: \n# my method\n" + + util_parser "add_my_method :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'RW', foo.rw + assert_equal "##\n# my method\n", foo.comment + end + + def test_parse_meta_attr_reader + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# :attr_reader: \n# my method\n" + + util_parser "add_my_method :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'R', foo.rw + assert_equal "##\n# my method\n", foo.comment + end + + def test_parse_meta_attr_writer + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# :attr_writer: \n# my method\n" + + util_parser "add_my_method :foo, :bar" + + tk = @parser.get_tk + + @parser.parse_meta_attr klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'W', foo.rw + assert_equal "##\n# my method\n", foo.comment + end + + def test_parse_class + comment = "##\n# my method\n" + + util_parser 'class Foo; end' + + tk = @parser.get_tk + + @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = @top_level.classes.first + assert_equal 'Foo', foo.full_name + assert_equal comment, foo.comment + end + + def test_parse_class_nested_superclass + foo = RDoc::NormalModule.new 'Foo' + foo.parent = @top_level + + util_parser "class Bar < Super\nend" + + tk = @parser.get_tk + + @parser.parse_class foo, RDoc::Parser::Ruby::NORMAL, tk, '' + + bar = foo.classes.first + assert_equal 'Super', bar.superclass + end + + def test_parse_module + comment = "##\n# my module\n" + + util_parser 'module Foo; end' + + tk = @parser.get_tk + + @parser.parse_module @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = @top_level.modules.first + assert_equal 'Foo', foo.full_name + assert_equal comment, foo.comment + end + + def test_parse_class_mistaken_for_module + # The code below is not strictly legal Ruby (Foo must have been defined + # before Foo::Bar is encountered), but RDoc might encounter Foo::Bar + # before Foo if they live in different files. + + code = <<-EOF +class Foo::Bar +end + +module Foo::Baz +end + +class Foo +end + EOF + + util_parser code + + @parser.scan + + assert_equal %w[Foo::Baz], RDoc::TopLevel.modules_hash.keys + assert_empty @top_level.modules + + foo = @top_level.classes.first + assert_equal 'Foo', foo.full_name + + bar = foo.classes.first + assert_equal 'Foo::Bar', bar.full_name + + baz = foo.modules.first + assert_equal 'Foo::Baz', baz.full_name + end + + def test_parse_class_definition_encountered_after_class_reference + # The code below is not strictly legal Ruby (Foo must have been defined + # before Foo.bar is encountered), but RDoc might encounter Foo.bar before + # Foo if they live in different files. + + code = <<-EOF +def Foo.bar +end + +class Foo < IO +end + EOF + + util_parser code + + @parser.scan + + assert_empty RDoc::TopLevel.modules_hash + # HACK why does it fail? + #assert_empty @top_level.modules + + foo = @top_level.classes.first + assert_equal 'Foo', foo.full_name + assert_equal 'IO', foo.superclass + + bar = foo.method_list.first + assert_equal 'bar', bar.name + end + + def test_parse_module_relative_to_top_level_namespace + comment = <<-EOF +# +# Weirdly named module +# +EOF + + code = comment + <<-EOF +module ::Foo + class Helper + end +end +EOF + + util_parser code + @parser.scan() + + foo = @top_level.modules.first + assert_equal 'Foo', foo.full_name + assert_equal comment, foo.comment + + helper = foo.classes.first + assert_equal 'Foo::Helper', helper.full_name + end + + def test_parse_comment_attr + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# :attr: foo\n# my attr\n" + + util_parser "\n" + + tk = @parser.get_tk + + @parser.parse_comment klass, tk, comment + + foo = klass.attributes.first + assert_equal 'foo', foo.name + assert_equal 'RW', foo.rw + assert_equal comment, foo.comment + + assert_equal nil, foo.viewer + assert_equal true, foo.document_children + assert_equal true, foo.document_self + assert_equal false, foo.done_documenting + assert_equal false, foo.force_documentation + assert_equal klass, foo.parent + assert_equal :public, foo.visibility + assert_equal "\n", foo.text + assert_equal klass.current_section, foo.section + end + + def test_parse_comment_method + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# :method: foo\n# my method\n" + + util_parser "\n" + + tk = @parser.get_tk + + @parser.parse_comment klass, tk, comment + + foo = klass.method_list.first + assert_equal 'foo', foo.name + assert_equal comment, foo.comment + + assert_equal [], foo.aliases + assert_equal nil, foo.block_params + assert_equal nil, foo.call_seq + assert_equal nil, foo.is_alias_for + assert_equal nil, foo.viewer + assert_equal true, foo.document_children + assert_equal true, foo.document_self + assert_equal '', foo.params + assert_equal false, foo.done_documenting + assert_equal false, foo.dont_rename_initialize + assert_equal false, foo.force_documentation + assert_equal klass, foo.parent + assert_equal false, foo.singleton + assert_equal :public, foo.visibility + assert_equal "\n", foo.text + assert_equal klass.current_section, foo.section + + stream = [ + tk(:COMMENT, 1, 1, nil, "# File #{@top_level.absolute_name}, line 1"), + RDoc::Parser::Ruby::NEWLINE_TOKEN, + tk(:SPACE, 1, 1, nil, ''), + ] + + assert_equal stream, foo.token_stream + end + + def test_parse_meta_method + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# my method\n" + + util_parser "add_my_method :foo, :bar\nadd_my_method :baz" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'foo', foo.name + assert_equal comment, foo.comment + + assert_equal [], foo.aliases + assert_equal nil, foo.block_params + assert_equal nil, foo.call_seq + assert_equal true, foo.document_children + assert_equal true, foo.document_self + assert_equal false, foo.done_documenting + assert_equal false, foo.dont_rename_initialize + assert_equal false, foo.force_documentation + assert_equal nil, foo.is_alias_for + assert_equal '', foo.params + assert_equal klass, foo.parent + assert_equal false, foo.singleton + assert_equal 'add_my_method :foo', foo.text + assert_equal nil, foo.viewer + assert_equal :public, foo.visibility + assert_equal klass.current_section, foo.section + + stream = [ + tk(:COMMENT, 1, 1, nil, "# File #{@top_level.absolute_name}, line 1"), + RDoc::Parser::Ruby::NEWLINE_TOKEN, + tk(:SPACE, 1, 1, nil, ''), + tk(:IDENTIFIER, 1, 0, 'add_my_method', 'add_my_method'), + tk(:SPACE, 1, 13, nil, ' '), + tk(:SYMBOL, 1, 14, nil, ':foo'), + tk(:COMMA, 1, 18, nil, ','), + tk(:SPACE, 1, 19, nil, ' '), + tk(:SYMBOL, 1, 20, nil, ':bar'), + tk(:NL, 1, 24, nil, "\n"), + ] + + assert_equal stream, foo.token_stream + end + + def test_parse_meta_method_name + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# :method: woo_hoo!\n# my method\n" + + util_parser "add_my_method :foo, :bar\nadd_my_method :baz" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'woo_hoo!', foo.name + assert_equal "##\n# my method\n", foo.comment + end + + def test_parse_meta_method_singleton + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# :singleton-method:\n# my method\n" + + util_parser "add_my_method :foo, :bar\nadd_my_method :baz" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'foo', foo.name + assert_equal true, foo.singleton, 'singleton method' + assert_equal "##\n# my method\n", foo.comment + end + + def test_parse_meta_method_singleton_name + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# :singleton-method: woo_hoo!\n# my method\n" + + util_parser "add_my_method :foo, :bar\nadd_my_method :baz" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'woo_hoo!', foo.name + assert_equal true, foo.singleton, 'singleton method' + assert_equal "##\n# my method\n", foo.comment + end + + def test_parse_meta_method_string_name + klass = RDoc::NormalClass.new 'Foo' + comment = "##\n# my method\n" + + util_parser "add_my_method 'foo'" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'foo', foo.name + assert_equal comment, foo.comment + end + + def test_parse_meta_method_unknown + klass = RDoc::NormalClass.new 'Foo' + comment = "##\n# my method\n" + + util_parser "add_my_method ('foo')" + + tk = @parser.get_tk + + @parser.parse_meta_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'unknown', foo.name + assert_equal comment, foo.comment + end + + def test_parse_method + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# my method\n" + + util_parser "def foo() :bar end" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal 'foo', foo.name + assert_equal comment, foo.comment + + assert_equal [], foo.aliases + assert_equal nil, foo.block_params + assert_equal nil, foo.call_seq + assert_equal nil, foo.is_alias_for + assert_equal nil, foo.viewer + assert_equal true, foo.document_children + assert_equal true, foo.document_self + assert_equal '()', foo.params + assert_equal false, foo.done_documenting + assert_equal false, foo.dont_rename_initialize + assert_equal false, foo.force_documentation + assert_equal klass, foo.parent + assert_equal false, foo.singleton + assert_equal :public, foo.visibility + assert_equal 'def foo', foo.text + assert_equal klass.current_section, foo.section + + stream = [ + tk(:COMMENT, 1, 1, nil, "# File #{@top_level.absolute_name}, line 1"), + RDoc::Parser::Ruby::NEWLINE_TOKEN, + tk(:SPACE, 1, 1, nil, ''), + tk(:DEF, 1, 0, 'def', 'def'), + tk(:SPACE, 1, 3, nil, ' '), + tk(:IDENTIFIER, 1, 4, 'foo', 'foo'), + tk(:LPAREN, 1, 7, nil, '('), + tk(:RPAREN, 1, 8, nil, ')'), + tk(:SPACE, 1, 9, nil, ' '), + tk(:COLON, 1, 10, nil, ':'), + tk(:IDENTIFIER, 1, 11, 'bar', 'bar'), + tk(:SPACE, 1, 14, nil, ' '), + tk(:END, 1, 15, 'end', 'end'), + ] + + assert_equal stream, foo.token_stream + end + + def test_parse_method_funky + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# my method\n" + + util_parser "def (blah).foo() :bar end" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + assert klass.method_list.empty? + end + + def test_parse_method_no_parens + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# my method\n" + + util_parser "def foo arg1, arg2\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal '(arg1, arg2)', foo.params + end + + def test_parse_method_parameters_comment + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# my method\n" + + util_parser "def foo arg1, arg2 # some useful comment\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal '(arg1, arg2)', foo.params + end + + def test_parse_method_parameters_comment_continue + klass = RDoc::NormalClass.new 'Foo' + klass.parent = @top_level + + comment = "##\n# my method\n" + + util_parser "def foo arg1, arg2, # some useful comment\narg3\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + foo = klass.method_list.first + assert_equal '(arg1, arg2, arg3)', foo.params + end + + def test_parse_method_toplevel + klass = @top_level + + comment = "##\n# my method\n" + + util_parser "def foo arg1, arg2\nend" + + tk = @parser.get_tk + + @parser.parse_method klass, RDoc::Parser::Ruby::NORMAL, tk, comment + + object = RDoc::TopLevel.find_class_named 'Object' + + foo = object.method_list.first + assert_equal 'Object#foo', foo.full_name + end + + def test_parse_statements_class_if + comment = "##\n# my method\n" + + util_parser <<-CODE +module Foo + X = if TRUE then + '' + end + + def blah + end +end + CODE + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, '' + + foo = @top_level.modules.first + assert_equal 'Foo', foo.full_name, 'module Foo' + + methods = foo.method_list + assert_equal 1, methods.length + assert_equal 'Foo#blah', methods.first.full_name + end + + def test_parse_statements_class_nested + comment = "##\n# my method\n" + + util_parser "module Foo\n#{comment}class Bar\nend\nend" + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, '' + + foo = @top_level.modules.first + assert_equal 'Foo', foo.full_name, 'module Foo' + + bar = foo.classes.first + assert_equal 'Foo::Bar', bar.full_name, 'class Foo::Bar' + assert_equal comment, bar.comment + end + + def test_parse_statements_identifier_meta_method + content = <<-EOF +class Foo + ## + # this is my method + add_my_method :foo +end + EOF + + util_parser content + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, '' + + foo = @top_level.classes.first.method_list.first + assert_equal 'foo', foo.name + end + + def test_parse_statements_identifier_alias_method + content = "class Foo def foo() end; alias_method :foo2, :foo end" + + util_parser content + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, '' + + foo = @top_level.classes.first.method_list[0] + assert_equal 'foo', foo.name + + foo2 = @top_level.classes.first.method_list.last + assert_equal 'foo2', foo2.name + assert_equal 'foo', foo2.is_alias_for.name + assert @top_level.classes.first.aliases.empty? + end + + def test_parse_statements_identifier_alias_method_before_original_method + # This is not strictly legal Ruby code, but it simulates finding an alias + # for a method before finding the original method, which might happen + # to rdoc if the alias is in a different file than the original method + # and rdoc processes the alias' file first. + content = <<-EOF +class Foo + alias_method :foo2, :foo + + alias_method :foo3, :foo + + def foo() + end + + alias_method :foo4, :foo + + alias_method :foo5, :unknown +end +EOF + + util_parser content + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, '' + + foo = @top_level.classes.first.method_list[0] + assert_equal 'foo', foo.name + + foo2 = @top_level.classes.first.method_list[1] + assert_equal 'foo2', foo2.name + assert_equal 'foo', foo2.is_alias_for.name + + foo3 = @top_level.classes.first.method_list[2] + assert_equal 'foo3', foo3.name + assert_equal 'foo', foo3.is_alias_for.name + + foo4 = @top_level.classes.first.method_list.last + assert_equal 'foo4', foo4.name + assert_equal 'foo', foo4.is_alias_for.name + + assert_equal 'unknown', @top_level.classes.first.aliases[0].old_name + end + + def test_parse_statements_identifier_constant + content = <<-EOF +class Foo + FIRST_CONSTANT = 5 + + SECOND_CONSTANT = [ + 1, + 2, + 3 + ] + + THIRD_CONSTANT = { + :foo => 'bar', + :x => 'y' + } + + FOURTH_CONSTANT = SECOND_CONSTANT.map do |element| + element + 1 + element + 2 + end + + FIFTH_CONSTANT = SECOND_CONSTANT.map { |element| element + 1 } +end +EOF + + util_parser content + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, '' + + constants = @top_level.classes.first.constants + + constant = constants[0] + assert_equal 'FIRST_CONSTANT', constant.name + assert_equal '5', constant.value + + constant = constants[1] + assert_equal 'SECOND_CONSTANT', constant.name + assert_equal '[ 1, 2, 3 ]', constant.value + + constant = constants[2] + assert_equal 'THIRD_CONSTANT', constant.name + assert_equal "{ :foo => 'bar', :x => 'y' }", constant.value + + constant = constants[3] + assert_equal 'FOURTH_CONSTANT', constant.name + assert_equal 'SECOND_CONSTANT.map do |element| element + 1 element + 2 end', constant.value + + constant = constants.last + assert_equal 'FIFTH_CONSTANT', constant.name + assert_equal 'SECOND_CONSTANT.map { |element| element + 1 }', constant.value + end + + def test_parse_statements_identifier_attr + content = "class Foo; attr :foo; end" + + util_parser content + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, '' + + foo = @top_level.classes.first.attributes.first + assert_equal 'foo', foo.name + assert_equal 'R', foo.rw + end + + def test_parse_statements_identifier_attr_accessor + content = "class Foo; attr_accessor :foo; end" + + util_parser content + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, '' + + foo = @top_level.classes.first.attributes.first + assert_equal 'foo', foo.name + assert_equal 'RW', foo.rw + end + + def test_parse_statements_identifier_include + content = "class Foo; include Bar; end" + + util_parser content + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, '' + + foo = @top_level.classes.first + assert_equal 'Foo', foo.name + assert_equal 1, foo.includes.length + end + + def test_parse_statements_identifier_module_function + content = "module Foo def foo() end; module_function :foo; end" + + util_parser content + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, '' + + foo, s_foo = @top_level.modules.first.method_list + assert_equal 'foo', foo.name, 'instance method name' + assert_equal :private, foo.visibility, 'instance method visibility' + assert_equal false, foo.singleton, 'instance method singleton' + + assert_equal 'foo', s_foo.name, 'module function name' + assert_equal :public, s_foo.visibility, 'module function visibility' + assert_equal true, s_foo.singleton, 'module function singleton' + end + + def test_parse_statements_identifier_private + content = "class Foo private; def foo() end end" + + util_parser content + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, '' + + foo = @top_level.classes.first.method_list.first + assert_equal 'foo', foo.name + assert_equal :private, foo.visibility + end + + def test_parse_statements_identifier_require + content = "require 'bar'" + + util_parser content + + @parser.parse_statements @top_level, RDoc::Parser::Ruby::NORMAL, nil, '' + + assert_equal 1, @top_level.requires.length + end + + def tk(klass, line, char, name, text) + klass = RDoc::RubyToken.const_get "Tk#{klass.to_s.upcase}" + + token = if klass.instance_method(:initialize).arity == 2 then + raise ArgumentError, "name not used for #{klass}" unless name.nil? + klass.new line, char + else + klass.new line, char, name + end + + token.set_text text + + token + end + + def util_parser(content) + @parser = RDoc::Parser::Ruby.new @top_level, @filename, content, @options, + @stats + end + + def util_two_parsers(first_file_content, second_file_content) + util_parser first_file_content + + @parser2 = RDoc::Parser::Ruby.new @top_level2, @filename, + second_file_content, @options, @stats + end + + def util_top_level + RDoc::TopLevel.reset + @top_level = RDoc::TopLevel.new @filename + @top_level2 = RDoc::TopLevel.new @filename2 + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_require.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_require.rb new file mode 100644 index 000000000..d5850bd16 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_require.rb @@ -0,0 +1,25 @@ +require 'test/xref_test_case' + +class TestRDocRequire < XrefTestCase + + def setup + super + + @req = RDoc::Require.new 'foo', 'comment' + end + + def test_initialize + assert_equal 'foo', @req.name + + req = RDoc::Require.new '"foo"', '' + assert_equal 'foo', @req.name + + req = RDoc::Require.new '\'foo\'', '' + assert_equal 'foo', @req.name + + req = RDoc::Require.new '|foo|', '' + assert_equal 'foo', @req.name, 'for fortran?' + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_attribute_formatter.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_attribute_formatter.rb new file mode 100644 index 000000000..a86312618 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_attribute_formatter.rb @@ -0,0 +1,44 @@ +require 'stringio' +require 'rubygems' +require 'minitest/unit' +require 'rdoc/ri/formatter' + +class TestRDocRIAttributeFormatter < MiniTest::Unit::TestCase + + def setup + @output = StringIO.new + @width = 78 + @indent = ' ' + + @f = RDoc::RI::AttributeFormatter.new @output, @width, @indent + end + + def test_wrap_empty + @f.wrap '' + assert_equal '', @output.string + end + + def test_wrap_long + @f.wrap 'a ' * (@width / 2) + assert_equal " a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a \n a \n", + @output.string + end + + def test_wrap_markup + @f.wrap 'a <tt>b</tt> c' + assert_equal " a b c\n", @output.string + end + + def test_wrap_nil + @f.wrap nil + assert_equal '', @output.string + end + + def test_wrap_short + @f.wrap 'a b c' + assert_equal " a b c\n", @output.string + end + +end + +MiniTest::Unit.autorun diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_default_display.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_default_display.rb new file mode 100644 index 000000000..54b900642 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_default_display.rb @@ -0,0 +1,302 @@ +require 'stringio' +require 'rubygems' +require 'minitest/unit' +require 'rdoc/ri/formatter' +require 'rdoc/ri/display' +require 'rdoc/ri/driver' + +class TestRDocRiDefaultDisplay < MiniTest::Unit::TestCase + + def setup + @output = StringIO.new + @width = 78 + @indent = ' ' + + @dd = RDoc::RI::DefaultDisplay.new RDoc::RI::Formatter, @width, true, + @output + + @some_method = h \ + 'aliases' => [{'name' => 'some_method_alias'}], + 'block_params' => 'block_param', + 'comment' => [RDoc::Markup::Flow::P.new('some comment')], + 'full_name' => 'SomeClass#some_method', + 'is_singleton' => false, + 'name' => 'some_method', + 'params' => '(arg1, arg2) {|block_param| ...}', + 'source_path' => '/nonexistent', + 'visibility' => 'public' + end + + def test_display_class_info + klass = h \ + 'attributes' => [ + { 'name' => 'attribute', 'rw' => 'RW', + 'comment' => [RDoc::Markup::Flow::P.new('attribute comment')] }, + { 'name' => 'attribute_no_comment', 'rw' => 'RW', + 'comment' => nil }, + ], + 'class_methods' => [ + { 'name' => 'class_method' }, + ], + 'class_method_extensions' => [ + { 'name' => 'class_method_extension' }, + ], + 'comment' => [RDoc::Markup::Flow::P.new('SomeClass comment')], + 'constants' => [ + { 'name' => 'CONSTANT', 'value' => '"value1"', + 'comment' => [RDoc::Markup::Flow::P.new('CONSTANT value')] }, + { 'name' => 'CONSTANT_NOCOMMENT', 'value' => '"value2"', + 'comment' => nil }, + ], + 'display_name' => 'Class', + 'full_name' => 'SomeClass', + 'includes' => [], + 'instance_methods' => [ + { 'name' => 'instance_method' }, + { 'name' => 'instance_method2' }, + ], + 'instance_method_extensions' => [ + { 'name' => 'instance_method_extension' }, + ], + 'superclass' => 'Object' + + @dd.display_class_info klass + + expected = <<-EOF +---------------------------------------------------- Class: SomeClass < Object + SomeClass comment + +------------------------------------------------------------------------------ + + +Constants: +---------- + + CONSTANT = "value1" + CONSTANT value + + CONSTANT_NOCOMMENT = "value2" + + +Attributes: +----------- + + attribute (RW): + attribute comment + + attribute_no_comment (RW) + + +Class methods: +-------------- + + class_method + + +Class method extensions: +------------------------ + + class_method_extension + + +Instance methods: +----------------- + + instance_method, instance_method2 + + +Instance method extensions: +--------------------------- + + instance_method_extension + EOF + + assert_equal expected, @output.string + end + + def test_display_flow + flow = [RDoc::Markup::Flow::P.new('flow')] + + @dd.display_flow flow + + assert_equal " flow\n\n", @output.string + end + + def test_display_flow_empty + @dd.display_flow [] + + assert_equal " [no description]\n", @output.string + end + + def test_display_flow_nil + @dd.display_flow nil + + assert_equal " [no description]\n", @output.string + end + + def test_display_method_info + @dd.display_method_info @some_method + + expected = <<-EOF +-------------------------------------------------------- SomeClass#some_method + some_method(arg1, arg2) {|block_param| ...} + + From /nonexistent +------------------------------------------------------------------------------ + some comment + + + (also known as some_method_alias) + EOF + + assert_equal expected, @output.string + end + + def test_display_method_info_singleton + method = RDoc::RI::Driver::OpenStructHash.new.update \ + 'aliases' => [], + 'block_params' => nil, + 'comment' => nil, + 'full_name' => 'SomeClass::some_method', + 'is_singleton' => true, + 'name' => 'some_method', + 'params' => '(arg1, arg2)', + 'visibility' => 'public' + + @dd.display_method_info method + + expected = <<-EOF +------------------------------------------------------- SomeClass::some_method + SomeClass::some_method(arg1, arg2) + + From +------------------------------------------------------------------------------ + [no description] + EOF + + assert_equal expected, @output.string + end + + def test_display_method_list + methods = [ + RDoc::RI::Driver::OpenStructHash.new.update( + "aliases" => [], + "block_params" => nil, + "comment" => nil, + "full_name" => "SomeClass#some_method", + "is_singleton" => false, + "name" => "some_method", + "params" => "()", + "visibility" => "public" + ), + RDoc::RI::Driver::OpenStructHash.new.update( + "aliases" => [], + "block_params" => nil, + "comment" => nil, + "full_name" => "SomeClass#some_other_method", + "is_singleton" => false, + "name" => "some_other_method", + "params" => "()", + "visibility" => "public" + ), + ] + + @dd.display_method_list methods + + expected = <<-EOF + More than one method matched your request. You can refine your search by + asking for information on one of: + +SomeClass#some_method [] +SomeClass#some_other_method [] + EOF + + assert_equal expected, @output.string + end + + def test_display_params + @dd.display_params @some_method + + expected = <<-EOF + some_method(arg1, arg2) {|block_param| ...} + + From /nonexistent + EOF + + assert_equal expected, @output.string + end + + def test_display_params_multiple + @some_method['params'] = <<-EOF +some_method(index) +some_method(start, length) + EOF + + @dd.display_params @some_method + + expected = <<-EOF + some_method(index) + some_method(start, length) + + From /nonexistent + EOF + + assert_equal expected, @output.string + end + + def test_display_params_singleton + @some_method['is_singleton'] = true + @some_method['full_name'] = 'SomeClass::some_method' + + @dd.display_params @some_method + + expected = <<-EOF + SomeClass::some_method(arg1, arg2) {|block_param| ...} + + From /nonexistent + EOF + + assert_equal expected, @output.string + end + + def test_list_known_classes + klasses = %w[SomeClass SomeModule] + + @dd.list_known_classes klasses + + expected = <<-EOF +---------------------------------------------------- Known classes and modules + + SomeClass + SomeModule + EOF + + assert_equal expected, @output.string + end + + def test_list_known_classes_empty + @dd.list_known_classes [] + + expected = <<-EOF +No ri data found + +If you've installed Ruby yourself, you need to generate documentation using: + + make install-doc + +from the same place you ran `make` to build ruby. + +If you installed Ruby from a packaging system, then you may need to +install an additional package, or ask the packager to enable ri generation. + EOF + + assert_equal expected, @output.string + end + + def h(hash) + RDoc::RI::Driver::OpenStructHash.convert hash + end + +end + +MiniTest::Unit.autorun diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_driver.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_driver.rb new file mode 100644 index 000000000..f16049205 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_driver.rb @@ -0,0 +1,94 @@ +require 'rubygems' +require 'minitest/unit' +require 'tmpdir' +require 'rdoc/ri/driver' + +class TestRDocRIDriver < MiniTest::Unit::TestCase + + def setup + @tmpdir = File.join Dir.tmpdir, "test_rdoc_ri_driver_#{$$}" + @home_ri = File.join @tmpdir, 'dot_ri' + @cache_dir = File.join @home_ri, 'cache' + @class_cache = File.join @cache_dir, 'classes' + + FileUtils.mkdir_p @tmpdir + FileUtils.mkdir_p @home_ri + FileUtils.mkdir_p @cache_dir + + @driver = RDoc::RI::Driver.new(RDoc::RI::Driver.process_args([])) + @driver.homepath = @home_ri + end + + def teardown + FileUtils.rm_rf @tmpdir + end + + def test_lookup_method + def @driver.load_cache_for(klassname) + { 'Foo#bar' => :found } + end + + assert @driver.lookup_method('Foo#bar', 'Foo') + end + + def test_lookup_method_class_method + def @driver.load_cache_for(klassname) + { 'Foo::Bar' => :found } + end + + assert @driver.lookup_method('Foo::Bar', 'Foo::Bar') + end + + def test_lookup_method_class_missing + def @driver.load_cache_for(klassname) end + + assert_nil @driver.lookup_method('Foo#bar', 'Foo') + end + + def test_lookup_method_dot_instance + def @driver.load_cache_for(klassname) + { 'Foo#bar' => :instance, 'Foo::bar' => :klass } + end + + assert_equal :instance, @driver.lookup_method('Foo.bar', 'Foo') + end + + def test_lookup_method_dot_class + def @driver.load_cache_for(klassname) + { 'Foo::bar' => :found } + end + + assert @driver.lookup_method('Foo.bar', 'Foo') + end + + def test_lookup_method_method_missing + def @driver.load_cache_for(klassname) {} end + + assert_nil @driver.lookup_method('Foo#bar', 'Foo') + end + + def test_parse_name + klass, meth = @driver.parse_name 'Foo::Bar' + + assert_equal 'Foo::Bar', klass, 'Foo::Bar class' + assert_equal nil, meth, 'Foo::Bar method' + + klass, meth = @driver.parse_name 'Foo#Bar' + + assert_equal 'Foo', klass, 'Foo#Bar class' + assert_equal 'Bar', meth, 'Foo#Bar method' + + klass, meth = @driver.parse_name 'Foo.Bar' + + assert_equal 'Foo', klass, 'Foo#Bar class' + assert_equal 'Bar', meth, 'Foo#Bar method' + + klass, meth = @driver.parse_name 'Foo::bar' + + assert_equal 'Foo', klass, 'Foo::bar class' + assert_equal 'bar', meth, 'Foo::bar method' + end + +end + +MiniTest::Unit.autorun diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_formatter.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_formatter.rb new file mode 100644 index 000000000..a70f9dcba --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_formatter.rb @@ -0,0 +1,320 @@ +require 'stringio' +require 'rubygems' +require 'minitest/unit' +require 'rdoc/ri/formatter' +require 'rdoc/markup/to_flow' + +class TestRDocRIFormatter < MiniTest::Unit::TestCase + + def setup + @output = StringIO.new + @width = 78 + @indent = ' ' + + @f = RDoc::RI::Formatter.new @output, @width, @indent + @markup = RDoc::Markup.new + @flow = RDoc::Markup::ToFlow.new + end + + def test_blankline + @f.blankline + + assert_equal "\n", @output.string + end + + def test_bold_print + @f.bold_print 'a b c' + + assert_equal 'a b c', @output.string + end + + def test_break_to_newline + @f.break_to_newline + + assert_equal '', @output.string + end + + def test_conv_html + assert_equal '> < " &', @f.conv_html('> < " &') + end + + def test_conv_markup + text = '<tt>a</tt> <code>b</code> <b>c</b> <em>d</em>' + + expected = '+a+ +b+ *c* _d_' + + assert_equal expected, @f.conv_markup(text) + end + + def test_display_flow + flow = [ + RDoc::Markup::Flow::H.new(1, 'heading'), + RDoc::Markup::Flow::P.new('paragraph'), + ] + + @f.display_flow flow + + assert_equal "\nHEADING\n=======\n\n paragraph\n\n", @output.string + end + + def test_display_flow_item_h + item = RDoc::Markup::Flow::H.new 1, 'heading' + + @f.display_flow_item item + + assert_equal "\nHEADING\n=======\n\n", @output.string + end + + def test_display_flow_item_li + item = RDoc::Markup::Flow::LI.new nil, 'paragraph' + + @f.display_flow_item item + + assert_equal " paragraph\n\n", @output.string + end + + def test_display_flow_item_list + item = RDoc::Markup::Flow::LIST.new :NUMBER + + @f.display_flow_item item + + assert_equal "", @output.string + end + + def test_display_flow_item_p + item = RDoc::Markup::Flow::P.new 'paragraph' + + @f.display_flow_item item + + assert_equal " paragraph\n\n", @output.string + end + + def test_display_flow_item_rule + item = RDoc::Markup::Flow::RULE.new 1 + + @f.display_flow_item item + + assert_equal "#{'-' * 78}\n", @output.string + end + + def test_display_flow_item_unknown + e = assert_raises RDoc::Error do + @f.display_flow_item Object.new + end + + assert_equal "Unknown flow element: Object", e.message + end + + def test_display_flow_item_verb + item = RDoc::Markup::Flow::VERB.new 'a b c' + + @f.display_flow_item item + + assert_equal " a b c\n\n", @output.string + end + + def test_display_heading_1 + @f.display_heading 'heading', 1, ' ' + + assert_equal "\nHEADING\n=======\n\n", @output.string + end + + def test_display_heading_2 + @f.display_heading 'heading', 2, ' ' + + assert_equal "\nheading\n-------\n\n", @output.string + end + + def test_display_heading_3 + @f.display_heading 'heading', 3, ' ' + + assert_equal " heading\n\n", @output.string + end + + def test_display_list + list = RDoc::Markup::Flow::LIST.new :NUMBER + list << RDoc::Markup::Flow::LI.new(nil, 'a b c') + list << RDoc::Markup::Flow::LI.new(nil, 'd e f') + + @f.display_list list + + assert_equal " 1. a b c\n\n 2. d e f\n\n", @output.string + end + + def test_display_list_bullet + list = RDoc::Markup::Flow::LIST.new :BULLET + list << RDoc::Markup::Flow::LI.new(nil, 'a b c') + + @f.display_list list + + assert_equal " * a b c\n\n", @output.string + end + + def test_display_list_labeled + list = RDoc::Markup::Flow::LIST.new :LABELED + list << RDoc::Markup::Flow::LI.new('label', 'a b c') + + @f.display_list list + + assert_equal " label a b c\n\n", @output.string + end + + def test_display_list_lower_alpha + list = RDoc::Markup::Flow::LIST.new :LOWERALPHA + list << RDoc::Markup::Flow::LI.new(nil, 'a b c') + + @f.display_list list + + assert_equal " a. a b c\n\n", @output.string + end + + def test_display_list_note + list = RDoc::Markup::Flow::LIST.new :NOTE + list << RDoc::Markup::Flow::LI.new('note:', 'a b c') + + @f.display_list list + + assert_equal " note: a b c\n\n", @output.string + end + + def test_display_list_number + list = RDoc::Markup::Flow::LIST.new :NUMBER + list << RDoc::Markup::Flow::LI.new(nil, 'a b c') + + @f.display_list list + + assert_equal " 1. a b c\n\n", @output.string + end + + def test_display_list_unknown + list = RDoc::Markup::Flow::LIST.new :UNKNOWN + list << RDoc::Markup::Flow::LI.new(nil, 'a b c') + + e = assert_raises ArgumentError do + @f.display_list list + end + + assert_equal 'unknown list type UNKNOWN', e.message + end + + def test_display_list_upper_alpha + list = RDoc::Markup::Flow::LIST.new :UPPERALPHA + list << RDoc::Markup::Flow::LI.new(nil, 'a b c') + + @f.display_list list + + assert_equal " A. a b c\n\n", @output.string + end + + def test_display_verbatim_flow_item + verbatim = RDoc::Markup::Flow::VERB.new "a b c\nd e f" + + @f.display_verbatim_flow_item verbatim + + assert_equal " a b c\n d e f\n\n", @output.string + end + + def test_display_verbatim_flow_item_bold + verbatim = RDoc::Markup::Flow::VERB.new "*a* b c" + + @f.display_verbatim_flow_item verbatim + + assert_equal " *a* b c\n\n", @output.string + end + + def test_draw_line + @f.draw_line + + expected = '-' * @width + "\n" + assert_equal expected, @output.string + end + + def test_draw_line_label + @f.draw_line 'label' + + expected = '-' * (@width - 6) + " label\n" + assert_equal expected, @output.string + end + + def test_draw_line_label_long + @f.draw_line 'a' * @width + + expected = '-' * @width + "\n" + ('a' * @width) + "\n" + assert_equal expected, @output.string + end + + def test_raw_print_line + @f.raw_print_line 'a b c' + + assert_equal "a b c", @output.string + end + + def test_strip_attributes_b + text = @f.strip_attributes 'hello <b>world</b>' + + expected = 'hello world' + + assert_equal expected, text + end + + def test_strip_attributes_code + text = @f.strip_attributes 'hello <code>world</code>' + + expected = 'hello world' + + assert_equal expected, text + end + + def test_strip_attributes_em + text = @f.strip_attributes 'hello <em>world</em>' + + expected = 'hello world' + + assert_equal expected, text + end + + def test_strip_attributes_i + text = @f.strip_attributes 'hello <i>world</i>' + + expected = 'hello world' + + assert_equal expected, text + end + + def test_strip_attributes_tt + text = @f.strip_attributes 'hello <tt>world</tt>' + + expected = 'hello world' + + assert_equal expected, text + end + + def test_wrap_empty + @f.wrap '' + assert_equal '', @output.string + end + + def test_wrap_long + @f.wrap 'a ' * (@width / 2) + assert_equal " a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a\n a \n", + @output.string + end + + def test_wrap_markup + @f.wrap 'a <tt>b</tt> c' + assert_equal " a +b+ c\n", @output.string + end + + def test_wrap_nil + @f.wrap nil + assert_equal '', @output.string + end + + def test_wrap_short + @f.wrap 'a b c' + assert_equal " a b c\n", @output.string + end + +end + +MiniTest::Unit.autorun diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_html_formatter.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_html_formatter.rb new file mode 100644 index 000000000..2206cd631 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_html_formatter.rb @@ -0,0 +1,141 @@ +require 'stringio' +require 'rubygems' +require 'minitest/unit' +require 'rdoc/ri/formatter' +require 'rdoc/markup/fragments' +require 'rdoc/markup/to_flow' + +class TestRDocRIHtmlFormatter < MiniTest::Unit::TestCase + + def setup + @output = StringIO.new + @width = 78 + @indent = ' ' + + @f = RDoc::RI::HtmlFormatter.new @output, @width, @indent + @markup = RDoc::Markup.new + @flow = RDoc::Markup::ToFlow.new + @af = RDoc::RI::AttributeFormatter + end + + def test_blankline + @f.blankline + + assert_equal "<p />\n", @output.string + end + + def test_bold_print + @f.bold_print 'text' + + assert_equal '<b>text</b>', @output.string + end + + def test_break_to_newline + @f.break_to_newline + + assert_equal "<br />\n", @output.string + end + + def test_display_heading + @f.display_heading 'text', 1, ' ' + + assert_equal "<h1>text</h1>\n", @output.string + end + + def test_display_heading_level_4 + @f.display_heading 'text', 4, ' ' + + assert_equal "<h4>text</h4>\n", @output.string + end + + def test_display_heading_level_5 + @f.display_heading 'text', 5, ' ' + + assert_equal "<h4>text</h4>\n", @output.string + end + + def test_display_list_bullet + list = RDoc::Markup::Flow::LIST.new :BULLET + list << RDoc::Markup::Flow::LI.new(nil, 'a b c') + list << RDoc::Markup::Flow::LI.new(nil, 'd e f') + + @f.display_list list + + expected = <<-EOF.strip +<ul><li>a b c<p /> +</li><li>d e f<p /> +</li></ul> + EOF + + assert_equal expected, @output.string + end + + def test_display_list_number + list = RDoc::Markup::Flow::LIST.new :NUMBER + list << RDoc::Markup::Flow::LI.new(nil, 'a b c') + list << RDoc::Markup::Flow::LI.new(nil, 'd e f') + + @f.display_list list + + expected = <<-EOF.strip +<ol><li>a b c<p /> +</li><li>d e f<p /> +</li></ol> + EOF + + assert_equal expected, @output.string + end + + def test_display_list_labeled + list = RDoc::Markup::Flow::LIST.new :LABELED + list << RDoc::Markup::Flow::LI.new('label', 'a b c') + list << RDoc::Markup::Flow::LI.new('label 2', 'd e f') + + @f.display_list list + + expected = <<-EOF.strip +<dl><dt><b>label</b></dt><dd>a b c<p /> +</dd><dt><b>label 2</b></dt><dd>d e f<p /> +</dd></dl> + EOF + + assert_equal expected, @output.string + end + + def test_display_list_note + list = RDoc::Markup::Flow::LIST.new :NOTE + list << RDoc::Markup::Flow::LI.new('note:', 'a b c') + list << RDoc::Markup::Flow::LI.new('note 2:', 'd e f') + + @f.display_list list + + expected = <<-EOF.strip +<table><tr valign="top"><td>note:</td><td>a b c<p /> +</td></tr><tr valign="top"><td>note 2:</td><td>d e f<p /> +</td></tr></table> + EOF + + assert_equal expected, @output.string + end + + def test_display_verbatim_flow_item + verbatim = RDoc::Markup::Flow::VERB.new '*a* > b > c' + @f.display_verbatim_flow_item verbatim + + assert_equal "<pre>*a* > b &gt; c\n</pre>\n", @output.string + end + + def test_draw_line + @f.draw_line + + assert_equal "<hr />\n", @output.string + end + + def test_draw_line_label + @f.draw_line 'label' + + assert_equal "<b>label</b><hr />\n", @output.string + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_overstrike_formatter.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_overstrike_formatter.rb new file mode 100644 index 000000000..38b95414d --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_ri_overstrike_formatter.rb @@ -0,0 +1,71 @@ +require 'stringio' +require 'rubygems' +require 'minitest/unit' +require 'rdoc/ri/formatter' +require 'rdoc/markup/fragments' +require 'rdoc/markup/to_flow' + +class TestRDocRIOverstrikeFormatter < MiniTest::Unit::TestCase + + def setup + @output = StringIO.new + @width = 78 + @indent = ' ' + + @f = RDoc::RI::OverstrikeFormatter.new @output, @width, @indent + @markup = RDoc::Markup.new + @flow = RDoc::Markup::ToFlow.new + + @af = RDoc::RI::AttributeFormatter + end + + def test_display_verbatim_flow_item_bold + verbatim = RDoc::Markup::Flow::VERB.new "*a* b c" + + @f.display_verbatim_flow_item verbatim + + assert_equal " *a* b c\n\n", @output.string + end + + def test_write_attribute_text_bold + line = [RDoc::RI::AttributeFormatter::AttrChar.new('b', @af::BOLD)] + + @f.write_attribute_text ' ', line + + assert_equal " b\bb\n", @output.string + end + + def test_write_attribute_text_bold_italic + attr = @af::BOLD | @af::ITALIC + line = [RDoc::RI::AttributeFormatter::AttrChar.new('d', attr)] + + @f.write_attribute_text ' ', line + + assert_equal " _\bd\bd\n", @output.string + end + + def test_write_attribute_text_code + line = [RDoc::RI::AttributeFormatter::AttrChar.new('c', @af::CODE)] + + @f.write_attribute_text ' ', line + + assert_equal " _\bc\n", @output.string + end + + def test_write_attribute_text_italic + line = [RDoc::RI::AttributeFormatter::AttrChar.new('a', @af::ITALIC)] + + @f.write_attribute_text ' ', line + + assert_equal " _\ba\n", @output.string + end + + def test_bold_print + @f.bold_print 'a b c' + + assert_equal "a\ba \b b\bb \b c\bc", @output.string + end + +end + +MiniTest::Unit.autorun diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_task.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_task.rb new file mode 100644 index 000000000..dd3114fb5 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_task.rb @@ -0,0 +1,64 @@ +require 'rubygems' +require 'minitest/autorun' +require 'rdoc/task' + +class TestRDocTask < MiniTest::Unit::TestCase + + def setup + Rake::Task.clear + end + + def test_tasks_creation + RDoc::Task.new + assert Rake::Task[:rdoc] + assert Rake::Task[:clobber_rdoc] + assert Rake::Task[:rerdoc] + end + + def test_tasks_creation_with_custom_name_symbol + rd = RDoc::Task.new(:rdoc_dev) + assert Rake::Task[:rdoc_dev] + assert Rake::Task[:clobber_rdoc_dev] + assert Rake::Task[:rerdoc_dev] + assert_equal :rdoc_dev, rd.name + end + + def test_tasks_creation_with_custom_name_string + rd = RDoc::Task.new("rdoc_dev") + assert Rake::Task[:rdoc_dev] + assert Rake::Task[:clobber_rdoc_dev] + assert Rake::Task[:rerdoc_dev] + assert_equal "rdoc_dev", rd.name + end + + def test_tasks_creation_with_custom_name_hash + options = { :rdoc => "rdoc", :clobber_rdoc => "rdoc:clean", :rerdoc => "rdoc:force" } + rd = RDoc::Task.new(options) + assert Rake::Task[:"rdoc"] + assert Rake::Task[:"rdoc:clean"] + assert Rake::Task[:"rdoc:force"] + assert_raises(RuntimeError) { Rake::Task[:clobber_rdoc] } + assert_equal options, rd.name + end + + def test_tasks_creation_with_custom_name_hash_will_use_default_if_an_option_isnt_given + rd = RDoc::Task.new(:clobber_rdoc => "rdoc:clean") + assert Rake::Task[:rdoc] + assert Rake::Task[:"rdoc:clean"] + assert Rake::Task[:rerdoc] + end + + def test_tasks_creation_with_custom_name_hash_raises_exception_if_invalid_option_given + assert_raises(ArgumentError) do + RDoc::Task.new(:foo => "bar") + end + + begin + RDoc::Task.new(:foo => "bar") + rescue ArgumentError => e + assert_match(/foo/, e.message) + end + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/test/test_rdoc_top_level.rb b/vendor/gems/rdoc-2.4.3/test/test_rdoc_top_level.rb new file mode 100644 index 000000000..3287eacfa --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/test_rdoc_top_level.rb @@ -0,0 +1,85 @@ +require 'rubygems' +require 'minitest/unit' +require 'test/xref_test_case' + +class TestRDocTopLevel < XrefTestCase + + def setup + super + + @top_level = RDoc::TopLevel.new 'path/top_level.rb' + end + + def test_class_all_classes_and_modules + assert_equal %w[C1 C2 C2::C3 C2::C3::H1 C3 C3::H1 C3::H2 C4 C4::C4 M1], + RDoc::TopLevel.all_classes_and_modules.map { |m| m.full_name }.sort + end + + def test_class_classes + assert_equal %w[C1 C2 C2::C3 C2::C3::H1 C3 C3::H1 C3::H2 C4 C4::C4], + RDoc::TopLevel.classes.map { |m| m.full_name }.sort + end + + def test_class_files + assert_equal %w[path/top_level.rb xref_data.rb], + RDoc::TopLevel.files.map { |m| m.full_name }.sort + end + + def test_class_find_class_named + assert_equal @c1, RDoc::TopLevel.find_class_named('C1') + end + + def test_class_find_file_named + assert_equal @xref_data, RDoc::TopLevel.find_file_named(@file_name) + end + + def test_class_find_module_named + assert_equal @m1, RDoc::TopLevel.find_module_named('M1') + end + + def test_class_modules + assert_equal %w[M1], + RDoc::TopLevel.modules.map { |m| m.full_name }.sort + end + + def test_class_reset + RDoc::TopLevel.reset + + assert_empty RDoc::TopLevel.classes + assert_empty RDoc::TopLevel.modules + assert_empty RDoc::TopLevel.files + end + + def test_base_name + assert_equal 'top_level.rb', @top_level.base_name + end + + def test_find_class_or_module_named + assert_equal @c1, @xref_data.find_class_or_module_named('C1') + assert_equal @c4, @xref_data.find_class_or_module_named('C4') + end + + def test_full_name + assert_equal 'path/top_level.rb', @top_level.full_name + end + + def test_http_url + assert_equal 'prefix/path/top_level_rb.html', @top_level.http_url('prefix') + end + + def test_last_modified + assert_equal 'Unknown', @top_level.last_modified + + stat = Object.new + def stat.mtime() 0 end + @top_level.file_stat = stat + + assert_equal '0', @top_level.last_modified + end + + def test_name + assert_equal 'top_level.rb', @top_level.name + end + +end + diff --git a/vendor/gems/rdoc-2.4.3/test/xref_data.rb b/vendor/gems/rdoc-2.4.3/test/xref_data.rb new file mode 100644 index 000000000..5d7e42bc2 --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/xref_data.rb @@ -0,0 +1,46 @@ +XREF_DATA = <<-XREF_DATA +class C1 + + attr :attr + attr_reader :attr_reader + attr_writer :attr_writer + attr_accessor :attr_accessor + + CONST = :const + + def self.m + end + + def m + end +end + +class C2 + class C3 + def m + end + + class H1 + def m? + end + end + end +end + +class C3 + class H1 + end + + class H2 + end +end + +class C4 + class C4 + end +end + +module M1 +end +XREF_DATA + diff --git a/vendor/gems/rdoc-2.4.3/test/xref_test_case.rb b/vendor/gems/rdoc-2.4.3/test/xref_test_case.rb new file mode 100644 index 000000000..9c8b4748d --- /dev/null +++ b/vendor/gems/rdoc-2.4.3/test/xref_test_case.rb @@ -0,0 +1,48 @@ +require 'rubygems' +require 'minitest/unit' +require 'rdoc/stats' +require 'rdoc/options' +require 'rdoc/code_objects' +require 'rdoc/parser/ruby' +require 'test/xref_data' + +class XrefTestCase < MiniTest::Unit::TestCase + + def setup + RDoc::TopLevel.reset + RDoc::AnyMethod.reset + + @file_name = 'xref_data.rb' + @xref_data = RDoc::TopLevel.new @file_name + + @options = RDoc::Options.new + @options.quiet = true + + stats = RDoc::Stats.new 0 + + parser = RDoc::Parser::Ruby.new @xref_data, @file_name, XREF_DATA, @options, + stats + @top_levels = [] + @top_levels.push parser.scan + + generator = Object.new + def generator.class_dir() nil end + def generator.file_dir() nil end + rdoc = RDoc::RDoc.new + RDoc::RDoc.current = rdoc + rdoc.generator = generator + + @c1 = @xref_data.find_module_named 'C1' + @c2 = @xref_data.find_module_named 'C2' + @c2_c3 = @xref_data.find_module_named 'C2::C3' + @c3 = @xref_data.find_module_named 'C3' + @c4 = @xref_data.find_module_named 'C4' + @c4_c4 = @xref_data.find_module_named 'C4::C4' + + @m1 = @xref_data.find_module_named 'M1' + end + +end + +MiniTest::Unit.autorun + |