spork 0.4.4 → 0.5.1

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.
@@ -0,0 +1,109 @@
1
+ class Spork::AppFramework::Rails < Spork::AppFramework
2
+
3
+ # TODO - subclass this out to handle different versions of rails
4
+ class NinjaPatcher
5
+ def self.run
6
+ ::Rails::Initializer.class_eval do
7
+ alias :load_environment_without_spork :load_environment unless method_defined?(:load_environment_without_spork)
8
+ def load_environment
9
+ result = load_environment_without_spork
10
+ Spork::AppFramework[:Rails].ninja_patcher.install_hooks
11
+ result
12
+ end
13
+ end
14
+ end
15
+
16
+ def self.install_hooks
17
+ auto_reestablish_db_connection
18
+ delay_observer_loading
19
+ delay_app_preload
20
+ delay_application_controller_loading
21
+ end
22
+
23
+ def self.delay_observer_loading
24
+ if ::Rails::Initializer.instance_methods.include?('load_observers')
25
+ Spork.trap_method(::Rails::Initializer, :load_observers)
26
+ end
27
+ if Object.const_defined?(:ActionController)
28
+ require "action_controller/dispatcher.rb"
29
+ Spork.trap_class_method(::ActionController::Dispatcher, :define_dispatcher_callbacks) if ActionController::Dispatcher.respond_to?(:define_dispatcher_callbacks)
30
+ end
31
+ end
32
+
33
+ def self.delay_app_preload
34
+ if ::Rails::Initializer.instance_methods.include?('load_application_classes')
35
+ Spork.trap_method(::Rails::Initializer, :load_application_classes)
36
+ end
37
+ end
38
+
39
+ def self.delay_application_controller_loading
40
+ if application_controller_source = ["#{Dir.pwd}/app/controllers/application.rb", "#{Dir.pwd}/app/controllers/application_controller.rb"].find { |f| File.exist?(f) }
41
+ application_helper_source = "#{Dir.pwd}/app/helpers/application_helper.rb"
42
+ load_paths = (::ActiveSupport.const_defined?(:Dependencies) ? ::ActiveSupport::Dependencies : ::Dependencies).load_paths
43
+ load_paths.unshift(File.expand_path('rails_stub_files', File.dirname(__FILE__)))
44
+ Spork.each_run do
45
+ require application_controller_source
46
+ require application_helper_source if File.exist?(application_helper_source)
47
+ end
48
+ end
49
+ end
50
+
51
+ def self.auto_reestablish_db_connection
52
+ if Object.const_defined?(:ActiveRecord)
53
+ Spork.each_run do
54
+ ActiveRecord::Base.establish_connection
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def bootstrap_required?
61
+ false
62
+ end
63
+
64
+ def preload(&block)
65
+ STDERR.puts "Preloading Rails environment"
66
+ STDERR.flush
67
+ ENV["RAILS_ENV"] ||= 'test'
68
+ preload_rails
69
+ require environment_file
70
+ yield
71
+ end
72
+
73
+ def environment_file
74
+ @environment_file ||= File.expand_path("config/environment.rb", Dir.pwd)
75
+ end
76
+
77
+ def boot_file
78
+ @boot_file ||= File.join(File.dirname(environment_file), 'boot')
79
+ end
80
+
81
+ def environment_contents
82
+ @environment_contents ||= File.read(environment_file)
83
+ end
84
+
85
+ def vendor
86
+ @vendor ||= File.expand_path("vendor/rails", Dir.pwd)
87
+ end
88
+
89
+ def version
90
+ @version ||= (
91
+ if /^[^#]*RAILS_GEM_VERSION\s*=\s*["']([!~<>=]*\s*[\d.]+)["']/.match(environment_contents)
92
+ $1
93
+ else
94
+ nil
95
+ end
96
+ )
97
+ end
98
+
99
+ def ninja_patcher
100
+ ::Spork::AppFramework::Rails::NinjaPatcher
101
+ end
102
+
103
+ def preload_rails
104
+ Object.const_set(:RAILS_GEM_VERSION, version) if version
105
+ require boot_file
106
+ ninja_patcher.run
107
+ end
108
+
109
+ end
@@ -0,0 +1,2 @@
1
+ class ::ApplicationController < ActionController::Base
2
+ end
@@ -0,0 +1,2 @@
1
+ class ::ApplicationController < ActionController::Base
2
+ end
@@ -0,0 +1,2 @@
1
+ module ::ApplicationHelper
2
+ end
@@ -0,0 +1,6 @@
1
+ class Spork::AppFramework::Unknown < Spork::AppFramework
2
+ def bootstrap_required?
3
+ true
4
+ end
5
+
6
+ end
@@ -0,0 +1,23 @@
1
+ module Spork::CustomIOStreams
2
+ def self.included(klass)
3
+ klass.send(:extend, ::Spork::CustomIOStreams::ClassMethods)
4
+ end
5
+
6
+ def stderr
7
+ self.class.stderr
8
+ end
9
+
10
+ def stdout
11
+ self.class.stdout
12
+ end
13
+
14
+ module ClassMethods
15
+ def stderr
16
+ $stderr
17
+ end
18
+
19
+ def stdout
20
+ $stdout
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,72 @@
1
+ class Spork::Diagnoser
2
+ class << self
3
+ def loaded_files
4
+ @loaded_files ||= {}
5
+ end
6
+
7
+ def install_hook!(dir = Dir.pwd)
8
+ @dir = File.expand_path(Dir.pwd, dir)
9
+
10
+ Kernel.class_eval do
11
+ alias :require_without_diagnoser :require
12
+ alias :load_without_diagnoser :load
13
+
14
+ def require(string)
15
+ ::Spork::Diagnoser.add_included_file(string, caller)
16
+ require_without_diagnoser(string)
17
+ end
18
+
19
+ def load(string)
20
+ ::Spork::Diagnoser.add_included_file(string, caller)
21
+ load_without_diagnoser(string)
22
+ end
23
+ end
24
+ end
25
+
26
+ def add_included_file(filename, callstack)
27
+ filename = expand_filename(filename)
28
+ return unless File.exist?(filename)
29
+ loaded_files[filename] = caller.select { |f| ! f.include?('lib/spork/diagnoser.rb')} if subdirectory?(filename)
30
+ end
31
+
32
+ def expand_filename(filename)
33
+ ([Dir.pwd] + $:).each do |attempted_path|
34
+ attempted_filename = File.expand_path(filename, attempted_path)
35
+ return attempted_filename if File.file?(attempted_filename)
36
+ attempted_filename = attempted_filename + ".rb"
37
+ return attempted_filename if File.file?(attempted_filename)
38
+ end
39
+ filename
40
+ end
41
+
42
+ def subdirectory?(directory)
43
+ File.expand_path(directory, Dir.pwd).include?(@dir)
44
+ end
45
+
46
+ def remove_hook!
47
+ return unless Kernel.private_instance_methods.include?('require_without_diagnoser')
48
+ Kernel.class_eval do
49
+ alias :require :require_without_diagnoser
50
+ alias :load :load_without_diagnoser
51
+
52
+ undef_method(:require_without_diagnoser)
53
+ undef_method(:load_without_diagnoser)
54
+ end
55
+ true
56
+ end
57
+
58
+ def output_results(stdout)
59
+ project_prefix = Dir.pwd + "/"
60
+ minimify = lambda { |f| f.gsub(project_prefix, '')}
61
+ stdout.puts "- Spork Diagnosis -\n"
62
+ stdout.puts "-- Summary --"
63
+ stdout.puts loaded_files.keys.sort.map(&minimify)
64
+ stdout.puts "\n\n\n"
65
+ stdout.puts "-- Detail --"
66
+ loaded_files.keys.sort.each do |file|
67
+ stdout.puts "\n\n\n--- #{minimify.call(file)} ---\n"
68
+ stdout.puts loaded_files[file].map(&minimify)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -19,6 +19,7 @@ module Spork
19
19
 
20
20
  opt.separator "Options:"
21
21
  opt.on("-b", "--bootstrap") {|ignore| @options[:bootstrap] = true }
22
+ opt.on("-d", "--diagnose") {|ignore| @options[:diagnose] = true }
22
23
  opt.on("-h", "--help") {|ignore| @options[:help] = true }
23
24
  non_option_args = args.select { |arg| ! args[0].match(/^-/) }
24
25
  @options[:server_matcher] = non_option_args[0]
@@ -45,7 +46,7 @@ module Spork
45
46
  if options[:server_matcher]
46
47
  @server = Spork::Server.supported_servers(options[:server_matcher]).first
47
48
  unless @server
48
- @output.puts <<-ERROR
49
+ @error.puts <<-ERROR
49
50
  #{options[:server_matcher].inspect} didn't match a supported test framework.
50
51
 
51
52
  #{supported_servers_text}
@@ -54,7 +55,7 @@ module Spork
54
55
  end
55
56
 
56
57
  unless @server.available?
57
- @output.puts <<-USEFUL_ERROR
58
+ @error.puts <<-USEFUL_ERROR
58
59
  I can't find the helper file #{@server.helper_file} for the #{@server.server_name} testing framework.
59
60
  Are you running me from the project directory?
60
61
  USEFUL_ERROR
@@ -63,7 +64,7 @@ Are you running me from the project directory?
63
64
  else
64
65
  @server = Spork::Server.available_servers.first
65
66
  if @server.nil?
66
- @output.puts <<-USEFUL_ERROR
67
+ @error.puts <<-USEFUL_ERROR
67
68
  I can't find any testing frameworks to use.
68
69
  Are you running me from a project directory?
69
70
  USEFUL_ERROR
@@ -76,12 +77,26 @@ Are you running me from a project directory?
76
77
  def run
77
78
  return false unless find_server
78
79
  ENV["DRB"] = 'true'
79
- ENV["RAILS_ENV"] ||= 'test' if server.using_rails?
80
- @output.puts "Using #{server.server_name}"
81
- return server.bootstrap if options[:bootstrap]
82
- return(false) unless server.preload
83
- server.run
84
- return true
80
+ @error.puts "Using #{server.server_name}"
81
+ @error.flush
82
+ case
83
+ when options[:bootstrap]
84
+ server.bootstrap
85
+ when options[:diagnose]
86
+ require 'spork/diagnoser'
87
+
88
+ Spork::Diagnoser.install_hook!
89
+ server.preload
90
+ Spork::Diagnoser.output_results(@output)
91
+ return true
92
+ else
93
+ return(false) unless server.preload
94
+ server.run
95
+ return true
96
+ end
97
+ end
98
+
99
+ def diagnose
85
100
  end
86
101
 
87
102
  private
@@ -1,6 +1,8 @@
1
1
  require 'drb/drb'
2
2
  require 'rbconfig'
3
3
  require 'spork/forker.rb'
4
+ require 'spork/custom_io_streams.rb'
5
+ require 'spork/app_framework.rb'
4
6
 
5
7
  # This is based off of spec_server.rb from rspec-rails (David Chelimsky), which was based on Florian Weber's TDDMate
6
8
  class Spork::Server
@@ -9,6 +11,8 @@ class Spork::Server
9
11
  LOAD_PREFERENCE = ['RSpec', 'Cucumber']
10
12
  BOOTSTRAP_FILE = File.dirname(__FILE__) + "/../../assets/bootstrap.rb"
11
13
 
14
+ include Spork::CustomIOStreams
15
+
12
16
  def self.port
13
17
  raise NotImplemented
14
18
  end
@@ -45,20 +49,16 @@ class Spork::Server
45
49
  LOAD_PREFERENCE.index(server_name) || LOAD_PREFERENCE.length
46
50
  end
47
51
 
48
- def self.using_rails?
49
- File.exist?("config/environment.rb")
50
- end
51
-
52
52
  def self.bootstrapped?
53
53
  File.read(helper_file).include?("Spork.prefork")
54
54
  end
55
55
 
56
56
  def self.bootstrap
57
57
  if bootstrapped?
58
- puts "Already bootstrapped!"
58
+ stderr.puts "Already bootstrapped!"
59
59
  return
60
60
  end
61
- puts "Bootstrapping #{helper_file}."
61
+ stderr.puts "Bootstrapping #{helper_file}."
62
62
  contents = File.read(helper_file)
63
63
  bootstrap_code = File.read(BOOTSTRAP_FILE)
64
64
  File.open(helper_file, "wb") do |f|
@@ -66,7 +66,7 @@ class Spork::Server
66
66
  f.puts contents
67
67
  end
68
68
 
69
- puts "Done. Edit #{helper_file} now with your favorite text editor and follow the instructions."
69
+ stderr.puts "Done. Edit #{helper_file} now with your favorite text editor and follow the instructions."
70
70
  true
71
71
  end
72
72
 
@@ -80,7 +80,8 @@ class Spork::Server
80
80
  trap("SIGTERM") { abort; exit!(0) }
81
81
  trap("USR2") { abort; restart } if Signal.list.has_key?("USR2")
82
82
  DRb.start_service("druby://127.0.0.1:#{port}", self)
83
- puts "Spork is ready and listening on #{port}!"
83
+ stderr.puts "Spork is ready and listening on #{port}!"
84
+ stderr.flush
84
85
  DRb.thread.join
85
86
  end
86
87
 
@@ -94,9 +95,10 @@ class Spork::Server
94
95
 
95
96
  def run(argv, stderr, stdout)
96
97
  return false if running?
98
+
97
99
  @child = ::Spork::Forker.new do
98
100
  $stdout, $stderr = stdout, stderr
99
- Spork.exec_each_run(helper_file)
101
+ Spork.exec_each_run { load helper_file }
100
102
  run_tests(argv, stderr, stdout)
101
103
  end
102
104
  @child.result
@@ -107,20 +109,30 @@ class Spork::Server
107
109
  end
108
110
 
109
111
  private
112
+ def self.framework
113
+ @framework ||= Spork::AppFramework.detect_framework
114
+ end
115
+
110
116
  def self.preload
111
- if bootstrapped?
112
- puts "Loading Spork.prefork block..."
113
- Spork.exec_prefork(helper_file)
114
- else
115
- puts "#{helper_file} has not been sporked. Run spork --bootstrap to do so."
116
- # are we in a rails app?
117
- if using_rails?
118
- puts "Preloading Rails environment"
119
- require "config/environment.rb"
120
- else
121
- puts "There's nothing I can really do for you. Bailing."
122
- return false
117
+ Spork.exec_prefork do
118
+ unless bootstrapped?
119
+ stderr.puts "#{helper_file} has not been bootstrapped. Run spork --bootstrap to do so."
120
+ stderr.flush
121
+
122
+ if framework.bootstrap_required?
123
+ stderr.puts "I can't do anything for you by default for the framework your using: #{framework.short_name}.\nYou must bootstrap #{helper_file} to continue."
124
+ stderr.flush
125
+ return false
126
+ end
123
127
  end
128
+
129
+ framework.preload do
130
+ if bootstrapped?
131
+ stderr.puts "Loading Spork.prefork block..."
132
+ stderr.flush
133
+ load(helper_file)
134
+ end
135
+ end
124
136
  end
125
137
  true
126
138
  end
@@ -130,7 +142,8 @@ class Spork::Server
130
142
  end
131
143
 
132
144
  def restart
133
- puts "restarting"
145
+ stderr.puts "restarting"
146
+ stderr.flush
134
147
  config = ::Config::CONFIG
135
148
  ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT']
136
149
  command_line = [ruby, $0, ARGV].flatten.join(' ')
@@ -144,7 +157,8 @@ class Spork::Server
144
157
  def sig_int_received
145
158
  if running?
146
159
  abort
147
- puts "Running tests stopped. Press CTRL-C again to stop the server."
160
+ stderr.puts "Running tests stopped. Press CTRL-C again to stop the server."
161
+ stderr.flush
148
162
  else
149
163
  exit!(0)
150
164
  end
@@ -1,20 +1,102 @@
1
1
  require 'rubygems'
2
2
  require 'spec'
3
3
 
4
- $LOAD_PATH.unshift(File.dirname(__FILE__))
5
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
- SPEC_TMP_DIR = File.dirname(__FILE__) + "/tmp"
7
- require 'spork'
8
- require 'spork/runner.rb'
9
- require 'spork/server.rb'
10
- require 'stringio'
11
-
12
- Spec::Runner.configure do |config|
13
- config.before(:each) do
14
- $test_stdout = StringIO.new
4
+ unless $spec_helper_loaded
5
+ $spec_helper_loaded = true
6
+
7
+ $LOAD_PATH.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
8
+ SPEC_TMP_DIR = File.expand_path('tmp', File.dirname(__FILE__))
9
+
10
+ require 'spork'
11
+ require 'spork/runner.rb'
12
+ require 'spork/server.rb'
13
+ require 'spork/diagnoser.rb'
14
+ require 'stringio'
15
+ require 'fileutils'
16
+
17
+ Spec::Runner.configure do |config|
18
+ config.before(:each) do
19
+ $test_stdout = StringIO.new
20
+ $test_stderr = StringIO.new
21
+ end
22
+
23
+ config.after(:each) do
24
+ FileUtils.rm_rf(SPEC_TMP_DIR) if File.directory?(SPEC_TMP_DIR)
25
+
26
+ end
27
+
28
+ def create_file(filename, contents)
29
+ FileUtils.mkdir_p(SPEC_TMP_DIR) unless File.directory?(SPEC_TMP_DIR)
30
+
31
+ in_current_dir do
32
+ FileUtils.mkdir_p(File.dirname(filename))
33
+ File.open(filename, 'wb') { |f| f << contents }
34
+ end
35
+ end
36
+
37
+ def in_current_dir(&block)
38
+ Dir.chdir(current_dir, &block)
39
+ end
40
+
41
+ def current_dir
42
+ @current_dir ||= SPEC_TMP_DIR
43
+ end
44
+ end
45
+
46
+
47
+ module Spec
48
+ module Matchers
49
+ class IncludeAStringLike
50
+ def initialize(substring_or_regex)
51
+ case substring_or_regex
52
+ when String
53
+ @regex = Regexp.new(Regexp.escape(substring_or_regex))
54
+ when Regexp
55
+ @regex = substring_or_regex
56
+ else
57
+ raise ArgumentError, "don't know what to do with the #{substring_or_regex.class} you provided"
58
+ end
59
+ end
60
+
61
+ def matches?(list_of_strings)
62
+ @list_of_strings = list_of_strings
63
+ @list_of_strings.any? { |s| s =~ @regex }
64
+ end
65
+ def failure_message
66
+ "#{@list_of_strings.inspect} expected to include a string like #{@regex.inspect}"
67
+ end
68
+ def negative_failure_message
69
+ "#{@list_of_strings.inspect} expected to not include a string like #{@regex.inspect}, but did"
70
+ end
71
+ end
72
+
73
+ def include_a_string_like(substring_or_regex)
74
+ IncludeAStringLike.new(substring_or_regex)
75
+ end
76
+ end
15
77
  end
78
+
79
+ module Spork::TestIOStreams
80
+ def self.included(klass)
81
+ klass.send(:extend, ::Spork::TestIOStreams::ClassMethods)
82
+ end
83
+
84
+ def stderr
85
+ self.class.stderr
86
+ end
87
+
88
+ def stdout
89
+ self.class.stdout
90
+ end
91
+
92
+ module ClassMethods
93
+ def stderr
94
+ $test_stderr
95
+ end
16
96
 
17
- config.after(:each) do
18
- FileUtils.rm_rf(SPEC_TMP_DIR)
97
+ def stdout
98
+ $test_stdout
99
+ end
100
+ end
19
101
  end
20
102
  end