guard-rails 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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