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.2.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.



64
65
66
67
68
69
70
71
72
73
# File 'lib/isolate.rb', line 64

def initialize path, options = {}, &block
  @enabled      = false
  @entries      = []
  @environments = []
  @install      = options.key?(:install) ? options[:install] : true
  @path         = path
  @verbose      = options.key?(:verbose) ? options[:verbose] : true

  instance_eval(&block) if block_given?
end

Instance Attribute Details

#entriesObject (readonly)

:nodoc:



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

def entries
  @entries
end

#pathObject (readonly)

:nodoc:



23
24
25
# File 'lib/isolate.rb', line 23

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.



29
30
31
# File 'lib/isolate.rb', line 29

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 => true, :verbose => true }


41
42
43
44
# File 'lib/isolate.rb', line 41

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

.instanceObject

:nodoc:



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

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.



55
56
57
58
59
# File 'lib/isolate.rb', line 55

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

Instance Method Details

#activate(environment = nil) ⇒ Object

:nodoc:



75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/isolate.rb', line 75

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

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

  entries.each do |e|
    Gem.activate e.name, *e.requirement.as_list if e.matches? env
  end

  self
end

#disableObject

:nodoc:



88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/isolate.rb', line 88

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

#enableObject

:nodoc:



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/isolate.rb', line 103

def enable # :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
  self
end

#enabled?Boolean

:nodoc:

Returns:

  • (Boolean)


126
127
128
# File 'lib/isolate.rb', line 126

def enabled? # :nodoc:
  @enabled
end

#environment(*environments, &block) ⇒ Object

Restricts gem calls inside block to a set of environments.



132
133
134
135
136
137
138
139
140
141
# File 'lib/isolate.rb', line 132

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

  begin
    instance_eval(&block)
  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.



147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/isolate.rb', line 147

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:



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/isolate.rb', line 160

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

  installable = entries.select do |e|
    !Gem.available?(e.name, *e.requirement.as_list) && e.matches?(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)


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

def install? # :nodoc:
  @install
end

#verbose?Boolean

:nodoc:

Returns:

  • (Boolean)


192
193
194
# File 'lib/isolate.rb', line 192

def verbose? # :nodoc:
  @verbose
end