diff --git a/README.md b/README.md index 45bf1dd..b02cd72 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,11 @@ gem-man(1) -- view a gem's man page ## SYNOPSIS - gem man - gem man
- gem man --system - gem man --latest + gem man + gem man
+ gem man --gem + gem man --system + gem man --latest gem man --exact gem man --all @@ -26,16 +27,21 @@ your shell). Metalicious. -## GEM +## PAGE -`gem man` expects to be passed the name of an installed gem. If there -are multiple man pages found for the gem, you will be asked which -you'd like to view. If only a single man page is found it will be -displayed. +Name of the manual page to view. All installed gems are searched for a +manual page named like this. Man pages are any files whose extension is a single digit [0-9], e.g. `ronn.1`. +## GEM + +If `--gem` is specified, `gem man` expects to be passed the name of an +installed gem. If there are multiple man pages found for the gem, you +will be asked which you'd like to view. If only a single man page is +found it will be displayed. + ## SECTION Specifying a `SECTION` as the first argument narrows the search to man @@ -53,6 +59,9 @@ man` will ask which you'd prefer. You can specify gems or list available gems using a few options. + * `-g`, `--gem`: + Display pages in a specific gem instead of searching all gems. + * `-s`, `--system`: Fall back to searching for system manuals. That is, `gem man -s mac` will first look for a gem named `mac` with a man page before @@ -65,7 +74,7 @@ You can specify gems or list available gems using a few options. * `-v`, `--version`: Specify version of gem to man. - * `-e`, `--exact`: + * `-e`, `--exact` (only with `-g`): Only list exact matches. * `-a`, `--all`: @@ -81,6 +90,7 @@ See `gem help man` to view the options at any time. gem man mustache gem man 1 ronn + gem man -g ronn gem man -a ## AUTHORING diff --git a/lib/rubygems/commands/man_command.rb b/lib/rubygems/commands/man_command.rb index 158a417..e3e5660 100644 --- a/lib/rubygems/commands/man_command.rb +++ b/lib/rubygems/commands/man_command.rb @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Much of this is stolen from the `open_gem` RubyGem's "read" # command - thanks Adam! # @@ -5,6 +6,11 @@ class Gem::Commands::ManCommand < Gem::Command include Gem::VersionOption + # Search result struct for #get_specs_for_page. +spec+ is the + # Gem::Specification, +manpath+ the relative path of the manpage + # to the spec’s +man_dir+. + SpecPage = Struct.new(:spec, :manpath) + def initialize super 'man', "Open a gem's manual", :command => nil, @@ -17,6 +23,7 @@ def initialize add_latest_version_option add_version_option add_exact_match_option + add_list_gem_option end def usage @@ -55,6 +62,12 @@ def add_exact_match_option end end + def add_list_gem_option + add_option("-g", "--gem", "List manpages for a gem") do |value, options| + options[:gem] = true + end + end + def execute if get_one_optional_argument =~ /^\d$/ section = get_one_optional_argument @@ -63,10 +76,8 @@ def execute if options[:all] puts "These gems have man pages:", '' - specs = Gem::Specification.respond_to?(:each) ? Gem::Specification : Gem.source_index.gems - specs.each do |*name_and_spec| - spec = name_and_spec.pop - puts "#{spec.name} #{spec.version}" if spec.has_manpage? + gems_with_manpages.each do |spec| + puts "#{spec.name} #{spec.version}" end else # gem man 1 mustache @@ -77,17 +88,50 @@ def execute name, section = section, nil end - # Try to read manpages. - if spec = get_spec(name) { |s| s.has_manpage?(section) } - read_manpage(spec, section) - elsif options[:system] - exec "man #{section} #{name}" + if options[:gem] + # Try to read manpages. + if spec = get_spec(name) { |s| s.has_manpage?(section) } + read_manpage(spec, section) + elsif options[:system] + exec "man #{section} #{name}" + else + abort "No manual entry for #{name}" + end else - abort "No manual entry for #{name}" + results = get_specs_for_page(name, section) + + if results.count.zero? + # No gemspec contains this manpage. Try system manpages + # if requested, otherwise fail. + if options[:system] + exec "man #{section} #{name}" + else + abort "No manual entry for #{name}" + end + elsif results.count == 1 + # Exactly one gemspec contains this manpage. Display. + exec "man #{File.join(results.first.spec.man_dir, results.first.manpath)}" + else + # Multiple gemspecs contain this manpage. Let the user choose + # depending on the :latest option. + if options[:latest] + i = -1 # Last ist newest + else + choices = results.map{|s| "#{s.spec.name} #{s.version}"} + c, i = choose_from_list "Open which gem?", choices + end + + exec "man #{File.join(results[i].spec.man_dir, results[i].manpath)}" if i + end end end end + def gems_with_manpages + specs = Gem::Specification.respond_to?(:each) ? Gem::Specification : Gem.source_index.gems + specs.select{|*name_and_spec| name_and_spec.pop.has_manpage?} + end + def read_manpage(spec, section = nil) return if spec.nil? @@ -113,10 +157,6 @@ def read_manpage(spec, section = nil) end end - def gem_path(spec) - File.join(spec.installation_path, "gems", spec.full_name) - end - def get_spec(name, &block) # Since Gem::Dependency.new doesn't want a Regexp # We'll do it ourself! @@ -146,4 +186,23 @@ def get_spec(name, &block) specs[i] if i end end + + # Search all existing specs for the given manpage. + # If requested, only search a specific section. + # Returns a sorted array of SpecPage instances. + def get_specs_for_page(name, section = nil) + gems_with_manpages.map do |spec| + # Check if this gem has the manpage. #manpages(section) + # narrows candidates, the final comparison excludes the + # trailing digit ([0..-2] part). + if manpath = spec.manpages(section).find{|path| path.split(".")[0..-2].join == name} + if options[:version].specific? + return [SpecPage.new(spec, manpath)] if options[:version].satisfied_by?(spec.version) + else + SpecPage.new(spec, manpath) + end + end + end.compact.sort_by{|s| s.spec.version} + end + end