isolate 2.0.0.pre.1 → 2.0.0.pre.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,12 @@
1
+ === 2.0.0.pre.2 / 2010-05-07
2
+
3
+ * Update docs.
4
+ * Add event hooks for better extension/integration.
5
+ * Add ISOLATED env var when Isolate is activated.
6
+ * Teach the Hoe plugin to recognize Isolate files.
7
+ * Add `env` as an alias for `environment`.
8
+ * Clean up Rake tasks.
9
+
1
10
  === 2.0.0.pre.1 / 2010-05-02
2
11
 
3
12
  * Don't provide a special way to set path, options is enough.
data/Manifest.txt CHANGED
@@ -6,6 +6,7 @@ Rakefile
6
6
  lib/hoe/isolate.rb
7
7
  lib/isolate.rb
8
8
  lib/isolate/entry.rb
9
+ lib/isolate/events.rb
9
10
  lib/isolate/now.rb
10
11
  lib/isolate/rake.rb
11
12
  lib/isolate/sandbox.rb
@@ -19,4 +20,5 @@ test/fixtures/with-hoe/specifications/rubyforge-1.0.4.gemspec
19
20
  test/isolate/test.rb
20
21
  test/test_isolate.rb
21
22
  test/test_isolate_entry.rb
23
+ test/test_isolate_events.rb
22
24
  test/test_isolate_sandbox.rb
data/README.rdoc CHANGED
@@ -5,18 +5,13 @@
5
5
  == Description
6
6
 
7
7
  Isolate is a very simple RubyGems sandbox. It provides a way to
8
- express and install your code's Gem dependencies.
8
+ express and automatically install your project's Gem dependencies.
9
9
 
10
- == How?
10
+ == Wha?
11
11
 
12
12
  When Isolate runs, it uses GEM_HOME, GEM_PATH, and a few other tricks
13
- to completely separate your code from the system's RubyGems
14
- configuration, leaving it free to run in blissful solitude.
15
-
16
- While Isolate doesn't make any assumptions about what sort of code
17
- you're writing, it was extracted from a few Rails apps, so it's
18
- naturally going to be most useful with stuff like Rails, Merb, or
19
- Sinatra.
13
+ to separate your code from the system's RubyGems configuration,
14
+ leaving it free to run in blissful solitude.
20
15
 
21
16
  Isolate is very, very, very stupid simple. For a much more
22
17
  full-featured Gem bundler, check out Yehuda Katz and Carl Lerche's
@@ -24,111 +19,116 @@ Bundler[http://github.com/carlhuda/bundler]: It does a lot of fancy
24
19
  AOT dependency resolution, supports non-gem (including git) resources,
25
20
  and is probably a better fit for you.
26
21
 
27
- YMMV, but I haven't tried Isolate with anything older than RubyGems
28
- 1.3.5.
22
+ == Requirements
23
+
24
+ RubyGems 1.3.6 or better, Ruby 1.8.7 or better.
29
25
 
30
- == Examples
26
+ == Getting Started
31
27
 
32
- === Defining Your Isolated Environment
28
+ === Rails 2
33
29
 
34
- It's pretty easy: <tt>gem</tt> is similar to RubyGems' method of the
35
- same name. Version specifiers are optional.
30
+ In <tt>config/preinitializer.rb</tt>:
36
31
 
37
32
  require "rubygems"
38
- require "isolate"
33
+ require "isolate/now"
39
34
 
40
- Isolate.now! do
41
- gem "johnson", "~> 1.1" # or maybe...
42
- gem "jbarnette-johnson"
43
- end
35
+ In <tt>Isolate</tt>:
44
36
 
45
- At the end of the <tt>Isolate.now!</tt> block, you're completely
46
- isolated. <tt>GEM_PATH</tt> and <tt>GEM_HOME</tt> are set, and all
47
- your specified gems have been activated.
37
+ gem "rails", "2.3.5"
38
+ gem "aasm", "2.0.0"
48
39
 
49
- If you need access to the original un-isolated environment for any
50
- reason, you can temporarily disable Isolate:
40
+ env :development, :test do
41
+ gem "sqlite3-ruby", "1.2.5"
42
+ end
51
43
 
52
- Isolate.disable { `heroku config` }
44
+ env :production do
45
+ gem "memcached", "0.19.2"
46
+ end
53
47
 
54
- I occasionally use this to call out to gems or tools that don't belong
55
- in my project.
48
+ Try running <tt>rake environment</tt>. Before anything else happens,
49
+ Isolate will make sure you have copies of every gem you need (extend
50
+ the example above to cover all your dependencies). If they're already
51
+ installed on your system Isolate will use them, otherwise a private
52
+ copy will be installed under <tt>tmp/isolate</tt>.
56
53
 
57
- === Conditionals
54
+ === Rails 3
58
55
 
59
- Sometimes different sets of gems are appropriate at different
60
- times. Isolate allows you to restrict gems by 'environment' (which is
61
- really just a string passed in when things are activated).
56
+ In <tt>config/boot.rb</tt>:
62
57
 
63
- Isolate.now! do
64
- gem "intercession"
58
+ require "rubygems"
59
+ require "isolate/now"
65
60
 
66
- environment :test, :cucumber do
67
- gem "mocha"
68
- end
69
- end
61
+ Construct your <tt>Isolate</tt> file as above. Be sure to remove any
62
+ references to <tt>Bundler.setup</tt> and <tt>Bundler.require</tt> from
63
+ <tt>config/boot.rb</tt> and <tt>config/application.rb</tt>.
70
64
 
71
- Unsurprisingly, the <tt>mocha</tt> gem will only be activated in the
72
- <tt>test</tt> and <tt>cucumber</tt> environments. See the Rails
73
- example below for an example of how to use <tt>RAILS_ENV</tt> to set
74
- your environment.
65
+ === Sinatra, Rack, and Anything Else
75
66
 
76
- === Options
67
+ There's nothing special about Rails, it's just an easy first
68
+ example. You can use Isolate with any library or framework by simply
69
+ putting an <tt>Isolate</tt> file in the root of your project and
70
+ requiring <tt>isolate/now</tt> as early as possible in the startup
71
+ process.
77
72
 
78
- Any trailing hash args to <tt>gem</tt> are attached to Isolate's gem
79
- entry as options. There are two well-known keys, <tt>:source</tt>
80
- and <tt>:args</tt>.
73
+ When you're starting up, Isolate tries to determine its environment by
74
+ looking at the <tt>ISOLATE_ENV</tt>, <tt>RACK_ENV</tt>, and
75
+ <tt>RAILS_ENV</tt> env vars. If none are set, it defaults to
76
+ <tt>development</tt>.
81
77
 
82
- # explicitly specify gem source
83
- gem "jbarnette-johnson", :source => "http://gems.github.com"
78
+ === Library Development
84
79
 
85
- # pass gem install args (the part after the '--')
86
- gem "agem", :args => "--no-blah"
80
+ If you're using Hoe[http://blog.zenspider.com/hoe] to manage your
81
+ library, you can use Isolate's Hoe plugin to automatically install
82
+ your lib's development, runtime, and test dependencies without
83
+ polluting your system RubyGems, and run your tests/specs in total
84
+ isolation.
87
85
 
88
- === An External File
86
+ Assuming you have a recent Hoe and isolate's installed, it's as simple
87
+ as putting:
89
88
 
90
- It's nice to play use <tt>Isolate.now!</tt> inline, but it's better to
91
- keep all your stuff in an external file. This is supported by default:
89
+ Hoe.plugin :isolate
92
90
 
93
- Isolate.now!
91
+ before the <tt>Hoe.spec</tt> call in your <tt>Rakefile</tt>.
94
92
 
95
- This will look for `Isolate` and `config/isolate.rb` files relative to
96
- the current directory, and `instance_eval` the first one it finds. If
97
- there's another matching file with a `.local` extension, Isolate will
98
- grab that one too. This makes it easy to have additional config that's
99
- specific to a deployment or developer.
93
+ If you're not using Hoe, you can use an <tt>Isolate.now!</tt> block at
94
+ the top of your Rakefile. See the RDoc for details.
100
95
 
101
- === Installing Isolated Gems
96
+ == Rake
102
97
 
103
- By default, Isolate will install and clean up your gems
104
- automatically. You can pass the <tt>:cleanup</tt>, <tt>:install</tt>,
105
- and <tt>:verbose</tt> options to control things:
98
+ Isolate provides a few useful Rake tasks.
106
99
 
107
- # don't remove unnecesary gems
108
- Isolate.now!, :cleanup => false
100
+ === isolate:env
109
101
 
110
- # install, but quietly
111
- Isolate.now! :verbose => false
102
+ This task shows you the current Isolate settings and gems.
112
103
 
113
- # don't install
114
- Isolate.now! :install => false
104
+ $ rake isolate:env
115
105
 
116
- All of these options can be set inside your `Isolate` file, too:
106
+ path: tmp/isolate/ruby-1.8
107
+ env: development
108
+ files: Isolate
117
109
 
118
- options :cleanup => false, :verbose => false
110
+ cleanup? true
111
+ enabled? true
112
+ install? true
113
+ multiruby? true
114
+ system? true
115
+ verbose? true
119
116
 
120
- === Interaction and Rake
117
+ [all environments]
118
+ gem rails, = 2.3.5
119
+ gem aasm, = 2.0.0
121
120
 
122
- You don't strictly need them, but Isolate provides a set of Rake tasks
123
- that make a few common thing easier. To use them, just drop a
124
- <tt>require</tt> in your <tt>Rakefile</tt>:
121
+ [development, test]
122
+ gem sqlite3-ruby, = 1.2.5
125
123
 
126
- require "isolate/rake"
124
+ [production]
125
+ gem memcached, = 0.19.2
127
126
 
128
- ==== Running Shell Commands
127
+ === isolate:sh
129
128
 
130
- When you're in an isolated subshell, the command-line tools provided
131
- by any of your gems are available on your PATH.
129
+ This task allows you to run a subshell or a command in the isolated
130
+ environment, making any command-line tools available on your
131
+ <tt>PATH</tt>.
132
132
 
133
133
  # run a single command in an isolated subshell
134
134
  $ rake isolate:sh['gem list']
@@ -136,92 +136,37 @@ by any of your gems are available on your PATH.
136
136
  # run a new isolated subshell
137
137
  $ rake isolate:sh
138
138
 
139
- ==== What's up?
140
-
141
- $ rake isolate:debug
142
-
143
- === A Rails 2 Example
144
-
145
- Here's a quick example (extracted from a real project) of how to use
146
- Isolate with Rails. This project doesn't use vendored Rails, and
147
- doesn't want to depend on any system gems (except isolate, of course).
148
-
149
- Let's edit <tt>config/preinitializer.rb</tt>:
150
-
151
- require "rubygems"
152
- require "isolate"
153
-
154
- Isolate.now!
155
-
156
- In <tt>config/isolate.rb</tt>:
157
-
158
- gem "rails", "= 2.2.2"
139
+ === isolate:stale
159
140
 
160
- # async emails!
161
- gem "ar_mailer", "~> 1.3", '>= 1.3.3'
141
+ This task lists gems that have a more recent released version than the
142
+ one you're using.
162
143
 
163
- # Facebook integration
164
- gem "facebooker", ">= 1.0.31"
144
+ $ rake isolate:stale
145
+ aasm (2.0.0 < 2.1.5)
165
146
 
166
- # Google contacts integration
167
- gem "gmail_contacts", "~> 1.7"
147
+ == Further Reading
168
148
 
169
- # View templates
170
- gem "haml", "~> 2.0"
149
+ <tt>require "isolate/now"</tt> is sugar for <tt>Isolate.now!</tt>,
150
+ which creates, configures, and activates a singleton version of
151
+ Isolate's sandbox. <tt>Isolate.now!</tt> takes a few useful options,
152
+ and lets you define an entire environment inline without using an
153
+ external file.
171
154
 
172
- # Session as model
173
- gem "intercession", "~> 1.0"
174
-
175
- # XML/HTML parsing in Facebooker and tests
176
- gem "nokogiri", ">= 1.2.3"
177
-
178
- # Twitter authentication
179
- gem "oauth", "~> 0.3"
180
-
181
- environment :cucumber, :development, :test do
182
- gem "cucumber" # stories!
183
- gem "modelizer" # easy model factories
184
- gem "sqlite3-ruby" # database support
185
- gem "vlad" # deployment
186
- gem "webrat" # integration tests
187
- end
188
-
189
- You could specify all this inside the <tt>Isolate.now!</tt> block, of
190
- course, but keeping everything in an external file is nicer.
191
-
192
- Since this is loaded in the preinitializer, Isolate will install and
193
- activate the all gems before Rails loads. The current environment is
194
- determined by looking at the <tt>ISOLATE_ENV</tt>, <tt>RAILS_ENV</tt>,
195
- or <tt>RACK_ENV</tt> environment variable. If none are set,
196
- <tt>"development"</tt> is the default.
197
-
198
- Pow. Isolated!
199
-
200
- === A Library Example
201
-
202
- If you're using Hoe[http://blog.zenspider.com/hoe] to manage your
203
- library, you can use Isolate's Hoe plugin to automatically install
204
- your lib's development, runtime, and test dependencies without
205
- polluting your system RubyGems, and run your tests/specs in total
206
- isolation.
207
-
208
- Assuming you have a recent Hoe and isolate's installed, it's as simple
209
- as putting:
210
-
211
- Hoe.plugin :isolate
212
-
213
- before the <tt>Hoe.spec</tt> call in your <tt>Rakefile</tt>.
214
-
215
- If you're not using Hoe, you can just do a regular
216
- <tt>Isolate.now!</tt> block at the top of your Rakefile.
155
+ For detailed information on <tt>Isolate.now!</tt> and the rest of the
156
+ public API, please see the RDoc.
217
157
 
218
158
  == Installation
219
159
 
220
160
  $ gem install isolate
221
161
 
162
+ == Meta
163
+
164
+ Bugs:: http://github.com/jbarnette/isolate/issues
165
+ Email:: isolate@librelist.com
166
+
222
167
  == License
223
168
 
224
- Copyright 2009 John Barnette, et al. (jbarnette@rubyforge.org)
169
+ Copyright 2009-2010 John Barnette, et al. (code@jbarnette.com)
225
170
 
226
171
  Permission is hereby granted, free of charge, to any person obtaining
227
172
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -15,5 +15,5 @@ Hoe.spec "isolate" do
15
15
  self.readme_file = "README.rdoc"
16
16
  self.testlib = :minitest
17
17
 
18
- extra_dev_deps << ["minitest", "~> 1.4"]
18
+ extra_dev_deps << ["minitest", "~> 1.6"]
19
19
  end
data/lib/hoe/isolate.rb CHANGED
@@ -19,23 +19,39 @@ class Hoe # :nodoc:
19
19
  module Isolate
20
20
 
21
21
  # Where should Isolate, um, isolate? [default: <tt>"tmp/isolate"</tt>]
22
+ # FIX: consider removing this and allowing +isolate_options+ instead.
22
23
 
23
24
  attr_accessor :isolate_dir
24
25
 
25
- def initialize_isolate # :nodoc:
26
+ def initialize_isolate
26
27
  # Tee hee! Move ourselves to the front to beat out :test.
27
28
  Hoe.plugins.unshift Hoe.plugins.delete(:isolate)
29
+
28
30
  self.isolate_dir ||= "tmp/isolate"
31
+ @sandbox = ::Isolate::Sandbox.new
32
+
33
+ @sandbox.entries.each do |entry|
34
+ dep = [entry.name, *entry.requirement.as_list]
35
+
36
+ if entry.environments.include? "development"
37
+ extra_dev_deps << dep
38
+ elsif entry.environments.empty?
39
+ extra_deps << dep
40
+ end
41
+ end
29
42
  end
30
43
 
31
44
  def define_isolate_tasks # HACK
32
- i = ::Isolate::Sandbox.new :path => isolate_dir
33
45
 
46
+ # reset, now that they've had a chance to change it
47
+ @sandbox.options :path => isolate_dir
48
+
49
+ # allows traditional extra{_dev}_deps calls to override
34
50
  (self.extra_deps + self.extra_dev_deps).each do |name, version|
35
- i.gem name, *Array(version)
51
+ @sandbox.gem name, *Array(version)
36
52
  end
37
53
 
38
- i.activate
54
+ @sandbox.activate
39
55
  end
40
56
  end
41
57
  end
data/lib/isolate.rb CHANGED
@@ -8,7 +8,7 @@ module Isolate
8
8
 
9
9
  # Duh.
10
10
 
11
- VERSION = "2.0.0.pre.1"
11
+ VERSION = "2.0.0.pre.2"
12
12
 
13
13
  # Disable Isolate. If a block is provided, isolation will be
14
14
  # disabled for the scope of the block.
@@ -17,10 +17,17 @@ module Isolate
17
17
  sandbox.disable(&block)
18
18
  end
19
19
 
20
+ # What environment should be isolated? Consults environment
21
+ # variables <tt>ISOLATE_ENV</tt>, <tt>RAILS_ENV</tt>, and
22
+ # <tt>RACK_ENV</tt>. Defaults to <tt>development"/tt> if none are
23
+ # set.
24
+
20
25
  def self.env
21
26
  ENV["ISOLATE_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
22
27
  end
23
28
 
29
+ # Deprecated. See Isolate.now!
30
+
24
31
  def self.gems path, options = {}, &block # :nodoc:
25
32
  warn "Isolate.gems is deprecated, use Isolate.now! instead.\n" +
26
33
  "Isolate.gems will be removed in v3.0."
@@ -28,6 +35,8 @@ module Isolate
28
35
  now! options.merge(:path => path), &block
29
36
  end
30
37
 
38
+ # Deprecated. See Isolate.sandbox.
39
+
31
40
  def self.instance
32
41
  warn "Isolate.instance is deprecated, use Isolate.sandbox instead.\n" +
33
42
  "Isolate.instance will be removed in v3.0."
@@ -37,21 +46,49 @@ module Isolate
37
46
 
38
47
  @@sandbox = nil
39
48
 
49
+ # A singleton instance of Isolate::Sandbox.
50
+
40
51
  def self.sandbox
41
52
  @@sandbox
42
53
  end
43
54
 
44
55
  # Declare an isolated RubyGems environment, installed in +path+. Any
45
- # block given will be <tt>instance_eval</tt>ed, see Isolate#gem and
46
- # Isolate#environment for the sort of stuff you can do.
56
+ # block given will be <tt>instance_eval</tt>ed, see
57
+ # Isolate::Sandbox#gem and Isolate::Sandbox#environment for the sort
58
+ # of stuff you can do.
59
+ #
60
+ # Valid options:
61
+ #
62
+ # :cleanup:: Should obsolete gems be removed? Default is +true+.
63
+ #
64
+ # :file:: Specify an Isolate file to +instance_eval+. Default is
65
+ # <tt>Isolate</tt> or <tt>config/isolate.rb</tt>, whichever
66
+ # is found first. Passing <tt>false</tt> disables file
67
+ # loading.
68
+ #
69
+ # :install:: Should missing gems be installed? Default is +true+.
70
+ #
71
+ # :multiruby:: Should Isolate assume that multiple Ruby versions
72
+ # will be used simultaneously? If so, gems will be
73
+ # segregated by Ruby version. Default is +true+.
74
+ #
75
+ # :path:: Where should isolated gems be kept? Default is
76
+ # <tt>tmp/isolate"</tt>, and a Ruby version specifier suffix
77
+ # will be added if <tt>:multiruby</tt> is +true+.
78
+ #
79
+ # :system:: Should system gems be allowed to satisfy dependencies?
80
+ # Default is +true+.
81
+ #
82
+ # :verbose:: Should Isolate be chatty during installs and nukes?
83
+ # Default is +true+.
47
84
 
48
85
  def self.now! options = {}, &block
49
86
  @@sandbox = Isolate::Sandbox.new options, &block
50
87
  @@sandbox.activate
51
88
  end
52
89
 
53
- # Poke RubyGems, we've probably monkeyed with a bunch of paths and
54
- # suchlike. Clears paths, loaded specs, and source indexes.
90
+ # Poke RubyGems, since we've probably monkeyed with a bunch of paths
91
+ # and suchlike. Clears paths, loaded specs, and source indexes.
55
92
 
56
93
  def self.refresh # :nodoc:
57
94
  Gem.loaded_specs.clear
data/lib/isolate/entry.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "isolate/events"
1
2
  require "rubygems"
2
3
  require "rubygems/command"
3
4
  require "rubygems/dependency_installer"
@@ -7,9 +8,12 @@ require "rubygems/version"
7
8
  module Isolate
8
9
 
9
10
  # An isolated Gem, with requirement, environment restrictions, and
10
- # installation options. Internal use only.
11
+ # installation options. Generally intended for internal use. This
12
+ # class exposes lifecycle events for extension, see Isolate::Events
13
+ # for more information.
11
14
 
12
15
  class Entry
16
+ include Events
13
17
 
14
18
  # Which environments does this entry care about? Generally an
15
19
  # Array of Strings. An empty array means "all", not "none".
@@ -31,9 +35,14 @@ module Isolate
31
35
  attr_reader :requirement
32
36
 
33
37
  # Create a new entry. Takes +sandbox+ (currently an instance of
34
- # Isolate), +name+ (as above), and any number of optional version
35
- # requirements (generally Strings). Options can be passed as a
36
- # trailing hash. FIX: document well-known keys.
38
+ # Isolate::Sandbox), +name+ (as above), and any number of optional
39
+ # version requirements (generally strings). Options can be passed
40
+ # as a trailing hash. Well-known keys:
41
+ #
42
+ # :args:: Command-line build arguments. Passed to the gem at
43
+ # installation time.
44
+ #
45
+ # :source:: An alternative RubyGems source for this gem.
37
46
 
38
47
  def initialize sandbox, name, *requirements
39
48
  @environments = []
@@ -53,26 +62,32 @@ module Isolate
53
62
  update(*requirements)
54
63
  end
55
64
 
65
+ # Activate this entry. Fires <tt>:activating</tt> and
66
+ # <tt>:activated</tt>.
67
+
56
68
  def activate
57
- Gem.activate name, *requirement.as_list
69
+ fire :activating, :activated do
70
+ Gem.activate name, *requirement.as_list
71
+ end
58
72
  end
59
73
 
60
- # Install this entry in the sandbox.
74
+ # Install this entry in the sandbox. Fires <tt>:installing</tt>
75
+ # and <tt>:installed</tt>.
61
76
 
62
77
  def install
63
78
  old = Gem.sources.dup
64
79
 
65
80
  begin
66
- cache = File.join @sandbox.path, "cache"
81
+ fire :installing, :installed do
82
+ installer = Gem::DependencyInstaller.new :development => false,
83
+ :generate_rdoc => false, :generate_ri => false,
84
+ :install_dir => @sandbox.path
67
85
 
68
- installer = Gem::DependencyInstaller.new :development => false,
69
- :generate_rdoc => false, :generate_ri => false,
70
- :install_dir => @sandbox.path
86
+ Gem.sources += Array(options[:source]) if options[:source]
87
+ Gem::Command.build_args = Array(options[:args]) if options[:args]
71
88
 
72
- Gem.sources += Array(options[:source]) if options[:source]
73
- Gem::Command.build_args = Array(options[:args]) if options[:args]
74
-
75
- installer.install @file || name, requirement
89
+ installer.install @file || name, requirement
90
+ end
76
91
  ensure
77
92
  Gem.sources = old
78
93
  Gem::Command.build_args = nil
@@ -92,14 +107,22 @@ module Isolate
92
107
  name == spec.name and requirement.satisfied_by? spec.version
93
108
  end
94
109
 
110
+ # The Gem::Specification for this entry.
111
+
112
+ def specification
113
+ Gem.source_index.find_name(name, requirement).first
114
+ end
115
+
95
116
  # Updates this entry's environments, options, and
96
117
  # requirement. Environments and options are merged, requirement is
97
- # replaced.
118
+ # replaced. Fires <tt>:updating</tt> and <tt>:updated</tt>.
98
119
 
99
120
  def update *reqs
100
- @environments |= @sandbox.environments
101
- @options.merge! reqs.pop if Hash === reqs.last
102
- @requirement = Gem::Requirement.new reqs unless reqs.empty?
121
+ fire :updating, :updated do
122
+ @environments |= @sandbox.environments
123
+ @options.merge! reqs.pop if Hash === reqs.last
124
+ @requirement = Gem::Requirement.new reqs unless reqs.empty?
125
+ end
103
126
 
104
127
  self
105
128
  end
@@ -0,0 +1,42 @@
1
+ module Isolate
2
+
3
+ # A simple way to watch and extend the Isolate lifecycle.
4
+ #
5
+ # Isolate::Events.watch Isolate::Sandbox, :initialized do |sandbox|
6
+ # puts "A sandbox just got initialized: #{sandbox}"
7
+ # end
8
+ #
9
+ # Read the source for Isolate::Sandbox and Isolate::Entry to see
10
+ # what sort of events are fired.
11
+
12
+ module Events
13
+
14
+ # Watch for an event called +name+ from an instance of
15
+ # +klass+. +block+ will be called when the event occurs. Block
16
+ # args vary by event, but usually an instance of the relevant
17
+ # class is passed.
18
+
19
+ def self.watch klass, name, &block
20
+ watchers[[klass, name]] << block
21
+ end
22
+
23
+ def self.fire klass, name, *args #:nodoc:
24
+ watchers[[klass, name]].each do |block|
25
+ block[*args]
26
+ end
27
+ end
28
+
29
+ def self.watchers #:nodoc:
30
+ @watchers ||= Hash.new { |h, k| h[k] = [] }
31
+ end
32
+
33
+ def fire name, after = nil, *args, &block #:nodoc:
34
+ Isolate::Events.fire self.class, name, *args
35
+
36
+ if after && block_given?
37
+ yield self
38
+ Isolate::Events.fire self.class, after, *args
39
+ end
40
+ end
41
+ end
42
+ end
data/lib/isolate/rake.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  namespace :isolate do
2
2
  desc "Show current isolated environment."
3
- task :debug do
3
+ task :env do
4
4
  require "pathname"
5
5
 
6
6
  sandbox = Isolate.sandbox
@@ -9,10 +9,10 @@ namespace :isolate do
9
9
  files = sandbox.files.map { |f| Pathname(f) }
10
10
 
11
11
  puts
12
- puts " sandbox: #{path}"
12
+ puts " path: #{path}"
13
13
  puts " env: #{Isolate.env}"
14
14
 
15
- files.collect! { |f| f.absolute? ? f.relative_path_from(here) : f }
15
+ files.map! { |f| f.absolute? ? f.relative_path_from(here) : f }
16
16
  puts " files: #{files.join ', '}"
17
17
  puts
18
18
 
@@ -45,4 +45,26 @@ namespace :isolate do
45
45
  task :sh, [:command] do |t, args|
46
46
  exec args.command || ENV["SHELL"]
47
47
  end
48
+
49
+ desc "Which isolated gems have updates available?"
50
+ task :stale do
51
+ require "rubygems/source_index"
52
+ require "rubygems/spec_fetcher"
53
+
54
+ index = Gem::SourceIndex.new
55
+ index.add_specs *Isolate.sandbox.entries.map { |e| e.specification }
56
+
57
+ outdated = index.outdated.map do |n|
58
+ Isolate.sandbox.entries.find { |e| e.name == n }
59
+ end
60
+
61
+ outdated.sort_by { |e| e.name }.each do |entry|
62
+ local = entry.specification.version
63
+ dep = Gem::Dependency.new entry.name, ">= #{local}"
64
+ remotes = Gem::SpecFetcher.fetcher.fetch dep
65
+ remote = remotes.last.first.version
66
+
67
+ puts "#{entry.name} (#{local} < #{remote})"
68
+ end
69
+ end
48
70
  end
@@ -1,17 +1,26 @@
1
1
  require "fileutils"
2
2
  require "isolate/entry"
3
+ require "isolate/events"
3
4
  require "rbconfig"
4
5
  require "rubygems/defaults"
5
6
  require "rubygems/uninstaller"
6
7
 
7
8
  module Isolate
9
+
10
+ # An isolated environment. This class exposes lifecycle events for
11
+ # extension, see Isolate::Events for more information.
12
+
8
13
  class Sandbox
14
+ include Events
15
+
9
16
  attr_reader :entries # :nodoc:
10
17
  attr_reader :environments # :nodoc:
11
18
  attr_reader :files # :nodoc:
12
19
 
13
- # Create a new Isolate instance. See Isolate.gems for the public
14
- # API. You probably don't want to use this constructor directly.
20
+ # Create a new Isolate::Sandbox instance. See Isolate.now! for the
21
+ # most common use of the API. You probably don't want to use this
22
+ # constructor directly. Fires <tt>:initializing</tt> and
23
+ # <tt>:initialized</tt>.
15
24
 
16
25
  def initialize options = {}, &block
17
26
  @enabled = false
@@ -22,6 +31,8 @@ module Isolate
22
31
 
23
32
  file, local = nil
24
33
 
34
+ fire :initializing
35
+
25
36
  unless FalseClass === options[:file]
26
37
  file = options[:file] || Dir["{Isolate,config/isolate.rb}"].first
27
38
  local = "#{file}.local" if file
@@ -36,6 +47,7 @@ module Isolate
36
47
  end
37
48
 
38
49
  load local if local && File.exist?(local)
50
+ fire :initialized
39
51
  end
40
52
 
41
53
  # Activate this set of isolated entries, respecting an optional
@@ -44,10 +56,12 @@ module Isolate
44
56
  # everything, and removes any superfluous gem (again, if
45
57
  # necessary). If +environment+ isn't specified, +ISOLATE_ENV+,
46
58
  # +RAILS_ENV+, and +RACK_ENV+ are checked before falling back to
47
- # <tt>"development"</tt>.
59
+ # <tt>"development"</tt>. Fires <tt>:activating</tt> and
60
+ # <tt>:activated</tt>.
48
61
 
49
62
  def activate environment = nil
50
63
  enable unless enabled?
64
+ fire :activating
51
65
 
52
66
  env = (environment || Isolate.env).to_s
53
67
 
@@ -58,38 +72,43 @@ module Isolate
58
72
  end
59
73
 
60
74
  cleanup if cleanup?
75
+ fire :activated
61
76
 
62
77
  self
63
78
  end
64
79
 
65
80
  def cleanup # :nodoc:
81
+ fire :cleaning
82
+
66
83
  activated = Gem.loaded_specs.values.map { |s| s.full_name }
67
84
  available = Gem.source_index.gems.values.sort
68
85
 
69
86
  extra = available.reject do |spec|
70
87
  active = activated.include? spec.full_name
71
- entry = entries.detect { |e| e.matches_spec? spec }
88
+ entry = entries.find { |e| e.matches_spec? spec }
72
89
  system = !spec.loaded_from.include?(path)
73
90
 
74
91
  active or entry or system
75
92
  end
76
93
 
77
- return if extra.empty?
78
-
79
- padding = Math.log10(extra.size).to_i + 1
80
- format = "[%0#{padding}d/%s] Nuking %s."
94
+ unless extra.empty?
95
+ padding = Math.log10(extra.size).to_i + 1
96
+ format = "[%0#{padding}d/%s] Nuking %s."
81
97
 
82
- extra.each_with_index do |e, i|
83
- log format % [i + 1, extra.size, e.full_name]
98
+ extra.each_with_index do |e, i|
99
+ log format % [i + 1, extra.size, e.full_name]
84
100
 
85
- Gem::DefaultUserInteraction.use_ui Gem::SilentUI.new do
86
- Gem::Uninstaller.new(e.name,
87
- :version => e.version,
88
- :ignore => true,
89
- :executables => true,
90
- :install_dir => path).uninstall
101
+ Gem::DefaultUserInteraction.use_ui Gem::SilentUI.new do
102
+ Gem::Uninstaller.new(e.name,
103
+ :version => e.version,
104
+ :ignore => true,
105
+ :executables => true,
106
+ :install_dir => path).uninstall
107
+ end
91
108
  end
92
109
  end
110
+
111
+ fire :cleaned
93
112
  end
94
113
 
95
114
  def cleanup?
@@ -98,9 +117,11 @@ module Isolate
98
117
 
99
118
  def disable &block
100
119
  return self if not enabled?
120
+ fire :disabling
101
121
 
102
122
  ENV["GEM_PATH"] = @old_gem_path
103
123
  ENV["GEM_HOME"] = @old_gem_home
124
+ ENV["ISOLATED"] = @old_isolated
104
125
  ENV["PATH"] = @old_path
105
126
  ENV["RUBYOPT"] = @old_ruby_opt
106
127
 
@@ -109,6 +130,8 @@ module Isolate
109
130
  @enabled = false
110
131
 
111
132
  Isolate.refresh
133
+ fire :disabled
134
+
112
135
  begin; return yield ensure enable end if block_given?
113
136
 
114
137
  self
@@ -116,9 +139,11 @@ module Isolate
116
139
 
117
140
  def enable # :nodoc:
118
141
  return self if enabled?
142
+ fire :enabling
119
143
 
120
144
  @old_gem_path = ENV["GEM_PATH"]
121
145
  @old_gem_home = ENV["GEM_HOME"]
146
+ @old_isolated = ENV["ISOLATED"]
122
147
  @old_path = ENV["PATH"]
123
148
  @old_ruby_opt = ENV["RUBYOPT"]
124
149
  @old_load_path = $LOAD_PATH.dup
@@ -151,10 +176,13 @@ module Isolate
151
176
  ENV["PATH"] = [bin, ENV["PATH"]].join File::PATH_SEPARATOR
152
177
  end
153
178
 
179
+ ENV["ISOLATED"] = path
180
+
154
181
  Isolate.refresh
155
182
  Gem.path.unshift path if system?
156
183
 
157
184
  @enabled = true
185
+ fire :enabled
158
186
 
159
187
  self
160
188
  end
@@ -174,12 +202,14 @@ module Isolate
174
202
  @environments = old
175
203
  end
176
204
 
205
+ alias_method :env, :environment
206
+
177
207
  # Express a gem dependency. Works pretty much like RubyGems' +gem+
178
208
  # method, but respects +environment+ and doesn't activate 'til
179
209
  # later.
180
210
 
181
211
  def gem name, *requirements
182
- entry = entries.detect { |e| e.name == name }
212
+ entry = entries.find { |e| e.name == name }
183
213
  return entry.update(*requirements) if entry
184
214
 
185
215
  entries << entry = Entry.new(self, name, *requirements)
@@ -187,22 +217,26 @@ module Isolate
187
217
  end
188
218
 
189
219
  def install environment # :nodoc:
220
+ fire :installing
221
+
190
222
  installable = entries.select do |e|
191
223
  !Gem.available?(e.name, *e.requirement.as_list) &&
192
224
  e.matches?(environment)
193
225
  end
194
226
 
195
- return self if installable.empty?
227
+ unless installable.empty?
228
+ padding = Math.log10(installable.size).to_i + 1
229
+ format = "[%0#{padding}d/%s] Isolating %s (%s)."
196
230
 
197
- padding = Math.log10(installable.size).to_i + 1
198
- format = "[%0#{padding}d/%s] Isolating %s (%s)."
231
+ installable.each_with_index do |entry, i|
232
+ log format % [i + 1, installable.size, entry.name, entry.requirement]
233
+ entry.install
234
+ end
199
235
 
200
- installable.each_with_index do |entry, i|
201
- log format % [i + 1, installable.size, entry.name, entry.requirement]
202
- entry.install
236
+ Gem.source_index.refresh!
203
237
  end
204
238
 
205
- Gem.source_index.refresh!
239
+ fire :installed
206
240
 
207
241
  self
208
242
  end
@@ -0,0 +1,44 @@
1
+ require "isolate/events"
2
+ require "isolate/test"
3
+
4
+ class TestIsolateEvents < Isolate::Test
5
+ include Isolate::Events
6
+
7
+ def setup
8
+ Isolate::Events.watchers.clear
9
+ super
10
+ end
11
+
12
+ def test_self_watch
13
+ b = lambda {}
14
+ Isolate::Events.watch String, :foo, &b
15
+ assert_equal [b], Isolate::Events.watchers[[String, :foo]]
16
+ end
17
+
18
+ def test_fire
19
+ count = 0
20
+
21
+ Isolate::Events.watch self.class, :increment do
22
+ count += 1
23
+ end
24
+
25
+ fire :increment
26
+ assert_equal 1, count
27
+ end
28
+
29
+ def test_fire_block
30
+ count = 0
31
+
32
+ [:increment, :incremented].each do |name|
33
+ Isolate::Events.watch self.class, name do
34
+ count += 1
35
+ end
36
+ end
37
+
38
+ fire :increment, :incremented do |x|
39
+ assert_same self, x
40
+ end
41
+
42
+ assert_equal 2, count
43
+ end
44
+ end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: isolate
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1923832043
4
+ hash: 1923832045
5
5
  prerelease: true
6
6
  segments:
7
7
  - 2
8
8
  - 0
9
9
  - 0
10
10
  - pre
11
- - 1
12
- version: 2.0.0.pre.1
11
+ - 2
12
+ version: 2.0.0.pre.2
13
13
  platform: ruby
14
14
  authors:
15
15
  - John Barnette
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2010-05-02 00:00:00 -07:00
21
+ date: 2010-05-07 00:00:00 -07:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -45,11 +45,11 @@ dependencies:
45
45
  requirements:
46
46
  - - ~>
47
47
  - !ruby/object:Gem::Version
48
- hash: 7
48
+ hash: 3
49
49
  segments:
50
50
  - 1
51
- - 4
52
- version: "1.4"
51
+ - 6
52
+ version: "1.6"
53
53
  type: :development
54
54
  version_requirements: *id002
55
55
  - !ruby/object:Gem::Dependency
@@ -70,7 +70,7 @@ dependencies:
70
70
  version_requirements: *id003
71
71
  description: |-
72
72
  Isolate is a very simple RubyGems sandbox. It provides a way to
73
- express and install your code's Gem dependencies.
73
+ express and automatically install your project's Gem dependencies.
74
74
  email:
75
75
  - jbarnette@rubyforge.org
76
76
  - ryand-ruby@zenspider.com
@@ -91,6 +91,7 @@ files:
91
91
  - lib/hoe/isolate.rb
92
92
  - lib/isolate.rb
93
93
  - lib/isolate/entry.rb
94
+ - lib/isolate/events.rb
94
95
  - lib/isolate/now.rb
95
96
  - lib/isolate/rake.rb
96
97
  - lib/isolate/sandbox.rb
@@ -104,6 +105,7 @@ files:
104
105
  - test/isolate/test.rb
105
106
  - test/test_isolate.rb
106
107
  - test/test_isolate_entry.rb
108
+ - test/test_isolate_events.rb
107
109
  - test/test_isolate_sandbox.rb
108
110
  has_rdoc: true
109
111
  homepage: http://github.com/jbarnette/isolate
@@ -147,4 +149,5 @@ summary: Isolate is a very simple RubyGems sandbox
147
149
  test_files:
148
150
  - test/test_isolate.rb
149
151
  - test/test_isolate_entry.rb
152
+ - test/test_isolate_events.rb
150
153
  - test/test_isolate_sandbox.rb