Class: Isolate

Inherits:
Object
  • Object
show all
Defined in:
lib/isolate.rb

Overview

Restricts GEM_PATH and GEM_HOME and provides a DSL for expressing your code’s runtime Gem dependencies. See README.rdoc for rationale, limitations, and examples.

Defined Under Namespace

Classes: Entry

Constant Summary collapse

VERSION =

:nodoc:

"1.0.1"
@@instance =
nil

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, options = {}, &block) ⇒ Isolate

Create a new Isolate instance. See Isolate.gems for the public API. Don’t use this constructor directly.



55
56
57
58
59
60
61
62
63
64
# File 'lib/isolate.rb', line 55

def initialize path, options = {}, &block
  @enabled      = false
  @entries      = []
  @environments = []
  @install      = options[:install]
  @path         = path
  @verbose      = options[:verbose]

  instance_eval(&block) if block_given?
end

Instance Attribute Details

#entriesObject (readonly)

:nodoc:



12
13
14
# File 'lib/isolate.rb', line 12

def entries
  @entries
end

#pathObject (readonly)

:nodoc:



14
15
16
# File 'lib/isolate.rb', line 14

def path
  @path
end

Class Method Details

.activate(environment) ⇒ Object

Activate (and possibly install) gems for a specific environment. This allows two-stage isolation, which is necessary for stuff like Rails. See README.rdoc for a detailed example.



20
21
22
# File 'lib/isolate.rb', line 20

def self.activate environment
  instance.activate environment
end

.gems(path, options = {}, &block) ⇒ Object

Declare an isolated RubyGems environment, installed in path. The block given will be instance_evaled, see Isolate#gem and Isolate#environment for the sort of stuff you can do.

Option defaults:

{ :install => false, :verbose => false }


32
33
34
35
# File 'lib/isolate.rb', line 32

def self.gems path, options = {}, &block
  @@instance = new path, options, &block
  @@instance.activate
end

.instanceObject

:nodoc:



39
40
41
# File 'lib/isolate.rb', line 39

def self.instance # :nodoc:
  @@instance
end

.refreshObject

Poke RubyGems, we’ve probably monkeyed with a bunch of paths and suchlike. Clears paths, loaded specs, and source indexes.



46
47
48
49
50
# File 'lib/isolate.rb', line 46

def self.refresh # :nodoc:
  Gem.loaded_specs.clear
  Gem.clear_paths
  Gem.source_index.refresh!
end

Instance Method Details

#activate(environment = nil) ⇒ Object

:nodoc:



66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/isolate.rb', line 66

def activate environment = nil # :nodoc:
  enable unless enabled?

  env = environment.to_s if environment
  install environment if install?

  entries.each do |e|
    if e.environments.empty? || e.environments.include?(env)
      Gem.activate e.name, *e.requirement.as_list
    end
  end

  self
end

#disableObject

:nodoc:



81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/isolate.rb', line 81

def disable # :nodoc:
  return self unless enabled?

  ENV["GEM_PATH"] = @old_gem_path
  ENV["GEM_HOME"] = @old_gem_home
  ENV["RUBYOPT"]  = @old_ruby_opt

  $LOAD_PATH.replace @old_load_path

  @enabled = false

  self.class.refresh
  self
end

#enable(&block) ⇒ Object

:nodoc:



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/isolate.rb', line 96

def enable &block # :nodoc:
  return self if enabled?

  @old_gem_path  = ENV["GEM_PATH"]
  @old_gem_home  = ENV["GEM_HOME"]
  @old_ruby_opt  = ENV["RUBYOPT"]
  @old_load_path = $LOAD_PATH.dup

  $LOAD_PATH.reject! { |p| Gem.path.any? { |gp| p.include?(gp) } }

  # HACK: Gotta keep isolate explicitly in the LOAD_PATH in
  # subshells, and the only way I can think of to do that is by
  # abusing RUBYOPT.

  ENV["RUBYOPT"]  = "#{ENV['RUBYOPT']} -I#{File.dirname(__FILE__)}"
  ENV["GEM_PATH"] = ENV["GEM_HOME"] = path

  self.class.refresh

  @enabled = true
  begin; yield; ensure disable end if block_given?
  self
end

#enabled?Boolean

:nodoc:

Returns:

  • (Boolean)


120
121
122
# File 'lib/isolate.rb', line 120

def enabled? # :nodoc:
  @enabled
end

#environment(*environments, &block) ⇒ Object

Restricts gem calls inside block to a set of environments.



126
127
128
129
130
131
132
133
134
135
# File 'lib/isolate.rb', line 126

def environment *environments, &block
  old = @environments.dup
  @environments.concat environments.map { |e| e.to_s }

  begin
    yield
  ensure
    @environments = old
  end
end

#gem(name, *requirements) ⇒ Object

Express a gem dependency. Works pretty much like RubyGems’ gem method, but respects environment and doesn’t activate ‘til later.



141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/isolate.rb', line 141

def gem name, *requirements
  options = Hash === requirements.last ? requirements.pop : {}

  requirement = requirements.empty? ?
    Gem::Requirement.default :
    Gem::Requirement.new(requirements)

  entry = Entry.new name, requirement, @environments.dup,  options

  @entries << entry
  entry
end

#install(environment = nil) ⇒ Object

:nodoc:



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/isolate.rb', line 154

def install environment = nil # :nodoc:
  env = environment.to_s if environment

  installable = entries.select do |e|
    !Gem.available?(e.name, *e.requirement.as_list) &&
      (env.nil? || e.environments.include?(env))
  end

  installable.each_with_index do |e, i|
    if verbose?
      padding  = installable.size.to_s.size
      progress = "[%0#{padding}d/%s]" % [i + 1, installable.size]
      warn "#{progress} Isolating #{e.name} (#{e.requirement})."
    end

    options     = e.options.dup.merge :install_dir => path
    old         = Gem.sources.dup
    source      = options.delete :source
    Gem.sources = Array(source) if source
    installer   = Gem::DependencyInstaller.new options

    installer.install e.name, e.requirement
    Gem.sources = old
  end

  Gem.source_index.refresh!
  self
end

#install?Boolean

:nodoc:

Returns:

  • (Boolean)


183
184
185
# File 'lib/isolate.rb', line 183

def install? # :nodoc:
  @install
end

#verbose?Boolean

:nodoc:

Returns:

  • (Boolean)


187
188
189
# File 'lib/isolate.rb', line 187

def verbose? # :nodoc:
  @verbose
end