spring-jruby 1.4.3

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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +364 -0
  4. data/bin/spring +49 -0
  5. data/lib/spring-jruby/application.rb +283 -0
  6. data/lib/spring-jruby/application/boot.rb +19 -0
  7. data/lib/spring-jruby/binstub.rb +13 -0
  8. data/lib/spring-jruby/boot.rb +9 -0
  9. data/lib/spring-jruby/client.rb +46 -0
  10. data/lib/spring-jruby/client/binstub.rb +188 -0
  11. data/lib/spring-jruby/client/command.rb +18 -0
  12. data/lib/spring-jruby/client/help.rb +62 -0
  13. data/lib/spring-jruby/client/rails.rb +34 -0
  14. data/lib/spring-jruby/client/run.rb +167 -0
  15. data/lib/spring-jruby/client/status.rb +30 -0
  16. data/lib/spring-jruby/client/stop.rb +22 -0
  17. data/lib/spring-jruby/client/version.rb +11 -0
  18. data/lib/spring-jruby/command_wrapper.rb +82 -0
  19. data/lib/spring-jruby/commands.rb +51 -0
  20. data/lib/spring-jruby/commands/rails.rb +112 -0
  21. data/lib/spring-jruby/commands/rake.rb +30 -0
  22. data/lib/spring-jruby/configuration.rb +60 -0
  23. data/lib/spring-jruby/env.rb +109 -0
  24. data/lib/spring-jruby/errors.rb +36 -0
  25. data/lib/spring-jruby/impl/application.rb +7 -0
  26. data/lib/spring-jruby/impl/application_manager.rb +7 -0
  27. data/lib/spring-jruby/impl/fork/application.rb +69 -0
  28. data/lib/spring-jruby/impl/fork/application_manager.rb +137 -0
  29. data/lib/spring-jruby/impl/fork/run.rb +47 -0
  30. data/lib/spring-jruby/impl/pool/application.rb +47 -0
  31. data/lib/spring-jruby/impl/pool/application_manager.rb +226 -0
  32. data/lib/spring-jruby/impl/pool/run.rb +27 -0
  33. data/lib/spring-jruby/impl/run.rb +7 -0
  34. data/lib/spring-jruby/io_helpers.rb +92 -0
  35. data/lib/spring-jruby/json.rb +626 -0
  36. data/lib/spring-jruby/platform.rb +23 -0
  37. data/lib/spring-jruby/process_title_updater.rb +65 -0
  38. data/lib/spring-jruby/server.rb +130 -0
  39. data/lib/spring-jruby/sid.rb +42 -0
  40. data/lib/spring-jruby/test.rb +18 -0
  41. data/lib/spring-jruby/test/acceptance_test.rb +371 -0
  42. data/lib/spring-jruby/test/application.rb +217 -0
  43. data/lib/spring-jruby/test/application_generator.rb +134 -0
  44. data/lib/spring-jruby/test/rails_version.rb +40 -0
  45. data/lib/spring-jruby/test/watcher_test.rb +167 -0
  46. data/lib/spring-jruby/version.rb +3 -0
  47. data/lib/spring-jruby/watcher.rb +30 -0
  48. data/lib/spring-jruby/watcher/abstract.rb +86 -0
  49. data/lib/spring-jruby/watcher/polling.rb +61 -0
  50. metadata +137 -0
@@ -0,0 +1,23 @@
1
+ module Spring
2
+ def self.fork?
3
+ Process.respond_to?(:fork)
4
+ end
5
+
6
+ def self.jruby?
7
+ RUBY_PLATFORM == "java"
8
+ end
9
+
10
+ def self.ruby_bin
11
+ if RUBY_PLATFORM == "java"
12
+ "jruby"
13
+ else
14
+ "ruby"
15
+ end
16
+ end
17
+
18
+ if jruby?
19
+ IGNORE_SIGNALS = %w(INT)
20
+ else
21
+ IGNORE_SIGNALS = %w(INT QUIT)
22
+ end
23
+ end
@@ -0,0 +1,65 @@
1
+ module Spring
2
+ # Yes, I know this reimplements a bunch of stuff in Active Support, but
3
+ # I don't want the spring client to depend on AS, in order to keep its
4
+ # load time down.
5
+ class ProcessTitleUpdater
6
+ SECOND = 1
7
+ MINUTE = 60
8
+ HOUR = 60*60
9
+
10
+ def self.run(&block)
11
+ updater = new(&block)
12
+
13
+ Thread.new {
14
+ $0 = updater.value
15
+ loop { $0 = updater.next }
16
+ }
17
+ end
18
+
19
+ attr_reader :block
20
+
21
+ def initialize(start = Time.now, &block)
22
+ @start = start
23
+ @block = block
24
+ end
25
+
26
+ def interval
27
+ distance = Time.now - @start
28
+
29
+ if distance < MINUTE
30
+ SECOND
31
+ elsif distance < HOUR
32
+ MINUTE
33
+ else
34
+ HOUR
35
+ end
36
+ end
37
+
38
+ def next
39
+ sleep interval
40
+ value
41
+ end
42
+
43
+ def value
44
+ block.call(distance_in_words)
45
+ end
46
+
47
+ def distance_in_words(now = Time.now)
48
+ distance = now - @start
49
+
50
+ if distance < MINUTE
51
+ pluralize(distance, "sec")
52
+ elsif distance < HOUR
53
+ pluralize(distance / MINUTE, "min")
54
+ else
55
+ pluralize(distance / HOUR, "hour")
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def pluralize(amount, unit)
62
+ "#{amount.to_i} #{amount.to_i == 1 ? unit : "#{unit}s"}"
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,130 @@
1
+ module Spring
2
+ ORIGINAL_ENV = ENV.to_hash
3
+ end
4
+
5
+ require "spring-jruby/boot"
6
+ require "spring-jruby/impl/application_manager"
7
+
8
+ # Must be last, as it requires bundler/setup, which alters the load path
9
+ require "spring-jruby/commands"
10
+
11
+ module Spring
12
+ class Server
13
+ def self.boot
14
+ new.boot
15
+ end
16
+
17
+ attr_reader :env
18
+
19
+ def initialize(env = Env.new)
20
+ @env = env
21
+ @applications = Hash.new { |h, k| h[k] = ApplicationManager.new(k) }
22
+ @pidfile = env.pidfile_path.open('a')
23
+ @mutex = Mutex.new
24
+ end
25
+
26
+ def log(message)
27
+ env.log "[server] #{message}"
28
+ end
29
+
30
+ def boot
31
+ Spring.verify_environment
32
+
33
+ write_pidfile
34
+ set_pgid
35
+ ignore_signals
36
+ set_exit_hook
37
+ set_process_title
38
+ start_server
39
+ end
40
+
41
+ def start_server
42
+ server = UNIXServer.open(env.socket_name)
43
+ log "started on #{env.socket_name}"
44
+ loop { serve server.accept }
45
+ end
46
+
47
+ def serve(client)
48
+ log "accepted client"
49
+ client.puts env.version
50
+
51
+ app_client = IOWrapper.recv_io(client)
52
+ command = JSON.load(client.read(client.gets.to_i))
53
+
54
+ args, default_rails_env = command.values_at('args', 'default_rails_env')
55
+
56
+ if Spring.command?(args.first)
57
+ log "running command #{args.first}"
58
+ client.puts
59
+ client.puts @applications[rails_env_for(args, default_rails_env)].run(app_client)
60
+ else
61
+ log "command not found #{args.first}"
62
+ client.close
63
+ end
64
+ rescue SocketError => e
65
+ raise e unless client.eof?
66
+ ensure
67
+ redirect_output
68
+ end
69
+
70
+ def rails_env_for(args, default_rails_env)
71
+ Spring.command(args.first).env(args.drop(1)) || default_rails_env
72
+ end
73
+
74
+ # Boot the server into the process group of the current session.
75
+ # This will cause it to be automatically killed once the session
76
+ # ends (i.e. when the user closes their terminal).
77
+ def set_pgid
78
+ Process.setpgid(0, SID.pgid)
79
+ end
80
+
81
+ # Ignore SIGINT and SIGQUIT otherwise the user typing ^C or ^\ on the command line
82
+ # will kill the server/application.
83
+ def ignore_signals
84
+ IGNORE_SIGNALS.each { |sig| trap(sig, "IGNORE") }
85
+ end
86
+
87
+ def set_exit_hook
88
+ server_pid = Process.pid
89
+
90
+ # We don't want this hook to run in any forks of the current process
91
+ at_exit { shutdown if Process.pid == server_pid }
92
+ end
93
+
94
+ def shutdown
95
+ log "shutting down"
96
+
97
+ [env.socket_path, env.pidfile_path].each do |path|
98
+ if path.exist?
99
+ path.unlink rescue nil
100
+ end
101
+ end
102
+
103
+ @applications.values.map { |a| Thread.new { a.stop } }.map(&:join)
104
+ end
105
+
106
+ def write_pidfile
107
+ if @pidfile.flock(File::LOCK_EX | File::LOCK_NB)
108
+ @pidfile.truncate(0)
109
+ @pidfile.write("#{Process.pid}\n")
110
+ @pidfile.fsync
111
+ else
112
+ exit 1
113
+ end
114
+ end
115
+
116
+ # We need to redirect STDOUT and STDERR, otherwise the server will
117
+ # keep the original FDs open which would break piping. (e.g.
118
+ # `spring rake -T | grep db` would hang forever because the server
119
+ # would keep the stdout FD open.)
120
+ def redirect_output
121
+ [STDOUT, STDERR].each { |stream| stream.reopen(env.log_file) }
122
+ end
123
+
124
+ def set_process_title
125
+ ProcessTitleUpdater.run { |distance|
126
+ "spring server | #{env.app_name} | started #{distance} ago"
127
+ }
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,42 @@
1
+ begin
2
+ # If rubygems is present, keep it out of the way when loading fiddle,
3
+ # otherwise if fiddle is not installed then rubygems will load all
4
+ # gemspecs in its (futile) search for fiddle, which is slow.
5
+ if respond_to?(:gem_original_require, true)
6
+ gem_original_require 'fiddle'
7
+ else
8
+ require 'fiddle'
9
+ end
10
+ rescue LoadError
11
+ end
12
+
13
+ module Spring
14
+ module SID
15
+ def self.fiddle_func
16
+ @fiddle_func ||= Fiddle::Function.new(
17
+ DL::Handle::DEFAULT['getsid'],
18
+ [Fiddle::TYPE_INT],
19
+ Fiddle::TYPE_INT
20
+ )
21
+ end
22
+
23
+ def self.sid
24
+ @sid ||= begin
25
+ if Process.respond_to?(:getsid)
26
+ # Ruby 2
27
+ Process.getsid
28
+ elsif defined?(Fiddle) and defined?(DL)
29
+ # Ruby 1.9.3 compiled with libffi support
30
+ fiddle_func.call(0)
31
+ else
32
+ # last resort: shell out
33
+ `ps -p #{Process.pid} -o sess=`.to_i
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.pgid
39
+ Process.getpgid(sid)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ require "active_support"
2
+ require "active_support/test_case"
3
+
4
+ ActiveSupport.test_order = :random
5
+
6
+ module Spring
7
+ module Test
8
+ class << self
9
+ attr_accessor :root
10
+ end
11
+
12
+ require "spring-jruby/test/application"
13
+ require "spring-jruby/test/application_generator"
14
+ require "spring-jruby/test/rails_version"
15
+ require "spring-jruby/test/watcher_test"
16
+ require "spring-jruby/test/acceptance_test"
17
+ end
18
+ end
@@ -0,0 +1,371 @@
1
+ require "io/wait"
2
+ require "timeout"
3
+ require "spring-jruby/sid"
4
+ require "spring-jruby/client"
5
+ require "active_support/core_ext/string/strip"
6
+
7
+ module Spring
8
+ module Test
9
+ class AcceptanceTest < ActiveSupport::TestCase
10
+ runnables.delete self # prevent Minitest running this class
11
+
12
+ DEFAULT_SPEEDUP = 0.8
13
+
14
+ def rails_version
15
+ ENV['RAILS_VERSION'] || '~> 4.2.0'
16
+ end
17
+
18
+ # Extension point for spring-watchers-listen
19
+ def generator_klass
20
+ Spring::Test::ApplicationGenerator
21
+ end
22
+
23
+ def generator
24
+ @@generator ||= generator_klass.new(rails_version)
25
+ end
26
+
27
+ def app
28
+ @app ||= Spring::Test::Application.new("#{Spring::Test.root}/apps/tmp")
29
+ end
30
+
31
+ def assert_output(artifacts, expected)
32
+ expected.each do |stream, output|
33
+ assert artifacts[stream].include?(output),
34
+ "expected #{stream} to include '#{output}'.\n\n#{app.debug(artifacts)}"
35
+ end
36
+ end
37
+
38
+ def assert_success(command, expected_output = nil)
39
+ artifacts = app.run(*Array(command))
40
+ assert artifacts[:status].success?, "expected successful exit status\n\n#{app.debug(artifacts)}"
41
+ assert_output artifacts, expected_output if expected_output
42
+ end
43
+
44
+ def assert_failure(command, expected_output = nil)
45
+ artifacts = app.run(*Array(command))
46
+ assert !artifacts[:status].success?, "expected unsuccessful exit status\n\n#{app.debug(artifacts)}"
47
+ assert_output artifacts, expected_output if expected_output
48
+ end
49
+
50
+ def assert_speedup(ratio = DEFAULT_SPEEDUP)
51
+ if ENV['CI']
52
+ yield
53
+ else
54
+ app.with_timing do
55
+ yield
56
+ assert app.timing_ratio < ratio, "#{app.last_time} was not less than #{ratio} of #{app.first_time}"
57
+ end
58
+ end
59
+ end
60
+
61
+ def without_gem(name)
62
+ gem_home = app.gem_home.join('gems')
63
+ FileUtils.mv(gem_home.join(name), app.root)
64
+ yield
65
+ ensure
66
+ FileUtils.mv(app.root.join(name), gem_home)
67
+ end
68
+
69
+ setup do
70
+ generator.generate_if_missing
71
+ generator.install_spring
72
+ generator.copy_to(app.root)
73
+ end
74
+
75
+ teardown do
76
+ app.stop_spring
77
+ end
78
+
79
+ test "basic" do
80
+ assert_speedup do
81
+ 2.times { app.run app.spring_test_command }
82
+ end
83
+ end
84
+
85
+ test "help message when called without arguments" do
86
+ assert_success "bin/spring", stdout: 'Usage: spring COMMAND [ARGS]'
87
+ assert app.spring_env.server_running?
88
+ end
89
+
90
+ test "shows help" do
91
+ assert_success "bin/spring help", stdout: 'Usage: spring COMMAND [ARGS]'
92
+ assert_success "bin/spring -h", stdout: 'Usage: spring COMMAND [ARGS]'
93
+ assert_success "bin/spring --help", stdout: 'Usage: spring COMMAND [ARGS]'
94
+ refute app.spring_env.server_running?
95
+ end
96
+
97
+ test "test changes are picked up" do
98
+ assert_speedup do
99
+ assert_success app.spring_test_command, stdout: "0 failures"
100
+
101
+ File.write(app.test, app.test.read.sub("get :index", "raise 'omg'"))
102
+ assert_failure app.spring_test_command, stdout: "RuntimeError: omg"
103
+ end
104
+ end
105
+
106
+ test "code changes are picked up" do
107
+ assert_speedup do
108
+ assert_success app.spring_test_command, stdout: "0 failures"
109
+
110
+ File.write(app.controller, app.controller.read.sub("@posts = Post.all", "raise 'omg'"))
111
+ assert_failure app.spring_test_command, stdout: "RuntimeError: omg"
112
+ end
113
+ end
114
+
115
+ test "code changes in pre-referenced app files are picked up" do
116
+ File.write(app.path("config/initializers/load_posts_controller.rb"), "PostsController\n")
117
+
118
+ assert_speedup do
119
+ assert_success app.spring_test_command, stdout: "0 failures"
120
+
121
+ File.write(app.controller, app.controller.read.sub("@posts = Post.all", "raise 'omg'"))
122
+ assert_failure app.spring_test_command, stdout: "RuntimeError: omg"
123
+ end
124
+ end
125
+
126
+ test "app gets reloaded when preloaded files change" do
127
+ assert_success app.spring_test_command
128
+
129
+ File.write(app.application_config, app.application_config.read + <<-RUBY.strip_heredoc)
130
+ class Foo
131
+ def self.omg
132
+ raise "omg"
133
+ end
134
+ end
135
+ RUBY
136
+ File.write(app.test, app.test.read.sub("get :index", "Foo.omg"))
137
+
138
+ app.await_reload
139
+ assert_failure app.spring_test_command, stdout: "RuntimeError: omg"
140
+ end
141
+
142
+ test "app gets reloaded even with a ton of boot output" do
143
+ limit = UNIXSocket.pair.first.getsockopt(:SOCKET, :SNDBUF).int
144
+
145
+ assert_success app.spring_test_command
146
+ File.write(app.path("config/initializers/verbose.rb"), "#{limit}.times { puts 'x' }")
147
+
148
+ app.await_reload
149
+ assert_success app.spring_test_command
150
+ end
151
+
152
+ test "app recovers when a boot-level error is introduced" do
153
+ config = app.application_config.read
154
+
155
+ assert_success app.spring_test_command
156
+
157
+ File.write(app.application_config, "#{config}\nomg")
158
+ app.await_reload
159
+
160
+ assert_failure app.spring_test_command
161
+
162
+ File.write(app.application_config, config)
163
+ assert_success app.spring_test_command
164
+ end
165
+
166
+ test "stop command kills server" do
167
+ app.run app.spring_test_command
168
+ assert app.spring_env.server_running?, "The server should be running but it isn't"
169
+
170
+ assert_success "bin/spring stop"
171
+ assert !app.spring_env.server_running?, "The server should not be running but it is"
172
+ end
173
+
174
+ test "custom commands" do
175
+ # Start spring before setting up the command, to test that it gracefully upgrades itself
176
+ assert_success "bin/rails runner ''"
177
+
178
+ File.write(app.spring_config, <<-RUBY.strip_heredoc)
179
+ class CustomCommand
180
+ def call
181
+ puts "omg"
182
+ end
183
+
184
+ def exec_name
185
+ "rake"
186
+ end
187
+ end
188
+
189
+ Spring.register_command "custom", CustomCommand.new
190
+ RUBY
191
+
192
+ assert_success "bin/spring custom", stdout: "omg"
193
+
194
+ assert_success "bin/spring binstub custom"
195
+ assert_success "bin/custom", stdout: "omg"
196
+
197
+ app.env["DISABLE_SPRING"] = "1"
198
+ assert_success %{bin/custom -e 'puts "foo"'}, stdout: "foo"
199
+ end
200
+
201
+ test "binstub" do
202
+ assert_success "bin/rails server --help", stdout: "Usage: rails server" # rails command fallback
203
+
204
+ assert_success "#{app.spring} binstub rake", stdout: "bin/rake: spring already present"
205
+
206
+ assert_success "#{app.spring} binstub --remove rake", stdout: "bin/rake: spring removed"
207
+ assert !app.path("bin/rake").read.include?(Spring::Client::Binstub::LOADER)
208
+ assert_success "bin/rake -T", stdout: "rake db:migrate"
209
+ end
210
+
211
+ test "binstub when spring is uninstalled" do
212
+ without_gem "spring-#{Spring::VERSION}" do
213
+ File.write(app.gemfile, app.gemfile.read.gsub(/gem 'spring.*/, ""))
214
+ assert_success "bin/rake -T", stdout: "rake db:migrate"
215
+ end
216
+ end
217
+
218
+ test "binstub upgrade" do
219
+ File.write(app.path("bin/rake"), <<-RUBY.strip_heredoc)
220
+ #!/usr/bin/env ruby
221
+
222
+ if !Process.respond_to?(:fork) || Gem::Specification.find_all_by_name("spring").empty?
223
+ exec "bundle", "exec", "rake", *ARGV
224
+ else
225
+ ARGV.unshift "rake"
226
+ load Gem.bin_path("spring", "spring")
227
+ end
228
+ RUBY
229
+
230
+ File.write(app.path("bin/rails"), <<-RUBY.strip_heredoc)
231
+ #!/usr/bin/env ruby
232
+
233
+ if !Process.respond_to?(:fork) || Gem::Specification.find_all_by_name("spring").empty?
234
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
235
+ require_relative '../config/boot'
236
+ require 'rails/commands'
237
+ else
238
+ ARGV.unshift "rails"
239
+ load Gem.bin_path("spring", "spring")
240
+ end
241
+ RUBY
242
+
243
+ assert_success "bin/spring binstub --all", stdout: "upgraded"
244
+
245
+ expected = <<-RUBY.gsub(/^ /, "")
246
+ #!/usr/bin/env ruby
247
+ #{Spring::Client::Binstub::LOADER.strip}
248
+ require 'bundler/setup'
249
+ load Gem.bin_path('rake', 'rake')
250
+ RUBY
251
+ assert_equal expected, app.path("bin/rake").read
252
+
253
+ expected = <<-RUBY.gsub(/^ /, "")
254
+ #!/usr/bin/env ruby
255
+ #{Spring::Client::Binstub::LOADER.strip}
256
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
257
+ require_relative '../config/boot'
258
+ require 'rails/commands'
259
+ RUBY
260
+ assert_equal expected, app.path("bin/rails").read
261
+ end
262
+
263
+ test "after fork callback" do
264
+ File.write(app.spring_config, "Spring.after_fork { puts '!callback!' }")
265
+ assert_success "bin/rails runner 'puts 2'", stdout: "!callback!\n2"
266
+ end
267
+
268
+ test "global config file evaluated" do
269
+ File.write("#{app.user_home}/.spring.rb", "Spring.after_fork { puts '!callback!' }")
270
+ assert_success "bin/rails runner 'puts 2'", stdout: "!callback!\n2"
271
+ end
272
+
273
+ test "can define client tasks" do
274
+ File.write("#{app.spring_config.sub('.rb', '_client.rb')}", <<-RUBY)
275
+ Spring::Client::COMMANDS["foo"] = lambda { |args| puts "bar -- \#{args.inspect}" }
276
+ RUBY
277
+ assert_success "bin/spring foo --baz", stdout: "bar -- [\"foo\", \"--baz\"]\n"
278
+ end
279
+
280
+ test "missing config/application.rb" do
281
+ app.application_config.delete
282
+ assert_failure "bin/rake -T", stderr: "unable to find your config/application.rb"
283
+ end
284
+
285
+ test "piping" do
286
+ assert_success "bin/rake -T | grep db", stdout: "rake db:migrate"
287
+ end
288
+
289
+ test "status" do
290
+ assert_success "bin/spring status", stdout: "Spring is not running"
291
+ assert_success "bin/rails runner ''"
292
+ assert_success "bin/spring status", stdout: "Spring is running"
293
+ end
294
+
295
+ test "runner command sets Rails environment from command-line options" do
296
+ assert_success "bin/rails runner -e test 'puts Rails.env'", stdout: "test"
297
+ assert_success "bin/rails runner --environment=test 'puts Rails.env'", stdout: "test"
298
+ end
299
+
300
+ test "forcing rails env via environment variable" do
301
+ app.env['RAILS_ENV'] = 'test'
302
+ assert_success "bin/rake -p 'Rails.env'", stdout: "test"
303
+ end
304
+
305
+ test "setting env vars with rake" do
306
+ File.write(app.path("lib/tasks/env.rake"), <<-RUBY.strip_heredoc)
307
+ task :print_rails_env => :environment do
308
+ puts Rails.env
309
+ end
310
+
311
+ task :print_env do
312
+ ENV.each { |k, v| puts "\#{k}=\#{v}" }
313
+ end
314
+
315
+ task(:default).clear.enhance [:print_rails_env]
316
+ RUBY
317
+
318
+ assert_success "bin/rake RAILS_ENV=test print_rails_env", stdout: "test"
319
+ assert_success "bin/rake FOO=bar print_env", stdout: "FOO=bar"
320
+ assert_success "bin/rake", stdout: "test"
321
+ end
322
+
323
+ test "changing the Gemfile works" do
324
+ assert_success %(bin/rails runner 'require "sqlite3"')
325
+
326
+ File.write(app.gemfile, app.gemfile.read.sub(%{gem 'sqlite3'}, %{# gem 'sqlite3'}))
327
+ app.await_reload
328
+
329
+ assert_failure %(bin/rails runner 'require "sqlite3"'), stderr: "sqlite3"
330
+ end
331
+
332
+ test "changing the Gemfile works when spring calls into itself" do
333
+ File.write(app.path("script.rb"), <<-RUBY.strip_heredoc)
334
+ gemfile = Rails.root.join("Gemfile")
335
+ File.write(gemfile, "\#{gemfile.read}gem 'devise'\\n")
336
+ Bundler.with_clean_env do
337
+ system(#{app.env.inspect}, "bundle install")
338
+ end
339
+ output = `\#{Rails.root.join('bin/rails')} runner 'require "devise"; puts "done";'`
340
+ exit output == "done\n"
341
+ RUBY
342
+
343
+ assert_success [%(bin/rails runner 'load Rails.root.join("script.rb")'), timeout: 60]
344
+ end
345
+
346
+ test "changing the environment between runs" do
347
+ File.write(app.application_config, "#{app.application_config.read}\nENV['BAR'] = 'bar'")
348
+
349
+ app.env["OMG"] = "1"
350
+ app.env["FOO"] = "1"
351
+ app.env["RUBYOPT"] = "-rubygems"
352
+
353
+ assert_success %(bin/rails runner 'p ENV["OMG"]'), stdout: "1"
354
+ assert_success %(bin/rails runner 'p ENV["BAR"]'), stdout: "bar"
355
+ assert_success %(bin/rails runner 'p ENV.key?("BUNDLE_GEMFILE")'), stdout: "true"
356
+ assert_success %(bin/rails runner 'p ENV["RUBYOPT"]'), stdout: "bundler"
357
+
358
+ app.env["OMG"] = "2"
359
+ app.env.delete "FOO"
360
+
361
+ assert_success %(bin/rails runner 'p ENV["OMG"]'), stdout: "2"
362
+ assert_success %(bin/rails runner 'p ENV.key?("FOO")'), stdout: "false"
363
+ end
364
+
365
+ test "Kernel.raise remains private" do
366
+ expr = "p Kernel.private_instance_methods.include?(:raise)"
367
+ assert_success %(bin/rails runner '#{expr}'), stdout: "true"
368
+ end
369
+ end
370
+ end
371
+ end