# File rubygems/commands/unpack_command.rb, line 20 def initialize require 'fileutils' super 'unpack', 'Unpack an installed gem to the current directory', :version => Gem::Requirement.default, :target => Dir.pwd add_option('--target=DIR', 'target directory for unpacking') do |value, options| options[:target] = value end add_option('--spec', 'unpack the gem specification') do |value, options| options[:spec] = true end add_security_option add_version_option end
# File rubygems/commands/unpack_command.rb, line 48 def description <<-EOF The unpack command allows you to examine the contents of a gem or modify them to help diagnose a bug. You can add the contents of the unpacked gem to the load path using the RUBYLIB environment variable or -I: $ gem unpack my_gem Unpacked gem: '.../my_gem-1.0' [edit my_gem-1.0/lib/my_gem.rb] $ ruby -Imy_gem-1.0/lib -S other_program You can repackage an unpacked gem using the build command. See the build command help for an example. EOF end
# File rubygems/commands/unpack_command.rb, line 75 def execute security_policy = options[:security_policy] get_all_gem_names.each do |name| dependency = Gem::Dependency.new name, options[:version] path = get_path dependency unless path alert_error "Gem '#{name}' not installed nor fetchable." next end if @options[:spec] spec, metadata = get_metadata path, security_policy if metadata.nil? alert_error "--spec is unsupported on '#{name}' (old format gem)" next end spec_file = File.basename spec.spec_file FileUtils.mkdir_p @options[:target] if @options[:target] destination = begin if @options[:target] File.join @options[:target], spec_file else spec_file end end File.open destination, 'w' do |io| io.write metadata end else basename = File.basename path, '.gem' target_dir = File.expand_path basename, options[:target] package = Gem::Package.new path, security_policy package.extract_files target_dir say "Unpacked gem: '#{target_dir}'" end end end
Find cached filename in Gem.path
. Returns nil if the file cannot be found.
# File rubygems/commands/unpack_command.rb, line 129 def find_in_cache(filename) Gem.path.each do |path| this_path = File.join(path, "cache", filename) return this_path if File.exist? this_path end return nil end
Extracts the Gem::Specification
and raw metadata from the .gem file at path
.
# File rubygems/commands/unpack_command.rb, line 183 def get_metadata(path, security_policy = nil) format = Gem::Package.new path, security_policy spec = format.spec metadata = nil File.open path, Gem.binary_mode do |io| tar = Gem::Package::TarReader.new io tar.each_entry do |entry| case entry.full_name when 'metadata' then metadata = entry.read when 'metadata.gz' then metadata = Gem::Util.gunzip entry.read end end end return spec, metadata end
Return the full path to the cached gem file matching the given name and version requirement. Returns 'nil' if no match.
Example:
get_path 'rake', '> 0.4' # "/usr/lib/ruby/gems/1.8/cache/rake-0.4.2.gem" get_path 'rake', '< 0.1' # nil get_path 'rak' # nil (exact name required)
# File rubygems/commands/unpack_command.rb, line 155 def get_path(dependency) return dependency.name if dependency.name =~ /\.gem$/i specs = dependency.matching_specs selected = specs.max_by { |s| s.version } return Gem::RemoteFetcher.fetcher.download_to_cache(dependency) unless selected return unless dependency.name =~ /^#{selected.name}$/i # We expect to find (basename).gem in the 'cache' directory. Furthermore, # the name match must be exact (ignoring case). path = find_in_cache File.basename selected.cache_file return Gem::RemoteFetcher.fetcher.download_to_cache(dependency) unless path path end