Commit f2942117 authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Change --help option behavior.

--help without arguments will now print a short list of all options.

--help=--option-name prints a detailed description of the given option.

Implemented with JsDuck::OptionParser class that extends builtin
OptionParser with the ability to print out help in two formats:
short list of all options & long description of specific option.
parent 185fc7ab
Loading
Loading
Loading
Loading
+106 −0
Original line number Diff line number Diff line
require 'optparse'

module JsDuck

  # JSDuck version of OptionParser
  #
  # Enhanced with ability to output options help in two ways:
  #
  # - short list of all options (with the built-in #help method)
  # - long description of one option (with the added #help_single method)
  #
  class OptionParser < ::OptionParser
    def initialize
      @full_options_index = {}
      super
    end

    # Override the #on method to do some pre-processing on its
    # parameters before passing them to the original #on method.
    #
    # Options are defined as usual:
    #
    #     opts.on("-v", "--version", Type, "First line of description.",
    #             "Second line of description.",
    #             "Third line of description.")
    #
    # But only the first line of description will be passed to
    # original #on method - meaning that #help method will also only
    # list this first line.
    #
    # The remaining lines are saved to a separate place and can be
    # retrieved through asking for full docs for an option with
    # #help_single method.
    #
    def on(*opts, &block)
      core = []
      keys = []
      desc = []

      desc_started = false
      opts.each do |o|
        if desc_started
          desc << o
        elsif String === o
          if o =~ /^-/
            core << o
            keys << o
          else
            core << o
            desc << o
            desc_started = true
          end
        else
          core << o
        end
      end

      full = {:keys => keys, :desc => desc}

      keys.each do |op|
        each_index_key(op) {|k| @full_options_index[k] = full }
      end

      super(*core, &block)
    end

    # Helper that turns option name like --images=PATH into list of
    # keys by which we index the options:
    #
    #     "--images=PATH" --> ["--images", "images"]
    #
    # For options containing "[no-]" all the alternative forms are expanded:
    #
    #     "--[no-]seo"    --> ["--[no-]seo", "[no-]seo", "--seo", "seo", "--no-seo", "no-seo"]
    #
    def each_index_key(option_name)
      key = option_name.sub(/\[?=.*/, '')
      plain_key = key.sub(/^-*/, '')
      [key, plain_key].each do |k|
        yield k
        if k =~ /\[no-\]/
          yield k.sub(/\[no-\]/, '')
          yield k.sub(/\[no-\]/, 'no-')
        end
      end
    end

    # Returns long help text for a single option.
    def help_single(option_name)
      o = @full_options_index[option_name] || {:keys => [option_name], :desc => ["No such option."]}

      r = []

      r << ""
      r << "    " + o[:keys].join(", ")
      r << ""

      o[:desc].each do |line|
        r << "            " + line
      end

      return r.join("\n")
    end
  end

end
+21 −39
Original line number Diff line number Diff line
require 'optparse'
require 'jsduck/option_parser'
require 'jsduck/meta_tag_registry'
require 'jsduck/logger'
require 'jsduck/json_duck'
@@ -142,8 +142,19 @@ module JsDuck
    end

    def create_option_parser
      optparser = OptionParser.new do | opts |
        opts.banner = "Usage: jsduck [options] files/dirs...\n\n"
      optparser = JsDuck::OptionParser.new do | opts |
        opts.banner = "Usage: jsduck [options] files/dirs..."
        opts.separator ""
        opts.separator "For example:"
        opts.separator ""
        opts.separator "    # Documentation for builtin JavaScript classes like Array and String"
        opts.separator "    jsduck --output output/dir  --builtin-classes"
        opts.separator ""
        opts.separator "    # Documentation for your own JavaScript"
        opts.separator "    jsduck --output output/dir  input-file.js some/input/dir"
        opts.separator ""
        opts.separator "The main options:"
        opts.separator ""

        opts.on('-o', '--output=PATH',
          "Directory to output all this amazing documentation.",
@@ -190,6 +201,7 @@ module JsDuck
          Logger.instance.verbose = true
        end

        opts.separator ""
        opts.separator "Customizing output:"
        opts.separator ""

@@ -312,6 +324,7 @@ module JsDuck
          @stats = true
        end

        opts.separator ""
        opts.separator "Debugging:"
        opts.separator ""

@@ -407,43 +420,12 @@ module JsDuck
          @working_dir = nil
        end

        opts.on('-h', '--help[=full]',
          "Short help or --help=full for all available options.", " ") do |v|
          if v == 'full'
            puts opts
        opts.on('-h', '--help[=--some-option]',
          "This help or --help=--option for help on specific option.", " ") do |v|
          if v
            puts opts.help_single(v)
          else
            puts opts.banner
            puts "For example:"
            puts
            puts "    # Documentation for builtin JavaScript classes like Array and String"
            puts "    jsduck --output output/dir  --builtin-classes"
            puts
            puts "    # Documentation for your own JavaScript"
            puts "    jsduck --output output/dir  input-file.js some/input/dir"
            puts
            puts "The main options:"
            puts

            show_help = false
            main_opts = [
              /--output/,
              /--builtin-classes/,
              /--encoding/,
              /--verbose/,
              /--help/,
              /--version/,
            ]
            opts.summarize([], opts.summary_width) do |helpline|
              if main_opts.any? {|re| helpline =~ re }
                puts helpline
                show_help = true
              elsif helpline =~ /^\s*$/ && show_help == true
                puts helpline
                show_help = false
              elsif show_help == true
                puts helpline
              end
            end
            puts opts.help
          end
          exit
        end