Permalink
Browse files

Rails integration hooks

  • Loading branch information...
1 parent c02e30f commit fc5e1d0773e0900d136ee2833cb0d26494349eff @timcharper timcharper committed Jun 4, 2009
View
@@ -1,3 +1,11 @@
+== 0.5.0 2009-06-05
+
+ === New Features
+
+ * Diagnostic mode: run 'spork -d' to find out which project files will be preloaded, and where they are being loading from.
+ * Better Rails integration: automatically delay loading of ApplicationController, observers, and entire app folder. Also, automatically re-establish the database connection each run if ActiveRecord is being used.
+ * Cucumber feature to test Spork from end to end (integrating with Rails)
+
== 0.4.4 2009-06-01
=== New Features
View
@@ -7,12 +7,12 @@ begin
s.name = %q{spork}
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.date = Date.today.to_s
s.description = %q{A forking Drb spec server}
s.email = ["timcharper+spork@gmail.com"]
s.executables = ["spork"]
s.extra_rdoc_files = ["README.rdoc", "MIT-LICENSE"]
- s.files = ["README.rdoc", "MIT-LICENSE"] + Dir["lib/**/*"] + Dir["assets/**/*"] + Dir["spec/**/*"]
+ s.files = ["README.rdoc", "MIT-LICENSE"] + Dir["lib/**/*"] + Dir["assets/**/*"] + Dir["spec/**/*"] + Dir["features/**/*"]
s.has_rdoc = true
s.homepage = %q{http://github.com/timcharper/spork}
s.rdoc_options = ["--main", "README.rdoc"]
View
@@ -1,4 +1,4 @@
---
:major: 0
-:minor: 4
-:patch: 4
+:minor: 5
+:patch: 0
@@ -30,20 +30,8 @@ Feature: Diagnostic Mode
end
"""
When I run spork --diagnose
- Then the output should contain
- """
- lib/awesome.rb
- """
- And the output should contain
- """
- spec/spec_helper.rb:5
- """
- And the output should not contain
- """
- super_duper.rb
- """
- And the output should not contain
- """
- diagnose.rb
- """
+ Then the output should contain "lib/awesome.rb"
+ And the output should contain "spec/spec_helper.rb:5"
+ And the output should not contain "super_duper.rb"
+ And the output should not contain "diagnose.rb"
@@ -0,0 +1,77 @@
+Feature: Rails Integration
+ To get a developer up and running quickly
+ Spork automatically integrates with rails
+ Providing default hooks and behaviors
+
+ Background: Rails App with RSpec and Spork
+
+ Given I am in a fresh rails project named "test_rails_project"
+ And a file named "spec/spec_helper.rb" with:
+ """
+ require 'rubygems'
+ require 'spork'
+ require 'spec'
+
+ Spork.prefork do
+ $run_phase = :prefork
+ require File.dirname(__FILE__) + '/../config/environment.rb'
+ end
+
+ Spork.each_run do
+ $run_phase = :each_run
+ puts "I'm loading the stuff just for this run..."
+ end
+
+ class ActiveRecord::Base
+ class << self
+ def establish_connection
+ ($loaded_stuff ||= []) << 'establish_connection'
+ puts "Database connection was automatically re-established!"
+ end
+ end
+ end
+ """
+ And a file named "app/models/user.rb" with:
+ """
+ class User < ActiveRecord::Base
+ ($loaded_stuff ||= []) << 'User'
+ end
+ """
+ And a file named "app/helpers/application_helper.rb" with:
+ """
+ module ApplicationHelper
+ ($loaded_stuff ||= []) << 'ApplicationHelper'
+ end
+ """
+ And a file named "app/models/user_observer.rb" with:
+ """
+ class UserObserver < ActiveRecord::Observer
+ ($loaded_stuff ||= []) << 'UserObserver'
+ end
+ """
+ And a file named "spec/models/user_spec.rb" with:
+ """
+ describe User do
+ it "does absoluately nothing" do
+ Spork.state.should == :using_spork
+ $loaded_stuff.should include('establish_connection')
+ $loaded_stuff.should include('User')
+ $loaded_stuff.should include('UserObserver')
+ $loaded_stuff.should include('ApplicationHelper')
+ puts "Specs successfully run within spork, and all initialization files were loaded"
+ end
+ end
+ """
+ Scenario: Analyzing files were preloaded
+ When I run spork --diagnose
+ Then the output should not contain "user_observer.rb"
+ Then the output should not contain "user.rb"
+ Then the output should not contain "app/controllers/application.rb"
+ Then the output should not contain "app/controllers/application_controller.rb"
+ Then the output should not contain "app/controllers/application_helper.rb"
+
+ Scenario: Running spork with a rails app and observers
+
+ When I fire up a spork instance with "spork rspec"
+ And I run spec --drb spec/models/user_spec.rb
+ Then the output should contain "Specs successfully run within spork, and all initialization files were loaded"
@@ -0,0 +1,5 @@
+Given /^I am in a fresh rails project named "(.+)"$/ do |folder_name|
+ @current_dir = SporkWorld::SANDBOX_DIR
+ run("#{SporkWorld::RUBY_BINARY} #{%x{which rails}.chomp} #{folder_name}")
+ @current_dir = File.join(File.join(SporkWorld::SANDBOX_DIR, folder_name))
+end
@@ -12,18 +12,49 @@
create_file(file_name, file_content)
end
-When /^I run spork (.*)$/ do |spork_opts|
- run "#{SporkWorld::RUBY_BINARY} #{SporkWorld::BINARY} #{spork_opts}"
+When /^I run (spork|spec)($| .*$)/ do |command, spork_opts|
+ if command == 'spork'
+ command = SporkWorld::BINARY
+ else
+ command = %x{which #{command}}.chomp
+ end
+ run "#{SporkWorld::RUBY_BINARY} #{command} #{spork_opts}"
+end
+
+When /^I fire up a spork instance with "spork(.*)"$/ do |spork_opts|
+ run_in_background "#{SporkWorld::RUBY_BINARY} #{SporkWorld::BINARY} #{spork_opts}"
+ output = ""
+ begin
+ status = Timeout::timeout(15) do
+ # Something that should be interrupted if it takes too much time...
+ while line = @bg_stderr.gets
+ output << line
+ puts line
+ break if line.include?("Spork is ready and listening")
+ end
+ end
+ rescue Timeout::Error
+ puts "I can't seem to launch Spork properly. Output was:\n#{output}"
+ true.should == false
+ end
end
Then /^the output should contain$/ do |text|
last_stdout.should include(text)
end
+Then /^the output should contain "(.+)"$/ do |text|
+ last_stdout.should include(text)
+end
+
Then /^the output should not contain$/ do |text|
last_stdout.should_not include(text)
end
+Then /^the output should not contain "(.+)"$/ do |text|
+ last_stdout.should_not include(text)
+end
+
Then /^the output should be$/ do |text|
last_stdout.should == text
end
View
@@ -3,6 +3,7 @@
require 'forwardable'
require 'tempfile'
require 'spec/expectations'
+require 'timeout'
class SporkWorld
RUBY_BINARY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
@@ -18,10 +19,11 @@ def spork_lib_dir
def initialize
@current_dir = SANDBOX_DIR
+ @background_jobs = []
end
private
- attr_reader :last_exit_status, :last_stderr, :last_stdout
+ attr_reader :last_exit_status, :last_stderr, :last_stdout, :background_jobs
def create_file(file_name, file_content)
file_content.gsub!("SPORK_LIB", "'#{spork_lib_dir}'") # Some files, such as Rakefiles need to use the lib dir
@@ -46,7 +48,29 @@ def run(command)
end
def run_in_background(command)
- background_jobs << Kernel.fork { exec command }
+ child_stdin, parent_stdin = IO::pipe
+ parent_stdout, child_stdout = IO::pipe
+ parent_stderr, child_stderr = IO::pipe
+
+ background_jobs << Kernel.fork do
+ # grandchild
+ [parent_stdin, parent_stdout, parent_stderr].each { |io| io.close }
+
+ STDIN.reopen(child_stdin)
+ STDOUT.reopen(child_stdout)
+ STDERR.reopen(child_stderr)
+
+ [child_stdin, child_stdout, child_stderr].each { |io| io.close }
+
+ in_current_dir do
+ exec command
+ end
+ end
+
+ [child_stdin, child_stdout, child_stderr].each { |io| io.close }
+ parent_stdin.sync = true
+
+ @bg_stdin, @bg_stdout, @bg_stderr = [parent_stdin, parent_stdout, parent_stderr]
end
def terminate_background_jobs
View
@@ -42,15 +42,40 @@ def exec_prefork(&block)
yield
end
- def exec_each_run
+ def exec_each_run(&block)
each_run_procs.each { |p| p.call }
each_run_procs.clear
+ yield if block_given?
end
def expanded_caller(caller_line)
file, line = caller_line.split(":")
line.gsub(/:.+/, '')
File.expand_path(Dir.pwd, file) + ":" + line
end
+
+ def trap_method(klass, method_name)
+ 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)
+ Spork.each_run_procs << lambda do
+ #{method_name}_without_spork(*args)
+ end
+ end
+ EOF
+ end
+
+ def trap_class_method(klass, method_name)
+ klass.class_eval <<-EOF, __FILE__, __LINE__ + 1
+ class << self
+ alias :#{method_name}_without_spork :#{method_name} unless method_defined?(:#{method_name}_without_spork)
+ def #{method_name}(*args)
+ Spork.each_run_procs << lambda do
+ #{method_name}_without_spork(*args)
+ end
+ end
+ end
+ EOF
+ end
end
end
View
@@ -0,0 +1,46 @@
+class Spork::AppFramework
+ SUPPORTED_FRAMEWORKS = {
+ :Rails => lambda do
+ File.exist?("config/environment.rb") && File.read("config/environment.rb").include?('RAILS_GEM_VERSION')
+ end
+ }
+
+ def self.detect_framework_name
+ SUPPORTED_FRAMEWORKS.each do |key, value|
+ return key if value.call
+ end
+ :Unknown
+ end
+
+ def self.detect_framework
+ name = detect_framework_name
+ self[name]
+ end
+
+ def self.[](name)
+ instances[name] ||= (
+ require File.join(File.dirname(__FILE__), "app_framework", name.to_s.downcase)
+ const_get(name).new
+ )
+ end
+
+ def self.instances
+ @instances ||= {}
+ end
+
+ def self.short_name
+ name.gsub('Spork::AppFramework::', '')
+ end
+
+ def bootstrap_required?
+ raise NotImplemented
+ end
+
+ def preload(&block)
+ yield
+ end
+
+ def name
+ self.class.short_name
+ end
+end
Oops, something went wrong.

0 comments on commit fc5e1d0

Please sign in to comment.