-
Notifications
You must be signed in to change notification settings - Fork 202
/
spork.rb
149 lines (129 loc) · 4.81 KB
/
spork.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
require 'pathname'
module Spork
BINARY = File.expand_path(File.dirname(__FILE__) + '/../bin/spork')
LIBDIR = Pathname.new(File.expand_path(File.dirname(__FILE__)))
autoload :Server, (LIBDIR + 'spork/server').to_s
autoload :TestFramework, (LIBDIR + 'spork/test_framework').to_s
autoload :AppFramework, (LIBDIR + 'spork/app_framework').to_s
autoload :RunStrategy, (LIBDIR + 'spork/run_strategy').to_s
autoload :Runner, (LIBDIR + 'spork/runner').to_s
autoload :Forker, (LIBDIR + 'spork/forker').to_s
autoload :Diagnoser, (LIBDIR + 'spork/diagnoser').to_s
autoload :GemHelpers, (LIBDIR + 'spork/gem_helpers').to_s
class << self
# 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.
#
# == Parameters
#
# * +prevent_double_run+ - Pass false to disable double run prevention
def prefork(prevent_double_run = true, &block)
return if prevent_double_run && already_ran?(caller.first)
yield
end
# 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.
#
# == Parameters
#
# * +prevent_double_run+ - Pass false to disable double run prevention
def each_run(prevent_double_run = true, &block)
return if prevent_double_run && already_ran?(caller.first)
if state == :prefork
each_run_procs << block
else
yield
end
end
# Run a block after specs are run.
#
# == Parameters
#
# * +prevent_double_run+ - Pass false to disable double run prevention
def after_each_run(prevent_double_run = true, &block)
return if prevent_double_run && already_ran?(caller.first)
after_each_run_procs << block
end
def using_spork?
state != :not_using_spork
end
def state
@state ||= :not_using_spork
end
# Used by the server. Called when loading the prefork blocks of the code.
def exec_prefork(&block)
@state = :prefork
yield
end
# Used by the server. Called to run all of the prefork blocks.
def exec_each_run(&block)
@state = :run
activate_after_each_run_at_exit_hook
each_run_procs.each { |p| p.call }
each_run_procs.clear
yield if block_given?
end
# Used by the server. Called to run all of the after_each_run blocks.
def exec_after_each_run
# processes in reverse order similar to at_exit
while p = after_each_run_procs.pop; p.call; end
true
end
# Traps an instance method of a class (or module) so any calls to it don't actually run until Spork.exec_each_run
def trap_method(klass, method_name)
method_name_without_spork, method_name_with_spork = alias_method_names(method_name, :spork)
klass.class_eval <<-EOF, __FILE__, __LINE__ + 1
alias :#{method_name_without_spork} :#{method_name} unless method_defined?(:#{method_name_without_spork})
def #{method_name}(*args, &block)
Spork.each_run(false) do
#{method_name_without_spork}(*args, &block)
end
end
EOF
end
# Same as trap_method, but for class methods instead
def trap_class_method(klass, method_name)
trap_method((class << klass; self; end), method_name)
end
def detect_and_require(pattern)
GemHelpers.find_files_using_latest_spec(pattern).uniq.each do |path|
next if path.match(/_spec\.rb/)
require path
end
end
private
def activate_after_each_run_at_exit_hook
Kernel.module_eval do
def at_exit(&block)
Spork.after_each_run(false, &block)
end
end
end
def alias_method_names(method_name, feature)
/^(.+?)([\?\!]{0,1})$/.match(method_name.to_s)
["#{$1}_without_spork#{$2}", "#{$1}_with_spork#{$2}"]
end
def already_ran
@already_ran ||= []
end
def expanded_caller(caller_line)
file, line = caller_line.split(/:(\d+)/)
line.gsub(/:.+/, '')
expanded = File.expand_path(file, Dir.pwd) + ":" + line
if ENV['OS'] == 'Windows_NT' # windows
expanded = expanded[2..-1]
end
expanded
end
def already_ran?(caller_script_and_line)
return true if already_ran.include?(expanded_caller(caller_script_and_line))
already_ran << expanded_caller(caller_script_and_line)
false
end
def each_run_procs
@each_run_procs ||= []
end
def after_each_run_procs
@after_each_run_procs ||= []
end
end
end