diff --git a/Gemfile b/Gemfile index 59807b6..a1b4dcf 100644 --- a/Gemfile +++ b/Gemfile @@ -3,3 +3,4 @@ source "http://rubygems.org" # Specify your gem's dependencies in guard-rails.gemspec gemspec gem 'rake', '0.8.7' +gem 'growl' diff --git a/Guardfile b/Guardfile new file mode 100644 index 0000000..35f2d5c --- /dev/null +++ b/Guardfile @@ -0,0 +1,8 @@ +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +guard 'rspec', :version => 2 do + watch(%r{^spec/.+_spec\.rb}) + watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" } + watch('spec/spec_helper.rb') { "spec" } +end diff --git a/guard-rails.gemspec b/guard-rails.gemspec index 07a2574..2073910 100644 --- a/guard-rails.gemspec +++ b/guard-rails.gemspec @@ -20,4 +20,7 @@ Gem::Specification.new do |s| s.require_paths = ["lib"] s.add_dependency 'guard', '>= 0.2.2' + + s.add_development_dependency 'rspec', '~> 2.6.0' + s.add_development_dependency 'mocha' end diff --git a/lib/guard/rails.rb b/lib/guard/rails.rb index 3a55092..ad44f37 100644 --- a/lib/guard/rails.rb +++ b/lib/guard/rails.rb @@ -1,10 +1,11 @@ require 'guard' require 'guard/guard' +require 'guard/rails/runner' require 'rbconfig' module Guard class Rails < ::Guard::Guard - attr_reader :options + attr_reader :options, :runner def initialize(watchers = [], options = {}) super @@ -14,6 +15,8 @@ module Guard :start_on_start => true, :force_run => false }.merge(options) + + @runner = Guard::RailsRunner.new(options) end def start @@ -22,56 +25,21 @@ module Guard end def run_all + UI.info "Restarting Rails" Notifier.notify("Rails restarting on port #{options[:port]} in #{options[:environment]} environment...", :title => "Restarting Rails...", :image => :pending) - stop_rails ; start_rails + runner.restart + UI.info "Rails restarted, pid #{File.read(pid_file)}" Notifier.notify("Rails restarted on port #{options[:port]}.", :title => "Rails restarted!", :image => :success) end def stop Notifier.notify("Until next time...", :title => "Rails shutting down.", :image => :pending) - stop_rails + runner.stop end def run_on_change(paths) run_all end - - private - def pid_file - File.expand_path("tmp/pids/#{options[:environment]}.pid") - end - - def start_rails - kill_unmanaged_pid! if options[:force_run] - system %{sh -c 'cd #{Dir.pwd} && rails s -e #{options[:environment]} -p #{options[:port]} --pid #{pid_file} &'} - while !File.file?(pid_file) - sleep 0.5 - end - UI.info "Rails restarted, pid #{File.read(pid_file)}" - end - - def stop_rails - if File.file?(pid_file) - system %{kill -INT #{File.read(pid_file).strip}} - end - end - - def unmanaged_pid - if RbConfig::CONFIG['host_os'] =~ /darwin/ - %x{lsof -P}.each_line { |line| - if line["*:#{options[:port]} "] - return line.split("\s")[1] - end - } - end - nil - end - - def kill_unmanaged_pid! - if pid = unmanaged_pid - system %{kill -INT #{pid}} - end - end end end diff --git a/lib/guard/rails/runner.rb b/lib/guard/rails/runner.rb new file mode 100644 index 0000000..526c34d --- /dev/null +++ b/lib/guard/rails/runner.rb @@ -0,0 +1,77 @@ +module Guard + class RailsRunner + attr_reader :options + + def initialize(options) + @options = options + end + + def start + kill_unmanaged_pid! if options[:force_run] + run_rails_command! + count = 0 + while !has_pid? && count < 10 + wait_for_pid_action + count += 1 + end + end + + def stop + if File.file?(pid_file) + system %{kill -INT #{File.read(pid_file).strip}} + end + end + + def restart + stop + start + end + + def build_rails_command + rails_options = [ + '-e', options[:environment], + '-p', options[:port], + '--pid', pid_file + ] + + rails_options << '-d' if options[:daemon] + + %{sh -c 'cd #{Dir.pwd} && rails s #{rails_options.join(' ')} &'} + end + + private + def run_rails_command! + system build_rails_command + end + + def has_pid? + File.file?(pid_file) + end + + def wait_for_pid_action + 0.5 + end + + def pid_file + File.expand_path("tmp/pids/#{options[:environment]}.pid") + end + + def kill_unmanaged_pid! + if pid = unmanaged_pid + system %{kill -INT #{pid}} + end + end + + def unmanaged_pid + if RbConfig::CONFIG['host_os'] =~ /darwin/ + %x{lsof -P}.each_line { |line| + if line["*:#{options[:port]} "] + return line.split("\s")[1] + end + } + end + nil + end + end +end + diff --git a/spec/lib/guard/rails/runner_spec.rb b/spec/lib/guard/rails/runner_spec.rb new file mode 100644 index 0000000..fa333c7 --- /dev/null +++ b/spec/lib/guard/rails/runner_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' +require 'guard/rails/runner' + +describe Guard::RailsRunner do + let(:runner) { Guard::RailsRunner.new(options) } + let(:environment) { 'development' } + let(:port) { 3000 } + + let(:default_options) { { :environment => environment, :port => port } } + let(:options) { default_options } + + + describe '#build_rails_command' do + context 'no daemon' do + it "should not have a daemon switch" do + runner.build_rails_command.should_not match(%r{ -d}) + end + end + + context 'daemon' do + let(:options) { default_options.merge(:daemon => true) } + + it "should have a daemon switch" do + runner.build_rails_command.should match(%r{ -d}) + end + end + end + + describe '#start' do + let(:kill_expectation) { runner.expects(:kill_unmanaged_pid!) } + let(:pid_stub) { runner.stubs(:has_pid?) } + + before do + runner.expects(:run_rails_command!).once + end + + context 'do not force run' do + before do + pid_stub.returns(true) + kill_expectation.never + runner.expects(:wait_for_pid_action).never + end + + it "should act properly" do + runner.start + end + end + + context 'force run' do + let(:options) { default_options.merge(:force_run => true) } + + before do + pid_stub.returns(true) + kill_expectation.once + runner.expects(:wait_for_pid_action).never + end + + it "should act properly" do + runner.start + end + end + + context "don't write the pid" do + before do + pid_stub.returns(false) + kill_expectation.never + runner.expects(:wait_for_pid_action).times(10) + end + + it "should act properly" do + runner.start + end + end + end +end diff --git a/spec/lib/guard/rails_spec.rb b/spec/lib/guard/rails_spec.rb new file mode 100644 index 0000000..e6aec1a --- /dev/null +++ b/spec/lib/guard/rails_spec.rb @@ -0,0 +1,7 @@ +require 'spec_helper' +require 'guard/rails' + +describe Guard::Rails do + +end + diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..63ec13b --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,5 @@ +require 'mocha' + +RSpec.configure do |c| + c.mock_with :mocha +end