Module: Gem

Defined in:
lib/reactive-core/ext/rubygems_activate_patch.rb

Overview

Monkey patch rubygems to let Gem.activate activate gems matching version requirements but not necessary the latest version

Class Method Summary collapse

Class Method Details

._activate(gem, *version_requirements) ⇒ Object

Raises:

  • (Gem::Exception)


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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
# File 'lib/reactive-core/ext/rubygems_activate_patch.rb', line 21

def self._activate(gem, *version_requirements)
  if version_requirements.empty? then
    version_requirements = Gem::Requirement.default
  end

  unless gem.respond_to?(:name) and
         gem.respond_to?(:version_requirements) then
    gem = Gem::Dependency.new(gem, version_requirements)
  end
puts "gem #{gem.inspect}"

  matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
  report_activate_error(gem) if matches.empty?

  if @loaded_specs[gem.name] then
    # This gem is already loaded.  If the currently loaded gem is not in the
    # list of candidate gems, then we have a version conflict.
    existing_spec = @loaded_specs[gem.name]

    unless matches.any? { |spec| spec.version == existing_spec.version } then
      raise Gem::Exception,
            "can't activate #{gem}, already activated #{existing_spec.full_name}"
    end

    return false
  end

  unhonored = nil
  spec = matches.reverse.find do |candidate|
    # Job done if Gem already loaded
    puts "LOADED #{candidate}" and return false if candidate.loaded?
    puts "candidate #{candidate}"

    candidate.loaded = true
    @loaded_specs[candidate.name] = candidate
    
    # Push the candidate to the stack
    @dependency_stack ||= Array.new
    @dependency_stack << candidate
    mark = @dependency_stack.size - 1

    # Load dependent gems first
    begin
      candidate.runtime_dependencies.each do |dep_gem|
        activate dep_gem
      end
      # Clean up stack
      @dependency_stack.pop
      # We found a valid candidate
      true
    rescue Gem::Exception => e
      unhonored = e.message
      # Deactivate every stacked gem until mark
      @dependency_stack.slice!(mark..-1).each {|spec| deactivate(spec) }
      # Continue with the previous version
      false
    end
  end
  raise Gem::Exception, "can't activate #{gem}, one of its dependencies can't be honored, the last was:\n  #{unhonored}\n#{matches.join("\n")}" if spec.nil?

  # bin directory must come before library directories
  spec.require_paths.unshift spec.bindir if spec.bindir

  require_paths = spec.require_paths.map do |path|
    File.join spec.full_gem_path, path
  end

  sitelibdir = ConfigMap[:sitelibdir]

  # gem directories must come after -I and ENV['RUBYLIB']
  insert_index = load_path_insert_index

  if insert_index then
    # gem directories must come after -I and ENV['RUBYLIB']
    $LOAD_PATH.insert(insert_index, *require_paths)
  else
    # we are probably testing in core, -I and RUBYLIB don't apply
    $LOAD_PATH.unshift(*require_paths)
  end

  return true
end

.activate(gem, *version_requirements) ⇒ Object



12
13
14
15
16
17
18
19
# File 'lib/reactive-core/ext/rubygems_activate_patch.rb', line 12

def self.activate(gem, *version_requirements)
  $indent += 1
  puts ">>activating #{gem.inspect}"
  _activate(gem, *version_requirements)
  puts "<<activated #{gem.inspect}"
ensure
  $indent -= 1
end

.deactivate(spec) ⇒ Object

deactivate a gem. This method is used internally to rollback a gem activation after a dependency mismatch.



105
106
107
108
109
110
111
112
113
114
# File 'lib/reactive-core/ext/rubygems_activate_patch.rb', line 105

def self.deactivate(spec)
  require_paths = spec.require_paths.map do |path|
    File.join spec.full_gem_path, path
  end

  $LOAD_PATH.reject! {|path| require_paths.include? path}
  
  spec.loaded = false
  @loaded_specs.delete(spec.name)
end

.puts(*args) ⇒ Object



6
7
8
9
10
11
# File 'lib/reactive-core/ext/rubygems_activate_patch.rb', line 6

def self.puts(*args)
  return nil
  args.each do |item|
    Kernel.puts item.to_s.gsub(/^/, " "*($indent*2))
  end
end