guard-rails 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -3,3 +3,11 @@ source "http://rubygems.org"
3
3
  # Specify your gem's dependencies in guard-rails.gemspec
4
4
  gemspec
5
5
  gem 'rake', '0.8.7'
6
+ gem 'fakefs', :require => nil
7
+ gem 'guard'
8
+ gem 'guard-rspec'
9
+
10
+ # TODO: make this more OS-independent...like the rest of the gem
11
+ gem 'growl'
12
+ gem 'rb-fsevent'
13
+
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch(%r{^spec/.+_spec\.rb})
6
+ watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
data/README.md CHANGED
@@ -5,13 +5,15 @@ Want to restart your Rails development server whilst you work? Now you can!
5
5
  watch(%r{^(config|lib)/.*})
6
6
  end
7
7
 
8
- Four fun options!
8
+ Lots of fun options!
9
9
 
10
10
  * `:port` is the port number to run on (default `3000`)
11
11
  * `:environment` is the environment to use (default `development`)
12
12
  * `:start_on_start` will start the server when starting Guard (default `true`)
13
13
  * `:force_run` kills any process that's holding open the listen port before attempting to (re)start Rails (default `false`).
14
+ * `:daemon` runs the server as a daemon, without any output to the terminal that ran `guard` (default `false`).
15
+ * `:timeout` waits this number of seconds when restarting the Rails server before reporting there's a problem (default `20`).
14
16
 
15
17
  This is super-alpha, but it works for me! Only really hand-tested in Mac OS X. Feel free to fork'n'fix for other
16
- OSes, and to add some real tests.
18
+ OSes, and to add some more real tests.
17
19
 
data/Rakefile CHANGED
@@ -1,2 +1,24 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
+
4
+ namespace :spec do
5
+ desc "Run on three Rubies"
6
+ task :platforms do
7
+ current = %x{rvm-prompt v}
8
+
9
+ fail = false
10
+ %w{1.8.7 1.9.2 ree}.each do |version|
11
+ puts "Switching to #{version}"
12
+ system %{rvm #{version}}
13
+ system %{bundle exec rspec spec}
14
+ if $?.exitstatus != 0
15
+ fail = true
16
+ break
17
+ end
18
+ end
19
+
20
+ system %{rvm #{current}}
21
+
22
+ exit (fail ? 1 : 0)
23
+ end
24
+ end
data/guard-rails.gemspec CHANGED
@@ -20,4 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.require_paths = ["lib"]
21
21
 
22
22
  s.add_dependency 'guard', '>= 0.2.2'
23
+
24
+ s.add_development_dependency 'rspec', '~> 2.6.0'
25
+ s.add_development_dependency 'mocha'
23
26
  end
data/lib/guard/rails.rb CHANGED
@@ -1,77 +1,52 @@
1
1
  require 'guard'
2
2
  require 'guard/guard'
3
+ require 'guard/rails/runner'
3
4
  require 'rbconfig'
4
5
 
5
6
  module Guard
6
7
  class Rails < ::Guard::Guard
7
- attr_reader :options
8
+ attr_reader :options, :runner
8
9
 
9
- def initialize(watchers = [], options = {})
10
- super
11
- @options = {
10
+ DEFAULT_OPTIONS = {
12
11
  :port => 3000,
13
12
  :environment => 'development',
14
13
  :start_on_start => true,
15
- :force_run => false
16
- }.merge(options)
14
+ :force_run => false,
15
+ :timeout => 20
16
+ }
17
+
18
+ def initialize(watchers = [], options = {})
19
+ super
20
+ @options = DEFAULT_OPTIONS.merge(options)
21
+
22
+ @runner = RailsRunner.new(@options)
17
23
  end
18
24
 
19
25
  def start
20
- UI.info "Guard::Rails restarting app on port #{options[:port]} using #{options[:environment]} environment."
26
+ UI.info "Guard::Rails will now restart your app on port #{options[:port]} using #{options[:environment]} environment."
21
27
  run_all if options[:start_on_start]
22
28
  end
23
29
 
24
30
  def run_all
31
+ UI.info "Restarting Rails..."
25
32
  Notifier.notify("Rails restarting on port #{options[:port]} in #{options[:environment]} environment...", :title => "Restarting Rails...", :image => :pending)
26
- stop_rails ; start_rails
27
- Notifier.notify("Rails restarted on port #{options[:port]}.", :title => "Rails restarted!", :image => :success)
33
+ if runner.restart
34
+ UI.info "Rails restarted, pid #{runner.pid}"
35
+ Notifier.notify("Rails restarted on port #{options[:port]}.", :title => "Rails restarted!", :image => :success)
36
+ else
37
+ UI.info "Rails NOT restarted, check your log files."
38
+ Notifier.notify("Rails NOT restarted, check your log files.", :title => "Rails NOT restarted!", :image => :failure)
39
+ end
28
40
  end
29
41
 
30
42
  def stop
31
43
  Notifier.notify("Until next time...", :title => "Rails shutting down.", :image => :pending)
32
- stop_rails
44
+ runner.stop
33
45
  end
34
46
 
35
47
  def run_on_change(paths)
36
48
  run_all
37
49
  end
38
-
39
- private
40
- def pid_file
41
- File.expand_path("tmp/pids/#{options[:environment]}.pid")
42
- end
43
-
44
- def start_rails
45
- kill_unmanaged_pid! if options[:force_run]
46
- system %{sh -c 'cd #{Dir.pwd} && rails s -e #{options[:environment]} -p #{options[:port]} --pid #{pid_file} &'}
47
- while !File.file?(pid_file)
48
- sleep 0.5
49
- end
50
- UI.info "Rails restarted, pid #{File.read(pid_file)}"
51
- end
52
-
53
- def stop_rails
54
- if File.file?(pid_file)
55
- system %{kill -INT #{File.read(pid_file).strip}}
56
- end
57
- end
58
-
59
- def unmanaged_pid
60
- if RbConfig::CONFIG['host_os'] =~ /darwin/
61
- %x{lsof -P}.each_line { |line|
62
- if line["*:#{options[:port]} "]
63
- return line.split("\s")[1]
64
- end
65
- }
66
- end
67
- nil
68
- end
69
-
70
- def kill_unmanaged_pid!
71
- if pid = unmanaged_pid
72
- system %{kill -INT #{pid}}
73
- end
74
- end
75
50
  end
76
51
  end
77
52
 
@@ -0,0 +1,88 @@
1
+ module Guard
2
+ class RailsRunner
3
+ MAX_WAIT_COUNT = 10
4
+
5
+ attr_reader :options
6
+
7
+ def initialize(options)
8
+ @options = options
9
+ end
10
+
11
+ def start
12
+ kill_unmanaged_pid! if options[:force_run]
13
+ run_rails_command!
14
+ count = 0
15
+ while !has_pid? && count < MAX_WAIT_COUNT
16
+ wait_for_pid_action
17
+ count += 1
18
+ end
19
+ !(count == MAX_WAIT_COUNT)
20
+ end
21
+
22
+ def stop
23
+ if File.file?(pid_file)
24
+ system %{kill -INT #{File.read(pid_file).strip}}
25
+ end
26
+ end
27
+
28
+ def restart
29
+ stop
30
+ start
31
+ end
32
+
33
+ def build_rails_command
34
+ rails_options = [
35
+ '-e', options[:environment],
36
+ '-p', options[:port],
37
+ '--pid', pid_file
38
+ ]
39
+
40
+ rails_options << '-d' if options[:daemon]
41
+
42
+ %{sh -c 'cd #{Dir.pwd} && rails s #{rails_options.join(' ')} &'}
43
+ end
44
+
45
+ def pid_file
46
+ File.expand_path("tmp/pids/#{options[:environment]}.pid")
47
+ end
48
+
49
+ def pid
50
+ File.file?(pid_file) ? File.read(pid_file).to_i : nil
51
+ end
52
+
53
+ def sleep_time
54
+ options[:timeout].to_f / MAX_WAIT_COUNT.to_f
55
+ end
56
+
57
+ private
58
+ def run_rails_command!
59
+ system build_rails_command
60
+ end
61
+
62
+ def has_pid?
63
+ File.file?(pid_file)
64
+ end
65
+
66
+ def wait_for_pid_action
67
+ sleep sleep_time
68
+ end
69
+
70
+ def kill_unmanaged_pid!
71
+ if pid = unmanaged_pid
72
+ system %{kill -INT #{pid}}
73
+ end
74
+ end
75
+
76
+ def unmanaged_pid
77
+ if RbConfig::CONFIG['host_os'] =~ /darwin/
78
+ %x{lsof -P}.each_line { |line|
79
+ if line["*:#{options[:port]} "]
80
+ return line.split("\s")[1]
81
+ end
82
+ }
83
+ end
84
+ nil
85
+ end
86
+ end
87
+ end
88
+
@@ -1,4 +1,4 @@
1
1
  module GuardRails
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
4
4
 
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+ require 'guard/rails/runner'
3
+ require 'fakefs/spec_helpers'
4
+
5
+ describe Guard::RailsRunner do
6
+ let(:runner) { Guard::RailsRunner.new(options) }
7
+ let(:environment) { 'development' }
8
+ let(:port) { 3000 }
9
+
10
+ let(:default_options) { { :environment => environment, :port => port } }
11
+ let(:options) { default_options }
12
+
13
+ describe '#pid' do
14
+ include FakeFS::SpecHelpers
15
+
16
+ context 'pid file exists' do
17
+ let(:pid) { 12345 }
18
+
19
+ before do
20
+ File.open(runner.pid_file, 'w') { |fh| fh.print pid }
21
+ end
22
+
23
+ it "should read the pid" do
24
+ runner.pid.should == pid
25
+ end
26
+ end
27
+
28
+ context 'pid file does not exist' do
29
+ it "should return nil" do
30
+ runner.pid.should be_nil
31
+ end
32
+ end
33
+ end
34
+
35
+ describe '#build_rails_command' do
36
+ context 'no daemon' do
37
+ it "should not have a daemon switch" do
38
+ runner.build_rails_command.should_not match(%r{ -d})
39
+ end
40
+ end
41
+
42
+ context 'daemon' do
43
+ let(:options) { default_options.merge(:daemon => true) }
44
+
45
+ it "should have a daemon switch" do
46
+ runner.build_rails_command.should match(%r{ -d})
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '#start' do
52
+ let(:kill_expectation) { runner.expects(:kill_unmanaged_pid!) }
53
+ let(:pid_stub) { runner.stubs(:has_pid?) }
54
+
55
+ before do
56
+ runner.expects(:run_rails_command!).once
57
+ end
58
+
59
+ context 'do not force run' do
60
+ before do
61
+ pid_stub.returns(true)
62
+ kill_expectation.never
63
+ runner.expects(:wait_for_pid_action).never
64
+ end
65
+
66
+ it "should act properly" do
67
+ runner.start.should be_true
68
+ end
69
+ end
70
+
71
+ context 'force run' do
72
+ let(:options) { default_options.merge(:force_run => true) }
73
+
74
+ before do
75
+ pid_stub.returns(true)
76
+ kill_expectation.once
77
+ runner.expects(:wait_for_pid_action).never
78
+ end
79
+
80
+ it "should act properly" do
81
+ runner.start.should be_true
82
+ end
83
+ end
84
+
85
+ context "don't write the pid" do
86
+ before do
87
+ pid_stub.returns(false)
88
+ kill_expectation.never
89
+ runner.expects(:wait_for_pid_action).times(Guard::RailsRunner::MAX_WAIT_COUNT)
90
+ end
91
+
92
+ it "should act properly" do
93
+ runner.start.should be_false
94
+ end
95
+ end
96
+ end
97
+
98
+ describe '#sleep_time' do
99
+ let(:timeout) { 30 }
100
+ let(:options) { default_options.merge(:timeout => timeout) }
101
+
102
+ it "should adjust the sleep time as necessary" do
103
+ runner.sleep_time.should == (timeout.to_f / Guard::RailsRunner::MAX_WAIT_COUNT.to_f)
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+ require 'guard/rails'
3
+
4
+ describe Guard::Rails do
5
+ let(:guard) { Guard::Rails.new(watchers, options) }
6
+ let(:watchers) { [] }
7
+ let(:options) { {} }
8
+
9
+ describe '#initialize' do
10
+ it "should initialize with options" do
11
+ guard
12
+
13
+ guard.runner.options[:port].should == 3000
14
+ end
15
+ end
16
+
17
+ describe '#start' do
18
+ let(:ui_expectation) { Guard::UI.expects(:info).with(regexp_matches(/#{Guard::Rails::DEFAULT_OPTIONS[:port]}/)) }
19
+
20
+ context 'start on start' do
21
+ it "should show the right message and run startup" do
22
+ guard.expects(:run_all).once
23
+ ui_expectation
24
+ guard.start
25
+ end
26
+ end
27
+
28
+ context 'no start on start' do
29
+ let(:options) { { :start_on_start => false } }
30
+
31
+ it "should show the right message and not run startup" do
32
+ guard.expects(:run_all).never
33
+ ui_expectation
34
+ guard.start
35
+ end
36
+ end
37
+ end
38
+
39
+ describe '#run_all' do
40
+ let(:pid) { '12345' }
41
+
42
+ before do
43
+ Guard::UI.expects(:info).with('Restarting Rails...')
44
+ Guard::Notifier.expects(:notify).with(regexp_matches(/Rails restarting/), anything)
45
+ Guard::RailsRunner.any_instance.stubs(:pid).returns(pid)
46
+ end
47
+
48
+ let(:runner_stub) { Guard::RailsRunner.any_instance.stubs(:restart) }
49
+
50
+ context 'with pid file' do
51
+ before do
52
+ runner_stub.returns(true)
53
+ end
54
+
55
+ it "should restart and show the pid file" do
56
+ Guard::UI.expects(:info).with(regexp_matches(/#{pid}/))
57
+ Guard::Notifier.expects(:notify).with(regexp_matches(/Rails restarted/), anything)
58
+
59
+ guard.run_all
60
+ end
61
+ end
62
+
63
+ context 'no pid file' do
64
+ before do
65
+ runner_stub.returns(false)
66
+ end
67
+
68
+ it "should restart and show the pid file" do
69
+ Guard::UI.expects(:info).with(regexp_matches(/#{pid}/)).never
70
+ Guard::UI.expects(:info).with(regexp_matches(/Rails NOT restarted/))
71
+ Guard::Notifier.expects(:notify).with(regexp_matches(/Rails NOT restarted/), anything)
72
+
73
+ guard.run_all
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '#stop' do
79
+ it "should stop correctly" do
80
+ Guard::Notifier.expects(:notify).with('Until next time...', anything)
81
+ guard.stop
82
+ end
83
+ end
84
+
85
+ describe '#run_on_change' do
86
+ it "should run on change" do
87
+ guard.expects(:run_all).once
88
+ guard.run_on_change([])
89
+ end
90
+ end
91
+ end
92
+
@@ -0,0 +1,5 @@
1
+ require 'mocha'
2
+
3
+ RSpec.configure do |c|
4
+ c.mock_with :mocha
5
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: guard-rails
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.0.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - John Bintz
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-05-31 00:00:00 -04:00
13
+ date: 2011-06-03 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -24,6 +24,28 @@ dependencies:
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 2.6.0
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: mocha
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :development
47
+ prerelease: false
48
+ version_requirements: *id003
27
49
  description: Restart Rails when things change in your app
28
50
  email:
29
51
  - john@coswellproductions.com
@@ -36,13 +58,18 @@ extra_rdoc_files: []
36
58
  files:
37
59
  - .gitignore
38
60
  - Gemfile
61
+ - Guardfile
39
62
  - README.md
40
63
  - Rakefile
41
64
  - guard-rails.gemspec
42
65
  - lib/guard-rails.rb
43
66
  - lib/guard/rails.rb
67
+ - lib/guard/rails/runner.rb
44
68
  - lib/guard/rails/templates/Guardfile
45
69
  - lib/guard/rails/version.rb
70
+ - spec/lib/guard/rails/runner_spec.rb
71
+ - spec/lib/guard/rails_spec.rb
72
+ - spec/spec_helper.rb
46
73
  has_rdoc: true
47
74
  homepage: ""
48
75
  licenses: []
@@ -57,7 +84,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
57
84
  requirements:
58
85
  - - ">="
59
86
  - !ruby/object:Gem::Version
60
- hash: 104230829909269231
87
+ hash: -1829971580643100829
61
88
  segments:
62
89
  - 0
63
90
  version: "0"
@@ -66,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
66
93
  requirements:
67
94
  - - ">="
68
95
  - !ruby/object:Gem::Version
69
- hash: 104230829909269231
96
+ hash: -1829971580643100829
70
97
  segments:
71
98
  - 0
72
99
  version: "0"
@@ -77,5 +104,7 @@ rubygems_version: 1.6.2
77
104
  signing_key:
78
105
  specification_version: 3
79
106
  summary: Restart Rails when things change in your app
80
- test_files: []
81
-
107
+ test_files:
108
+ - spec/lib/guard/rails/runner_spec.rb
109
+ - spec/lib/guard/rails_spec.rb
110
+ - spec/spec_helper.rb