Module: Guard
- Defined in:
- lib/guard.rb,
lib/guard/ui.rb,
lib/guard/dsl.rb,
lib/guard/cli.rb,
lib/guard/hook.rb,
lib/guard/group.rb,
lib/guard/guard.rb,
lib/guard/version.rb,
lib/guard/watcher.rb,
lib/guard/listener.rb,
lib/guard/notifier.rb,
lib/guard/interactor.rb,
lib/guard/dsl_describer.rb,
lib/guard/notifiers/gntp.rb,
lib/guard/listeners/linux.rb,
lib/guard/notifiers/growl.rb,
lib/guard/listeners/darwin.rb,
lib/guard/listeners/polling.rb,
lib/guard/listeners/windows.rb,
lib/guard/interactors/simple.rb,
lib/guard/notifiers/libnotify.rb,
lib/guard/notifiers/rb_notifu.rb,
lib/guard/interactors/readline.rb,
lib/guard/notifiers/notifysend.rb,
lib/guard/notifiers/growl_notify.rb
Overview
Guard is the main module for all Guard related modules and classes. Also other Guard implementation should use this namespace.
Defined Under Namespace
Modules: Hook, Notifier, UI Classes: CLI, Darwin, Dsl, DslDescriber, Group, Guard, Interactor, Linux, Listener, Polling, ReadlineInteractor, SimpleInteractor, Watcher, Windows
Constant Summary
- GUARDFILE_TEMPLATE =
The Guardfile template for `guard init`
File.('../guard/templates/Guardfile', __FILE__)
- HOME_TEMPLATES =
The location of user defined templates
File.('~/.guard/templates')
- VERSION =
The current gem version of Guard
'1.0.2'
Class Attribute Summary (collapse)
-
+ (Object) interactor
Returns the value of attribute interactor.
-
+ (Object) listener
Returns the value of attribute listener.
-
+ (Object) lock
Returns the value of attribute lock.
-
+ (Object) options
Returns the value of attribute options.
Class Method Summary (collapse)
-
+ (Guard::Group) add_group(name, options = {})
Add a Guard group.
-
+ (Guard::Guard) add_guard(name, watchers = [], callbacks = [], options = {})
Add a Guard to use.
-
+ (Array<String>) changed_paths(paths)
Detects the paths that have changed.
-
+ (Object) create_guardfile(options = {})
Creates the initial Guardfile template when it does not already exist.
-
+ (Object) debug_command_execution
Adds a command logger in debug mode.
-
+ (Array<String>) deleted_paths(paths)
Detects the paths that have been deleted.
-
+ (Class?) get_guard_class(name, fail_gracefully = false)
Tries to load the Guard main class.
-
+ (Array<Group>) groups(filter = nil)
Smart accessor for retrieving a specific group or several groups at once.
-
+ (Array<String>) guard_gem_names
Returns a list of guard Gem names installed locally.
-
+ (Symbol) guard_symbol(guard)
Get the symbol we have to catch when running a supervised task.
-
+ (Array<Guard>) guards(filter = nil)
Smart accessor for retrieving a specific guard or several guards at once.
-
+ (Object) initialize_all_templates
Adds the templates of all installed Guard implementations to an existing Guardfile.
-
+ (Object) initialize_template(guard_name)
Adds the Guardfile template of a Guard implementation to an existing Guardfile.
-
+ (String) locate_guard(name)
Locate a path to a Guard gem.
-
+ (Object) pause
Pause Guard listening to file changes.
-
+ (Object) reload(scopes)
Reload all Guards currently enabled.
-
+ (Object) reset_groups
Initialize the groups array with the `:default` group.
-
+ (Object) run { ... }
Run a block where the listener and the interactor is blocked.
-
+ (Object) run_all(scopes)
Trigger `run_all` on all Guards currently enabled.
-
+ (Object) run_on_change(files)
Trigger `run_on_change` on all Guards currently enabled.
-
+ (Object) run_on_change_task(files, guard)
Run the `:run_on_change` task.
-
+ (Object) run_on_guards(scopes = {}) { ... }
Loop through all groups and run the given task for each Guard.
-
+ (Object) run_supervised_task(guard, task, *args)
Run a Guard task, but remove the Guard when his work leads to a system failure.
-
+ (Object) setup(options = {})
Initialize the Guard singleton:.
-
+ (Object) start(options = {})
Start Guard by evaluate the `Guardfile`, initialize the declared Guards and start the available file change listener.
-
+ (Object) stop
Stop Guard listening to file changes.
Class Attribute Details
+ (Object) interactor
Returns the value of attribute interactor
24 25 26 |
# File 'lib/guard.rb', line 24 def interactor @interactor end |
+ (Object) listener
Returns the value of attribute listener
24 25 26 |
# File 'lib/guard.rb', line 24 def listener @listener end |
+ (Object) lock
Returns the value of attribute lock
24 25 26 |
# File 'lib/guard.rb', line 24 def lock @lock end |
+ (Object) options
Returns the value of attribute options
24 25 26 |
# File 'lib/guard.rb', line 24 def @options end |
Class Method Details
+ (Guard::Group) add_group(name, options = {})
Add a Guard group.
457 458 459 460 461 462 463 464 |
# File 'lib/guard.rb', line 457 def add_group(name, = {}) group = groups(name) if group.nil? group = Group.new(name, ) @groups << group end group end |
+ (Guard::Guard) add_guard(name, watchers = [], callbacks = [], options = {})
Add a Guard to use.
438 439 440 441 442 443 444 445 446 447 448 |
# File 'lib/guard.rb', line 438 def add_guard(name, watchers = [], callbacks = [], = {}) if name.to_sym == :ego UI.deprecation('Guard::Ego is now part of Guard. You can remove it from your Guardfile.') else guard_class = get_guard_class(name) callbacks.each { |callback| Hook.add_callback(callback[:listener], guard_class, callback[:events]) } guard = guard_class.new(watchers, ) @guards << guard guard end end |
+ (Array<String>) changed_paths(paths)
Detects the paths that have changed.
Deleted paths are prefixed by an exclamation point.
366 367 368 |
# File 'lib/guard.rb', line 366 def changed_paths(paths) paths.select { |f| !f.respond_to?(:start_with?) || !f.start_with?('!') } end |
+ (Object) create_guardfile(options = {})
Creates the initial Guardfile template when it does not already exist.
34 35 36 37 38 39 40 41 42 |
# File 'lib/guard.rb', line 34 def create_guardfile( = {}) if !File.exist?('Guardfile') ::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile" FileUtils.cp(GUARDFILE_TEMPLATE, 'Guardfile') elsif [:abort_on_existence] ::Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile" abort end end |
+ (Object) debug_command_execution
Adds a command logger in debug mode. This wraps common command execution functions and logs the executed command before execution.
534 535 536 537 538 539 540 541 542 543 544 545 546 |
# File 'lib/guard.rb', line 534 def debug_command_execution Kernel.send(:alias_method, :original_system, :system) Kernel.send(:define_method, :system) do |command, *args| ::Guard::UI.debug "Command execution: #{ command } #{ args.join(' ') }" original_system command, *args end Kernel.send(:alias_method, :original_backtick, :`') Kernel.send(:define_method, :`') do |command| ::Guard::UI.debug "Command execution: #{ command }" original_backtick command end end |
+ (Array<String>) deleted_paths(paths)
Detects the paths that have been deleted.
Deleted paths are prefixed by an exclamation point.
378 379 380 |
# File 'lib/guard.rb', line 378 def deleted_paths(paths) paths.select { |f| f.respond_to?(:start_with?) && f.start_with?('!') }.map { |f| f.slice(1..-1) } end |
+ (Class?) get_guard_class(name, fail_gracefully = false)
Tries to load the Guard main class. This transforms the supplied Guard name into a class name:
-
`guardname` will become `Guard::Guardname`
-
`dashed-guard-name` will become `Guard::DashedGuardName`
-
`underscore_guard_name` will become `Guard::UnderscoreGuardName`
When no class is found with the strict case sensitive rules, another try is made to locate the class without matching case:
-
`rspec` will find a class `Guard::RSpec`
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/guard.rb', line 482 def get_guard_class(name, fail_gracefully=false) name = name.to_s try_require = false const_name = name.gsub(/\/(.?)/) { "::#{ $1.upcase }" }.gsub(/(?:^|[_-])(.)/) { $1.upcase } begin require "guard/#{ name.downcase }" if try_require self.const_get(self.constants.find { |c| c.to_s == const_name } || self.constants.find { |c| c.to_s.downcase == const_name.downcase }) rescue TypeError unless try_require try_require = true retry else UI.error "Could not find class Guard::#{ const_name.capitalize }" end rescue LoadError => loadError unless fail_gracefully UI.error "Could not load 'guard/#{ name.downcase }' or find class Guard::#{ const_name.capitalize }" UI.error loadError.to_s end end end |
+ (Array<Group>) groups(filter = nil)
Smart accessor for retrieving a specific group or several groups at once.
169 170 171 172 173 174 175 176 177 178 |
# File 'lib/guard.rb', line 169 def groups(filter = nil) case filter when String, Symbol @groups.find { |group| group.name == filter.to_sym } when Regexp @groups.find_all { |group| group.name.to_s =~ filter } else @groups end end |
+ (Array<String>) guard_gem_names
Returns a list of guard Gem names installed locally.
523 524 525 526 527 528 529 |
# File 'lib/guard.rb', line 523 def guard_gem_names if Gem::Version.create(Gem::VERSION) >= Gem::Version.create('1.8.0') Gem::Specification.find_all.select { |x| x.name =~ /^guard-/ } else Gem.source_index.find_name(/^guard-/) end.map { |x| x.name.sub(/^guard-/, '') } end |
+ (Symbol) guard_symbol(guard)
Get the symbol we have to catch when running a supervised task. If we are within a Guard group that has the `:halt_on_fail` option set, we do NOT catch it here, it will be catched at the group level.
421 422 423 424 425 426 427 428 |
# File 'lib/guard.rb', line 421 def guard_symbol(guard) if guard.group.class == Symbol group = groups(guard.group) group.[:halt_on_fail] ? :no_catch : :task_has_failed else :task_has_failed end end |
+ (Array<Guard>) guards(filter = nil)
Smart accessor for retrieving a specific guard or several guards at once.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/guard.rb', line 134 def guards(filter = nil) @guards ||= [] case filter when String, Symbol @guards.find { |guard| guard.class.to_s.downcase.sub('guard::', '') == filter.to_s.downcase.gsub('-', '') } when Regexp @guards.find_all { |guard| guard.class.to_s.downcase.sub('guard::', '') =~ filter } when Hash filter.inject(@guards) do |matches, (k, v)| if k.to_sym == :name matches.find_all { |guard| guard.class.to_s.downcase.sub('guard::', '') == v.to_s.downcase.gsub('-', '') } else matches.find_all { |guard| guard.send(k).to_sym == v.to_sym } end end else @guards end end |
+ (Object) initialize_all_templates
Adds the templates of all installed Guard implementations to an existing Guardfile.
78 79 80 |
# File 'lib/guard.rb', line 78 def initialize_all_templates guard_gem_names.each {|g| initialize_template(g) } end |
+ (Object) initialize_template(guard_name)
Adds the Guardfile template of a Guard implementation to an existing Guardfile.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/guard.rb', line 51 def initialize_template(guard_name) guard_class = ::Guard.get_guard_class(guard_name, true) if guard_class guard_class.init(guard_name) elsif File.exist?(File.join(HOME_TEMPLATES, guard_name)) content = File.read('Guardfile') template = File.read(File.join(HOME_TEMPLATES, guard_name)) File.open('Guardfile', 'wb') do |f| f.puts(content) f.puts("") f.puts(template) end ::Guard::UI.info "#{ guard_name } template added to Guardfile, feel free to edit it" else const_name = guard_name.downcase.gsub('-', '') UI.error "Could not load 'guard/#{ guard_name.downcase }' or '~/.guard/templates/#{ guard_name.downcase }' or find class Guard::#{ const_name.capitalize }" end end |
+ (String) locate_guard(name)
Locate a path to a Guard gem.
509 510 511 512 513 514 515 516 517 |
# File 'lib/guard.rb', line 509 def locate_guard(name) if Gem::Version.create(Gem::VERSION) >= Gem::Version.create('1.8.0') Gem::Specification.find_by_name("guard-#{ name }").full_gem_path else Gem.source_index.find_name("guard-#{ name }").last.full_gem_path end rescue UI.error "Could not find 'guard-#{ name }' gem path." end |
+ (Object) pause
Pause Guard listening to file changes.
271 272 273 274 275 276 277 278 279 280 |
# File 'lib/guard.rb', line 271 def pause if listener.paused? UI.info 'Un-paused files modification listening', :reset => true listener.clear_changed_files listener.run else UI.info 'Paused files modification listening', :reset => true listener.pause end end |
+ (Object) reload(scopes)
Reload all Guards currently enabled.
249 250 251 252 253 254 255 |
# File 'lib/guard.rb', line 249 def reload(scopes) run do run_on_guards(scopes) do |guard| run_supervised_task(guard, :reload) end end end |
+ (Object) reset_groups
Initialize the groups array with the `:default` group.
184 185 186 |
# File 'lib/guard.rb', line 184 def reset_groups @groups = [Group.new(:default)] end |
+ (Object) run { ... }
Run a block where the listener and the interactor is blocked.
297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/guard.rb', line 297 def run UI.clear if [:clear] lock.synchronize do begin interactor.stop if interactor yield rescue Interrupt end interactor.start if interactor end end |
+ (Object) run_all(scopes)
Trigger `run_all` on all Guards currently enabled.
261 262 263 264 265 266 267 |
# File 'lib/guard.rb', line 261 def run_all(scopes) run do run_on_guards(scopes) do |guard| run_supervised_task(guard, :run_all) end end end |
+ (Object) run_on_change(files)
Trigger `run_on_change` on all Guards currently enabled.
284 285 286 287 288 289 290 |
# File 'lib/guard.rb', line 284 def run_on_change(files) run do run_on_guards do |guard| run_on_change_task(files, guard) end end end |
+ (Object) run_on_change_task(files, guard)
Run the `:run_on_change` task. When the option `:watch_all_modifications` is set, the task is split to run changed paths on Guard::Guard#run_on_change, whereas deleted paths run on Guard::Guard#run_on_deletion.
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/guard.rb', line 342 def run_on_change_task(files, guard) paths = Watcher.match_files(guard, files) changes = changed_paths(paths) deletions = deleted_paths(paths) unless changes.empty? UI.debug "#{ guard.class.name }#run_on_change with #{ changes.inspect }" run_supervised_task(guard, :run_on_change, changes) end unless deletions.empty? UI.debug "#{ guard.class.name }#run_on_deletion with #{ deletions.inspect }" run_supervised_task(guard, :run_on_deletion, deletions) end end |
+ (Object) run_on_guards(scopes = {}) { ... }
Loop through all groups and run the given task for each Guard.
Stop the task run for the all Guards within a group if one Guard throws `:task_has_failed`.
319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
# File 'lib/guard.rb', line 319 def run_on_guards(scopes = {}) if scope_guard = scopes[:guard] yield(scope_guard) else groups = scopes[:group] ? [scopes[:group]] : @groups groups.each do |group| catch :task_has_failed do guards(:group => group.name).each do |guard| yield(guard) end end end end end |
+ (Object) run_supervised_task(guard, task, *args)
Run a Guard task, but remove the Guard when his work leads to a system failure.
When the Group has `:halt_on_fail` disabled, we've to catch `:task_has_failed` here in order to avoid an uncaught throw error.
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
# File 'lib/guard.rb', line 392 def run_supervised_task(guard, task, *args) catch guard_symbol(guard) do guard.hook("#{ task }_begin", *args) result = guard.send(task, *args) guard.hook("#{ task }_end", result) result end rescue Exception => ex UI.error("#{ guard.class.name } failed to achieve its <#{ task.to_s }>, exception was:" + "\n#{ ex.class }: #{ ex. }\n#{ ex.backtrace.join("\n") }") guards.delete guard UI.info("\n#{ guard.class.name } has just been fired") ex end |
+ (Object) setup(options = {})
Initialize the Guard singleton:
-
Initialize the internal Guard state.
-
Create the interactor when necessary for user interaction.
-
Select and initialize the file change listener.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/guard.rb', line 96 def setup( = {}) @lock = Mutex.new @options = @guards = [] self.reset_groups @listener = Listener.select_and_init() if Signal.list.keys.include?('USR1') Signal.trap('USR1') { ::Guard.pause unless @listener.paused? } end if Signal.list.keys.include?('USR2') Signal.trap('USR2') { ::Guard.pause if @listener.paused? } end UI.clear if @options[:clear] debug_command_execution if @options[:verbose] self end |
+ (Object) start(options = {})
Start Guard by evaluate the `Guardfile`, initialize the declared Guards and start the available file change listener. Main method for Guard that is called from the CLI when guard starts.
-
Setup Guard internals
-
Evaluate the `Guardfile`
-
Configure Notifiers
-
Initialize the declared Guards
-
Start the available file change listener
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/guard.rb', line 205 def start( = {}) setup() Dsl.evaluate_guardfile() UI.error 'No guards found in Guardfile, please add at least one.' if ::Guard.guards.empty? [:notify] && ENV['GUARD_NOTIFY'] != 'false' ? Notifier.turn_on : Notifier.turn_off listener.on_change do |files| Dsl.reevaluate_guardfile if Watcher.match_guardfile?(files) listener.changed_files += files if Watcher.match_files?(guards, files) end UI.info "Guard is now watching at '#{ listener.directory }'" run_on_guards do |guard| run_supervised_task(guard, :start) end unless [:no_interactions] @interactor = Interactor.fabricate @interactor.start if @interactor end listener.start end |
+ (Object) stop
Stop Guard listening to file changes
234 235 236 237 238 239 240 241 242 243 |
# File 'lib/guard.rb', line 234 def stop run_on_guards do |guard| run_supervised_task(guard, :stop) end interactor.stop if interactor listener.stop UI.info 'Bye bye...', :reset => true end |