guard-puma 0.1.0 → 0.2.0

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/CHANGES.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changes
2
2
 
3
+ ## 0.2.0
4
+
5
+ * Switched to puma's control server. pid file was too messy.
6
+
3
7
  ## 0.1.0
4
8
 
5
9
  * Fixed pid file path. Ready for general consumption.
data/README.md CHANGED
@@ -39,11 +39,9 @@ end
39
39
  * `:debugger` runs the server with the debugger enabled (default `false`). Required ruby-debug gem.
40
40
  * `:timeout` waits this number of seconds when restarting the Puma server before reporting there's a problem (default `20`).
41
41
  * `:config` is the path to the Puma config file (optional)
42
- * `:pidfile`` is the path to store the pid file (optional)
43
42
  * `:bind` is URI to bind to (tcp:// and unix:// only) (optional)
44
- * `:state` is the path to store the state details (optional)
45
- * `:control` is the bind URL to use for the control server. Use 'auto' to use temp unix server (optional)
46
43
  * `:control_token` is the token to use as authentication for the control server(optional)
44
+ * `:control_port` is the port to use for the control server(optional)
47
45
  * `:threads` is the min:max number of threads to use. Defaults to 0:16 (optional)
48
46
 
49
47
  ## Contributing
@@ -19,8 +19,7 @@ Gem::Specification.new do |gem|
19
19
  gem.add_dependency "puma"
20
20
  gem.add_development_dependency "rake", "~> 0.9.2.2"
21
21
  gem.add_development_dependency "rspec", "~> 2.9.0"
22
- gem.add_development_dependency "guard-rspec", "~> 0.6.0"
22
+ gem.add_development_dependency "guard-rspec", "~> 0.7.0"
23
23
  gem.add_development_dependency "bundler", "~> 1.1.0"
24
24
  gem.add_development_dependency "fakefs"
25
- gem.add_development_dependency "mocha"
26
25
  end
@@ -21,17 +21,18 @@ module Guard
21
21
  @options = DEFAULT_OPTIONS.merge(options)
22
22
  @runner = ::Guard::PumaRunner.new(@options)
23
23
  end
24
- def start
24
+
25
+ def start
25
26
  server = options[:server] ? "#{options[:server]} and " : ""
26
- UI.info "Guard::Puma will now restart your app on port #{options[:port]} using #{server}#{options[:environment]} environment."
27
- reload if options[:start_on_start]
27
+ UI.info "Guard::Puma will now start your app on port #{options[:port]} using #{server}#{options[:environment]} environment."
28
+ runner.start if options[:start_on_start]
28
29
  end
29
30
 
30
31
  def reload
31
32
  UI.info "Restarting Puma..."
32
33
  Notifier.notify("Puma restarting on port #{options[:port]} in #{options[:environment]} environment...", :title => "Restarting Puma...", :image => :pending)
33
34
  if runner.restart
34
- UI.info "Puma restarted, pid #{runner.pid}"
35
+ UI.info "Puma restarted"
35
36
  Notifier.notify("Puma restarted on port #{options[:port]}.", :title => "Puma restarted!", :image => :success)
36
37
  else
37
38
  UI.info "Puma NOT restarted, check your log files."
@@ -41,7 +42,7 @@ def start
41
42
 
42
43
  def stop
43
44
  Notifier.notify("Until next time...", :title => "Puma shutting down.", :image => :pending)
44
- runner.stop
45
+ runner.halt
45
46
  end
46
47
 
47
48
  def run_on_change(paths)
@@ -1,58 +1,40 @@
1
- require 'fileutils'
2
- require 'tmpdir'
1
+ require 'net/http'
3
2
 
4
3
  module Guard
5
4
  class PumaRunner
6
5
 
7
6
  MAX_WAIT_COUNT = 20
8
7
 
9
- attr_reader :options
8
+ attr_reader :options, :control_url, :control_token
10
9
 
11
10
  def initialize(options)
11
+ @control_token = (options.delete(:control_token) || 'pumarules')
12
+ @control = "0.0.0.0"
13
+ @control_port = (options.delete(:control_port) || '9293')
14
+ @control_url = "#{@control}:#{@control_port}"
12
15
  @options = options
13
16
  end
14
17
 
15
18
  def start
16
- kill_unmanaged_pid! if options[:force_run]
17
- run_puma_command!
18
- wait_for_pid
19
- end
20
-
21
- def stop
22
- if File.file?(pid_file)
23
- system %{kill -KILL #{File.read(pid_file).strip}}
24
- wait_for_no_pid if $?.exitstatus == 0
25
- FileUtils.rm pid_file
26
- end
27
- end
28
-
29
- def restart
30
- stop
31
- start
32
- end
33
-
34
- def build_puma_command
35
19
  puma_options = {
36
20
  '--port' => options[:port],
37
- '--pidfile' => pid_file,
21
+ '--control-token' => @control_token,
22
+ '--control' => "tcp://#{@control_url}"
38
23
  }
39
- [:config, :bind, :state, :control, :threads].each do |opt|
24
+ [:config, :bind, :threads].each do |opt|
40
25
  puma_options["--#{opt}"] = options[opt] if options[opt]
41
26
  end
42
- puma_options["--control-token"] = options[:control_token] if options[:control_token]
43
27
  opts = puma_options.to_a.flatten << '-q'
44
28
 
45
29
  %{sh -c 'cd #{Dir.pwd} && puma #{opts.join(' ')} &'}
46
30
  end
47
31
 
48
- def pid_file
49
- pidfilepath = File.expand_path(options[:pidfile]) if options[:pidfile]
50
- @pf ||= (pidfilepath || \
51
- File.expand_path("#{Dir.tmpdir}/guard-puma-#{options[:environment]}.pid"))
32
+ def halt
33
+ run_puma_command!("halt")
52
34
  end
53
35
 
54
- def pid
55
- File.file?(pid_file) ? File.read(pid_file).to_i : nil
36
+ def restart
37
+ run_puma_command!("restart")
56
38
  end
57
39
 
58
40
  def sleep_time
@@ -61,54 +43,14 @@ module Guard
61
43
 
62
44
  private
63
45
 
64
- def run_puma_command!
65
- system build_puma_command
66
- end
67
-
68
- def has_pid?
69
- File.file?(pid_file)
70
- end
71
-
72
- def wait_for_pid_action
73
- sleep sleep_time
74
- end
75
-
76
- def kill_unmanaged_pid!
77
- if pid = unmanaged_pid
78
- system %{kill -KILL #{pid}}
79
- FileUtils.rm pid_file
80
- wait_for_no_pid
81
- end
46
+ def run_puma_command!(cmd)
47
+ Net::HTTP.get((build_uri(cmd)))
82
48
  end
83
49
 
84
- def unmanaged_pid
85
- %x{lsof -n -i TCP:#{options[:port]}}.each_line { |line|
86
- if line["*:#{options[:port]} "]
87
- return line.split("\s")[1]
88
- end
89
- }
90
- nil
50
+ def build_uri(cmd)
51
+ URI("http://#{control_url}/#{cmd}?token=#{control_token}")
91
52
  end
92
53
 
93
- private
94
-
95
- def wait_for_pid
96
- wait_for_pid_loop
97
- end
98
-
99
- def wait_for_no_pid
100
- wait_for_pid_loop(false)
101
- end
102
-
103
- def wait_for_pid_loop(check_for_existence = true)
104
- count = 0
105
- while !(check_for_existence ? has_pid? : !has_pid?) && count < MAX_WAIT_COUNT
106
- wait_for_pid_action
107
- count += 1
108
- end
109
- !(count == MAX_WAIT_COUNT)
110
- end
111
-
112
54
  end
113
55
  end
114
56
 
@@ -1,5 +1,5 @@
1
1
  module Guard
2
2
  module PumaVersion
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
@@ -1,6 +1,5 @@
1
1
  require 'spec_helper'
2
2
  require 'guard/puma/runner'
3
- require 'fakefs/spec_helpers'
4
3
 
5
4
  describe Guard::PumaRunner do
6
5
  let(:runner) { Guard::PumaRunner.new(options) }
@@ -9,80 +8,26 @@ describe Guard::PumaRunner do
9
8
 
10
9
  let(:default_options) { { :environment => environment, :port => port } }
11
10
  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
- FileUtils.mkdir_p File.split(runner.pid_file).first
21
- File.open(runner.pid_file, 'w') { |fh| fh.print pid }
22
- end
23
11
 
24
- it "reads the pid" do
25
- runner.pid.should == pid
26
- end
27
- end
28
-
29
- context 'pid file does not exist' do
30
- it "returns nil" do
31
- if defined?(Rubinius)
32
- runner.pid.should == nil
33
- else
34
- runner.pid.should be_nil
35
- end
36
- end
12
+ describe "#initialize" do
13
+ it "sets options" do
14
+ runner.options.should eq(options)
37
15
  end
38
16
  end
39
-
40
- describe '#start' do
41
- let(:kill_expectation) { runner.expects(:kill_unmanaged_pid!) }
42
- let(:pid_stub) { runner.stubs(:has_pid?) }
43
-
44
- before do
45
- runner.expects(:run_puma_command!).once
46
- end
47
-
48
- context 'do not force run' do
49
- before do
50
- pid_stub.returns(true)
51
- kill_expectation.never
52
- runner.expects(:wait_for_pid_action).never
53
- end
54
-
55
- it "acts properly" do
56
- runner.start.should be_true
57
- end
58
- end
59
-
60
- context 'force run' do
61
- let(:options) { default_options.merge(:force_run => true) }
62
-
63
- before do
64
- pid_stub.returns(true)
65
- kill_expectation.once
66
- runner.expects(:wait_for_pid_action).never
67
- end
68
-
69
- it "acts properly" do
70
- runner.start.should be_true
71
- end
72
- end
73
-
74
- context "don't write the pid" do
17
+
18
+ %w(halt restart).each do |cmd|
19
+ describe cmd do
75
20
  before do
76
- pid_stub.returns(false)
77
- kill_expectation.never
78
- runner.expects(:wait_for_pid_action).times(Guard::PumaRunner::MAX_WAIT_COUNT)
21
+ runner.stub(:build_uri).with(cmd).and_return(uri)
79
22
  end
80
-
81
- it "acts properly" do
82
- runner.start.should be_false
23
+ let(:uri) { URI("http://#{runner.control_url}/#{cmd}?token=#{runner.control_token}") }
24
+ it "#{cmd}s" do
25
+ Net::HTTP.should_receive(:get).with(uri).once
26
+ runner.send(cmd.intern)
83
27
  end
84
28
  end
85
29
  end
30
+
86
31
 
87
32
  describe '#sleep_time' do
88
33
  let(:timeout) { 30 }
@@ -94,9 +39,8 @@ describe Guard::PumaRunner do
94
39
  end
95
40
 
96
41
  describe "#build_puma_command" do
97
- let(:command) {
98
- Guard::PumaRunner.new(options).build_puma_command
99
- }
42
+ let(:command) { Guard::PumaRunner.new(options).start }
43
+
100
44
  context "with config" do
101
45
  let(:options) {{ :config => path }}
102
46
  let(:path) { "/tmp/elephants" }
@@ -113,22 +57,6 @@ describe Guard::PumaRunner do
113
57
  end
114
58
  end
115
59
 
116
- context "with state" do
117
- let(:options) {{ :state => path }}
118
- let(:path) { "/tmp/zebras" }
119
- it "adds path to command" do
120
- command.should match("--state #{path}")
121
- end
122
- end
123
-
124
- context "with control" do
125
- let(:options) {{ :control => uri }}
126
- let(:uri) { "http://foo" }
127
- it "adds path to command" do
128
- command.should match("--control #{uri}")
129
- end
130
- end
131
-
132
60
  context "with control_token" do
133
61
  let(:options) {{ :control_token => token }}
134
62
  let(:token) { "IMMA_TOKEN" }
@@ -15,12 +15,10 @@ describe Guard::Puma do
15
15
  end
16
16
 
17
17
  describe '#start' do
18
- let(:ui_expectation) { Guard::UI.expects(:info).with(regexp_matches(/#{Guard::Puma::DEFAULT_OPTIONS[:port]}/)) }
19
18
 
20
19
  context 'start on start' do
21
- it "shows the right message and run startup" do
22
- guard.expects(:reload).once
23
- ui_expectation
20
+ it "runs startup" do
21
+ guard.should_receive(:start).once
24
22
  guard.start
25
23
  end
26
24
  end
@@ -29,62 +27,42 @@ describe Guard::Puma do
29
27
  let(:options) { { :start_on_start => false } }
30
28
 
31
29
  it "shows the right message and not run startup" do
32
- guard.expects(:reload).never
33
- ui_expectation
30
+ guard.runner.should_receive(:start).never
34
31
  guard.start
35
32
  end
36
33
  end
37
34
  end
38
35
 
39
36
  describe '#reload' do
40
- let(:pid) { '12345' }
41
37
 
42
38
  before do
43
- Guard::UI.expects(:info).with('Restarting Puma...')
44
- Guard::Notifier.expects(:notify).with(regexp_matches(/Puma restarting/), has_entry(:image => :pending))
45
- Guard::PumaRunner.any_instance.stubs(:pid).returns(pid)
39
+ Guard::UI.should_receive(:info).with('Restarting Puma...')
40
+ Guard::Notifier.should_receive(:notify).with(/Puma restarting/, hash_including(:image => :pending))
41
+ guard.runner.stub(:restart).and_return(true)
46
42
  end
47
43
 
48
- let(:runner_stub) { Guard::PumaRunner.any_instance.stubs(:restart) }
44
+ let(:runner_stub) { Guard::PumaRunner.any_instance.stub(:halt) }
49
45
 
50
- context 'with pid file' do
51
- before do
52
- runner_stub.returns(true)
53
- end
54
-
55
- it "restarts and show the pid file" do
56
- Guard::UI.expects(:info).with(regexp_matches(/#{pid}/))
57
- Guard::Notifier.expects(:notify).with(regexp_matches(/Puma restarted/), has_entry(:image => :success))
46
+ it "restarts and show the message" do
47
+ Guard::UI.should_receive(:info)
48
+ Guard::Notifier.should_receive(:notify).with(/Puma restarted/, hash_including(:image => :success))
58
49
 
59
- guard.reload
60
- end
50
+ guard.reload
61
51
  end
62
52
 
63
- context 'no pid file' do
64
- before do
65
- runner_stub.returns(false)
66
- end
67
-
68
- it "restarts and show the pid file" do
69
- Guard::UI.expects(:info).with(regexp_matches(/#{pid}/)).never
70
- Guard::UI.expects(:info).with(regexp_matches(/Puma NOT restarted/))
71
- Guard::Notifier.expects(:notify).with(regexp_matches(/Puma NOT restarted/), has_entry(:image => :failed))
72
-
73
- guard.reload
74
- end
75
- end
76
53
  end
77
54
 
78
55
  describe '#stop' do
79
56
  it "stops correctly" do
80
- Guard::Notifier.expects(:notify).with('Until next time...', anything)
57
+ Guard::Notifier.should_receive(:notify).with('Until next time...', anything)
58
+ guard.runner.should_receive(:halt).once
81
59
  guard.stop
82
60
  end
83
61
  end
84
62
 
85
63
  describe '#run_on_change' do
86
64
  it "reloads on change" do
87
- guard.expects(:reload).once
65
+ guard.should_receive(:reload).once
88
66
  guard.run_on_change([])
89
67
  end
90
68
  end
@@ -6,11 +6,10 @@
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
7
  ENV["GUARD_ENV"] = 'test'
8
8
  require 'rspec'
9
- require 'mocha'
10
9
 
11
10
  RSpec.configure do |config|
12
11
  config.treat_symbols_as_metadata_keys_with_true_values = true
13
12
  config.run_all_when_everything_filtered = true
14
13
  config.filter_run :focus
15
- config.mock_with :mocha
14
+ config.mock_with :rspec
16
15
  end
metadata CHANGED
@@ -1,176 +1,115 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: guard-puma
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
5
4
  prerelease:
5
+ version: 0.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jesse Cooke
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-22 00:00:00.000000000 Z
12
+ date: 2012-04-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: guard
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: 1.0.1
22
15
  type: :runtime
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
16
+ version_requirements: &6804 !ruby/object:Gem::Requirement
26
17
  requirements:
27
18
  - - ! '>='
28
19
  - !ruby/object:Gem::Version
29
20
  version: 1.0.1
30
- - !ruby/object:Gem::Dependency
31
- name: rb-inotify
32
- requirement: !ruby/object:Gem::Requirement
33
21
  none: false
34
- requirements:
35
- - - ! '>='
36
- - !ruby/object:Gem::Version
37
- version: '0'
38
- type: :runtime
39
22
  prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ! '>='
44
- - !ruby/object:Gem::Version
45
- version: '0'
23
+ name: guard
24
+ requirement: *6804
46
25
  - !ruby/object:Gem::Dependency
47
- name: libnotify
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: '0'
54
26
  type: :runtime
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
27
+ version_requirements: &6860 !ruby/object:Gem::Requirement
58
28
  requirements:
59
29
  - - ! '>='
60
30
  - !ruby/object:Gem::Version
61
31
  version: '0'
62
- - !ruby/object:Gem::Dependency
63
- name: puma
64
- requirement: !ruby/object:Gem::Requirement
65
32
  none: false
33
+ prerelease: false
34
+ name: rb-inotify
35
+ requirement: *6860
36
+ - !ruby/object:Gem::Dependency
37
+ type: :runtime
38
+ version_requirements: &6904 !ruby/object:Gem::Requirement
66
39
  requirements:
67
40
  - - ! '>='
68
41
  - !ruby/object:Gem::Version
69
42
  version: '0'
70
- type: :runtime
71
- prerelease: false
72
- version_requirements: !ruby/object:Gem::Requirement
73
43
  none: false
44
+ prerelease: false
45
+ name: libnotify
46
+ requirement: *6904
47
+ - !ruby/object:Gem::Dependency
48
+ type: :runtime
49
+ version_requirements: &6948 !ruby/object:Gem::Requirement
74
50
  requirements:
75
51
  - - ! '>='
76
52
  - !ruby/object:Gem::Version
77
53
  version: '0'
78
- - !ruby/object:Gem::Dependency
79
- name: rake
80
- requirement: !ruby/object:Gem::Requirement
81
54
  none: false
82
- requirements:
83
- - - ~>
84
- - !ruby/object:Gem::Version
85
- version: 0.9.2.2
86
- type: :development
87
55
  prerelease: false
88
- version_requirements: !ruby/object:Gem::Requirement
89
- none: false
56
+ name: puma
57
+ requirement: *6948
58
+ - !ruby/object:Gem::Dependency
59
+ type: :development
60
+ version_requirements: &6992 !ruby/object:Gem::Requirement
90
61
  requirements:
91
62
  - - ~>
92
63
  - !ruby/object:Gem::Version
93
64
  version: 0.9.2.2
94
- - !ruby/object:Gem::Dependency
95
- name: rspec
96
- requirement: !ruby/object:Gem::Requirement
97
65
  none: false
98
- requirements:
99
- - - ~>
100
- - !ruby/object:Gem::Version
101
- version: 2.9.0
102
- type: :development
103
66
  prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
105
- none: false
67
+ name: rake
68
+ requirement: *6992
69
+ - !ruby/object:Gem::Dependency
70
+ type: :development
71
+ version_requirements: &7036 !ruby/object:Gem::Requirement
106
72
  requirements:
107
73
  - - ~>
108
74
  - !ruby/object:Gem::Version
109
75
  version: 2.9.0
110
- - !ruby/object:Gem::Dependency
111
- name: guard-rspec
112
- requirement: !ruby/object:Gem::Requirement
113
76
  none: false
114
- requirements:
115
- - - ~>
116
- - !ruby/object:Gem::Version
117
- version: 0.6.0
118
- type: :development
119
77
  prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
- requirements:
123
- - - ~>
124
- - !ruby/object:Gem::Version
125
- version: 0.6.0
78
+ name: rspec
79
+ requirement: *7036
126
80
  - !ruby/object:Gem::Dependency
127
- name: bundler
128
- requirement: !ruby/object:Gem::Requirement
129
- none: false
81
+ type: :development
82
+ version_requirements: &7080 !ruby/object:Gem::Requirement
130
83
  requirements:
131
84
  - - ~>
132
85
  - !ruby/object:Gem::Version
133
- version: 1.1.0
134
- type: :development
135
- prerelease: false
136
- version_requirements: !ruby/object:Gem::Requirement
86
+ version: 0.7.0
137
87
  none: false
88
+ prerelease: false
89
+ name: guard-rspec
90
+ requirement: *7080
91
+ - !ruby/object:Gem::Dependency
92
+ type: :development
93
+ version_requirements: &7124 !ruby/object:Gem::Requirement
138
94
  requirements:
139
95
  - - ~>
140
96
  - !ruby/object:Gem::Version
141
97
  version: 1.1.0
142
- - !ruby/object:Gem::Dependency
143
- name: fakefs
144
- requirement: !ruby/object:Gem::Requirement
145
98
  none: false
146
- requirements:
147
- - - ! '>='
148
- - !ruby/object:Gem::Version
149
- version: '0'
150
- type: :development
151
99
  prerelease: false
152
- version_requirements: !ruby/object:Gem::Requirement
153
- none: false
154
- requirements:
155
- - - ! '>='
156
- - !ruby/object:Gem::Version
157
- version: '0'
100
+ name: bundler
101
+ requirement: *7124
158
102
  - !ruby/object:Gem::Dependency
159
- name: mocha
160
- requirement: !ruby/object:Gem::Requirement
161
- none: false
162
- requirements:
163
- - - ! '>='
164
- - !ruby/object:Gem::Version
165
- version: '0'
166
103
  type: :development
167
- prerelease: false
168
- version_requirements: !ruby/object:Gem::Requirement
169
- none: false
104
+ version_requirements: &7168 !ruby/object:Gem::Requirement
170
105
  requirements:
171
106
  - - ! '>='
172
107
  - !ruby/object:Gem::Version
173
108
  version: '0'
109
+ none: false
110
+ prerelease: false
111
+ name: fakefs
112
+ requirement: *7168
174
113
  description:
175
114
  email:
176
115
  - jesse@jc00ke.com
@@ -201,20 +140,20 @@ rdoc_options: []
201
140
  require_paths:
202
141
  - lib
203
142
  required_ruby_version: !ruby/object:Gem::Requirement
204
- none: false
205
143
  requirements:
206
144
  - - ! '>='
207
145
  - !ruby/object:Gem::Version
208
146
  version: '0'
209
- required_rubygems_version: !ruby/object:Gem::Requirement
210
147
  none: false
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
211
149
  requirements:
212
150
  - - ! '>='
213
151
  - !ruby/object:Gem::Version
214
152
  version: '0'
153
+ none: false
215
154
  requirements: []
216
155
  rubyforge_project:
217
- rubygems_version: 1.8.19
156
+ rubygems_version: 1.8.12
218
157
  signing_key:
219
158
  specification_version: 3
220
159
  summary: Restart puma when files change