Skip to content

Commit

Permalink
The first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
timcharper committed May 20, 2009
0 parents commit b58847b
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 0 deletions.
33 changes: 33 additions & 0 deletions README.rdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
= Spork

* http://github.com/timcharper/spork

== SYNOPSIS:

Spork is a Drb spec server (similar to the script/spec_server provided by rspec-rails), except rather than using the Rails constant unloading to reload your files, it forks a copy of the server each time you run your specs. The result? Spork runs more solid: it doesn't get corrupted over time, and it properly handles modules and any voo-doo meta programming you may have put in your app.

Because Spork uses Kernel.fork, it only works on POSIX systems. This means Windows users are not invited to this party. Sorry :(

Spork is still experimental, but is performing solid for us.

== Some potential issues and ways to overcome them:

=== ActiveRecord reports "connection has gone away" for the first few specs

Not sure why this happens, but if you simply add a line to re-establish your database connection on each line as follows, the problem goes away:

Spork.each_run do
ActiveRecord::Base.establish_connection # make sure that the db connection is ready.
end

== INSTALL:

[sudo] gem install timcharper-spork --source http://gems.github.com/

alternatively:

git clone git://github.com/timcharper/spork.git
cd spork
gem build spork.gemspec
sudo gem install spork.gemspec

64 changes: 64 additions & 0 deletions bin/spork
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env ruby
gem 'test-unit', '1.2.3' if RUBY_VERSION.to_f >= 1.9

SPEC_HELPER_FILE = File.join(Dir.pwd, "spec/spec_helper.rb")
require 'rubygems'

unless File.exist?(SPEC_HELPER_FILE)
puts <<-USEFUL_ERROR
Bummer!
I can't find the file spec/spec_helper.rb, which I need in order to run.
Are you running me from a project directory that has rspec set up?
USEFUL_ERROR
end

ENV["DRB"] = 'true'
ENV["RAILS_ENV"] ||= 'test' if File.exist?("config/environment.rb")

require 'rubygems'
require 'spork'

if File.read(SPEC_HELPER_FILE).include?("Spork.prefork")
puts "Loading Spork.prefork block..."
Spork.preforking!
load SPEC_HELPER_FILE
else
puts <<-NO_SPORK_BLOCK
spec_helper.rb is has not been sporked. Run spork --bootstrap to do so.
NO_SPORK_BLOCK
# are we in a rails app?
if File.exist?("config/environment.rb")
puts "Preloading Rails environment"
require "config/environment.rb"
else
puts "There's nothing I can really do for you. Bailing."
end

end

require 'optparse'

options = {}
parser = OptionParser.new
parser.on("-d", "--daemon") {|ignore| options[:daemon] = true }
parser.on("-b", "--bootstrap") {|ignore| options[:bootstrap] = true }
parser.on("-p", "--pid PIDFILE"){|pid| options[:pid] = pid }
parser.parse!(ARGV)

case
when options[:bootstrap]
require 'spork/bootstrapper'
if Spork::Bootstrapper.run
exit 0
else
exit 1
end
when options[:daemon]
require 'spork/spec_server'
::Spork::SpecServer.daemonize(options[:pid])
else
require 'spork/spec_server'
::Spork::SpecServer.run
end
25 changes: 25 additions & 0 deletions lib/spork.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class Spork
def self.prefork(&block)
return if @already_preforked
@already_preforked = true
yield
end

def self.each_run(&block)
return if @state == :preforking || (@state != :not_using_spork && @already_run)
@already_run = true
yield
end

def self.preforking!
@state = :preforking
end

def self.running!
@state = :running
end

def self.state
@state ||= :not_using_spork
end
end
44 changes: 44 additions & 0 deletions lib/spork/bootstrapper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
class Spork::Bootstrapper
def self.run
puts "Bootstrapping #{SPEC_HELPER_FILE}"
contents = File.read(SPEC_HELPER_FILE)
File.open(SPEC_HELPER_FILE, "wb") do |f|
f.puts <<-BOOTSTRAP
require 'rubygems'
require 'spork'
Spork.prefork do
# Loading more in this block will cause your specs to run faster. However,
# if you change any configuration or code from libraries loaded here, you'll
# need to restart spork for it take effect.
end
Spork.each_run do
# This code will be run each time you run your specs.
end
# --- Instructions ---
# - Sort through your spec_helper file. Place as much environment loading
# code that you don't normally modify during development in the
# Spork.prefork block.
# - Place the rest under Spork.each_run block
# - Any code that is left outside of the blocks will be ran during preforking
# and during each_run!
# - These instructions should self-destruct in 10 seconds. If they don't,
# feel free to delete them.
#
BOOTSTRAP

f.puts(contents)
end

true
end
end
58 changes: 58 additions & 0 deletions lib/spork/spec_server.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
require 'drb/drb'
require 'rbconfig'

# This is based off of spec_server.rb from rspec-rails (David Chelimsky), which was based on Florian Weber's TDDMate
class Spork::SpecServer
DRB_PORT = 8989
def self.restart_test_server
puts "restarting"
config = ::Config::CONFIG
ruby = File::join(config['bindir'], config['ruby_install_name']) + config['EXEEXT']
command_line = [ruby, $0, ARGV].flatten.join(' ')
exec(command_line)
end

def self.daemonize(pid_file = nil)
return yield if $DEBUG
pid = Process.fork{
Process.setsid
trap("SIGINT"){ exit! 0 }
trap("SIGTERM"){ exit! 0 }
trap("SIGHUP"){ restart_test_server }
File.open("/dev/null"){|f|
STDERR.reopen f
STDIN.reopen f
STDOUT.reopen f
}
run
}
puts "spec_server launched (PID: %d)" % pid
File.open(pid_file,"w"){|f| f.puts pid } if pid_file
exit! 0
end

def self.run
trap("USR2") { ::Spork::SpecServer.restart_test_server } if Signal.list.has_key?("USR2")
DRb.start_service("druby://127.0.0.1:#{DRB_PORT}", ::Spork::SpecServer.new)
puts "Spork is ready and listening on #{DRB_PORT}!"
DRb.thread.join
end

def run(argv, stderr, stdout)
$stdout = stdout
$stderr = stderr
child_pid = Kernel.fork do
Spork.running!
load SPEC_HELPER_FILE

::Spec::Runner::CommandLine.run(
::Spec::Runner::OptionParser.parse(
argv,
$stderr,
$stdout
)
)
end
Process.wait(child_pid)
end
end
22 changes: 22 additions & 0 deletions spork.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# -*- encoding: utf-8 -*-

Gem::Specification.new do |s|
s.name = %q{spork}
s.version = "0.1"

s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Tim Harper"]
s.date = %q{2009-05-20}
s.description = %q{A forking Drb spec server}
s.email = ["[email protected]"]
s.executables = ["spork"]
s.extra_rdoc_files = ["README.rdoc"]
s.files = ["README.rdoc"] + Dir["lib/**/*"]
s.has_rdoc = true
s.homepage = %q{http://github.com/timcharper/spork}
s.rdoc_options = ["--main", "README.rdoc"]
s.require_paths = ["lib"]
s.rubyforge_project = %q{spork}
s.rubygems_version = %q{1.3.1}
s.summary = %{spork #{s.version}}
end

0 comments on commit b58847b

Please sign in to comment.