Permalink
Browse files

The first commit

  • Loading branch information...
0 parents commit b58847b659110651ab6b0e87af7e574cb3651b3f @timcharper timcharper committed May 20, 2009
Showing with 246 additions and 0 deletions.
  1. +33 −0 README.rdoc
  2. +64 −0 bin/spork
  3. +25 −0 lib/spork.rb
  4. +44 −0 lib/spork/bootstrapper.rb
  5. +58 −0 lib/spork/spec_server.rb
  6. +22 −0 spork.gemspec
33 README.rdoc
@@ -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 bin/spork
@@ -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 lib/spork.rb
@@ -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 lib/spork/bootstrapper.rb
@@ -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 lib/spork/spec_server.rb
@@ -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 spork.gemspec
@@ -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 = ["timcharper+spork@gmail.com"]
+ 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.