# Copyright (C) 2006 Mauricio Fernandez # emulate rubygems.rb and define Gem.path if not loaded # This is much faster than requiring rubygems.rb, which loads way too much # stuff. unless defined? ::Gem require 'rbconfig' module Gem def self.path [ENV['GEM_HOME'], ENV['GEM_PATH'], default_dir].compact.flatten end def self.default_dir if defined? RUBY_FRAMEWORK_VERSION paths = [] paths << APPLE_GEM_HOME if defined? APPLE_GEM_HOME path = File.join(File.dirname(Config::CONFIG["sitedir"]), "Gems") newpath = File.join(path, Config::CONFIG['ruby_version']) # RubyGems post r1498 appends the ruby version to the path. This # modification was included in the RubyGems shipped with 10.5.0. if File.directory?(newpath) # try new path first, user might have upgraded RubyGems and left old # installation behind paths + [ newpath ] else # pre-10.5.0 or older RubyGems paths + [ path ] end else [ File.join(Config::CONFIG['libdir'], 'ruby', 'gems', Config::CONFIG['ruby_version']) ] end end end end # don't let rdoc/ri/ri_paths load rubygems.rb, that takes ~100ms ! emulation = $".all?{|x| /rubygems\.rb$/ !~ x} # 1.9 compatibility $".unshift "rubygems.rb" if emulation require 'rdoc/ri/ri_paths' $".delete "rubygems.rb" if emulation require 'rdoc/ri/ri_writer' module FastRI module Util # Return an array of [name, version, path] arrays corresponding to # the last version of each installed gem. +path+ is the base path of the RI # documentation from the gem. If the version cannot be determined, it will # be +nil+, and the corresponding gem might be repeated in the output array # (once per version). def gem_directories_unique return [] unless defined? Gem gemdirs = Gem.path.map{|p| Dir["#{p}/doc/*/ri"]}.flatten gems = Hash.new{|h,k| h[k] = []} gemdirs.each do |path| gemname, version = %r{/([^/]+)-([^-]*)/ri$}.match(path).captures if gemname.nil? # doesn't follow any conventions :( gems[path[%r{/([^/]+)/ri$}, 1]] << [nil, path] else gems[gemname] << [version, path] end end gems.sort_by{|name, _| name}.map do |name, versions| version, path = versions.sort.last [name, version, File.expand_path(path)] end end module_function :gem_directories_unique # Return the [name, version, path] array for the gem owning the RI # information stored in +path+, or +nil+. def gem_info_for_path(path, gem_dir_info = FastRI::Util.gem_directories_unique) path = File.expand_path(path) matches = gem_dir_info.select{|name, version, gem_path| path.index(gem_path) == 0} matches.sort_by{|name, version, gem_path| [gem_path.size, version, name]}.last end module_function :gem_info_for_path # Return the +full_name+ (in ClassEntry or MethodEntry's sense) given a path # to a .yaml file relative to a "base RI DB path". def gem_relpath_to_full_name(relpath) case relpath when %r{^(.*)/cdesc-([^/]*)\.yaml$} path, name = $~.captures (path.split(%r{/})[0..-2] << name).join("::") when %r{^(.*)/([^/]*)-(i|c)\.yaml$} path, escaped_name, type = $~.captures name = RI::RiWriter.external_to_internal(escaped_name) sep = ( type == 'c' ) ? "." : "#" path.gsub("/", "::") + sep + name end end module_function :gem_relpath_to_full_name # Returns the home directory (win32-aware). def find_home # stolen from RubyGems ['HOME', 'USERPROFILE'].each do |homekey| return ENV[homekey] if ENV[homekey] end if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] return "#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}" end begin File.expand_path("~") rescue StandardError => ex if File::ALT_SEPARATOR "C:/" else "/" end end end module_function :find_home def change_query_method_type(query) if md = /\A(.*)(#|\.|::)([^#.:]+)\z/.match(query) namespace, sep, meth = md.captures case sep when /::/ then "#{namespace}##{meth}" when /#/ then "#{namespace}::#{meth}" else query end else query end end module_function :change_query_method_type module MagicHelp def help_method_extract(m) # :nodoc: unless m.inspect =~ %r[\A#<(?:Unbound)?Method: (.*?)>\Z] raise "Cannot parse result of #{m.class}#inspect: #{m.inspect}" end $1.sub(/\A.*?\((.*?)\)(.*)\Z/){ "#{$1}#{$2}" }.sub(/\./, "::").sub(/##/) { "#{$1}::" } end def magic_help(query) if query =~ /\A(.*?)(#|::|\.)([^:#.]+)\Z/ c, k, m = $1, $2, $3 mid = m begin c = c.split(/::/).inject(Object){|s,x| s.const_get(x)} m = case k when "#" c.instance_method(m) when "::" c.method(m) when "." begin # if it's a private_instance_method, assume it was created # with module_function if c.private_instance_methods.include?(m) c.instance_method(m) else c.method(m) end rescue NameError c.instance_method(m) end end ret = help_method_extract(m) if ret == 'Class#new' and c.private_method_defined?(:initialize) return c.name + "::new" elsif ret =~ /^Kernel#/ and Kernel.instance_methods(false).include? mid return "Object##{mid}" end ret rescue Exception query end else query end end end end # module Util end # module FastRI