pietervisser-spork 0.7.5
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +11 -0
- data/assets/bootstrap.rb +29 -0
- data/bin/spork +20 -0
- data/features/cucumber_rails_integration.feature +118 -0
- data/features/diagnostic_mode.feature +41 -0
- data/features/rails_delayed_loading_workarounds.feature +115 -0
- data/features/rspec_rails_integration.feature +93 -0
- data/features/spork_debugger.feature +108 -0
- data/features/steps/general_steps.rb +3 -0
- data/features/steps/rails_steps.rb +53 -0
- data/features/steps/sandbox_steps.rb +115 -0
- data/features/support/background_job.rb +63 -0
- data/features/support/env.rb +111 -0
- data/features/unknown_app_framework.feature +42 -0
- data/geminstaller.yml +9 -0
- data/lib/spork/app_framework/rails.rb +158 -0
- data/lib/spork/app_framework/rails_stub_files/application.rb +1 -0
- data/lib/spork/app_framework/rails_stub_files/application_controller.rb +22 -0
- data/lib/spork/app_framework/rails_stub_files/application_helper.rb +3 -0
- data/lib/spork/app_framework/unknown.rb +6 -0
- data/lib/spork/app_framework.rb +74 -0
- data/lib/spork/custom_io_streams.rb +25 -0
- data/lib/spork/diagnoser.rb +103 -0
- data/lib/spork/ext/ruby-debug.rb +150 -0
- data/lib/spork/forker.rb +70 -0
- data/lib/spork/run_strategy/forking.rb +30 -0
- data/lib/spork/run_strategy.rb +40 -0
- data/lib/spork/runner.rb +90 -0
- data/lib/spork/server.rb +74 -0
- data/lib/spork/test_framework/cucumber.rb +24 -0
- data/lib/spork/test_framework/rspec.rb +14 -0
- data/lib/spork/test_framework.rb +167 -0
- data/lib/spork.rb +130 -0
- data/spec/spec_helper.rb +108 -0
- data/spec/spork/app_framework/rails_spec.rb +22 -0
- data/spec/spork/app_framework/unknown_spec.rb +12 -0
- data/spec/spork/app_framework_spec.rb +16 -0
- data/spec/spork/diagnoser_spec.rb +105 -0
- data/spec/spork/forker_spec.rb +44 -0
- data/spec/spork/run_strategy/forking_spec.rb +38 -0
- data/spec/spork/runner_spec.rb +50 -0
- data/spec/spork/server_spec.rb +15 -0
- data/spec/spork/test_framework/cucumber_spec.rb +11 -0
- data/spec/spork/test_framework/rspec_spec.rb +10 -0
- data/spec/spork/test_framework_spec.rb +114 -0
- data/spec/spork_spec.rb +157 -0
- data/spec/support/fake_framework.rb +15 -0
- data/spec/support/fake_run_strategy.rb +21 -0
- metadata +119 -0
@@ -0,0 +1,115 @@
|
|
1
|
+
Given /^I am in the directory "(.*)"$/ do |sandbox_dir_relative_path|
|
2
|
+
path = File.join(SporkWorld::SANDBOX_DIR, sandbox_dir_relative_path)
|
3
|
+
FileUtils.mkdir_p(path)
|
4
|
+
@current_dir = File.join(path)
|
5
|
+
end
|
6
|
+
|
7
|
+
Given /^a file named "([^\"]*)"$/ do |file_name|
|
8
|
+
create_file(file_name, '')
|
9
|
+
end
|
10
|
+
|
11
|
+
Given /^a file named "([^\"]*)" with:$/ do |file_name, file_content|
|
12
|
+
create_file(file_name, file_content)
|
13
|
+
end
|
14
|
+
|
15
|
+
When /^the contents of "([^\"]*)" are changed to:$/ do |file_name, file_content|
|
16
|
+
create_file(file_name, file_content)
|
17
|
+
end
|
18
|
+
|
19
|
+
# the following code appears in "config/environment.rb" after /Rails::Initializer.run/:
|
20
|
+
Given /^the following code appears in "([^\"]*)" after \/([^\\\/]*)\/:$/ do |file_name, regex, content|
|
21
|
+
regex = Regexp.new(regex)
|
22
|
+
in_current_dir do
|
23
|
+
content_lines = File.read(file_name).split("\n")
|
24
|
+
0.upto(content_lines.length - 1) do |line_index|
|
25
|
+
if regex.match(content_lines[line_index])
|
26
|
+
content_lines.insert(line_index + 1, content)
|
27
|
+
break
|
28
|
+
end
|
29
|
+
end
|
30
|
+
File.open(file_name, 'wb') { |f| f << (content_lines * "\n") }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
When /^I run (spork|spec|cucumber)(| .*)$/ do |command, args|
|
35
|
+
run(localized_command(command, args))
|
36
|
+
end
|
37
|
+
|
38
|
+
When /^I run this in the background: (spork|spec|cucumber)(| .*)$/ do |command, args|
|
39
|
+
@background_script = run_in_background(localized_command(command, args))
|
40
|
+
end
|
41
|
+
|
42
|
+
When /^I fire up a spork instance with "spork(.*)"$/ do |spork_opts|
|
43
|
+
@spork_server = run_in_background("#{SporkWorld::RUBY_BINARY} -I #{Cucumber::LIBDIR} #{SporkWorld::BINARY} #{spork_opts}")
|
44
|
+
|
45
|
+
output = ""
|
46
|
+
begin
|
47
|
+
status = Timeout::timeout(15) do
|
48
|
+
# Something that should be interrupted if it takes too much time...
|
49
|
+
while line = @spork_server.stderr.gets
|
50
|
+
output << line
|
51
|
+
puts line
|
52
|
+
break if line.include?("Spork is ready and listening")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
rescue Timeout::Error
|
56
|
+
puts "I can't seem to launch Spork properly. Output was:\n#{output}"
|
57
|
+
true.should == false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Then /^the spork window should output a line containing "(.+)"/ do |expected|
|
62
|
+
output = ""
|
63
|
+
begin
|
64
|
+
status = Timeout::timeout(5) do
|
65
|
+
# Something that should be interrupted if it takes too much time...
|
66
|
+
while line = @spork_server.stdout.gets
|
67
|
+
output << line
|
68
|
+
puts line
|
69
|
+
break if output.include?(expected)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
rescue Timeout::Error
|
73
|
+
output.should include(expected)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
When /^I type this in the spork window: "(.+)"/ do |line|
|
78
|
+
@spork_server.stdin.puts(line)
|
79
|
+
@spork_server.stdin.flush
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
Then /^the file "([^\"]*)" should include "([^\"]*)"$/ do |filename, content|
|
84
|
+
in_current_dir do
|
85
|
+
File.read(filename).should include(content)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
Then /^the (error output|output) should contain$/ do |which, text|
|
90
|
+
(which == "error output" ? last_stderr : last_stdout).should include(text)
|
91
|
+
end
|
92
|
+
|
93
|
+
Then /^the (error output|output) should contain "(.+)"$/ do |which, text|
|
94
|
+
(which == "error output" ? last_stderr : last_stdout).should include(text)
|
95
|
+
end
|
96
|
+
|
97
|
+
Then /^the (error output|output) should match \/(.+)\/$/ do |which, regex|
|
98
|
+
(which == "error output" ? last_stderr : last_stdout).should match(Regexp.new(regex))
|
99
|
+
end
|
100
|
+
|
101
|
+
Then /^the (error output|output) should not contain$/ do |which, text|
|
102
|
+
(which == "error output" ? last_stderr : last_stdout).should_not include(text)
|
103
|
+
end
|
104
|
+
|
105
|
+
Then /^the (error output|output) should not contain "(.+)"$/ do |which, text|
|
106
|
+
(which == "error output" ? last_stderr : last_stdout).should_not include(text)
|
107
|
+
end
|
108
|
+
|
109
|
+
Then /^the (error output|output) should be empty$/ do |which|
|
110
|
+
(which == "error output" ? last_stderr : last_stdout).should == ""
|
111
|
+
end
|
112
|
+
|
113
|
+
Then /^the (error output|output) should be$/ do |which, text|
|
114
|
+
(which == "error output" ? last_stderr : last_stdout).should == text
|
115
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class BackgroundJob
|
2
|
+
attr_reader :stdin, :stdout, :stderr, :pid
|
3
|
+
def initialize(pid, stdin, stdout, stderr)
|
4
|
+
@pid, @stdin, @stdout, @stderr = pid, stdin, stdout, stderr
|
5
|
+
ObjectSpace.define_finalizer(self) { kill }
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.run(command)
|
9
|
+
command = sanitize_params(command) if command.is_a?(Array)
|
10
|
+
child_stdin, parent_stdin = IO::pipe
|
11
|
+
parent_stdout, child_stdout = IO::pipe
|
12
|
+
parent_stderr, child_stderr = IO::pipe
|
13
|
+
|
14
|
+
pid = Kernel.fork do
|
15
|
+
[parent_stdin, parent_stdout, parent_stderr].each { |io| io.close }
|
16
|
+
|
17
|
+
STDIN.reopen(child_stdin)
|
18
|
+
STDOUT.reopen(child_stdout)
|
19
|
+
STDERR.reopen(child_stderr)
|
20
|
+
|
21
|
+
[child_stdin, child_stdout, child_stderr].each { |io| io.close }
|
22
|
+
|
23
|
+
exec command
|
24
|
+
end
|
25
|
+
|
26
|
+
[child_stdin, child_stdout, child_stderr].each { |io| io.close }
|
27
|
+
parent_stdin.sync = true
|
28
|
+
|
29
|
+
new(pid, parent_stdin, parent_stdout, parent_stderr)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.sanitize_params(params)
|
33
|
+
params.map { |p| p.gsub(' ', '\ ') }.join(" ")
|
34
|
+
end
|
35
|
+
|
36
|
+
def kill(signal = 'TERM')
|
37
|
+
if running?
|
38
|
+
Process.kill(Signal.list[signal], @pid)
|
39
|
+
true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def interrupt
|
44
|
+
kill('INT')
|
45
|
+
end
|
46
|
+
|
47
|
+
def running?
|
48
|
+
return false unless @pid
|
49
|
+
Process.getpgid(@pid)
|
50
|
+
true
|
51
|
+
rescue Errno::ESRCH
|
52
|
+
false
|
53
|
+
end
|
54
|
+
|
55
|
+
def wait(timeout = 1000)
|
56
|
+
Timeout.timeout(timeout) do
|
57
|
+
Process.wait(@pid)
|
58
|
+
end
|
59
|
+
true
|
60
|
+
rescue Timeout::Error
|
61
|
+
false
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'forwardable'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'spec/expectations'
|
6
|
+
require 'timeout'
|
7
|
+
require 'spork'
|
8
|
+
|
9
|
+
require(File.dirname(__FILE__) + '/background_job.rb')
|
10
|
+
|
11
|
+
class SporkWorld
|
12
|
+
BINARY = File.expand_path(File.dirname(__FILE__) + '/../../bin/spork')
|
13
|
+
RUBY_BINARY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
|
14
|
+
SANDBOX_DIR = File.expand_path(File.join(File.dirname(__FILE__), '../../tmp/sandbox'))
|
15
|
+
|
16
|
+
extend Forwardable
|
17
|
+
def_delegators SporkWorld, :sandbox_dir, :spork_lib_dir
|
18
|
+
|
19
|
+
def spork_lib_dir
|
20
|
+
@spork_lib_dir ||= File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@current_dir = SANDBOX_DIR
|
25
|
+
@background_jobs = []
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
attr_reader :last_exit_status, :last_stderr, :last_stdout, :background_jobs
|
30
|
+
def last_stderr
|
31
|
+
return @last_stderr if @last_stderr
|
32
|
+
if @background_job
|
33
|
+
@last_stderr = @background_job.stderr.read
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def last_stdout
|
39
|
+
return @last_stdout if @last_stdout
|
40
|
+
if @background_job
|
41
|
+
@last_stdout = @background_job.stdout.read
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_file(file_name, file_content)
|
46
|
+
file_content.gsub!("SPORK_LIB", "'#{spork_lib_dir}'") # Some files, such as Rakefiles need to use the lib dir
|
47
|
+
in_current_dir do
|
48
|
+
FileUtils.mkdir_p(File.dirname(file_name))
|
49
|
+
File.open(file_name, 'w') { |f| f << file_content }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def in_current_dir(&block)
|
54
|
+
Dir.chdir(@current_dir, &block)
|
55
|
+
end
|
56
|
+
|
57
|
+
def localized_command(command, args)
|
58
|
+
case command
|
59
|
+
when 'spork'
|
60
|
+
command = SporkWorld::BINARY
|
61
|
+
when 'cucumber'
|
62
|
+
command = Cucumber::BINARY
|
63
|
+
else
|
64
|
+
command = %x{which #{command}}.chomp
|
65
|
+
end
|
66
|
+
"#{SporkWorld::RUBY_BINARY} -I #{Cucumber::LIBDIR} #{command} #{args}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def run(command)
|
70
|
+
stderr_file = Tempfile.new('spork')
|
71
|
+
stderr_file.close
|
72
|
+
in_current_dir do
|
73
|
+
@last_stdout = `#{command} 2> #{stderr_file.path}`
|
74
|
+
@last_exit_status = $?.exitstatus
|
75
|
+
end
|
76
|
+
@last_stderr = IO.read(stderr_file.path)
|
77
|
+
end
|
78
|
+
|
79
|
+
def run_in_background(command)
|
80
|
+
in_current_dir do
|
81
|
+
@background_job = BackgroundJob.run(command)
|
82
|
+
end
|
83
|
+
@background_jobs << @background_job
|
84
|
+
@background_job
|
85
|
+
end
|
86
|
+
|
87
|
+
def terminate_background_jobs
|
88
|
+
if @background_jobs
|
89
|
+
@background_jobs.each do |background_job|
|
90
|
+
background_job.kill
|
91
|
+
end
|
92
|
+
end
|
93
|
+
@background_jobs.clear
|
94
|
+
@background_job = nil
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
World do
|
100
|
+
SporkWorld.new
|
101
|
+
end
|
102
|
+
|
103
|
+
Before do
|
104
|
+
FileUtils.rm_rf SporkWorld::SANDBOX_DIR
|
105
|
+
FileUtils.mkdir_p SporkWorld::SANDBOX_DIR
|
106
|
+
end
|
107
|
+
|
108
|
+
After do
|
109
|
+
# FileUtils.rm_rf SporkWorld::SANDBOX_DIR
|
110
|
+
terminate_background_jobs
|
111
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
Feature: Unknown app frameworks
|
2
|
+
To increase to usefulness of Spork
|
3
|
+
Spork will work with unknown (or no) application frameworks
|
4
|
+
|
5
|
+
Scenario: Unsporked spec_helper
|
6
|
+
|
7
|
+
Given a file named "spec/spec_helper.rb" with:
|
8
|
+
"""
|
9
|
+
require 'rubygems'
|
10
|
+
require 'spec'
|
11
|
+
"""
|
12
|
+
When I run spork
|
13
|
+
Then the error output should contain "Using RSpec"
|
14
|
+
Then the error output should match /You must bootstrap .+spec\/spec_helper\.rb to continue/
|
15
|
+
|
16
|
+
Scenario: Sporked spec_helper
|
17
|
+
Given a file named "spec/spec_helper.rb" with:
|
18
|
+
"""
|
19
|
+
require 'rubygems'
|
20
|
+
require 'spork'
|
21
|
+
|
22
|
+
Spork.prefork do
|
23
|
+
require 'spec'
|
24
|
+
end
|
25
|
+
|
26
|
+
Spork.each_run do
|
27
|
+
$each_run
|
28
|
+
end
|
29
|
+
"""
|
30
|
+
And a file named "spec/did_it_work_spec.rb" with:
|
31
|
+
"""
|
32
|
+
describe "Did it work?" do
|
33
|
+
it "checks to see if all worked" do
|
34
|
+
Spork.state.should == :using_spork
|
35
|
+
puts "Specs successfully run within spork"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
"""
|
39
|
+
When I fire up a spork instance with "spork rspec"
|
40
|
+
And I run spec --drb spec/did_it_work_spec.rb
|
41
|
+
Then the output should contain "Specs successfully run within spork"
|
42
|
+
|
data/geminstaller.yml
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
defaults:
|
2
|
+
install_options: "--no-ri --no-rdoc"
|
3
|
+
gems:
|
4
|
+
- { name: 'sqlite3-ruby', version: '>= 1.2.5' }
|
5
|
+
- { name: 'cucumber', version: '>= 0.4.0' }
|
6
|
+
- { name: 'rspec', version: '>= 1.2.9' }
|
7
|
+
- { name: 'rspec-rails', version: '>= 1.2.9' }
|
8
|
+
- { name: 'rails', version: '>= 2.3' }
|
9
|
+
- { name: 'ruby-debug', version: '>= 0.10.3' }
|
@@ -0,0 +1,158 @@
|
|
1
|
+
class Spork::AppFramework::Rails < Spork::AppFramework
|
2
|
+
|
3
|
+
# TODO - subclass this out to handle different versions of rails
|
4
|
+
# Also... this is the nastiest duck punch ever. Clean this up.
|
5
|
+
module NinjaPatcher
|
6
|
+
def self.included(klass)
|
7
|
+
klass.class_eval do
|
8
|
+
unless method_defined?(:load_environment_without_spork)
|
9
|
+
alias :load_environment_without_spork :load_environment
|
10
|
+
alias :load_environment :load_environment_with_spork
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.run_with_spork(*args, &block) # it's all fun and games until someone gets an eye poked out
|
14
|
+
if ENV['RAILS_ENV']
|
15
|
+
Object.send(:remove_const, :RAILS_ENV)
|
16
|
+
Object.const_set(:RAILS_ENV, ENV['RAILS_ENV'].dup)
|
17
|
+
end
|
18
|
+
run_without_spork(*args, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
unless method_defined?(:run_without_spork)
|
23
|
+
alias :run_without_spork :run
|
24
|
+
alias :run :run_with_spork
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def load_environment_with_spork
|
31
|
+
result = load_environment_without_spork
|
32
|
+
install_hooks
|
33
|
+
result
|
34
|
+
end
|
35
|
+
|
36
|
+
def install_hooks
|
37
|
+
auto_reestablish_db_connection
|
38
|
+
delay_observer_loading
|
39
|
+
delay_app_preload
|
40
|
+
delay_application_controller_loading
|
41
|
+
delay_route_loading
|
42
|
+
delay_eager_view_loading
|
43
|
+
end
|
44
|
+
|
45
|
+
def reset_rails_env
|
46
|
+
return unless ENV['RAILS_ENV']
|
47
|
+
Object.send(:remove_const, :RAILS_ENV)
|
48
|
+
Object.const_set(:RAILS_ENV, ENV['RAILS_ENV'].dup)
|
49
|
+
end
|
50
|
+
|
51
|
+
def delay_observer_loading
|
52
|
+
if ::Rails::Initializer.instance_methods.include?('load_observers')
|
53
|
+
Spork.trap_method(::Rails::Initializer, :load_observers)
|
54
|
+
end
|
55
|
+
if Object.const_defined?(:ActionController)
|
56
|
+
require "action_controller/dispatcher.rb"
|
57
|
+
Spork.trap_class_method(::ActionController::Dispatcher, :define_dispatcher_callbacks) if ActionController::Dispatcher.respond_to?(:define_dispatcher_callbacks)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def delay_app_preload
|
62
|
+
if ::Rails::Initializer.instance_methods.include?('load_application_classes')
|
63
|
+
Spork.trap_method(::Rails::Initializer, :load_application_classes)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def delay_application_controller_loading
|
68
|
+
if application_controller_source = ["#{Dir.pwd}/app/controllers/application.rb", "#{Dir.pwd}/app/controllers/application_controller.rb"].find { |f| File.exist?(f) }
|
69
|
+
application_helper_source = "#{Dir.pwd}/app/helpers/application_helper.rb"
|
70
|
+
load_paths = (::ActiveSupport.const_defined?(:Dependencies) ? ::ActiveSupport::Dependencies : ::Dependencies).load_paths
|
71
|
+
load_paths.unshift(File.expand_path('rails_stub_files', File.dirname(__FILE__)))
|
72
|
+
Spork.each_run do
|
73
|
+
require application_controller_source
|
74
|
+
require application_helper_source if File.exist?(application_helper_source)
|
75
|
+
# update the rails magic to refresh the module
|
76
|
+
ApplicationController.send(:helper, ApplicationHelper)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def auto_reestablish_db_connection
|
82
|
+
if Object.const_defined?(:ActiveRecord)
|
83
|
+
Spork.each_run do
|
84
|
+
# rails lib/test_help.rb is very aggressive about overriding RAILS_ENV and will switch it back to test after the cucumber env was loaded
|
85
|
+
reset_rails_env
|
86
|
+
ActiveRecord::Base.establish_connection
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def delay_route_loading
|
92
|
+
if ::Rails::Initializer.instance_methods.include?('initialize_routing')
|
93
|
+
Spork.trap_method(::Rails::Initializer, :initialize_routing)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def delay_eager_view_loading
|
98
|
+
# So, in testing mode it seems it would be optimal to not eager load
|
99
|
+
# views (as your may only run a test that uses one or two views).
|
100
|
+
# However, I decided to delay eager loading rather than force it to
|
101
|
+
# disable because you may wish to eager load your views (I.E. you're
|
102
|
+
# testing concurrency)
|
103
|
+
|
104
|
+
# Rails 2.3.x +
|
105
|
+
if defined?(::ActionView::Template::EagerPath)
|
106
|
+
Spork.trap_method(::ActionView::Template::EagerPath, :load!)
|
107
|
+
end
|
108
|
+
# Rails 2.2.x
|
109
|
+
if defined?(::ActionView::PathSet::Path)
|
110
|
+
Spork.trap_method(::ActionView::PathSet::Path, :load)
|
111
|
+
end
|
112
|
+
# Rails 2.0.5 - 2.1.x don't appear to eager cache views.
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def preload(&block)
|
117
|
+
STDERR.puts "Preloading Rails environment"
|
118
|
+
STDERR.flush
|
119
|
+
ENV["RAILS_ENV"] ||= 'test'
|
120
|
+
preload_rails
|
121
|
+
yield
|
122
|
+
end
|
123
|
+
|
124
|
+
def entry_point
|
125
|
+
@entry_point ||= File.expand_path("config/environment.rb", Dir.pwd)
|
126
|
+
end
|
127
|
+
|
128
|
+
alias :environment_file :entry_point
|
129
|
+
|
130
|
+
def boot_file
|
131
|
+
@boot_file ||= File.join(File.dirname(environment_file), 'boot')
|
132
|
+
end
|
133
|
+
|
134
|
+
def environment_contents
|
135
|
+
@environment_contents ||= File.read(environment_file)
|
136
|
+
end
|
137
|
+
|
138
|
+
def vendor
|
139
|
+
@vendor ||= File.expand_path("vendor/rails", Dir.pwd)
|
140
|
+
end
|
141
|
+
|
142
|
+
def version
|
143
|
+
@version ||= (
|
144
|
+
if /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/.match(environment_contents)
|
145
|
+
$1
|
146
|
+
else
|
147
|
+
nil
|
148
|
+
end
|
149
|
+
)
|
150
|
+
end
|
151
|
+
|
152
|
+
def preload_rails
|
153
|
+
Object.const_set(:RAILS_GEM_VERSION, version) if version
|
154
|
+
require boot_file
|
155
|
+
::Rails::Initializer.send(:include, Spork::AppFramework::Rails::NinjaPatcher)
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
load(File.dirname(__FILE__) + "/application_controller.rb")
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# This is a stub used to help Spork delay the loading of the real ApplicationController
|
2
|
+
class ::ApplicationController < ActionController::Base
|
3
|
+
@@preloading = true
|
4
|
+
class << self
|
5
|
+
def inherited(klass)
|
6
|
+
(@_descendants ||= []) << klass if @@preloading
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def reapply_inheritance!
|
11
|
+
@@preloading = false
|
12
|
+
Array(@_descendants).each do |descendant|
|
13
|
+
descendant.master_helper_module.send(:include, master_helper_module)
|
14
|
+
descendant.send(:default_helper_module!)
|
15
|
+
|
16
|
+
descendant.respond_to?(:reapply_inheritance!) && descendant.reapply_inheritance!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Spork.each_run { ApplicationController.reapply_inheritance! }
|
@@ -0,0 +1,74 @@
|
|
1
|
+
class Spork::AppFramework
|
2
|
+
# A hash of procs where the key is the class name, and the proc takes no arguments and returns true if it detects that said application framework is being used in the project.
|
3
|
+
#
|
4
|
+
# The key :Rails maps to Spork::AppFramework::Rails
|
5
|
+
#
|
6
|
+
# This is used to reduce the amount of code needed to be loaded - only the detected application framework's support code is loaded.
|
7
|
+
SUPPORTED_FRAMEWORKS = {
|
8
|
+
:Rails => lambda {
|
9
|
+
File.exist?("config/environment.rb") && File.read("config/environment.rb").include?('RAILS_GEM_VERSION')
|
10
|
+
}
|
11
|
+
} unless defined? SUPPORTED_FRAMEWORKS
|
12
|
+
|
13
|
+
def self.setup_autoload
|
14
|
+
([:Unknown] + SUPPORTED_FRAMEWORKS.keys).each do |name|
|
15
|
+
autoload name, File.join(File.dirname(__FILE__), "app_framework", name.to_s.downcase)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Iterates through all SUPPORTED_FRAMEWORKS and returns the symbolic name of the project application framework detected. Otherwise, returns :Unknown
|
20
|
+
def self.detect_framework_name
|
21
|
+
SUPPORTED_FRAMEWORKS.each do |key, value|
|
22
|
+
return key if value.call
|
23
|
+
end
|
24
|
+
:Unknown
|
25
|
+
end
|
26
|
+
|
27
|
+
# Same as detect_framework_name, but returns an instance of the specific AppFramework class.
|
28
|
+
def self.detect_framework
|
29
|
+
name = detect_framework_name
|
30
|
+
self[name]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Initializes, stores, and returns a singleton instance of the named AppFramework.
|
34
|
+
#
|
35
|
+
# == Parameters
|
36
|
+
#
|
37
|
+
# # +name+ - A symbolic name of a AppFramework subclass
|
38
|
+
#
|
39
|
+
# == Example
|
40
|
+
#
|
41
|
+
# Spork::AppFramework[:Rails]
|
42
|
+
def self.[](name)
|
43
|
+
instances[name] ||= const_get(name).new
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.short_name
|
47
|
+
name.gsub('Spork::AppFramework::', '')
|
48
|
+
end
|
49
|
+
|
50
|
+
# If there is some stuff out of the box that the Spork can do to speed up tests without the test helper file being bootstrapped, this should return false.
|
51
|
+
def bootstrap_required?
|
52
|
+
entry_point.nil?
|
53
|
+
end
|
54
|
+
|
55
|
+
# Abstract: The path to the file that loads the project environment, ie config/environment.rb. Returns nil if there is none.
|
56
|
+
def entry_point
|
57
|
+
raise NotImplementedError
|
58
|
+
end
|
59
|
+
|
60
|
+
def preload(&block)
|
61
|
+
yield
|
62
|
+
end
|
63
|
+
|
64
|
+
def short_name
|
65
|
+
self.class.short_name
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
def self.instances
|
70
|
+
@instances ||= {}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
Spork::AppFramework.setup_autoload
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# This class is mainly used for testing.
|
2
|
+
# When included (and used), it gives us an opportunity to stub out the output streams used for a given class
|
3
|
+
module Spork::CustomIOStreams
|
4
|
+
def self.included(klass)
|
5
|
+
klass.send(:extend, ::Spork::CustomIOStreams::ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
def stderr
|
9
|
+
self.class.stderr
|
10
|
+
end
|
11
|
+
|
12
|
+
def stdout
|
13
|
+
self.class.stdout
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def stderr
|
18
|
+
$stderr
|
19
|
+
end
|
20
|
+
|
21
|
+
def stdout
|
22
|
+
$stdout
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|