milhouse-spork 0.7.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +100 -0
  3. data/assets/bootstrap.rb +29 -0
  4. data/bin/spork +20 -0
  5. data/features/cucumber_rails_integration.feature +118 -0
  6. data/features/diagnostic_mode.feature +41 -0
  7. data/features/rails_delayed_loading_workarounds.feature +115 -0
  8. data/features/rspec_rails_integration.feature +93 -0
  9. data/features/spork_debugger.feature +108 -0
  10. data/features/steps/general_steps.rb +3 -0
  11. data/features/steps/rails_steps.rb +53 -0
  12. data/features/steps/sandbox_steps.rb +115 -0
  13. data/features/support/background_job.rb +63 -0
  14. data/features/support/env.rb +111 -0
  15. data/features/unknown_app_framework.feature +42 -0
  16. data/geminstaller.yml +9 -0
  17. data/lib/spork/app_framework/rails.rb +158 -0
  18. data/lib/spork/app_framework/rails_stub_files/application.rb +1 -0
  19. data/lib/spork/app_framework/rails_stub_files/application_controller.rb +22 -0
  20. data/lib/spork/app_framework/rails_stub_files/application_helper.rb +3 -0
  21. data/lib/spork/app_framework/unknown.rb +6 -0
  22. data/lib/spork/app_framework.rb +74 -0
  23. data/lib/spork/custom_io_streams.rb +25 -0
  24. data/lib/spork/diagnoser.rb +103 -0
  25. data/lib/spork/ext/ruby-debug.rb +150 -0
  26. data/lib/spork/forker.rb +70 -0
  27. data/lib/spork/run_strategy/forking.rb +30 -0
  28. data/lib/spork/run_strategy/magazine/magazine_slave.rb +30 -0
  29. data/lib/spork/run_strategy/magazine/magazine_slave_provider.rb +27 -0
  30. data/lib/spork/run_strategy/magazine/ring_server.rb +10 -0
  31. data/lib/spork/run_strategy/magazine.rb +110 -0
  32. data/lib/spork/run_strategy.rb +44 -0
  33. data/lib/spork/runner.rb +90 -0
  34. data/lib/spork/server.rb +74 -0
  35. data/lib/spork/test_framework/cucumber.rb +24 -0
  36. data/lib/spork/test_framework/rspec.rb +14 -0
  37. data/lib/spork/test_framework.rb +167 -0
  38. data/lib/spork.rb +126 -0
  39. data/spec/spec_helper.rb +108 -0
  40. data/spec/spork/app_framework/rails_spec.rb +22 -0
  41. data/spec/spork/app_framework/unknown_spec.rb +12 -0
  42. data/spec/spork/app_framework_spec.rb +16 -0
  43. data/spec/spork/diagnoser_spec.rb +105 -0
  44. data/spec/spork/forker_spec.rb +44 -0
  45. data/spec/spork/run_strategy/forking_spec.rb +38 -0
  46. data/spec/spork/runner_spec.rb +50 -0
  47. data/spec/spork/server_spec.rb +15 -0
  48. data/spec/spork/test_framework/cucumber_spec.rb +11 -0
  49. data/spec/spork/test_framework/rspec_spec.rb +10 -0
  50. data/spec/spork/test_framework_spec.rb +114 -0
  51. data/spec/spork_spec.rb +151 -0
  52. data/spec/support/fake_framework.rb +15 -0
  53. data/spec/support/fake_run_strategy.rb +21 -0
  54. metadata +134 -0
@@ -0,0 +1,53 @@
1
+ Given /^I am in a fresh rails project named "(.+)"$/ do |folder_name|
2
+ @current_dir = SporkWorld::SANDBOX_DIR
3
+ version_argument = ENV['RAILS_VERSION'] ? "_#{ENV['RAILS_VERSION']}_" : nil
4
+ # run("#{SporkWorld::RUBY_BINARY} #{%x{which rails}.chomp} #{folder_name}")
5
+ run([SporkWorld::RUBY_BINARY, '-I', Cucumber::LIBDIR, %x{which rails}.chomp, version_argument, folder_name].compact * " ")
6
+ @current_dir = File.join(File.join(SporkWorld::SANDBOX_DIR, folder_name))
7
+ end
8
+
9
+
10
+ Given "the application has a model, observer, route, and application helper" do
11
+ Given 'a file named "app/models/user.rb" with:',
12
+ """
13
+ class User < ActiveRecord::Base
14
+ $loaded_stuff << 'User'
15
+ end
16
+ """
17
+ Given 'a file named "app/models/user_observer.rb" with:',
18
+ """
19
+ class UserObserver < ActiveRecord::Observer
20
+ $loaded_stuff << 'UserObserver'
21
+ end
22
+ """
23
+ Given 'a file named "app/helpers/application_helper.rb" with:',
24
+ """
25
+ module ApplicationHelper
26
+ $loaded_stuff << 'ApplicationHelper'
27
+ end
28
+ """
29
+ Given 'the following code appears in "config/environment.rb" after /Rails::Initializer.run/:',
30
+ """
31
+ config.active_record.observers = :user_observer
32
+ """
33
+ Given 'the following code appears in "config/routes.rb" after /^end/:',
34
+ """
35
+ $loaded_stuff << 'config/routes.rb'
36
+ """
37
+ Given 'a file named "config/initializers/initialize_loaded_stuff.rb" with:',
38
+ """
39
+ $loaded_stuff ||= []
40
+ """
41
+ Given 'a file named "config/initializers/log_establish_connection_calls.rb" with:',
42
+ """
43
+ class ActiveRecord::Base
44
+ class << self
45
+ def establish_connection_with_load_logging(*args)
46
+ establish_connection_without_load_logging(*args)
47
+ $loaded_stuff << 'ActiveRecord::Base.establish_connection'
48
+ end
49
+ alias_method_chain :establish_connection, :load_logging
50
+ end
51
+ end
52
+ """
53
+ end
@@ -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,3 @@
1
+ # This is a stub used to help Spork delay the loading of the real ApplicationHelper
2
+ module ::ApplicationHelper
3
+ end
@@ -0,0 +1,6 @@
1
+ # This is used if no supported appliction framework is detected
2
+ class Spork::AppFramework::Unknown < Spork::AppFramework
3
+ def entry_point
4
+ nil
5
+ end
6
+ end
@@ -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