diff options
author | dave <dave@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-01-06 05:59:31 +0000 |
---|---|---|
committer | dave <dave@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-01-06 05:59:31 +0000 |
commit | 96ff9b04c1e350621e3f2b4e5e35fa1bd7fb0b2d (patch) | |
tree | e5fae3ab529798283234a6cd58f04c4271b851a9 /lib | |
parent | 79c0e644a175754540399ff2148f3fdb5c998339 (diff) | |
download | ruby-96ff9b04c1e350621e3f2b4e5e35fa1bd7fb0b2d.tar.gz |
Split out ri display code and make pluggable
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5386 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rdoc/ri/ri_display.rb | 254 | ||||
-rw-r--r-- | lib/rdoc/ri/ri_driver.rb | 122 | ||||
-rw-r--r-- | lib/rdoc/ri/ri_options.rb | 10 |
3 files changed, 386 insertions, 0 deletions
diff --git a/lib/rdoc/ri/ri_display.rb b/lib/rdoc/ri/ri_display.rb new file mode 100644 index 0000000000..6899fe165a --- /dev/null +++ b/lib/rdoc/ri/ri_display.rb @@ -0,0 +1,254 @@ +require 'rdoc/ri/ri_util' +require 'rdoc/ri/ri_formatter' +require 'rdoc/ri/ri_options' + + +# This is a kind of 'flag' module. If you want to write your +# own 'ri' display module (perhaps because you'r writing +# an IDE or somesuch beast), you simply write a class +# which implements the various 'display' methods in 'DefaultDisplay', +# and include the 'RiDisplay' module in that class. +# +# To access your class from the command line, you can do +# +# ruby -r <your source file> ../ri .... +# +# If folks _really_ want to do this from the command line, +# I'll build an option in + +module RiDisplay + @@display_class = nil + + def RiDisplay.append_features(display_class) + @@display_class = display_class + end + + def RiDisplay.new(*args) + @@display_class.new(*args) + end +end + +###################################################################### +# +# A paging display module. Uses the ri_formatter class to do the +# actual presentation +# + +class DefaultDisplay + + include RiDisplay + + def initialize(options) + @options = options + @formatter = @options.formatter.new(@options, " ") + end + + + ###################################################################### + + def display_usage + page do + RI::Options::OptionList.usage(short_form=true) + end + end + + + ###################################################################### + + 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 && !method.aliases.empty? + @formatter.blankline + aka = "(also known as " + aka << method.aliases.map {|a| a.name }.join(", ") + aka << ")" + @formatter.wrap(aka) + end + end + end + + ###################################################################### + + def display_class_info(klass, ri_reader) + page do + superclass = klass.superclass_string + + 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| + inc_desc = ri_reader.find_class_by_name(inc.name) + if inc_desc + str = inc.name + "(" + str << inc_desc.instance_methods.map{|m| m.name}.join(", ") + str << ")" + incs << str + else + incs << inc.name + end + end + @formatter.wrap(incs.sort.join(', ')) + end + + unless klass.constants.empty? + @formatter.blankline + @formatter.display_heading("Constants:", 2, "") + len = 0 + klass.constants.each { |c| len = c.name.length if c.name.length > len } + len += 2 + klass.constants.each do |c| + @formatter.wrap(c.value, + @formatter.indent+((c.name+":").ljust(len))) + end + end + + unless klass.class_methods.empty? + @formatter.blankline + @formatter.display_heading("Class methods:", 2, "") + @formatter.wrap(klass.class_methods.map{|m| m.name}.sort.join(', ')) + end + + unless klass.instance_methods.empty? + @formatter.blankline + @formatter.display_heading("Instance methods:", 2, "") + @formatter.wrap(klass.instance_methods.map{|m| m.name}.sort.join(', ')) + end + + unless klass.attributes.empty? + @formatter.blankline + @formatter.wrap("Attributes:", "") + @formatter.wrap(klass.attributes.map{|a| a.name}.sort.join(', ')) + end + end + end + + ###################################################################### + + # Display a list of method names + + def display_method_list(methods) + page do + puts "More than one method matched your request. You can refine" + puts "your search by asking for information on one of:\n\n" + @formatter.wrap(methods.map {|m| m.full_name} .join(", ")) + end + end + + ###################################################################### + + def display_class_list(namespaces) + page do + puts "More than one class or module matched your request. You can refine" + puts "your search by asking for information on one of:\n\n" + @formatter.wrap(namespaces.map {|m| m.full_name}.join(", ")) + end + end + + ###################################################################### + + def list_known_classes(classes) + if classes.empty? + puts "Before using ri, you need to generate documentation" + puts "using 'rdoc' with the --ri option" + else + page do + @formatter.draw_line("Known classes and modules") + @formatter.blankline + @formatter.wrap(classes.sort.join(", ")) + end + end + end + + ###################################################################### + + private + + ###################################################################### + + def page + setup_pager + begin + yield + page_output + ensure + STDOUT.reopen(@save_stdout) if @save_stdout + end + end + + ###################################################################### + + def setup_pager + unless @options.use_stdout + require 'tempfile' + + @save_stdout = STDOUT.clone + STDOUT.reopen(Tempfile.new("ri_")) + end + end + + ###################################################################### + + def page_output + unless @options.use_stdout + path = STDOUT.path + STDOUT.reopen(@save_stdout) + @save_stdout = nil + paged = false + for pager in [ ENV['PAGER'], "less", "more <", 'pager' ].compact.uniq + if system("#{pager} #{path}") + paged = true + break + end + end + if !paged + @options.use_stdout = true + puts File.read(path) + end + end + end + + ###################################################################### + + def display_params(method) + + params = method.params + + if params[0,1] == "(" + if method.is_singleton + params = method.full_name + params + else + params = method.name + params + end + end + params.split(/\n/).each {|p| @formatter.wrap(p) } + end + + ###################################################################### + + def display_flow(flow) + if !flow || flow.empty? + @formatter.wrap("(no description...)") + else + @formatter.display_flow(flow) + end + end + + +end # class RiDisplay diff --git a/lib/rdoc/ri/ri_driver.rb b/lib/rdoc/ri/ri_driver.rb new file mode 100644 index 0000000000..0ca3b4c224 --- /dev/null +++ b/lib/rdoc/ri/ri_driver.rb @@ -0,0 +1,122 @@ +require 'rdoc/ri/ri_paths' +require 'rdoc/ri/ri_cache' +require 'rdoc/ri/ri_util' +require 'rdoc/ri/ri_reader' +require 'rdoc/ri/ri_formatter' +require 'rdoc/ri/ri_options' + + +###################################################################### + +class RiDriver + + def initialize + @options = RI::Options.instance + @options.parse + paths = @options.paths || RI::Paths::PATH + if paths.empty? + $stderr.puts "No ri documentation found in:" + [ RI::Paths::SYSDIR, RI::Paths::SITEDIR, RI::Paths::HOMEDIR].each do |d| + $stderr.puts " #{d}" + end + $stderr.puts "\nWas rdoc run to create documentation?" + exit 1 + end + @ri_reader = RI::RiReader.new(RI::RiCache.new(paths)) + @display = @options.displayer + end + + + + ###################################################################### + + # If the list of matching methods contains exactly one entry, or + # if it contains an entry that exactly matches the requested method, + # then display that entry, otherwise display the list of + # matching method names + + def report_method_stuff(requested_method_name, methods) + if methods.size == 1 + method = @ri_reader.get_method(methods[0]) + @display.display_method_info(method) + else + entries = methods.find_all {|m| m.name == requested_method_name} + if entries.size == 1 + method = @ri_reader.get_method(entries[0]) + @display.display_method_info(method) + else + @display.display_method_list(methods) + end + end + end + + ###################################################################### + + def report_class_stuff(requested_class_name, namespaces) + if namespaces.size == 1 + klass = @ri_reader.get_class(namespaces[0]) + @display.display_class_info(klass, @ri_reader) + else + entries = namespaces.find_all {|m| m.full_name == requested_class_name} + if entries.size == 1 + klass = @ri_reader.get_class(entries[0]) + @display.display_class_info(klass, @ri_reader) + else + @display.display_class_list(namespaces) + end + end + end + + ###################################################################### + + + def get_info_for(arg) + desc = NameDescriptor.new(arg) + + namespaces = @ri_reader.top_level_namespace + + for class_name in desc.class_names + namespaces = @ri_reader.lookup_namespace_in(class_name, namespaces) + if namespaces.empty? + raise RiError.new("Nothing known about #{arg}") + end + end + + if desc.method_name.nil? + report_class_stuff(desc.class_names.join('::'), namespaces) + else + methods = @ri_reader.find_methods(desc.method_name, + desc.is_class_method, + namespaces) + + if methods.empty? + raise RiError.new("Nothing known about #{arg}") + else + report_method_stuff(desc.method_name, methods) + end + end + end + + ###################################################################### + + def process_args + if @options.list_classes + classes = @ri_reader.class_names + @display.list_known_classes(classes) + else + if ARGV.size.zero? + @display.display_usage + else + begin + ARGV.each do |arg| + get_info_for(arg) + end + rescue RiError => e + $stderr.puts(e.message) + exit(1) + end + end + end + end + +end # class RiDriver diff --git a/lib/rdoc/ri/ri_options.rb b/lib/rdoc/ri/ri_options.rb index f0ba69f4d3..c62335c147 100644 --- a/lib/rdoc/ri/ri_options.rb +++ b/lib/rdoc/ri/ri_options.rb @@ -3,6 +3,8 @@ module RI + require 'rdoc/ri/ri_display' + VERSION_STRING = "alpha 0.1" class Options @@ -201,6 +203,14 @@ module RI def paths @doc_dir ? [ @doc_dir ] : nil end + + # Return an instance of the displayer (the thing that actually writes + # the information). This allows us to load in new displayer classes + # at runtime (for example to help with IDE integration) + + def displayer + ::RiDisplay.new(self) + end end end |