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 CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Thibaud Guillaume-Gentil
1
+ Copyright (c) 2011 Thibaud Guillaume-Gentil
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -1,6 +1,6 @@
1
1
  = Guard
2
2
 
3
- Guard is a command line tool to easly handle events on files modifications.
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 guard(s) you need (see available guards below)
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 ruby/rails project with:
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 -c
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 stop guard(s) method before)
77
- - Ctrl-\ - Call run_all guard(s) method
78
- - Ctrl-Z - Call reload guard(s) method
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-rspec}[http://github.com/guard/guard-rspec]
83
- - {guard-test}[http://github.com/guard/guard-test]
84
- - {guard-minitest}[http://github.com/guard/guard-minitest]
85
- - {guard-livereload}[http://github.com/guard/guard-livereload]
86
- - {guard-sass}[http://github.com/guard/guard-sass]
87
- - {guard-compass}[http://github.com/guard/guard-compass]
88
- - {guard-shell}[http://github.com/guard/guard-shell]
89
- - {guard-bundler}[http://github.com/guard/guard-bundler]
90
- - {guard-passenger}[http://github.com/guard/guard-passenger]
91
-
92
- guard ideas:
93
-
94
- - guard-spork
95
- - guard-cucumber
96
- - others ideas?
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}[http://github.com/guard/guard]
186
- - Report issues/Questions/Feature requests on {GitHub Issues}[http://github.com/guard/guard/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}[http://github.com/thibaudgg]
241
+ {Thibaud Guillaume-Gentil}[https://github.com/thibaudgg]
@@ -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
- def start(options = {})
14
+
15
+ # initialize this singleton
16
+ def setup(options = {})
16
17
  @options = options
17
- @listener = Listener.init
18
+ @listener = Listener.select_and_init
18
19
  @guards = []
19
-
20
- Dsl.evaluate_guardfile
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 it at least one."
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
- run do
28
- guards.each do |guard|
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 { |g| g.start }
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 "^guard::#{name.downcase}"
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 the current Gemfile."
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
@@ -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 the guard's version information"
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 add it given guard"
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"
@@ -1,28 +1,45 @@
1
1
  module Guard
2
2
  class Dsl
3
-
4
- def self.evaluate_guardfile
5
- guardfile = "#{Dir.pwd}/Guardfile"
6
- dsl = new
7
- dsl.instance_eval(File.read(guardfile.to_s), guardfile.to_s, 1)
8
- rescue
9
- UI.error "Guardfile not found or invalid"
10
- exit 1
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 self.guardfile_included?(guard_name)
14
- File.read('Guardfile').include?("guard '#{guard_name}'")
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 = {}, &definition)
33
+
34
+ def guard(name, options = {}, &watch_definition)
18
35
  @watchers = []
19
- definition.call if definition
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
@@ -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.guardfile_included?(name)
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 content
18
- f.puts ""
19
- f.puts guard
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
- # Retrieve a true value if the instance successfuly stopped
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
@@ -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 { |g| g.run_all }
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
- if ::Guard.guards.all? { |g| g.stop }
16
- UI.info "Bye bye...", :reset => true
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 { |g| g.reload }
23
+ ::Guard.guards.each { |guard| ::Guard.supervised_task(guard, :reload) }
27
24
  end
28
25
  end
29
26
  end
@@ -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.init
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
- private
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
- def update_last_event
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.5')
29
- UI.info "Please update rb-fsevent (>= 0.3.5)"
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
@@ -70,4 +70,4 @@ module Guard
70
70
  end
71
71
 
72
72
  end
73
- end
73
+ 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 http://github.com/guard/guard#readme
2
+ # More info at https://github.com/guard/guard#readme
@@ -9,12 +9,16 @@ module Guard
9
9
  end
10
10
  end
11
11
 
12
- def error(message)
13
- puts "ERROR: #{message}"
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
@@ -1,3 +1,3 @@
1
1
  module Guard
2
- VERSION = "0.2.2"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -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 = file.match(watcher.pattern)
24
+ if matches = watcher.match_file?(file)
13
25
  if watcher.action
14
- begin
15
- if watcher.action.arity == 1
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
- - 2
9
- - 2
10
- version: 0.2.2
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: 2010-10-26 00:00:00 +02:00
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: 17
29
+ hash: 25
30
30
  segments:
31
31
  - 1
32
32
  - 0
33
- - 3
34
- version: 1.0.3
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: 13
45
+ hash: 31
46
46
  segments:
47
47
  - 2
48
+ - 4
48
49
  - 0
49
- - 1
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: 19
61
+ hash: 9
62
62
  segments:
63
63
  - 0
64
64
  - 1
65
- - 4
66
- version: 0.1.4
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: 33
77
+ hash: 43
78
78
  segments:
79
79
  - 0
80
80
  - 14
81
- - 3
82
- version: 0.14.3
81
+ - 6
82
+ version: 0.14.6
83
83
  type: :runtime
84
84
  version_requirements: *id004
85
85
  - !ruby/object:Gem::Dependency