spring 1.0.0 → 1.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ab103d29ee132ac8637c7ddca8d5c41fc567c31e
4
- data.tar.gz: 88e600c6e1d59b4150625769f20f6d543958087c
3
+ metadata.gz: fe796fa453e40306865cb1cf6e6541ca01571d5d
4
+ data.tar.gz: 7210043ae71cdb012a21734c86984922a8127afe
5
5
  SHA512:
6
- metadata.gz: 7b4d762562b8d4c1832bcec43819b6bcc6d9168473095fac089a743c0c421d4450f77e7c0a3cf31902256ed42a3d0fa57e7767cd4a0cf9d0bd55dc24c758f460
7
- data.tar.gz: 9c929b2636980dc30486f475caeacb1f3de296420c22e9f0a52c67ce732a8953e28f1b090258a18456d210ce217610e8e4df8ffeb7a1a8ebd0e2b546554235ec
6
+ metadata.gz: 3c1bcd8097999582b66b2507029e807be714455fe95f70a52e222a3221c5e3921e89ba1131e3b16bd0d775eaae7f65c660b87e65c22526d3e2e79544a226e532
7
+ data.tar.gz: a0c20068387c73fd9203e6fc408ab1789240e9b244e4e627dc233f04f9850e3c984aca138a81f59b7c553958859e02349c15659910aa789ee95b5595cf95db5c
@@ -1,7 +1,10 @@
1
1
  language: ruby
2
+ before_install: if [[ "$TRAVIS_RUBY_VERSION" = "1.9.3" ]]; then gem install bundler --version="1.3.5"; else gem install bundler; fi
2
3
  rvm:
3
4
  - 1.9.3
4
5
  - 2.0.0
6
+ - 2.1.0
5
7
  env:
6
8
  - RAILS_VERSION="~> 3.2.0"
7
9
  - RAILS_VERSION="~> 4.0.0"
10
+ - RAILS_VERSION="~> 4.1.0.beta1"
@@ -1,3 +1,18 @@
1
+ ## Next version
2
+
3
+ * A `bin/spring` binstub is now generated. This allows us to load spring
4
+ correctly if you have it installed locally with a `BUNDLE_PATH`, so
5
+ it's no longer necessary to install spring system-wide. Note that you
6
+ still can't have spring in your Gemfile as a git repository or local
7
+ path; it must be a proper gem.
8
+ * Various changes to how springified binstubs are implemented. Existing
9
+ binstubs will continue to work, but it's recommended to run `spring binstub`
10
+ again to upgrade them to the new format.
11
+ * `spring binstub --remove` option added for removing spring from
12
+ binstubs. This won't work unless you have upgraded your binstubs to
13
+ the new format.
14
+ * `config/database.yml` is watched
15
+
1
16
  ## 1.0.0
2
17
 
3
18
  * Enterprise ready secret sauce added
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Spring
2
2
 
3
3
  [![Build Status](https://travis-ci.org/jonleighton/spring.png?branch=master)](https://travis-ci.org/jonleighton/spring)
4
+ [![Gem Version](https://badge.fury.io/rb/spring.png)](http://badge.fury.io/rb/spring)
4
5
 
5
6
  Spring is a Rails application preloader. It speeds up development by
6
7
  keeping your application running in the background so you don't need to
@@ -15,24 +16,50 @@ boot it every time you run a test, rake task or migration.
15
16
 
16
17
  ## Compatibility
17
18
 
18
- * Ruby versions: MRI 1.9.3, MRI 2.0.0
19
+ * Ruby versions: MRI 1.9.3, MRI 2.0, MRI 2.1
19
20
  * Rails versions: 3.2, 4.0
20
21
 
21
- Spring makes extensive use of `Process#fork`, so won't be able to
22
+ Spring makes extensive use of `Process.fork`, so won't be able to
22
23
  provide a speed up on platforms which don't support forking (Windows, JRuby).
23
24
 
24
25
  ## Walkthrough
25
26
 
26
- Either `gem install spring` or add it to your Gemfile:
27
+ ### Setup
28
+
29
+ Add spring to your Gemfile:
30
+
31
+ ``` ruby
32
+ gem "spring", group: :development
33
+ ```
34
+
35
+ It's recommended to 'springify' the executables in your `bin/`
36
+ directory:
37
+
38
+ ```
39
+ $ bundle install
40
+ $ bundle exec spring binstub --all
41
+ ```
42
+
43
+ This generates a `bin/spring` executable, and inserts a small snippet of
44
+ code into relevant existing executables. The snippet looks like this:
27
45
 
28
46
  ``` ruby
29
- group :development do
30
- gem "spring"
47
+ begin
48
+ load File.expand_path("../spring", __FILE__)
49
+ rescue LoadError
31
50
  end
32
51
  ```
33
52
 
34
- Spring is designed to be used *without* bundle exec, so use `spring
35
- [command]` rather than `bundle exec spring [command]`.
53
+ On platforms where spring is installed and supported, this snippet
54
+ hooks spring into the execution of commands. In other cases, the snippet
55
+ will just be silently ignored and the lines after it will be executed as
56
+ normal.
57
+
58
+ If you don't want to prefix every command you type with `bin/`, you
59
+ can [use direnv](https://github.com/zimbatm/direnv) to automatically add
60
+ `./bin` to your `PATH` when you `cd` into your application.
61
+
62
+ ### Usage
36
63
 
37
64
  For this walkthrough I've generated a new Rails application, and run
38
65
  `rails generate scaffold posts name:string`.
@@ -40,7 +67,7 @@ For this walkthrough I've generated a new Rails application, and run
40
67
  Let's run a test:
41
68
 
42
69
  ```
43
- $ time spring rake test test/functional/posts_controller_test.rb
70
+ $ time bin/rake test test/functional/posts_controller_test.rb
44
71
  Run options:
45
72
 
46
73
  # Running tests:
@@ -60,7 +87,7 @@ That wasn't particularly fast because it was the first run, so spring
60
87
  had to boot the application. It's now running:
61
88
 
62
89
  ```
63
- $ spring status
90
+ $ bin/spring status
64
91
  Spring is running:
65
92
 
66
93
  26150 spring server | spring-demo-app | started 3 secs ago
@@ -70,7 +97,7 @@ Spring is running:
70
97
  The next run is faster:
71
98
 
72
99
  ```
73
- $ time spring rake test test/functional/posts_controller_test.rb
100
+ $ time bin/rake test test/functional/posts_controller_test.rb
74
101
  Run options:
75
102
 
76
103
  # Running tests:
@@ -86,20 +113,6 @@ user 0m0.276s
86
113
  sys 0m0.059s
87
114
  ```
88
115
 
89
- Writing `spring` before every command gets a bit tedious. Spring binstubs solve this:
90
-
91
- ```
92
- $ spring binstub rake rails
93
- ```
94
-
95
- This will generate `bin/rake` and `bin/rails`. They
96
- replace any binstubs that you might already have in your `bin/`
97
- directory. Check them in to source control.
98
-
99
- If you don't want to prefix every command you type with `bin/`, you
100
- can [use direnv](https://github.com/zimbatm/direnv) to automatically add
101
- `./bin` to your `PATH` when you `cd` into your application.
102
-
103
116
  If we edit any of the application files, or test files, the changes will
104
117
  be picked up on the next run without the background process having to
105
118
  restart. This works in exactly the same way as the code reloading
@@ -114,7 +127,7 @@ Let's "edit" `config/application.rb`:
114
127
 
115
128
  ```
116
129
  $ touch config/application.rb
117
- $ spring status
130
+ $ bin/spring status
118
131
  Spring is running:
119
132
 
120
133
  26150 spring server | spring-demo-app | started 36 secs ago
@@ -137,7 +150,7 @@ edit_post GET /posts/:id/edit(.:format) posts#edit
137
150
  PUT /posts/:id(.:format) posts#update
138
151
  DELETE /posts/:id(.:format) posts#destroy
139
152
 
140
- $ spring status
153
+ $ bin/spring status
141
154
  Spring is running:
142
155
 
143
156
  26150 spring server | spring-demo-app | started 1 min ago
@@ -150,25 +163,18 @@ when you close your terminal. However if you do want to do a manual shut
150
163
  down, use the `stop` command:
151
164
 
152
165
  ```
153
- $ spring stop
166
+ $ bin/spring stop
154
167
  Spring stopped.
155
168
  ```
156
169
 
157
- ## Commands
158
-
159
- The following commands are shipped by default.
170
+ ### Removal
160
171
 
161
- Custom commands can be specified in the Spring config file. See
162
- [`lib/spring/commands/`](https://github.com/jonleighton/spring/blob/master/lib/spring/commands/)
163
- for examples.
172
+ To remove spring:
164
173
 
165
- You can add the following gems to your Gemfile for additional commands:
174
+ * 'Unspring' your bin/ executables: `bin/spring binstub --remove --all`
175
+ * Remove spring from your Gemfile
166
176
 
167
- * [spring-commands-rspec](https://github.com/jonleighton/spring-commands-rspec)
168
- * [spring-commands-cucumber](https://github.com/jonleighton/spring-commands-cucumber)
169
- * [spring-commands-testunit](https://github.com/jonleighton/spring-commands-testunit) - useful for
170
- running `Test::Unit` tests on Rails 3, since only Rails 4 allows you
171
- to use `rake test path/to/test` to run a particular test/directory.
177
+ ## Commands
172
178
 
173
179
  ### `rake`
174
180
 
@@ -194,6 +200,28 @@ a different sub command (e.g. `rails server`) then spring will automatically
194
200
  pass it through to the underlying `rails` executable (without the
195
201
  speed-up).
196
202
 
203
+ ### Additional commands
204
+
205
+ You can add these to your Gemfile for additional commands (run `spring stop` afterwards
206
+ to pick up the changes):
207
+
208
+ * [spring-commands-rspec](https://github.com/jonleighton/spring-commands-rspec)
209
+ * [spring-commands-cucumber](https://github.com/jonleighton/spring-commands-cucumber)
210
+ * [spring-commands-testunit](https://github.com/jonleighton/spring-commands-testunit) - useful for
211
+ running `Test::Unit` tests on Rails 3, since only Rails 4 allows you
212
+ to use `rake test path/to/test` to run a particular test/directory.
213
+
214
+ ## Use without adding to bundle
215
+
216
+ If you don't want spring-related code checked into your source
217
+ repository, it's possible to use spring without adding to your Gemfile.
218
+ However, using spring binstubs without adding spring to the Gemfile is not
219
+ supported.
220
+
221
+ To use spring like this, do a `gem install spring` and then prefix
222
+ commands with `spring`. For example, rather than running `bin/rake -T`,
223
+ you'd run `spring rake -T`.
224
+
197
225
  ## Configuration
198
226
 
199
227
  Spring will read `~/.spring.rb` and `config/spring.rb` for custom
@@ -223,9 +251,14 @@ which get run when your application initializers, such as
223
251
  `config/initializers/*.rb`.
224
252
 
225
253
  For example, if loading your test helper is slow, you might like to
226
- preload it to speed up your test runs. To do this you could put a
227
- `require Rails.root.join("test/helper")` in
228
- `config/environments/test.rb`.
254
+ preload it to speed up your test runs. To do this you could add the
255
+ following to your `config/environments/test.rb`:
256
+
257
+ ``` ruby
258
+ config.after_initialize do
259
+ require Rails.root.join("test/helper")
260
+ end
261
+ ```
229
262
 
230
263
  ### Running code after forking
231
264
 
@@ -9,7 +9,6 @@ module Spring
9
9
  def initialize(manager, watcher = Spring.watcher)
10
10
  @manager = manager
11
11
  @watcher = watcher
12
- @setup = Set.new
13
12
  @spring_env = Env.new
14
13
  @preloaded = false
15
14
  @mutex = Mutex.new
@@ -54,6 +53,7 @@ module Spring
54
53
  watcher.add loaded_application_features
55
54
  watcher.add Spring.gemfile, "#{Spring.gemfile}.lock"
56
55
  watcher.add Rails.application.paths["config/initializers"]
56
+ watcher.add Rails.application.paths["config/database"]
57
57
 
58
58
  @preloaded = true
59
59
  end
@@ -116,22 +116,17 @@ module Spring
116
116
  # Load in the current env vars, except those which *were* changed when spring started
117
117
  env.each { |k, v| ENV[k] ||= v }
118
118
 
119
+ # requiring is faster, and we don't need constant reloading in this process
120
+ ActiveSupport::Dependencies.mechanism = :require
121
+ Rails.application.config.cache_classes = true
122
+
119
123
  connect_database
120
124
  srand
121
125
 
122
126
  invoke_after_fork_callbacks
123
127
  shush_backtraces
124
128
 
125
- if command.respond_to?(:call)
126
- command.call
127
- else
128
- exec_name = command.exec_name
129
- gem_name = command.gem_name if command.respond_to?(:gem_name)
130
-
131
- exec = Gem.bin_path(gem_name || exec_name, exec_name)
132
- $0 = exec
133
- load exec
134
- end
129
+ command.call
135
130
  }
136
131
 
137
132
  disconnect_database
@@ -167,11 +162,7 @@ module Spring
167
162
  # main process so that they are cached. For example a test command wants to
168
163
  # load the helper file once and have it cached.
169
164
  def setup(command)
170
- return if @setup.include?(command.class)
171
- @setup << command.class
172
-
173
- if command.respond_to?(:setup)
174
- command.setup
165
+ if command.setup
175
166
  watcher.add loaded_application_features # loaded features may have changed
176
167
  end
177
168
  end
@@ -0,0 +1,12 @@
1
+ command = File.basename($0)
2
+
3
+ if command == "spring"
4
+ load Gem.bin_path("spring", "spring")
5
+ else
6
+ disable = ENV["DISABLE_SPRING"]
7
+
8
+ if Process.respond_to?(:fork) && (disable.nil? || disable.empty? || disable == "0")
9
+ ARGV.unshift(command)
10
+ load Gem.bin_path("spring", "spring")
11
+ end
12
+ end
@@ -8,15 +8,18 @@ require "spring/client/binstub"
8
8
  require "spring/client/stop"
9
9
  require "spring/client/status"
10
10
  require "spring/client/rails"
11
+ require "spring/client/version"
11
12
 
12
13
  module Spring
13
14
  module Client
14
15
  COMMANDS = {
15
- "help" => Client::Help,
16
- "binstub" => Client::Binstub,
17
- "stop" => Client::Stop,
18
- "status" => Client::Status,
19
- "rails" => Client::Rails
16
+ "help" => Client::Help,
17
+ "binstub" => Client::Binstub,
18
+ "stop" => Client::Stop,
19
+ "status" => Client::Status,
20
+ "rails" => Client::Rails,
21
+ "-v" => Client::Version,
22
+ "--version" => Client::Version
20
23
  }
21
24
 
22
25
  def self.run(args)
@@ -1,46 +1,160 @@
1
+ require 'set'
2
+
1
3
  module Spring
2
4
  module Client
3
5
  class Binstub < Command
4
- attr_reader :bindir, :commands
6
+ SHEBANG = /\#\!.*\n/
7
+
8
+ # If loading the bin/spring file works, it'll run spring which will
9
+ # eventually call Kernel.exit. This means that in the client process
10
+ # we will never execute the lines after this block. But if the spring
11
+ # client is not invoked for whatever reason, then the Kernel.exit won't
12
+ # happen, and so we'll fall back to the lines after this block, which
13
+ # should cause the "unsprung" version of the command to run.
14
+ LOADER = <<CODE
15
+ begin
16
+ load File.expand_path("../spring", __FILE__)
17
+ rescue LoadError
18
+ end
19
+ CODE
20
+
21
+ # The defined? check ensures these lines don't execute when we load the
22
+ # binstub from the application process. Which means that in the application
23
+ # process we'll execute the lines which come after the LOADER block, which
24
+ # is what we want.
25
+ #
26
+ # Gem.try_activate would be called inside rubygems due to the #require.
27
+ # However, when that happens $! gets set and it appears that there is a
28
+ # LoadError, which can cause problems. So we activate the gem separately
29
+ # to requiring the file.
30
+ SPRING = <<CODE
31
+ #!/usr/bin/env ruby
32
+
33
+ unless defined?(Spring)
34
+ require "rubygems"
35
+ require "bundler"
36
+
37
+ ENV["GEM_HOME"] = ""
38
+ ENV["GEM_PATH"] = Bundler.bundle_path.to_s
39
+ Gem.paths = ENV
40
+
41
+ Gem.try_activate("spring/binstub")
42
+ require "spring/binstub"
43
+ end
44
+ CODE
45
+
46
+ OLD_BINSTUB = %{if !Process.respond_to?(:fork) || Gem::Specification.find_all_by_name("spring").empty?}
47
+
48
+ class Item
49
+ attr_reader :command, :existing
50
+
51
+ def initialize(command)
52
+ @command = command
53
+
54
+ if command.binstub.exist?
55
+ @existing = command.binstub.read
56
+ elsif command.name == "rails"
57
+ scriptfile = Spring.application_root_path.join("script/rails")
58
+ @existing = scriptfile.read if scriptfile.exist?
59
+ end
60
+ end
61
+
62
+ def status(text, stream = $stdout)
63
+ stream.puts "* #{command.binstub_name}: #{text}"
64
+ end
65
+
66
+ def add
67
+ if existing
68
+ if existing.include?(OLD_BINSTUB)
69
+ fallback = existing.match(/#{Regexp.escape OLD_BINSTUB}\n(.*)else/m)[1]
70
+ fallback.gsub!(/^ /, "")
71
+ fallback = nil if fallback.include?("exec")
72
+ generate(fallback)
73
+ status "upgraded"
74
+ elsif existing =~ /load .*spring/
75
+ status "spring already present"
76
+ else
77
+ head, shebang, tail = existing.partition(SHEBANG)
78
+
79
+ if shebang.include?("ruby")
80
+ unless command.binstub.exist?
81
+ FileUtils.touch command.binstub
82
+ command.binstub.chmod 0755
83
+ end
84
+
85
+ File.write(command.binstub, "#{head}#{shebang}#{LOADER}#{tail}")
86
+ status "spring inserted"
87
+ else
88
+ status "doesn't appear to be ruby, so cannot use spring", $stderr
89
+ exit 1
90
+ end
91
+ end
92
+ else
93
+ generate
94
+ status "generated with spring"
95
+ end
96
+ end
97
+
98
+ def generate(fallback = nil)
99
+ unless fallback
100
+ fallback = "require 'bundler/setup'\n" \
101
+ "load Gem.bin_path('#{command.gem_name}', '#{command.exec_name}')\n"
102
+ end
103
+
104
+ File.write(command.binstub, "#!/usr/bin/env ruby\n#{LOADER}#{fallback}")
105
+ command.binstub.chmod 0755
106
+ end
107
+
108
+ def remove
109
+ if existing
110
+ File.write(command.binstub, existing.sub(LOADER, ""))
111
+ status "spring removed"
112
+ end
113
+ end
114
+ end
115
+
116
+ attr_reader :bindir, :items
5
117
 
6
118
  def self.description
7
119
  "Generate spring based binstubs. Use --all to generate a binstub for all known commands."
8
120
  end
9
121
 
122
+ def self.rails_command
123
+ @rails_command ||= CommandWrapper.new("rails")
124
+ end
125
+
10
126
  def self.call(args)
11
127
  require "spring/commands"
12
128
  super
13
129
  end
14
130
 
15
- class RailsCommand
16
- def fallback
17
- <<CODE
18
- APP_PATH = File.expand_path('../../config/application', __FILE__)
19
- require_relative '../config/boot'
20
- require 'rails/commands'
21
- CODE
22
- end
23
- end
24
-
25
131
  def initialize(args)
26
132
  super
27
133
 
28
- @bindir = env.root.join("bin")
29
- @commands = args.drop(1).inject({}) { |mem, name| mem.merge(find_commands(name)) }
134
+ @bindir = env.root.join("bin")
135
+ @all = false
136
+ @mode = :add
137
+ @items = args.drop(1)
138
+ .map { |name| find_commands name }
139
+ .inject(Set.new, :|)
140
+ .map { |command| Item.new(command) }
30
141
  end
31
142
 
32
143
  def find_commands(name)
33
144
  case name
34
145
  when "--all"
35
- commands = Spring.commands
146
+ @all = true
147
+ commands = Spring.commands.dup
36
148
  commands.delete_if { |name, _| name.start_with?("rails_") }
37
- commands["rails"] = RailsCommand.new
38
- commands
149
+ commands.values + [self.class.rails_command]
150
+ when "--remove"
151
+ @mode = :remove
152
+ []
39
153
  when "rails"
40
- { name => RailsCommand.new }
154
+ [self.class.rails_command]
41
155
  else
42
156
  if command = Spring.commands[name]
43
- { name => command }
157
+ [command]
44
158
  else
45
159
  $stderr.puts "The '#{name}' command is not known to spring."
46
160
  exit 1
@@ -49,32 +163,27 @@ CODE
49
163
  end
50
164
 
51
165
  def call
52
- bindir.mkdir unless bindir.exist?
53
- commands.each { |name, command| generate_binstub(name, command) }
54
- end
55
-
56
- def generate_binstub(name, command)
57
- File.write(bindir.join(name), <<CODE)
58
- #!/usr/bin/env ruby
59
-
60
- if !Process.respond_to?(:fork) || Gem::Specification.find_all_by_name("spring").empty?
61
- #{fallback(name, command).strip.gsub(/^/, " ")}
62
- else
63
- ARGV.unshift "#{name}"
64
- load Gem.bin_path("spring", "spring")
65
- end
66
- CODE
166
+ case @mode
167
+ when :add
168
+ bindir.mkdir unless bindir.exist?
67
169
 
68
- bindir.join(name).chmod 0755
69
- end
170
+ unless spring_binstub.exist?
171
+ File.write(spring_binstub, SPRING)
172
+ spring_binstub.chmod 0755
173
+ end
70
174
 
71
- def fallback(name, command)
72
- if command.respond_to?(:fallback)
73
- command.fallback
175
+ items.each(&:add)
176
+ when :remove
177
+ spring_binstub.delete if @all
178
+ items.each(&:remove)
74
179
  else
75
- %{exec "bundle", "exec", "#{name}", *ARGV}
180
+ raise ArgumentError
76
181
  end
77
182
  end
183
+
184
+ def spring_binstub
185
+ bindir.join("spring")
186
+ end
78
187
  end
79
188
  end
80
189
  end