From 690face91a21878fc96bf31b63b5288054186809 Mon Sep 17 00:00:00 2001 From: dave Date: Fri, 13 Aug 2004 17:50:11 +0000 Subject: [PATCH] Commit miss git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@6766 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/rdoc/usage.rb | 220 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 lib/rdoc/usage.rb diff --git a/lib/rdoc/usage.rb b/lib/rdoc/usage.rb new file mode 100644 index 0000000000..d04f347f8e --- /dev/null +++ b/lib/rdoc/usage.rb @@ -0,0 +1,220 @@ +# = Synopsis +# +# This library allows command-line tools to encapsulate their usage +# as a comment at the top of the main file. Calling RDoc::show_usage +# then displays some or all of that comment, and optionally exits +# the program with an exit status. We always look for the comment +# in the main program file, so it is safe to call this method +# from anywhere in the executing program. +# +# = Usage +# +# RDoc::usage( [ exit_status ], [ section, ...], [options]) +# RDoc::usage_no_exit( [ section, ...], [options]) +# +# where: +# +# exit_status:: +# the integer exit code (default zero). RDoc::usage will exit +# the calling program with this status. +# +# section:: +# an optional list of section names. If specified, only the +# sections with the given names as headings will be output. +# For example, this section is named 'Usage', and the next +# section is named 'Examples'. The section names are case +# insensitive. +# +# options:: +# a hash of options. Option keys and values must implement +to_str+. +# Supported options are: +# +# formatter:: +# plain | html | bs | ansi +# +# Select the output format: plain text, html, text using +# backspace combinations to do underling and bold, or +# text using ANSI escape sequences to colorize bold, italic, etc +# +# +# = Examples +# +# # Comment block describing usage +# # with (optional) section headings +# # . . . +# +# require 'rdoc/usage' +# +# # Display all usage and exit with a status of 0 +# +# RDoc::usage +# +# # Display all usage and exit with a status of 99 +# +# RDoc::usage(99) +# +# # Display usage in the 'Summary' section only, then +# # exit with a status of 99 +# +# RDoc::usage(99, 'Summary') +# +# # Display information in the Author and Copyright +# # sections, then exit 0. Use the ANSI formatter +# # (which colorized using ANSI escape sequences) +# +# RDoc::usage('Author', 'Copyright', :formatter => :ansi) +# +# # Display information in the Author and Copyright +# # sections, but don't exit +# +# RDoc::usage_no_exit('Author', 'Copyright') +# +# = Author +# +# Dave Thomas, The Pragmatic Programmers, LLC +# +# = Copyright +# +# Copyright (c) 2004 Dave Thomas. +# Licensed under the same terms as Ruby +# + +require 'rdoc/markup/simple_markup' +require 'rdoc/markup/simple_markup/to_flow' +require 'rdoc/ri/ri_formatter' +require 'rdoc/ri/ri_options' + +module RDoc + + # Display usage information from the comment at the top of + # the file. String arguments identify specific sections of the + # comment to display. An optional integer first argument + # specifies the exit status (defaults to 0) + + def RDoc.usage(*args) + exit_code = 0 + + if args.size > 0 + status = args[0] + if status.respond_to?(:to_int) + exit_code = status.to_int + args.shift + end + end + + # display the usage and exit with the given code + usage_no_exit(*args) + exit(exit_code) + end + + # Display usage + def RDoc.usage_no_exit(*args) + main_program_file, = caller[-1].split(/:/, 2) + comment = File.open(main_program_file) do |file| + find_comment(file) + end + + comment = comment.gsub(/^\s*#/, '') + + markup = SM::SimpleMarkup.new + flow_convertor = SM::ToFlow.new + + flow = markup.convert(comment, flow_convertor) + + format = "plain" + + unless args.empty? + if args[-1].class == Hash + options = args.pop + o_format = options[:formatter] || options['formatter'] + format = o_format.to_s if o_format + end + flow = extract_sections(flow, args) + end + + options = RI::Options.instance + formatter = RI::TextFormatter.for(format).new(options, " ") + formatter.display_flow(flow) + end + + ###################################################################### + + private + + # Find the first comment in the file (that isn't a shebang line) + # If the file doesn't start with a comment, report the fact + # and return nil + + def RDoc.find_comment(file) + # skip leading blank lines and shebangs + while line = file.gets + break unless line =~ /^(#!|\s*$)/ + end + + comment = [] + + while line && line =~ /^\s*#/ + comment << line + line = file.gets + end + + return no_comment if comment.empty? + + comment.join + end + + + ##### + # Given an array of flow items and an array of section names, extract those + # sections from the flow which have headings corresponding to + # a section name in the list. Return them in the order + # of names in the +sections+ array. + + def RDoc.extract_sections(flow, sections) + result = [] + sections.each do |name| + name = name.downcase + copy_upto_level = nil + + flow.each do |item| + case item + when SM::Flow::H + if copy_upto_level && item.level >= copy_upto_level + copy_upto_level = nil + else + if item.text[0].downcase == name + result << item + copy_upto_level = item.level + end + end + else + if copy_upto_level + result << item + end + end + end + end + result + end + + ##### + # Report the fact that no doc comment count be found + def RDoc.no_comment + $stderr.puts "No usage information available for this program" + nil + end +end + + +if $0 == __FILE__ + + opts = {} + if ARGV[0] && ARGV[0] =~ /^(plain|ansi|html|bs)$/ + opts[:formatter] = ARGV.shift + end + + ARGV.push opts unless opts.empty? + + RDoc::usage(*ARGV) + +end