Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class and example reloading #31

Merged
merged 6 commits into from
May 30, 2013
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 30 additions & 8 deletions lib/guard/jruby-rspec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'guard'
require 'guard/guard'
require 'guard/rspec'
require 'guard/jruby-rspec/reloaders'

module Guard
class JRubyRSpec < ::Guard::RSpec
Expand All @@ -15,7 +16,8 @@ def initialize(watchers = [], options = {})
:spec_paths => ["spec"],
:spec_file_suffix => "_spec.rb",
:run_all => {},
:monitor_file => ".guard-jruby-rspec"
:monitor_file => ".guard-jruby-rspec",
:custom_reloaders => []
}.merge(options)
@last_failed = false
@failed_paths = []
Expand All @@ -41,7 +43,7 @@ def initialize(watchers = [], options = {})

@inspector = Inspector.new(@options)
@runner = Runner.new(@options)

@reloaders = set_up_reloaders(@options)
end

# Call once when guard starts
Expand All @@ -51,7 +53,8 @@ def start
end

def run_on_changes(raw_paths)
reload_paths(raw_paths)
unload_previous_examples
@reloaders.reload(raw_paths)

unless @custom_watchers.nil? or @custom_watchers.empty?
paths = []
Expand All @@ -69,6 +72,13 @@ def run_on_changes(raw_paths)
# Guard 1.1 renamed run_on_change to run_on_changes
alias_method :run_on_change, :run_on_changes

def reload_rails(*)
if defined? ::ActionDispatch::Reloader
ActionDispatch::Reloader.cleanup!
ActionDispatch::Reloader.prepare!
end
end

def reload_paths(paths)
paths.reject {|p| p.end_with?(@options[:spec_file_suffix])}.each do |p|
if File.exists?(p)
Expand All @@ -85,18 +95,30 @@ def reload_paths(paths)
# end
else
# reload the file
begin
Containment.new.protect do
load p
rescue
UI.error $!.message
UI.error $!.backtrace.join "\n"
throw :task_has_failed
end
end
end
end
end

private

def set_up_reloaders(options)
reloaders = Reloaders.new
reloader_methods = [:reload_rails, :reload_paths]
reloader_procs = reloader_methods.map { |name| method(name) }
reloader_procs += options[:custom_reloaders]
reloader_procs.each { |reloader| reloaders.register &reloader }

reloaders
end

def unload_previous_examples
::RSpec.configuration.reset
::RSpec.world.reset
end
end
end

25 changes: 25 additions & 0 deletions lib/guard/jruby-rspec/containment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module Guard
class JRubyRSpec
class Containment
def initialize(options = {})
@error_handler = options.fetch(:error_handler, method(:output_as_guard_error))
end

def protect
yield
rescue Exception => e
error_handler.call e
throw :task_has_failed
end

private

attr_reader :error_handler

def output_as_guard_error(exception)
UI.error $!.message
UI.error $!.backtrace.join "\n"
end
end
end
end
20 changes: 20 additions & 0 deletions lib/guard/jruby-rspec/reloaders.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Reloaders
def initialize
@reloaders = []
end

# Add a reloader to be called on reload
def register(options = {}, &block)
if options[:prepend]
@reloaders.unshift block
else
@reloaders << block
end
end

def reload(paths = [])
@reloaders.each do |reloader|
reloader.call(paths)
end
end
end
8 changes: 3 additions & 5 deletions lib/guard/jruby-rspec/runner.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'rspec'
require 'guard/jruby-rspec/containment'
require 'guard/jruby-rspec/formatters/notification_rspec'

module Guard
Expand Down Expand Up @@ -44,13 +45,10 @@ def run(paths, options = {})
# end
else
orig_configuration = ::RSpec.configuration
begin
Containment.new.protect do
::RSpec::Core::Runner.run(rspec_arguments(paths, @options))
rescue SyntaxError => e
UI.error e.message
ensure
::RSpec.instance_variable_set(:@configuration, orig_configuration)
end
::RSpec.instance_variable_set(:@configuration, orig_configuration)
end
end

Expand Down
29 changes: 29 additions & 0 deletions spec/guard/jruby-rspec/containment_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require 'spec_helper'
require 'guard/jruby-rspec/containment'

class Guard::JRubyRSpec
describe Containment do
subject(:containment) { described_class.new }

describe '#protect' do
it 'runs the block that is passed to it' do
expect { |block| containment.protect &block }.to yield_control
end

it 'uses a default error_handler' do
Guard::UI.should_receive(:error).at_least(1).times
expect { containment.protect { raise 'busted' } }.to throw_symbol(:task_has_failed)
end

context 'with a custom error_handler' do
subject(:containment) { described_class.new(:error_handler => lambda { @custom_handler_called = true }) }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec failed for me, with wrong number of arguments (1 for 0). But changing the lambda to lambda { |e| ... fixed it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I'll add a commit to fix that. I forgot that my JRuby was running in 1.8 mode. Thanks.


it 'calls the custom error_handler' do
Guard::UI.should_receive(:error).never
expect { containment.protect { raise 'busted' } }.to throw_symbol(:task_has_failed)
@custom_handler_called.should be_true
end
end
end
end
end
45 changes: 45 additions & 0 deletions spec/guard/jruby-rspec/reloaders_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require 'spec_helper'

describe Reloaders do
subject(:reloaders) { described_class.new }

describe 'storing blocks to be executed at reload time' do
it 'passes the paths to be reloaded to the reloaders' do
reloaders.register do |paths|
paths.should == ['/path/to/file']
end
reloaders.reload ['/path/to/file']
end

describe 'the order in which reloaders are executed' do
before :each do
@a = @b = @counter = 0
reloaders.register do
@counter += 1
@a = @counter
end
reloaders.register(:prepend => prepend) do
@counter += 1
@b = @counter
end
reloaders.reload
end

context 'in normal order' do
let(:prepend) { false }
it 'reloads in the same order as reloaders registered' do
@a.should == 1
@b.should == 2
end
end

context 'with the 2nd reloader prepended' do
let(:prepend) { true }
it 'reloads in the same order as reloaders registered' do
@a.should == 2
@b.should == 1
end
end
end
end
end
6 changes: 4 additions & 2 deletions spec/guard/jruby-rspec/runner_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ class Guard::JRubyRSpec::Runner::UI; end
context 'when one of the source files is bad' do
it 'recovers from syntax errors in files by displaying the error' do
RSpec::Core::Runner.stub(:run).and_raise(SyntaxError.new('Bad Karma'))
Guard::JRubyRSpec::Runner::UI.should_receive(:error).with('Bad Karma')
subject.run(['spec/foo'])
Guard::UI.should_receive(:error).at_least(1).times
expect {
subject.run(['spec/foo'])
}.to throw_symbol(:task_has_failed)
end
end
end
Expand Down
13 changes: 11 additions & 2 deletions spec/guard/jruby-rspec_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
:spec_paths => ['spec'],
:spec_file_suffix => "_spec.rb",
:run_all => {},
:monitor_file=> ".guard-jruby-rspec"
:monitor_file => ".guard-jruby-rspec",
:custom_reloaders => []
}
end

Expand Down Expand Up @@ -108,8 +109,16 @@
it_should_behave_like 'clear failed paths'
end

describe '#reload_paths' do
describe '#reload_rails' do
it 'continues silently if the supported Rails 3.2+ version of Rails reloading is not supported' do
defined?(::ActionDispatch::Reloader).should be_false
expect {
subject.reload_rails
}.not_to raise_exception
end
end

describe '#reload_paths' do
it 'should reload files other than spec files' do
lib_file = 'lib/myapp/greeter.rb'
spec_file = 'specs/myapp/greeter_spec.rb'
Expand Down