Class: GemBench::Jersey
- Inherits:
-
Object
- Object
- GemBench::Jersey
- Defined in:
- lib/gem_bench/jersey.rb
Overview
Re-write a gem to a temp directory, re-namespace the primary namespace of that gem module, and load it. If the original gem defines multiple top-level namespaces, they can all be renamed by providing more key value pairs. If the original gem monkey patches other libraries, that behavior can’t be isolated, so YMMV.
NOTE: Non-top-level namespaces do not need to be renamed, as they are isolated within their parent namespace.
Usage
jersey = GemBench::Jersey.new(
gem_name: "alt_memery"
trades: {
"Memery" => "AltMemery"
},
metadata: {
something: "a value here",
something_else: :obviously,
},
)
jersey.doff_and_don
# The re-namespaced constant is now available!
AltMemery # => AltMemery
Benchmarking Example
See: https://github.com/panorama-ed/memo_wise/blob/main/benchmarks/benchmarks.rb
Instance Attribute Summary collapse
-
#files ⇒ Object
readonly
Returns the value of attribute files.
-
#gem_name ⇒ Object
readonly
Returns the value of attribute gem_name.
-
#gem_path ⇒ Object
readonly
Returns the value of attribute gem_path.
-
#metadata ⇒ Object
readonly
Returns the value of attribute metadata.
-
#trades ⇒ Object
readonly
Returns the value of attribute trades.
-
#verbose ⇒ Object
readonly
Returns the value of attribute verbose.
Instance Method Summary collapse
-
#as_klass ⇒ Class?
Will raise NameError if called before #doff_and_don.
-
#doff_and_don(&block) ⇒ Object
Generates a temp directory, and creates a copy of a gem within it.
-
#doffed_primary_namespace ⇒ String
Namespace of the doffed (original) gem.
-
#donned_primary_namespace ⇒ String
Namespace of the donned gem.
-
#initialize(gem_name:, trades:, metadata: {}, verbose: false) ⇒ Jersey
constructor
A new instance of Jersey.
-
#required? ⇒ Boolean
return [true, false] proxy for whether the copied, re-namespaced gem has been successfully loaded.
Constructor Details
#initialize(gem_name:, trades:, metadata: {}, verbose: false) ⇒ Jersey
Returns a new instance of Jersey.
38 39 40 41 42 43 44 45 |
# File 'lib/gem_bench/jersey.rb', line 38 def initialize(gem_name:, trades:, metadata: {}, verbose: false) @gem_name = gem_name @gem_path = Gem.loaded_specs[gem_name]&.full_gem_path @gem_lib_dir = Gem @trades = trades @metadata = @verbose = verbose end |
Instance Attribute Details
#files ⇒ Object (readonly)
Returns the value of attribute files.
35 36 37 |
# File 'lib/gem_bench/jersey.rb', line 35 def files @files end |
#gem_name ⇒ Object (readonly)
Returns the value of attribute gem_name.
31 32 33 |
# File 'lib/gem_bench/jersey.rb', line 31 def gem_name @gem_name end |
#gem_path ⇒ Object (readonly)
Returns the value of attribute gem_path.
32 33 34 |
# File 'lib/gem_bench/jersey.rb', line 32 def gem_path @gem_path end |
#metadata ⇒ Object (readonly)
Returns the value of attribute metadata.
34 35 36 |
# File 'lib/gem_bench/jersey.rb', line 34 def @metadata end |
#trades ⇒ Object (readonly)
Returns the value of attribute trades.
33 34 35 |
# File 'lib/gem_bench/jersey.rb', line 33 def trades @trades end |
#verbose ⇒ Object (readonly)
Returns the value of attribute verbose.
36 37 38 |
# File 'lib/gem_bench/jersey.rb', line 36 def verbose @verbose end |
Instance Method Details
#as_klass ⇒ Class?
Will raise NameError if called before #doff_and_don
121 122 123 |
# File 'lib/gem_bench/jersey.rb', line 121 def as_klass Object.const_get(donned_primary_namespace) if gem_path end |
#doff_and_don(&block) ⇒ Object
Generates a temp directory, and creates a copy of a gem within it. Re-namespaces the copy according to the ‘trades` configuration. Then requires each file of the “copied gem”, resulting
in a loaded gem that will not have namespace
collisions when loaded alongside the original-namespaced gem.
Note that “copied gem” in the previous sentence is ambiguous without the supporting context. The “copied gem” can mean either the original, or the “copy”, which is why this gem refers to
a "doffed gem" (the original) and a "donned gem" (the copy).
If a block is provided the contents of each file will be yielded to the block,
after all namespace substitutions from `trades` are complete, but before the contents
are written to the re-namespaced gem. The return value of the block will be
written to the file in this scenario.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/gem_bench/jersey.rb', line 66 def doff_and_don(&block) return puts "[#{gem_name}] Skipped (not loaded on #{RUBY_VERSION})" unless gem_path puts "[#{gem_name}] Doffing #{gem_path}" if verbose Dir.mktmpdir do |tmp_dir| files = [] Dir[File.join(gem_path, "lib", "**", "*.rb")].map do |file| if verbose puts "[#{gem_name}] --------------------------------" puts "[#{gem_name}] Doffing file #{file}" puts "[#{gem_name}] --------------------------------" end basename = File.basename(file) dirname = File.dirname(file) puts "[#{gem_name}][#{basename}] dirname: #{dirname}" if verbose is_at_gem_root = dirname[(-4)..(-1)] == "/lib" puts "[#{gem_name}][#{basename}] is_at_gem_root: #{is_at_gem_root}" if verbose lib_split = dirname.split("/lib/")[-1] puts "[#{gem_name}][#{basename}] lib_split: #{lib_split}" if verbose # lib_split could be like: # - "ruby/gems/3.2.0/gems/method_source-1.1.0/lib" # - "method_source" # Se we check to make sure it is actually a subdir of the gem's lib directory full_path = File.join(gem_path, "lib", lib_split) relative_path = !is_at_gem_root && Dir.exist?(full_path) && lib_split puts "[#{gem_name}][#{basename}] relative_path: #{relative_path}" if verbose if relative_path dir_path = File.join(tmp_dir, relative_path) Dir.mkdir(dir_path) unless Dir.exist?(dir_path) puts "[#{gem_name}][#{basename}] copying file to #{dir_path}" if verbose files << create_tempfile_copy(file, dir_path, basename, :dd1, &block) else puts "[#{gem_name}][#{basename}] directory not relative (#{tmp_dir})" if verbose files << create_tempfile_copy(file, tmp_dir, basename, :dd2, &block) end end load_gem_copy(tmp_dir, files) end nil end |
#doffed_primary_namespace ⇒ String
Returns Namespace of the doffed (original) gem.
110 111 112 |
# File 'lib/gem_bench/jersey.rb', line 110 def doffed_primary_namespace trades.keys.first end |
#donned_primary_namespace ⇒ String
Returns Namespace of the donned gem.
115 116 117 |
# File 'lib/gem_bench/jersey.rb', line 115 def donned_primary_namespace trades.values.first end |
#required? ⇒ Boolean
return [true, false] proxy for whether the copied, re-namespaced gem has been successfully loaded
48 49 50 |
# File 'lib/gem_bench/jersey.rb', line 48 def required? gem_path && trades.values.all? { |new_namespace| Object.const_defined?(new_namespace) } end |