Skip to content

Instantly share code, notes, and snippets.

@drbrain

drbrain/bm.rb Secret

Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drbrain/3ea0befdadc187cf88dc to your computer and use it in GitHub Desktop.
Save drbrain/3ea0befdadc187cf88dc to your computer and use it in GitHub Desktop.
requirable_files implementation for rubygems/rubygems#971
require 'benchmark/ips'
Gem::Specification.each do |spec|
begin
spec.activate
rescue Gem::LoadError
end
end
def old_find_files_from_load_path glob # :nodoc:
$LOAD_PATH.map { |load_path|
Dir["#{File.expand_path glob, load_path}#{Gem.suffix_pattern}"]
}.flatten.select { |file| File.file? file.untaint }
end
def find_files_from_requirable_files glob
files = []
pattern = "#{glob}#{Gem.suffix_pattern}"
Gem.loaded_specs.each_value do |spec|
files.concat spec.requirable_files.select { |file|
File.fnmatch(pattern, file, File::FNM_EXTGLOB)
}
end
files
end
search = "minitest/*_plugin"
p old_find_files_from_load_path search
p find_files_from_requirable_files search
Benchmark.ips do |x|
x.report('old') { old_find_files_from_load_path search }
x.report('requirable_files') { find_files_from_requirable_files search }
end
$ ruby -Ilib bin/gem pristine --all
[…]
$ ruby -Ilib bm.rb
["/usr/local/lib/ruby/gems/2.1.0/gems/minitest-5.3.5/lib/minitest/pride_plugin.rb"]
["minitest/pride_plugin.rb"]
Calculating -------------------------------------
old 29 i/100ms
requirable_files 12 i/100ms
-------------------------------------------------
old 293.3 (±2.4%) i/s - 1479 in 5.046004s
requirable_files 124.7 (±1.6%) i/s - 624 in 5.004588s
diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb
index 18fb3b3..29d9af1 100644
--- a/lib/rubygems/installer.rb
+++ b/lib/rubygems/installer.rb
@@ -10,6 +10,7 @@ require 'rubygems/package'
require 'rubygems/ext'
require 'rubygems/user_interaction'
require 'fileutils'
+require 'pathname'
##
# The installer installs the files contained in the .gem into the Gem.home.
@@ -246,6 +247,7 @@ class Gem::Installer
generate_bin
write_spec
write_cache_file
+ write_requirable_files
end
say spec.post_install_message unless spec.post_install_message.nil?
@@ -806,5 +808,23 @@ TEXT
FileUtils.cp @gem, cache_file unless File.exist? cache_file
end
+ def write_requirable_files
+ files = []
+
+ spec.full_require_paths.each do |dir|
+ dir = Pathname dir
+ next unless dir.directory?
+
+ dir.find do |entry|
+ files << entry.relative_path_from(dir).to_s unless entry.directory?
+ end
+
+ end
+
+ File.open spec.requirable_files_file, 'w' do |io|
+ io.write files.join "\n"
+ end
+ end
+
end
diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
index 8f4213c..dd27cdf 100644
--- a/lib/rubygems/specification.rb
+++ b/lib/rubygems/specification.rb
@@ -2123,6 +2123,15 @@ class Gem::Specification < Gem::BasicSpecification
self.require_paths = Array(path)
end
+ def requirable_files_file # :nodoc:
+ File.join spec_dir, "#{full_name}.requirable_files"
+ end
+
+ def requirable_files # :nodoc:
+ return [] unless File.exist? requirable_files_file
+ File.read(requirable_files_file).split "\n"
+ end
+
##
# Set requirements to +req+, ensuring it is an array. Don't
# use this, push onto the array instead.
diff --git a/test/rubygems/test_gem_commands_install_command.rb b/test/rubygems/test_gem_commands_install_command.rb
index f03285a..e457cf2 100644
--- a/test/rubygems/test_gem_commands_install_command.rb
+++ b/test/rubygems/test_gem_commands_install_command.rb
@@ -461,6 +461,8 @@ ERROR: Possible alternatives: non_existent_with_hint
a2_gemspec = File.join(gemdir, "a-2.gemspec")
a1_gemspec = File.join(gemdir, "a-1.gemspec")
+ a1_requirable_files = File.join gemdir, "a-1.requirable_files"
+
FileUtils.rm_rf a1_gemspec
FileUtils.rm_rf a2_gemspec
@@ -480,7 +482,7 @@ ERROR: Possible alternatives: non_existent_with_hint
fin = Dir["#{gemdir}/*"]
- assert_equal [a1_gemspec], fin - start
+ assert_equal [a1_gemspec, a1_requirable_files], fin - start
end
def test_execute_two
diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb
index 33b6080..7c98060 100644
--- a/test/rubygems/test_gem_installer.rb
+++ b/test/rubygems/test_gem_installer.rb
@@ -1474,6 +1474,28 @@ gem 'other', version
assert_equal ['bin/executable'], default_spec.files
end
+ def test_write_requirable_files
+ spec = quick_gem 'a' do |s|
+ util_make_exec s
+ s.files = %w[lib/a.rb lib/a/b.rb lib/a.txt]
+ end
+
+ util_build_gem spec
+ installer = util_installer spec, @gemhome
+
+ installer.extract_files
+
+ refute_path_exists spec.requirable_files_file
+
+ installer.write_requirable_files
+
+ assert_path_exists spec.requirable_files_file
+
+ expected = %w[a/b.rb a.rb a.txt].join "\n"
+
+ assert_equal expected, File.read(spec.requirable_files_file)
+ end
+
def old_ruby_required
spec = util_spec 'old_ruby_required', '1' do |s|
s.required_ruby_version = '= 1.4.6'
diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb
index 723a4be..718f3cf 100644
--- a/test/rubygems/test_gem_specification.rb
+++ b/test/rubygems/test_gem_specification.rb
@@ -2974,6 +2974,25 @@ end
assert_equal ["default-2.0.0.0"], Gem::Specification.map(&:full_name)
end
+ def test_requirables_files
+ a = quick_gem 'a'
+
+ expected = %w[a.rb a/b.rb]
+
+ open a.requirable_files_file, 'w' do |io|
+ io.write expected.join "\n"
+ end
+
+ assert_equal expected, a.requirable_files
+ end
+
+ def test_requirables_files_file
+ a = quick_gem 'a'
+
+ assert_equal File.join(a.spec_dir, 'a-2.requirable_files'),
+ a.requirable_files_file
+ end
+
def util_setup_deps
@gem = util_spec "awesome", "1.0" do |awesome|
awesome.add_runtime_dependency "bonobo", []
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment