guard 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|