milhouse-spork 0.7.5.2 → 0.7.5.4

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 +19 -19
  2. data/README.rdoc +99 -99
  3. data/assets/bootstrap.rb +29 -29
  4. data/bin/spork +20 -20
  5. data/features/cucumber_rails_integration.feature +118 -118
  6. data/features/diagnostic_mode.feature +40 -40
  7. data/features/rails_delayed_loading_workarounds.feature +115 -115
  8. data/features/rspec_rails_integration.feature +93 -93
  9. data/features/spork_debugger.feature +108 -108
  10. data/features/steps/general_steps.rb +3 -3
  11. data/features/steps/rails_steps.rb +52 -52
  12. data/features/steps/sandbox_steps.rb +115 -115
  13. data/features/support/background_job.rb +63 -63
  14. data/features/support/env.rb +111 -111
  15. data/features/unknown_app_framework.feature +41 -41
  16. data/geminstaller.yml +9 -9
  17. data/lib/spork.rb +126 -126
  18. data/lib/spork/app_framework.rb +73 -73
  19. data/lib/spork/app_framework/rails.rb +157 -157
  20. data/lib/spork/app_framework/rails_stub_files/application.rb +1 -1
  21. data/lib/spork/app_framework/rails_stub_files/application_controller.rb +22 -22
  22. data/lib/spork/app_framework/rails_stub_files/application_helper.rb +2 -2
  23. data/lib/spork/app_framework/unknown.rb +5 -5
  24. data/lib/spork/custom_io_streams.rb +24 -24
  25. data/lib/spork/diagnoser.rb +103 -103
  26. data/lib/spork/ext/ruby-debug.rb +150 -150
  27. data/lib/spork/forker.rb +70 -70
  28. data/lib/spork/run_strategy.rb +44 -44
  29. data/lib/spork/run_strategy/forking.rb +29 -29
  30. data/lib/spork/run_strategy/magazine.rb +8 -7
  31. data/lib/spork/run_strategy/magazine/magazine_slave.rb +0 -0
  32. data/lib/spork/run_strategy/magazine/magazine_slave_provider.rb +2 -2
  33. data/lib/spork/run_strategy/magazine/ring_server.rb +1 -1
  34. data/lib/spork/runner.rb +90 -90
  35. data/lib/spork/server.rb +74 -74
  36. data/lib/spork/test_framework.rb +167 -167
  37. data/lib/spork/test_framework/cucumber.rb +24 -24
  38. data/lib/spork/test_framework/rspec.rb +14 -14
  39. data/spec/spec_helper.rb +108 -108
  40. data/spec/spork/app_framework/rails_spec.rb +22 -22
  41. data/spec/spork/app_framework/unknown_spec.rb +12 -12
  42. data/spec/spork/app_framework_spec.rb +16 -16
  43. data/spec/spork/diagnoser_spec.rb +105 -105
  44. data/spec/spork/forker_spec.rb +44 -44
  45. data/spec/spork/run_strategy/forking_spec.rb +38 -38
  46. data/spec/spork/runner_spec.rb +50 -50
  47. data/spec/spork/server_spec.rb +15 -15
  48. data/spec/spork/test_framework/cucumber_spec.rb +11 -11
  49. data/spec/spork/test_framework/rspec_spec.rb +10 -10
  50. data/spec/spork/test_framework_spec.rb +114 -114
  51. data/spec/spork_spec.rb +151 -151
  52. data/spec/support/fake_framework.rb +15 -15
  53. data/spec/support/fake_run_strategy.rb +21 -21
  54. metadata +14 -6
data/lib/spork.rb CHANGED
@@ -1,126 +1,126 @@
1
- $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
2
- require 'pathname'
3
- module Spork
4
- BINARY = File.expand_path(File.dirname(__FILE__) + '/../bin/spork')
5
- LIBDIR = Pathname.new(File.expand_path(File.dirname(__FILE__)))
6
-
7
- autoload :Server, (LIBDIR + 'spork/server').to_s
8
- autoload :TestFramework, (LIBDIR + 'spork/test_framework').to_s
9
- autoload :AppFramework, (LIBDIR + 'spork/app_framework').to_s
10
- autoload :RunStrategy, (LIBDIR + 'spork/run_strategy').to_s
11
- autoload :Runner, (LIBDIR + 'spork/runner').to_s
12
- autoload :Forker, (LIBDIR + 'spork/forker').to_s
13
- autoload :Diagnoser, (LIBDIR + 'spork/diagnoser').to_s
14
-
15
- class << self
16
- # Run a block, during prefork mode. By default, if prefork is called twice in the same file and line number, the supplied block will only be ran once.
17
- #
18
- # == Parameters
19
- #
20
- # * +prevent_double_run+ - Pass false to disable double run prevention
21
- def prefork(prevent_double_run = true, &block)
22
- return if prevent_double_run && already_ran?(caller.first)
23
- yield
24
- end
25
-
26
- # Run a block AFTER the fork occurs. By default, if prefork is called twice in the same file and line number, the supplied block will only be ran once.
27
- #
28
- # == Parameters
29
- #
30
- # * +prevent_double_run+ - Pass false to disable double run prevention
31
- def each_run(prevent_double_run = true, &block)
32
- return if prevent_double_run && already_ran?(caller.first)
33
- if @state == :using_spork
34
- each_run_procs << block
35
- else
36
- yield
37
- end
38
- end
39
-
40
- # Used by the server. Sets the state to activate spork. Otherwise, prefork and each_run are run in passive mode, allowing specs without a Spork server.
41
- def using_spork!
42
- @state = :using_spork
43
- end
44
-
45
- def using_spork?
46
- @state == :using_spork
47
- end
48
-
49
- # Used by the server. Returns the current state of Spork.
50
- def state
51
- @state ||= :not_using_spork
52
- end
53
-
54
- # Used by the server. Called when loading the prefork blocks of the code.
55
- def exec_prefork(&block)
56
- using_spork!
57
- yield
58
- end
59
-
60
- # Used by the server. Called to run all of the prefork blocks.
61
- def exec_each_run(&block)
62
- each_run_procs.each { |p| p.call }
63
- each_run_procs.clear
64
- yield if block_given?
65
- end
66
-
67
- # Traps an instance method of a class (or module) so any calls to it don't actually run until Spork.exec_each_run
68
- def trap_method(klass, method_name)
69
- method_name_without_spork, method_name_with_spork = alias_method_names(method_name, :spork)
70
-
71
- klass.class_eval <<-EOF, __FILE__, __LINE__ + 1
72
- alias :#{method_name_without_spork} :#{method_name} unless method_defined?(:#{method_name_without_spork})
73
- def #{method_name}(*args)
74
- Spork.each_run(false) do
75
- #{method_name_without_spork}(*args)
76
- end
77
- end
78
- EOF
79
- end
80
-
81
- # Same as trap_method, but for class methods instead
82
- def trap_class_method(klass, method_name)
83
- trap_method((class << klass; self; end), method_name)
84
- end
85
-
86
- def detect_and_require(subfolder)
87
- ([LIBDIR.to_s] + other_spork_gem_load_paths).uniq.each do |gem_path|
88
- Dir.glob(File.join(gem_path, subfolder)).each { |file| require file }
89
- end
90
- end
91
-
92
- def other_spork_gem_load_paths
93
- @other_spork_gem_load_paths ||= (
94
- Gem.latest_load_paths.grep(/spork/).select do |g|
95
- not g.match(%r{/spork-[0-9\-.]+/lib}) # don't include other versions of spork
96
- end
97
- )
98
- end
99
-
100
- private
101
- def alias_method_names(method_name, feature)
102
- /^(.+?)([\?\!]{0,1})$/.match(method_name.to_s)
103
- ["#{$1}_without_spork#{$2}", "#{$1}_with_spork#{$2}"]
104
- end
105
-
106
- def already_ran
107
- @already_ran ||= []
108
- end
109
-
110
- def expanded_caller(caller_line)
111
- file, line = caller_line.split(":")
112
- line.gsub(/:.+/, '')
113
- File.expand_path(file, Dir.pwd) + ":" + line
114
- end
115
-
116
- def already_ran?(caller_script_and_line)
117
- return true if already_ran.include?(expanded_caller(caller_script_and_line))
118
- already_ran << expanded_caller(caller_script_and_line)
119
- false
120
- end
121
-
122
- def each_run_procs
123
- @each_run_procs ||= []
124
- end
125
- end
126
- end
1
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
2
+ require 'pathname'
3
+ module Spork
4
+ BINARY = File.expand_path(File.dirname(__FILE__) + '/../bin/spork')
5
+ LIBDIR = Pathname.new(File.expand_path(File.dirname(__FILE__)))
6
+
7
+ autoload :Server, (LIBDIR + 'spork/server').to_s
8
+ autoload :TestFramework, (LIBDIR + 'spork/test_framework').to_s
9
+ autoload :AppFramework, (LIBDIR + 'spork/app_framework').to_s
10
+ autoload :RunStrategy, (LIBDIR + 'spork/run_strategy').to_s
11
+ autoload :Runner, (LIBDIR + 'spork/runner').to_s
12
+ autoload :Forker, (LIBDIR + 'spork/forker').to_s
13
+ autoload :Diagnoser, (LIBDIR + 'spork/diagnoser').to_s
14
+
15
+ class << self
16
+ # Run a block, during prefork mode. By default, if prefork is called twice in the same file and line number, the supplied block will only be ran once.
17
+ #
18
+ # == Parameters
19
+ #
20
+ # * +prevent_double_run+ - Pass false to disable double run prevention
21
+ def prefork(prevent_double_run = true, &block)
22
+ return if prevent_double_run && already_ran?(caller.first)
23
+ yield
24
+ end
25
+
26
+ # Run a block AFTER the fork occurs. By default, if prefork is called twice in the same file and line number, the supplied block will only be ran once.
27
+ #
28
+ # == Parameters
29
+ #
30
+ # * +prevent_double_run+ - Pass false to disable double run prevention
31
+ def each_run(prevent_double_run = true, &block)
32
+ return if prevent_double_run && already_ran?(caller.first)
33
+ if @state == :using_spork
34
+ each_run_procs << block
35
+ else
36
+ yield
37
+ end
38
+ end
39
+
40
+ # Used by the server. Sets the state to activate spork. Otherwise, prefork and each_run are run in passive mode, allowing specs without a Spork server.
41
+ def using_spork!
42
+ @state = :using_spork
43
+ end
44
+
45
+ def using_spork?
46
+ @state == :using_spork
47
+ end
48
+
49
+ # Used by the server. Returns the current state of Spork.
50
+ def state
51
+ @state ||= :not_using_spork
52
+ end
53
+
54
+ # Used by the server. Called when loading the prefork blocks of the code.
55
+ def exec_prefork(&block)
56
+ using_spork!
57
+ yield
58
+ end
59
+
60
+ # Used by the server. Called to run all of the prefork blocks.
61
+ def exec_each_run(&block)
62
+ each_run_procs.each { |p| p.call }
63
+ each_run_procs.clear
64
+ yield if block_given?
65
+ end
66
+
67
+ # Traps an instance method of a class (or module) so any calls to it don't actually run until Spork.exec_each_run
68
+ def trap_method(klass, method_name)
69
+ method_name_without_spork, method_name_with_spork = alias_method_names(method_name, :spork)
70
+
71
+ klass.class_eval <<-EOF, __FILE__, __LINE__ + 1
72
+ alias :#{method_name_without_spork} :#{method_name} unless method_defined?(:#{method_name_without_spork})
73
+ def #{method_name}(*args)
74
+ Spork.each_run(false) do
75
+ #{method_name_without_spork}(*args)
76
+ end
77
+ end
78
+ EOF
79
+ end
80
+
81
+ # Same as trap_method, but for class methods instead
82
+ def trap_class_method(klass, method_name)
83
+ trap_method((class << klass; self; end), method_name)
84
+ end
85
+
86
+ def detect_and_require(subfolder)
87
+ ([LIBDIR.to_s] + other_spork_gem_load_paths).uniq.each do |gem_path|
88
+ Dir.glob(File.join(gem_path, subfolder)).each { |file| require file }
89
+ end
90
+ end
91
+
92
+ def other_spork_gem_load_paths
93
+ @other_spork_gem_load_paths ||= (
94
+ Gem.latest_load_paths.grep(/spork/).select do |g|
95
+ not g.match(%r{/spork-[0-9\-.]+/lib}) # don't include other versions of spork
96
+ end
97
+ )
98
+ end
99
+
100
+ private
101
+ def alias_method_names(method_name, feature)
102
+ /^(.+?)([\?\!]{0,1})$/.match(method_name.to_s)
103
+ ["#{$1}_without_spork#{$2}", "#{$1}_with_spork#{$2}"]
104
+ end
105
+
106
+ def already_ran
107
+ @already_ran ||= []
108
+ end
109
+
110
+ def expanded_caller(caller_line)
111
+ file, line = caller_line.split(":")
112
+ line.gsub(/:.+/, '')
113
+ File.expand_path(file, Dir.pwd) + ":" + line
114
+ end
115
+
116
+ def already_ran?(caller_script_and_line)
117
+ return true if already_ran.include?(expanded_caller(caller_script_and_line))
118
+ already_ran << expanded_caller(caller_script_and_line)
119
+ false
120
+ end
121
+
122
+ def each_run_procs
123
+ @each_run_procs ||= []
124
+ end
125
+ end
126
+ end
@@ -1,74 +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
-
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
74
  Spork::AppFramework.setup_autoload
@@ -1,158 +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
-
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
158
  end