guard 0.2.2 → 0.3.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/LICENSE +1 -1
- data/README.rdoc +108 -60
- data/lib/guard.rb +60 -33
- data/lib/guard/cli.rb +5 -3
- data/lib/guard/dsl.rb +33 -16
- data/lib/guard/guard.rb +18 -14
- data/lib/guard/interactor.rb +5 -8
- data/lib/guard/listener.rb +85 -18
- data/lib/guard/listeners/darwin.rb +9 -9
- data/lib/guard/listeners/linux.rb +1 -1
- data/lib/guard/listeners/polling.rb +8 -8
- data/lib/guard/templates/Guardfile +1 -1
- data/lib/guard/ui.rb +7 -3
- data/lib/guard/version.rb +1 -1
- data/lib/guard/watcher.rb +40 -12
- metadata +16 -16
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Guard
|
2
2
|
|
3
|
-
Guard is a command line tool
|
3
|
+
Guard is a command line tool that easily handle events on files modifications.
|
4
4
|
|
5
5
|
== Features
|
6
6
|
|
@@ -27,73 +27,90 @@ Generate an empty Guardfile with:
|
|
27
27
|
|
28
28
|
guard init
|
29
29
|
|
30
|
-
Add
|
30
|
+
Add the guards you need (see available guards below)
|
31
31
|
|
32
32
|
=== On Mac OS X
|
33
33
|
|
34
|
-
Install rb-fsevent for {FSEvent}[http://en.wikipedia.org/wiki/FSEvents] support
|
34
|
+
Install rb-fsevent for {FSEvent}[http://en.wikipedia.org/wiki/FSEvents] support:
|
35
35
|
|
36
36
|
gem install rb-fsevent
|
37
37
|
|
38
|
-
Install growl for Growl notification support
|
38
|
+
Install growl for Growl notification support:
|
39
39
|
|
40
40
|
gem install growl
|
41
41
|
|
42
|
-
And add it to you Gemfile
|
42
|
+
And add it to you Gemfile:
|
43
43
|
|
44
44
|
gem 'growl'
|
45
45
|
|
46
46
|
=== On Linux
|
47
47
|
|
48
|
-
Install rb-inotify for {inotify}[http://en.wikipedia.org/wiki/Inotify] support
|
48
|
+
Install rb-inotify for {inotify}[http://en.wikipedia.org/wiki/Inotify] support:
|
49
49
|
|
50
50
|
gem install rb-inotify
|
51
51
|
|
52
|
-
Install libnotify for libonity notification support
|
52
|
+
Install libnotify for libonity notification support:
|
53
53
|
|
54
54
|
gem install libnotify
|
55
55
|
|
56
|
-
And add it to you Gemfile
|
56
|
+
And add it to you Gemfile:
|
57
57
|
|
58
58
|
gem 'libnotify'
|
59
59
|
|
60
60
|
== Usage
|
61
61
|
|
62
|
-
Just launch Guard inside your
|
62
|
+
Just launch Guard inside your Ruby / Rails project with:
|
63
63
|
|
64
64
|
guard
|
65
65
|
|
66
|
+
or if you use Bundler, to run the Guard executable specific to your bundle:
|
67
|
+
|
68
|
+
bundle exec guard
|
69
|
+
|
70
|
+
== Command line options
|
71
|
+
|
66
72
|
Shell can be cleared after each change with:
|
67
73
|
|
68
|
-
guard
|
74
|
+
guard --clear
|
75
|
+
guard -c # shortcut
|
76
|
+
|
77
|
+
The guards to start can be specified by group (see Guardfile DSL below) specifying the `--group` (or `-g`) option:
|
78
|
+
|
79
|
+
guard --group group_name another_group_name
|
80
|
+
guard -g group_name another_group_name # shortcut
|
69
81
|
|
70
82
|
Options list is available with:
|
71
83
|
|
72
84
|
guard help [TASK]
|
73
85
|
|
86
|
+
== Signal handlers
|
87
|
+
|
74
88
|
Signal handlers are used to interact with Guard:
|
75
89
|
|
76
|
-
- Ctrl-C - Quit Guard (call
|
77
|
-
- Ctrl-\ - Call
|
78
|
-
- Ctrl-Z - Call
|
90
|
+
- Ctrl-C - Quit Guard (call each guard's run_all method, in the same order they are declared in the Guarfile)
|
91
|
+
- Ctrl-\ - Call each guard's run_all method, in the same order they are declared in the Guarfile
|
92
|
+
- Ctrl-Z - Call each guard's reload method, in the same order they are declared in the Guarfile
|
79
93
|
|
80
94
|
== Available Guards
|
81
95
|
|
82
|
-
- {guard-
|
83
|
-
- {guard-
|
84
|
-
- {guard-
|
85
|
-
- {guard-
|
86
|
-
- {guard-
|
87
|
-
- {guard-
|
88
|
-
- {guard-
|
89
|
-
- {guard-
|
90
|
-
- {guard-
|
91
|
-
|
92
|
-
guard
|
93
|
-
|
94
|
-
- guard-
|
95
|
-
- guard-
|
96
|
-
-
|
96
|
+
- {guard-bundler}[https://github.com/guard/guard-bundler] by {Yann Lugrin}[https://github.com/yannlugrin]
|
97
|
+
- {guard-coffeescript}[https://github.com/guard/guard-coffeescript] by {Michael Kessler}[https://github.com/netzpirat]
|
98
|
+
- {guard-compass}[https://github.com/guard/guard-compass] by {Olivier Amblet}[https://github.com/oliamb]
|
99
|
+
- {guard-cucumber}[https://github.com/guard/guard-cucumber] by {Michael Kessler}[https://github.com/netzpirat]
|
100
|
+
- {guard-ego}[https://github.com/guard/guard-ego] by {Fabio Kuhn}[https://github.com/mordaroso]
|
101
|
+
- {guard-jammit}[https://github.com/guard/guard-jammit] by {Pelle Braendgaard}[https://github.com/pelle]
|
102
|
+
- {guard-less}[https://github.com/guard/guard-less] by {Brendan Erwin}[https://github.com/brendanjerwin]
|
103
|
+
- {guard-livereload}[https://github.com/guard/guard-livereload] by {Thibaud Guillaume-Gentil}[https://github.com/thibaudgg]
|
104
|
+
- {guard-minitest}[https://github.com/guard/guard-minitest] by {Yann Lugrin}[https://github.com/yannlugrin]
|
105
|
+
- {guard-nanoc}[https://github.com/guard/guard-nanoc] by {Yann Lugrin}[https://github.com/yannlugrin]
|
106
|
+
- {guard-passenger}[https://github.com/guard/guard-passenger] by {Fabio Kuhn}[https://github.com/mordaroso]
|
107
|
+
- {guard-rspec}[https://github.com/guard/guard-rspec] by {Thibaud Guillaume-Gentil}[https://github.com/thibaudgg]
|
108
|
+
- {guard-sass}[https://github.com/guard/guard-sass] by {Joshua Hawxwell}[https://github.com/hawx]
|
109
|
+
- {guard-shell}[https://github.com/guard/guard-shell] by {Joshua Hawxwell}[https://github.com/hawx]
|
110
|
+
- {guard-soca}[https://github.com/guard/guard-soca] by {Luke Amdor}[https://github.com/rubbish]
|
111
|
+
- {guard-spork}[https://github.com/guard/guard-spork] by {Thibaud Guillaume-Gentil}[https://github.com/thibaudgg]
|
112
|
+
- {guard-stendhal}[https://github.com/guard/guard-stendhal] by {Josep Mª Bach}[https://github.com/txus]
|
113
|
+
- {guard-test}[https://github.com/guard/guard-test] by {Rémy Coutable}[https://github.com/rymai]
|
97
114
|
|
98
115
|
=== Add a guard to your Guardfile
|
99
116
|
|
@@ -107,6 +124,46 @@ Add guard definition to your Guardfile by running this command:
|
|
107
124
|
|
108
125
|
You are good to go!
|
109
126
|
|
127
|
+
== Guardfile DSL
|
128
|
+
|
129
|
+
The Guardfile DSL consists of just three simple main methods: `guard`, `watch` & `group`.
|
130
|
+
|
131
|
+
Required:
|
132
|
+
- The `guard` method allows you to add a guard with an optional options hash.
|
133
|
+
- The `watch` method allows you to define which files are supervised per this guard. A optional block can be added to overwrite path sent to run_on_change guard method or launch simple command.
|
134
|
+
|
135
|
+
Optional:
|
136
|
+
- The `group` method allows you to group several guards. Groups to run can be specified with the Guard DSL option `--group` (or `-g`). This comes in handy especially when you have a huge Guardfile and want to focus your development.
|
137
|
+
|
138
|
+
Example:
|
139
|
+
|
140
|
+
group 'backend' do
|
141
|
+
guard 'bundler' do
|
142
|
+
watch('Gemfile')
|
143
|
+
end
|
144
|
+
|
145
|
+
guard 'rspec' do
|
146
|
+
# Regexp watch patterns are matched with Regexp#match
|
147
|
+
watch(%r{^spec/(.+)_spec\.rb})
|
148
|
+
watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
149
|
+
watch(%r{^spec/models/.+\.rb}) { ["spec/models", "spec/acceptance"] }
|
150
|
+
watch(%r{^spec/.+\.rb}) { `say hello` }
|
151
|
+
|
152
|
+
# String watch patterns are matched with simple '=='
|
153
|
+
watch('spec/spec_helper.rb') { "spec" }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
group 'frontend' do
|
158
|
+
guard 'coffeescript', :output => 'public/javascripts/compiled' do
|
159
|
+
watch(%r{app/coffeescripts/.+\.coffee})
|
160
|
+
end
|
161
|
+
|
162
|
+
guard 'livereload' do
|
163
|
+
watch(%r{app/.+\.(erb|haml)})
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
110
167
|
== Create a guard
|
111
168
|
|
112
169
|
Create a new guard is very easy, just create a new gem with this basic structure:
|
@@ -122,72 +179,63 @@ lib/guard/guard-name.rb inherit from guard/guard and should overwrite at least o
|
|
122
179
|
|
123
180
|
require 'guard'
|
124
181
|
require 'guard/guard'
|
125
|
-
|
182
|
+
|
126
183
|
module Guard
|
127
184
|
class GuardName < Guard
|
128
|
-
|
185
|
+
|
186
|
+
def initialize(watchers = [], options = {})
|
187
|
+
super
|
188
|
+
# init stuff here, thx!
|
189
|
+
end
|
190
|
+
|
129
191
|
# ================
|
130
192
|
# = Guard method =
|
131
193
|
# ================
|
132
|
-
|
194
|
+
|
195
|
+
# If one of those methods raise an exception, the Guard instance
|
196
|
+
# will be removed from the active guard.
|
197
|
+
|
133
198
|
# Call once when guard starts
|
199
|
+
# Please override initialize method to init stuff
|
134
200
|
def start
|
135
201
|
true
|
136
202
|
end
|
137
|
-
|
138
|
-
# Call with Ctrl-C signal (when Guard quit)
|
139
|
-
# This method must return a true value
|
140
|
-
# if everything went well or guard will not stop.
|
203
|
+
|
204
|
+
# Call with Ctrl-C signal (when Guard quit)
|
141
205
|
def stop
|
142
206
|
true
|
143
207
|
end
|
144
|
-
|
208
|
+
|
145
209
|
# Call with Ctrl-Z signal
|
210
|
+
# This method should be mainly used for "reload" (really!) actions like reloading passenger/spork/bundler/...
|
146
211
|
def reload
|
147
212
|
true
|
148
213
|
end
|
149
|
-
|
214
|
+
|
150
215
|
# Call with Ctrl-/ signal
|
216
|
+
# This method should be principally used for long action like running all specs/tests/...
|
151
217
|
def run_all
|
152
218
|
true
|
153
219
|
end
|
154
|
-
|
220
|
+
|
155
221
|
# Call on file(s) modifications
|
156
222
|
def run_on_change(paths)
|
157
223
|
true
|
158
224
|
end
|
159
|
-
|
225
|
+
|
160
226
|
end
|
161
227
|
end
|
162
228
|
|
163
229
|
Looks at available guards code for more concrete example.
|
164
230
|
|
165
|
-
== Guardfile DSL
|
166
|
-
|
167
|
-
Guardfile DSL consists of just two simple methods: guard & watch. Example:
|
168
|
-
|
169
|
-
guard 'rspec', :version => 2 do
|
170
|
-
watch('^spec/(.*)_spec.rb')
|
171
|
-
watch('^lib/(.*)\.rb') { |m| "spec/lib/#{m[1]}_spec.rb" }
|
172
|
-
watch('^spec/spec_helper.rb') { "spec" }
|
173
|
-
watch('^spec/spec_helper.rb') { `say hello` }
|
174
|
-
end
|
175
|
-
|
176
|
-
- "guard" method allow to add a guard with an optional options hash
|
177
|
-
- "watch" method allow to define which files are supervised per this guard. A optional block can be added to overwrite path sending to run_on_change guard method or launch simple command.
|
178
|
-
|
179
|
-
== TODO
|
180
|
-
|
181
|
-
- Add more specs, help are welcome because I'm not sure about how to test stuff like this :-)
|
182
|
-
|
183
231
|
== Development
|
184
232
|
|
185
|
-
- Source hosted at {GitHub}[
|
186
|
-
- Report issues/Questions/Feature requests on {GitHub Issues}[
|
233
|
+
- Source hosted at {GitHub}[https://github.com/guard/guard]
|
234
|
+
- Report issues/Questions/Feature requests on {GitHub Issues}[https://github.com/guard/guard/issues]
|
187
235
|
|
188
236
|
Pull requests are very welcome! Make sure your patches are well tested. Please create a topic branch for every separate change
|
189
237
|
you make.
|
190
238
|
|
191
239
|
== Authors
|
192
240
|
|
193
|
-
{Thibaud Guillaume-Gentil}[
|
241
|
+
{Thibaud Guillaume-Gentil}[https://github.com/thibaudgg]
|
data/lib/guard.rb
CHANGED
@@ -1,74 +1,101 @@
|
|
1
1
|
require 'bundler'
|
2
2
|
|
3
3
|
module Guard
|
4
|
-
|
4
|
+
|
5
5
|
autoload :UI, 'guard/ui'
|
6
6
|
autoload :Dsl, 'guard/dsl'
|
7
7
|
autoload :Interactor, 'guard/interactor'
|
8
8
|
autoload :Listener, 'guard/listener'
|
9
9
|
autoload :Watcher, 'guard/watcher'
|
10
10
|
autoload :Notifier, 'guard/notifier'
|
11
|
-
|
11
|
+
|
12
12
|
class << self
|
13
13
|
attr_accessor :options, :guards, :listener
|
14
|
-
|
15
|
-
|
14
|
+
|
15
|
+
# initialize this singleton
|
16
|
+
def setup(options = {})
|
16
17
|
@options = options
|
17
|
-
@listener = Listener.
|
18
|
+
@listener = Listener.select_and_init
|
18
19
|
@guards = []
|
19
|
-
|
20
|
-
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def start(options = {})
|
24
|
+
setup(options)
|
25
|
+
|
26
|
+
Interactor.init_signal_traps
|
27
|
+
Dsl.evaluate_guardfile(options)
|
28
|
+
|
21
29
|
if guards.empty?
|
22
|
-
UI.error "No guards found in Guardfile, please add
|
30
|
+
UI.error "No guards found in Guardfile, please add at least one."
|
23
31
|
else
|
24
|
-
Interactor.init_signal_traps
|
25
|
-
|
26
32
|
listener.on_change do |files|
|
27
|
-
|
28
|
-
|
29
|
-
paths = Watcher.match_files(guard, files)
|
30
|
-
guard.run_on_change(paths) unless paths.empty?
|
31
|
-
end
|
33
|
+
if Watcher.match_files?(guards, files)
|
34
|
+
run { run_on_change_for_all_guards(files) }
|
32
35
|
end
|
33
36
|
end
|
34
|
-
|
37
|
+
|
35
38
|
UI.info "Guard is now watching at '#{Dir.pwd}'"
|
36
|
-
guards.each { |
|
39
|
+
guards.each { |guard| supervised_task(guard, :start) }
|
37
40
|
listener.start
|
38
41
|
end
|
39
42
|
end
|
40
|
-
|
43
|
+
|
44
|
+
def run_on_change_for_all_guards(files)
|
45
|
+
guards.each do |guard|
|
46
|
+
paths = Watcher.match_files(guard, files)
|
47
|
+
supervised_task(guard, :run_on_change, paths) unless paths.empty?
|
48
|
+
end
|
49
|
+
# Reparse the whole directory to catch new files modified during the guards run
|
50
|
+
new_modified_files = listener.modified_files([Dir.pwd + '/'], :all => true)
|
51
|
+
listener.update_last_event
|
52
|
+
unless new_modified_files.empty?
|
53
|
+
run_on_change_for_all_guards(new_modified_files)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Let a guard execute its task but
|
58
|
+
# fire it if his work leads to a system failure
|
59
|
+
def supervised_task(guard, task_to_supervise, *args)
|
60
|
+
guard.send(task_to_supervise, *args)
|
61
|
+
rescue Exception
|
62
|
+
UI.error("#{guard.class.name} guard failed to achieve its <#{task_to_supervise.to_s}> command: #{$!}")
|
63
|
+
::Guard.guards.delete guard
|
64
|
+
UI.info("Guard #{guard.class.name} has just been fired")
|
65
|
+
return $!
|
66
|
+
end
|
67
|
+
|
68
|
+
def run
|
69
|
+
listener.stop
|
70
|
+
UI.clear if options[:clear]
|
71
|
+
begin
|
72
|
+
yield
|
73
|
+
rescue Interrupt
|
74
|
+
end
|
75
|
+
listener.start
|
76
|
+
end
|
77
|
+
|
41
78
|
def add_guard(name, watchers = [], options = {})
|
42
79
|
guard_class = get_guard_class(name)
|
43
80
|
@guards << guard_class.new(watchers, options)
|
44
81
|
end
|
45
|
-
|
82
|
+
|
46
83
|
def get_guard_class(name)
|
47
84
|
require "guard/#{name.downcase}"
|
48
85
|
klasses = []
|
49
86
|
ObjectSpace.each_object(Class) do |klass|
|
50
|
-
klasses << klass if klass.to_s.downcase.match
|
87
|
+
klasses << klass if klass.to_s.downcase.match(/^guard::#{name.downcase}/)
|
51
88
|
end
|
52
89
|
klasses.first
|
53
90
|
rescue LoadError
|
54
|
-
UI.error "Could not find gem 'guard-#{name}' in
|
91
|
+
UI.error "Could not find gem 'guard-#{name}', please add it in your Gemfile."
|
55
92
|
end
|
56
|
-
|
93
|
+
|
57
94
|
def locate_guard(name)
|
58
95
|
`gem open guard-#{name} --latest --command echo`.chomp
|
59
96
|
rescue
|
60
97
|
UI.error "Could not find 'guard-#{name}' gem path."
|
61
98
|
end
|
62
|
-
|
63
|
-
def run
|
64
|
-
listener.stop
|
65
|
-
UI.clear if options[:clear]
|
66
|
-
begin
|
67
|
-
yield
|
68
|
-
rescue Interrupt
|
69
|
-
end
|
70
|
-
listener.start
|
71
|
-
end
|
72
|
-
|
99
|
+
|
73
100
|
end
|
74
101
|
end
|
data/lib/guard/cli.rb
CHANGED
@@ -5,20 +5,22 @@ module Guard
|
|
5
5
|
class CLI < Thor
|
6
6
|
default_task :start
|
7
7
|
|
8
|
-
desc "start", "Starts guard"
|
9
8
|
method_option :clear, :type => :boolean, :default => false, :aliases => '-c', :banner => "Auto clear shell before each change/run_all/reload"
|
10
9
|
method_option :debug, :type => :boolean, :default => false, :aliases => '-d', :banner => "Print debug messages"
|
10
|
+
method_option :group, :type => :array, :default => [], :aliases => '-g', :banner => "Run only the passed groups"
|
11
|
+
|
12
|
+
desc "start", "Starts Guard"
|
11
13
|
def start
|
12
14
|
::Guard.start(options)
|
13
15
|
end
|
14
16
|
|
15
|
-
desc "version", "Prints
|
17
|
+
desc "version", "Prints Guard's version information"
|
16
18
|
def version
|
17
19
|
::Guard::UI.info "Guard version #{Guard::VERSION}"
|
18
20
|
end
|
19
21
|
map %w(-v --version) => :version
|
20
22
|
|
21
|
-
desc "init [GUARD]", "Generates a Guardfile into the current working directory, or
|
23
|
+
desc "init [GUARD]", "Generates a Guardfile into the current working directory, or insert the given GUARD"
|
22
24
|
def init(guard_name = nil)
|
23
25
|
if !File.exist?("Guardfile")
|
24
26
|
puts "Writing new Guardfile to #{Dir.pwd}/Guardfile"
|
data/lib/guard/dsl.rb
CHANGED
@@ -1,28 +1,45 @@
|
|
1
1
|
module Guard
|
2
2
|
class Dsl
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def evaluate_guardfile(options = {})
|
6
|
+
@@options = options
|
7
|
+
|
8
|
+
if File.exists?(guardfile_path)
|
9
|
+
begin
|
10
|
+
new.instance_eval(File.read(guardfile_path), guardfile_path, 1)
|
11
|
+
rescue
|
12
|
+
UI.error "Invalid Guardfile, original error is:\n#{$!}"
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
else
|
16
|
+
UI.error "No Guardfile in current folder, please create one."
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def guardfile_include?(guard_name)
|
22
|
+
File.read(guardfile_path).match(/^guard\s*\(?\s*['":]#{guard_name}['"]?/)
|
23
|
+
end
|
24
|
+
|
25
|
+
def guardfile_path
|
26
|
+
File.join(Dir.pwd, 'Guardfile')
|
27
|
+
end
|
11
28
|
end
|
12
|
-
|
13
|
-
def
|
14
|
-
|
29
|
+
|
30
|
+
def group(name, &guard_definition)
|
31
|
+
guard_definition.call if guard_definition && (@@options[:group].empty? || @@options[:group].include?(name))
|
15
32
|
end
|
16
|
-
|
17
|
-
def guard(name, options = {}, &
|
33
|
+
|
34
|
+
def guard(name, options = {}, &watch_definition)
|
18
35
|
@watchers = []
|
19
|
-
|
36
|
+
watch_definition.call if watch_definition
|
20
37
|
::Guard.add_guard(name, @watchers, options)
|
21
38
|
end
|
22
|
-
|
39
|
+
|
23
40
|
def watch(pattern, &action)
|
24
41
|
@watchers << ::Guard::Watcher.new(pattern, action)
|
25
42
|
end
|
26
|
-
|
43
|
+
|
27
44
|
end
|
28
45
|
end
|
data/lib/guard/guard.rb
CHANGED
@@ -1,51 +1,55 @@
|
|
1
1
|
module Guard
|
2
2
|
class Guard
|
3
3
|
attr_accessor :watchers, :options
|
4
|
-
|
4
|
+
|
5
5
|
def initialize(watchers = [], options = {})
|
6
6
|
@watchers, @options = watchers, options
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
# Guardfile template needed inside guard gem
|
10
10
|
def self.init(name)
|
11
|
-
if ::Guard::Dsl.
|
11
|
+
if ::Guard::Dsl.guardfile_include?(name)
|
12
12
|
::Guard::UI.info "Guardfile already include #{name} guard"
|
13
13
|
else
|
14
14
|
content = File.read('Guardfile')
|
15
15
|
guard = File.read("#{::Guard.locate_guard(name)}/lib/guard/#{name}/templates/Guardfile")
|
16
16
|
File.open('Guardfile', 'wb') do |f|
|
17
|
-
f.puts
|
18
|
-
f.puts
|
19
|
-
f.puts
|
17
|
+
f.puts(content)
|
18
|
+
f.puts("")
|
19
|
+
f.puts(guard)
|
20
20
|
end
|
21
21
|
::Guard::UI.info "#{name} guard added to Guardfile, feel free to edit it"
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
# ================
|
26
26
|
# = Guard method =
|
27
27
|
# ================
|
28
|
-
|
28
|
+
|
29
|
+
# Call once when guard starts
|
30
|
+
# Please override initialize method to init stuff
|
29
31
|
def start
|
30
32
|
true
|
31
33
|
end
|
32
|
-
|
33
|
-
#
|
34
|
+
|
35
|
+
# Call once when guard quit
|
34
36
|
def stop
|
35
37
|
true
|
36
38
|
end
|
37
|
-
|
39
|
+
|
40
|
+
# Should be mainly used for "reload" (really!) actions like reloading passenger/spork/bundler/...
|
38
41
|
def reload
|
39
42
|
true
|
40
43
|
end
|
41
|
-
|
44
|
+
|
45
|
+
# Should be principally used for long action like running all specs/tests/...
|
42
46
|
def run_all
|
43
47
|
true
|
44
48
|
end
|
45
|
-
|
49
|
+
|
46
50
|
def run_on_change(paths)
|
47
51
|
true
|
48
52
|
end
|
49
|
-
|
53
|
+
|
50
54
|
end
|
51
55
|
end
|
data/lib/guard/interactor.rb
CHANGED
@@ -5,25 +5,22 @@ module Guard
|
|
5
5
|
# Run all (Ctrl-\)
|
6
6
|
Signal.trap('QUIT') do
|
7
7
|
::Guard.run do
|
8
|
-
::Guard.guards.each { |
|
8
|
+
::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :run_all) }
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
# Stop (Ctrl-C)
|
13
13
|
Signal.trap('INT') do
|
14
|
+
UI.info "Bye bye...", :reset => true
|
14
15
|
::Guard.listener.stop
|
15
|
-
|
16
|
-
|
17
|
-
abort("\n")
|
18
|
-
else
|
19
|
-
::Guard.listener.start
|
20
|
-
end
|
16
|
+
::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :stop) }
|
17
|
+
abort("\n")
|
21
18
|
end
|
22
19
|
|
23
20
|
# Reload (Ctrl-Z)
|
24
21
|
Signal.trap('TSTP') do
|
25
22
|
::Guard.run do
|
26
|
-
::Guard.guards.each { |
|
23
|
+
::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :reload) }
|
27
24
|
end
|
28
25
|
end
|
29
26
|
end
|
data/lib/guard/listener.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'rbconfig'
|
2
2
|
|
3
3
|
module Guard
|
4
|
-
|
4
|
+
|
5
5
|
autoload :Darwin, 'guard/listeners/darwin'
|
6
6
|
autoload :Linux, 'guard/listeners/linux'
|
7
7
|
autoload :Polling, 'guard/listeners/polling'
|
8
|
-
|
8
|
+
|
9
9
|
class Listener
|
10
10
|
attr_reader :last_event
|
11
|
-
|
12
|
-
def self.
|
11
|
+
|
12
|
+
def self.select_and_init
|
13
13
|
if mac? && Darwin.usable?
|
14
14
|
Darwin.new
|
15
15
|
elsif linux? && Linux.usable?
|
@@ -19,40 +19,107 @@ module Guard
|
|
19
19
|
Polling.new
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def initialize
|
24
24
|
update_last_event
|
25
25
|
end
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
|
27
|
+
def update_last_event
|
28
|
+
@last_event = Time.now
|
29
|
+
end
|
30
|
+
|
29
31
|
def modified_files(dirs, options = {})
|
30
32
|
files = potentially_modified_files(dirs, options).select { |path| File.file?(path) && recent_file?(path) }
|
31
33
|
files.map! { |file| file.gsub("#{Dir.pwd}/", '') }
|
32
34
|
end
|
33
|
-
|
35
|
+
|
36
|
+
private
|
37
|
+
|
34
38
|
def potentially_modified_files(dirs, options = {})
|
35
39
|
match = options[:all] ? "**/*" : "*"
|
36
40
|
Dir.glob(dirs.map { |dir| "#{dir}#{match}" })
|
37
41
|
end
|
38
|
-
|
42
|
+
|
39
43
|
def recent_file?(file)
|
40
44
|
File.mtime(file) >= last_event
|
41
45
|
rescue
|
42
46
|
false
|
43
47
|
end
|
44
|
-
|
45
|
-
|
46
|
-
@last_event = Time.now
|
47
|
-
end
|
48
|
-
|
48
|
+
|
49
|
+
|
49
50
|
def self.mac?
|
50
51
|
Config::CONFIG['target_os'] =~ /darwin/i
|
51
52
|
end
|
52
|
-
|
53
|
+
|
53
54
|
def self.linux?
|
54
55
|
Config::CONFIG['target_os'] =~ /linux/i
|
55
56
|
end
|
56
|
-
|
57
|
+
|
57
58
|
end
|
58
|
-
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# require 'rbconfig'
|
62
|
+
#
|
63
|
+
# module Guard
|
64
|
+
#
|
65
|
+
# autoload :Darwin, 'guard/listeners/darwin'
|
66
|
+
# autoload :Linux, 'guard/listeners/linux'
|
67
|
+
# autoload :Polling, 'guard/listeners/polling'
|
68
|
+
#
|
69
|
+
# class Listener
|
70
|
+
# attr_accessor :last_event, :changed_files
|
71
|
+
#
|
72
|
+
# def self.select_and_init
|
73
|
+
# if mac? && Darwin.usable?
|
74
|
+
# Darwin.new
|
75
|
+
# elsif linux? && Linux.usable?
|
76
|
+
# Linux.new
|
77
|
+
# else
|
78
|
+
# UI.info "Using polling (Please help us to support your system better than that.)"
|
79
|
+
# Polling.new
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# def initialize
|
84
|
+
# @changed_files = []
|
85
|
+
# update_last_event
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# def get_and_clear_changed_files
|
89
|
+
# files = changed_files.dup
|
90
|
+
# changed_files.clear
|
91
|
+
# files.uniq
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# private
|
95
|
+
#
|
96
|
+
# def find_changed_files(dirs, options = {})
|
97
|
+
# files = potentially_changed_files(dirs, options).select { |path| File.file?(path) && changed_file?(path) }
|
98
|
+
# files.map! { |file| file.gsub("#{Dir.pwd}/", '') }
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# def potentially_changed_files(dirs, options = {})
|
102
|
+
# match = options[:all] ? "**/*" : "*"
|
103
|
+
# Dir.glob(dirs.map { |dir| "#{dir}#{match}" })
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# def changed_file?(file)
|
107
|
+
# File.mtime(file) >= last_event
|
108
|
+
# rescue
|
109
|
+
# false
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# def update_last_event
|
113
|
+
# @last_event = Time.now
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# def self.mac?
|
117
|
+
# Config::CONFIG['target_os'] =~ /darwin/i
|
118
|
+
# end
|
119
|
+
#
|
120
|
+
# def self.linux?
|
121
|
+
# Config::CONFIG['target_os'] =~ /linux/i
|
122
|
+
# end
|
123
|
+
#
|
124
|
+
# end
|
125
|
+
# end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Guard
|
2
2
|
class Darwin < Listener
|
3
3
|
attr_reader :fsevent
|
4
|
-
|
4
|
+
|
5
5
|
def initialize
|
6
6
|
super
|
7
7
|
@fsevent = FSEvent.new
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def on_change(&callback)
|
11
11
|
@fsevent.watch Dir.pwd do |modified_dirs|
|
12
12
|
files = modified_files(modified_dirs)
|
@@ -14,19 +14,19 @@ module Guard
|
|
14
14
|
callback.call(files)
|
15
15
|
end
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def start
|
19
19
|
@fsevent.run
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def stop
|
23
23
|
@fsevent.stop
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def self.usable?
|
27
27
|
require 'rb-fsevent'
|
28
|
-
if !defined?(FSEvent::VERSION) || Gem::Version.new(FSEvent::VERSION) < Gem::Version.new('0.3.
|
29
|
-
UI.info "Please update rb-fsevent (>= 0.3.
|
28
|
+
if !defined?(FSEvent::VERSION) || Gem::Version.new(FSEvent::VERSION) < Gem::Version.new('0.3.9')
|
29
|
+
UI.info "Please update rb-fsevent (>= 0.3.9)"
|
30
30
|
false
|
31
31
|
else
|
32
32
|
true
|
@@ -35,6 +35,6 @@ module Guard
|
|
35
35
|
UI.info "Please install rb-fsevent gem for Mac OSX FSEvents support"
|
36
36
|
false
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
end
|
40
|
-
end
|
40
|
+
end
|
@@ -1,27 +1,27 @@
|
|
1
1
|
module Guard
|
2
2
|
class Polling < Listener
|
3
3
|
attr_reader :callback, :latency
|
4
|
-
|
4
|
+
|
5
5
|
def initialize
|
6
6
|
super
|
7
7
|
@latency = 1.5
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def on_change(&callback)
|
11
11
|
@callback = callback
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def start
|
15
15
|
@stop = false
|
16
16
|
watch_change
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def stop
|
20
20
|
@stop = true
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
private
|
24
|
-
|
24
|
+
|
25
25
|
def watch_change
|
26
26
|
while !@stop
|
27
27
|
start = Time.now.to_f
|
@@ -32,6 +32,6 @@ module Guard
|
|
32
32
|
sleep(nap_time) if nap_time > 0
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
end
|
37
|
-
end
|
37
|
+
end
|
@@ -1,2 +1,2 @@
|
|
1
1
|
# A sample Guardfile
|
2
|
-
# More info at
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
data/lib/guard/ui.rb
CHANGED
@@ -9,12 +9,16 @@ module Guard
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
def error(message)
|
13
|
-
|
12
|
+
def error(message, options = {})
|
13
|
+
unless ENV["GUARD_ENV"] == "test"
|
14
|
+
reset_line if options[:reset]
|
15
|
+
puts "ERROR: #{message}"
|
16
|
+
end
|
14
17
|
end
|
15
18
|
|
16
|
-
def debug(message)
|
19
|
+
def debug(message, options = {})
|
17
20
|
unless ENV["GUARD_ENV"] == "test"
|
21
|
+
reset_line if options[:reset]
|
18
22
|
puts "DEBUG: #{message}" if ::Guard.options && ::Guard.options[:debug]
|
19
23
|
end
|
20
24
|
end
|
data/lib/guard/version.rb
CHANGED
data/lib/guard/watcher.rb
CHANGED
@@ -4,29 +4,57 @@ module Guard
|
|
4
4
|
|
5
5
|
def initialize(pattern, action = nil)
|
6
6
|
@pattern, @action = pattern, action
|
7
|
+
@@warning_printed ||= false
|
8
|
+
|
9
|
+
# deprecation warning
|
10
|
+
if @pattern.is_a?(String) && @pattern =~ /(^(\^))|(>?(\\\.)|(\.\*))|(\(.*\))|(\[.*\])|(\$$)/
|
11
|
+
unless @@warning_printed
|
12
|
+
UI.info "*"*20 + "\nDEPRECATION WARNING!\n" + "*"*20
|
13
|
+
UI.info "You have strings in your Guardfile's watch patterns that seem to represent regexps.\nGuard matchs String with == and Regexp with Regexp#match.\nYou should either use plain String (without Regexp special characters) or real Regexp.\n"
|
14
|
+
@@warning_printed = true
|
15
|
+
end
|
16
|
+
UI.info "\"#{@pattern}\" has been converted to #{Regexp.new(@pattern).inspect}\n"
|
17
|
+
@pattern = Regexp.new(@pattern)
|
18
|
+
end
|
7
19
|
end
|
8
20
|
|
9
21
|
def self.match_files(guard, files)
|
10
22
|
guard.watchers.inject([]) do |paths, watcher|
|
11
23
|
files.each do |file|
|
12
|
-
if matches =
|
24
|
+
if matches = watcher.match_file?(file)
|
13
25
|
if watcher.action
|
14
|
-
|
15
|
-
|
16
|
-
result = watcher.action.call(matches)
|
17
|
-
else
|
18
|
-
result = watcher.action.call
|
19
|
-
end
|
20
|
-
rescue
|
21
|
-
UI.info "Problem with watch action"
|
22
|
-
end
|
23
|
-
paths << result if result.is_a?(String) && result != ''
|
26
|
+
result = watcher.call_action(matches)
|
27
|
+
paths << Array(result) if result.respond_to?(:empty?) && !result.empty?
|
24
28
|
else
|
25
29
|
paths << matches[0]
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
29
|
-
paths
|
33
|
+
paths.flatten.map { |p| p.to_s }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.match_files?(guards, files)
|
38
|
+
guards.any? do |guard|
|
39
|
+
guard.watchers.any? do |watcher|
|
40
|
+
files.any? { |file| watcher.match_file?(file) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def match_file?(file)
|
46
|
+
if @pattern.is_a?(Regexp)
|
47
|
+
file.match(@pattern)
|
48
|
+
else
|
49
|
+
file == @pattern ? [file] : nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def call_action(matches)
|
54
|
+
begin
|
55
|
+
@action.arity > 0 ? @action.call(matches) : @action.call
|
56
|
+
rescue
|
57
|
+
UI.error "Problem with watch action!"
|
30
58
|
end
|
31
59
|
end
|
32
60
|
|
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Thibaud Guillaume-Gentil
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-01-19 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -26,12 +26,12 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
29
|
+
hash: 25
|
30
30
|
segments:
|
31
31
|
- 1
|
32
32
|
- 0
|
33
|
-
-
|
34
|
-
version: 1.0.
|
33
|
+
- 7
|
34
|
+
version: 1.0.7
|
35
35
|
type: :development
|
36
36
|
version_requirements: *id001
|
37
37
|
- !ruby/object:Gem::Dependency
|
@@ -42,12 +42,12 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
hash:
|
45
|
+
hash: 31
|
46
46
|
segments:
|
47
47
|
- 2
|
48
|
+
- 4
|
48
49
|
- 0
|
49
|
-
|
50
|
-
version: 2.0.1
|
50
|
+
version: 2.4.0
|
51
51
|
type: :development
|
52
52
|
version_requirements: *id002
|
53
53
|
- !ruby/object:Gem::Dependency
|
@@ -58,12 +58,12 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
hash:
|
61
|
+
hash: 9
|
62
62
|
segments:
|
63
63
|
- 0
|
64
64
|
- 1
|
65
|
-
-
|
66
|
-
version: 0.1.
|
65
|
+
- 9
|
66
|
+
version: 0.1.9
|
67
67
|
type: :development
|
68
68
|
version_requirements: *id003
|
69
69
|
- !ruby/object:Gem::Dependency
|
@@ -74,12 +74,12 @@ dependencies:
|
|
74
74
|
requirements:
|
75
75
|
- - ~>
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
hash:
|
77
|
+
hash: 43
|
78
78
|
segments:
|
79
79
|
- 0
|
80
80
|
- 14
|
81
|
-
-
|
82
|
-
version: 0.14.
|
81
|
+
- 6
|
82
|
+
version: 0.14.6
|
83
83
|
type: :runtime
|
84
84
|
version_requirements: *id004
|
85
85
|
- !ruby/object:Gem::Dependency
|