summaryrefslogtreecommitdiff
path: root/lib/rdoc/usage.rb
diff options
context:
space:
mode:
authordave <dave@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-08-13 17:50:11 +0000
committerdave <dave@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-08-13 17:50:11 +0000
commit690face91a21878fc96bf31b63b5288054186809 (patch)
tree727835dea5d8bf7af5b261fca943bf65d92756c7 /lib/rdoc/usage.rb
parent6bf86382c0f2cf890a4a777c52b1c49ebd2f5322 (diff)
Commit miss
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@6766 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/rdoc/usage.rb')
-rw-r--r--lib/rdoc/usage.rb220
1 files changed, 220 insertions, 0 deletions
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 <tt>RDoc::show_usage</tt>
+# 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