guard 1.4.0 → 2.18.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.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -677
  3. data/LICENSE +4 -2
  4. data/README.md +91 -753
  5. data/bin/_guard-core +11 -0
  6. data/bin/guard +108 -3
  7. data/lib/guard/aruba_adapter.rb +59 -0
  8. data/lib/guard/cli/environments/bundler.rb +22 -0
  9. data/lib/guard/cli/environments/evaluate_only.rb +35 -0
  10. data/lib/guard/cli/environments/valid.rb +69 -0
  11. data/lib/guard/cli.rb +129 -128
  12. data/lib/guard/commander.rb +104 -0
  13. data/lib/guard/commands/all.rb +37 -0
  14. data/lib/guard/commands/change.rb +31 -0
  15. data/lib/guard/commands/notification.rb +26 -0
  16. data/lib/guard/commands/pause.rb +29 -0
  17. data/lib/guard/commands/reload.rb +36 -0
  18. data/lib/guard/commands/scope.rb +38 -0
  19. data/lib/guard/commands/show.rb +24 -0
  20. data/lib/guard/config.rb +18 -0
  21. data/lib/guard/deprecated/dsl.rb +45 -0
  22. data/lib/guard/deprecated/evaluator.rb +39 -0
  23. data/lib/guard/deprecated/guard.rb +328 -0
  24. data/lib/guard/deprecated/guardfile.rb +84 -0
  25. data/lib/guard/deprecated/watcher.rb +27 -0
  26. data/lib/guard/dsl.rb +332 -363
  27. data/lib/guard/dsl_describer.rb +132 -122
  28. data/lib/guard/dsl_reader.rb +51 -0
  29. data/lib/guard/group.rb +34 -14
  30. data/lib/guard/guardfile/evaluator.rb +232 -0
  31. data/lib/guard/guardfile/generator.rb +128 -0
  32. data/lib/guard/guardfile.rb +24 -60
  33. data/lib/guard/interactor.rb +31 -255
  34. data/lib/guard/internals/debugging.rb +68 -0
  35. data/lib/guard/internals/groups.rb +40 -0
  36. data/lib/guard/internals/helpers.rb +13 -0
  37. data/lib/guard/internals/plugins.rb +53 -0
  38. data/lib/guard/internals/queue.rb +51 -0
  39. data/lib/guard/internals/scope.rb +121 -0
  40. data/lib/guard/internals/session.rb +180 -0
  41. data/lib/guard/internals/state.rb +25 -0
  42. data/lib/guard/internals/tracing.rb +33 -0
  43. data/lib/guard/internals/traps.rb +10 -0
  44. data/lib/guard/jobs/base.rb +21 -0
  45. data/lib/guard/jobs/pry_wrapper.rb +336 -0
  46. data/lib/guard/jobs/sleep.rb +26 -0
  47. data/lib/guard/notifier.rb +46 -212
  48. data/lib/guard/options.rb +22 -0
  49. data/lib/guard/plugin.rb +303 -0
  50. data/lib/guard/plugin_util.rb +191 -0
  51. data/lib/guard/rake_task.rb +42 -0
  52. data/lib/guard/runner.rb +80 -140
  53. data/lib/guard/templates/Guardfile +14 -0
  54. data/lib/guard/terminal.rb +13 -0
  55. data/lib/guard/ui/colors.rb +56 -0
  56. data/lib/guard/ui/config.rb +70 -0
  57. data/lib/guard/ui/logger.rb +30 -0
  58. data/lib/guard/ui.rb +163 -128
  59. data/lib/guard/version.rb +1 -2
  60. data/lib/guard/watcher/pattern/deprecated_regexp.rb +45 -0
  61. data/lib/guard/watcher/pattern/match_result.rb +18 -0
  62. data/lib/guard/watcher/pattern/matcher.rb +33 -0
  63. data/lib/guard/watcher/pattern/pathname_path.rb +15 -0
  64. data/lib/guard/watcher/pattern/simple_path.rb +23 -0
  65. data/lib/guard/watcher/pattern.rb +24 -0
  66. data/lib/guard/watcher.rb +52 -95
  67. data/lib/guard.rb +108 -376
  68. data/lib/tasks/releaser.rb +116 -0
  69. data/man/guard.1 +12 -9
  70. data/man/guard.1.html +18 -12
  71. metadata +148 -77
  72. data/images/guard.png +0 -0
  73. data/lib/guard/guard.rb +0 -156
  74. data/lib/guard/hook.rb +0 -120
  75. data/lib/guard/interactors/coolline.rb +0 -64
  76. data/lib/guard/interactors/helpers/completion.rb +0 -32
  77. data/lib/guard/interactors/helpers/terminal.rb +0 -46
  78. data/lib/guard/interactors/readline.rb +0 -94
  79. data/lib/guard/interactors/simple.rb +0 -19
  80. data/lib/guard/notifiers/emacs.rb +0 -69
  81. data/lib/guard/notifiers/gntp.rb +0 -118
  82. data/lib/guard/notifiers/growl.rb +0 -99
  83. data/lib/guard/notifiers/growl_notify.rb +0 -92
  84. data/lib/guard/notifiers/libnotify.rb +0 -96
  85. data/lib/guard/notifiers/notifysend.rb +0 -84
  86. data/lib/guard/notifiers/rb_notifu.rb +0 -102
  87. data/lib/guard/notifiers/terminal_notifier.rb +0 -66
  88. data/lib/guard/notifiers/tmux.rb +0 -69
  89. data/lib/guard/version.rbc +0 -130
data/lib/guard/runner.rb CHANGED
@@ -1,62 +1,40 @@
1
- module Guard
1
+ require "lumberjack"
2
+
3
+ require "guard/ui"
4
+ require "guard/watcher"
2
5
 
3
- # The runner is responsible for running all methods defined on each guards.
6
+ module Guard
7
+ # The runner is responsible for running all methods defined on each plugin.
4
8
  #
5
9
  class Runner
6
-
7
- require 'guard'
8
- require 'guard/ui'
9
- require 'guard/watcher'
10
-
11
- # Deprecation message for the `run_on_change` method
12
- RUN_ON_CHANGE_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
13
- Starting with Guard v1.1 the use of the 'run_on_change' method in the '%s' guard is deprecated.
14
-
15
- Please consider replacing that method-call with 'run_on_changes' if the type of change
16
- is not important for your usecase or using either 'run_on_modifications' or 'run_on_additions'
17
- based on the type of the changes you want to handle.
18
-
19
- For more information on how to update existing guards, please head over to:
20
- https://github.com/guard/guard/wiki/Upgrade-guide-for-existing-guards-to-Guard-v1.1
21
- EOS
22
-
23
- # Deprecation message for the `run_on_deletion` method
24
- RUN_ON_DELETION_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
25
- Starting with Guard v1.1 the use of the 'run_on_deletion' method in the '%s' guard is deprecated.
26
-
27
- Please consider replacing that method-call with 'run_on_removals' for future proofing your code.
28
-
29
- For more information on how to update existing guards, please head over to:
30
- https://github.com/guard/guard/wiki/Upgrade-guide-for-existing-guards-to-Guard-v1.1
31
- EOS
32
-
33
- # Displays a warning for each deprecated-method used is any registered guard.
34
- #
35
- def deprecation_warning
36
- ::Guard.guards.each do |guard|
37
- ::Guard::UI.deprecation(RUN_ON_CHANGE_DEPRECATION % guard.class.name) if guard.respond_to?(:run_on_change)
38
- ::Guard::UI.deprecation(RUN_ON_DELETION_DEPRECATION % guard.class.name) if guard.respond_to?(:run_on_deletion)
39
- end
40
- end
41
-
42
- # Runs a Guard-task on all registered guards.
10
+ # Runs a Guard-task on all registered plugins.
43
11
  #
44
12
  # @param [Symbol] task the task to run
45
- # @param [Hash] scopes either the Guard plugin or the group to run the task on
46
13
  #
47
- # @see self.run_supervised_task
14
+ # @param [Hash] scope_hash either the Guard plugin or the group to run the task
15
+ # on
48
16
  #
49
- def run(task, scopes = {})
50
- scoped_guards(scopes) do |guard|
51
- run_supervised_task(guard, task)
17
+ def run(task, scope_hash = {})
18
+ Lumberjack.unit_of_work do
19
+ items = Guard.state.scope.grouped_plugins(scope_hash || {})
20
+ items.each do |_group, plugins|
21
+ _run_group_plugins(plugins) do |plugin|
22
+ _supervise(plugin, task) if plugin.respond_to?(task)
23
+ end
24
+ end
52
25
  end
53
26
  end
54
27
 
55
- MODIFICATION_TASKS = [:run_on_modifications, :run_on_changes, :run_on_change]
56
- ADDITION_TASKS = [:run_on_additions, :run_on_changes, :run_on_change]
57
- REMOVAL_TASKS = [:run_on_removals, :run_on_changes, :run_on_deletion]
28
+ PLUGIN_FAILED = "%s has failed, other group's plugins will be skipped."
58
29
 
59
- # Runs the appropriate tasks on all registered guards
30
+ MODIFICATION_TASKS = [
31
+ :run_on_modifications, :run_on_changes, :run_on_change
32
+ ]
33
+
34
+ ADDITION_TASKS = [:run_on_additions, :run_on_changes, :run_on_change]
35
+ REMOVAL_TASKS = [:run_on_removals, :run_on_changes, :run_on_deletion]
36
+
37
+ # Runs the appropriate tasks on all registered plugins
60
38
  # based on the passed changes.
61
39
  #
62
40
  # @param [Array<String>] modified the modified paths.
@@ -64,50 +42,60 @@ module Guard
64
42
  # @param [Array<String>] removed the removed paths.
65
43
  #
66
44
  def run_on_changes(modified, added, removed)
67
- ::Guard::UI.clearable
68
- scoped_guards do |guard|
69
- modified_paths = ::Guard::Watcher.match_files(guard, modified)
70
- added_paths = ::Guard::Watcher.match_files(guard, added)
71
- removed_paths = ::Guard::Watcher.match_files(guard, removed)
72
-
73
- ::Guard::UI.clear if clearable?(guard, modified_paths, added_paths, removed_paths)
74
-
75
- run_first_task_found(guard, MODIFICATION_TASKS, modified_paths) unless modified_paths.empty?
76
- run_first_task_found(guard, ADDITION_TASKS, added_paths) unless added_paths.empty?
77
- run_first_task_found(guard, REMOVAL_TASKS, removed_paths) unless removed_paths.empty?
45
+ types = {
46
+ MODIFICATION_TASKS => modified,
47
+ ADDITION_TASKS => added,
48
+ REMOVAL_TASKS => removed
49
+ }
50
+
51
+ UI.clearable
52
+
53
+ Guard.state.scope.grouped_plugins.each do |_group, plugins|
54
+ _run_group_plugins(plugins) do |plugin|
55
+ UI.clear
56
+ types.each do |tasks, unmatched_paths|
57
+ next if unmatched_paths.empty?
58
+ match_result = Watcher.match_files(plugin, unmatched_paths)
59
+ next if match_result.empty?
60
+ task = tasks.detect { |meth| plugin.respond_to?(meth) }
61
+ _supervise(plugin, task, match_result) if task
62
+ end
63
+ end
78
64
  end
79
65
  end
80
66
 
81
- # Run a Guard plugin task, but remove the Guard plugin when his work leads to a system failure.
67
+ # Run a Guard plugin task, but remove the Guard plugin when his work leads
68
+ # to a system failure.
82
69
  #
83
- # When the Group has `:halt_on_fail` disabled, we've to catch `:task_has_failed`
84
- # here in order to avoid an uncaught throw error.
70
+ # When the Group has `:halt_on_fail` disabled, we've to catch
71
+ # `:task_has_failed` here in order to avoid an uncaught throw error.
85
72
  #
86
- # @param [Guard::Guard] guard the Guard to execute
73
+ # @param [Guard::Plugin] plugin guard the Guard to execute
87
74
  # @param [Symbol] task the task to run
88
75
  # @param [Array] args the arguments for the task
89
76
  # @raise [:task_has_failed] when task has failed
90
77
  #
91
- def run_supervised_task(guard, task, *args)
92
- begin
93
- catch Runner.stopping_symbol_for(guard) do
94
- guard.hook("#{ task }_begin", *args)
95
- result = guard.send(task, *args)
96
- guard.hook("#{ task }_end", result)
97
- result
78
+ def _supervise(plugin, task, *args)
79
+ catch self.class.stopping_symbol_for(plugin) do
80
+ plugin.hook("#{ task }_begin", *args)
81
+ result = UI.options.with_progname(plugin.class.name) do
82
+ begin
83
+ plugin.send(task, *args)
84
+ rescue Interrupt
85
+ throw(:task_has_failed)
86
+ end
98
87
  end
99
-
100
- rescue NoMethodError
101
- # Do nothing
102
- rescue Exception => ex
103
- ::Guard::UI.error("#{ guard.class.name } failed to achieve its <#{ task.to_s }>, exception was:" +
104
- "\n#{ ex.class }: #{ ex.message }\n#{ ex.backtrace.join("\n") }")
105
-
106
- ::Guard.guards.delete guard
107
- ::Guard::UI.info("\n#{ guard.class.name } has just been fired")
108
-
109
- ex
88
+ plugin.hook("#{ task }_end", result)
89
+ result
110
90
  end
91
+ rescue ScriptError, StandardError, RuntimeError
92
+ UI.error("#{ plugin.class.name } failed to achieve its"\
93
+ " <#{ task }>, exception was:" \
94
+ "\n#{ $!.class }: #{ $!.message }" \
95
+ "\n#{ $!.backtrace.join("\n") }")
96
+ Guard.state.session.plugins.remove(plugin)
97
+ UI.info("\n#{ plugin.class.name } has just been fired")
98
+ $!
111
99
  end
112
100
 
113
101
  # Returns the symbol that has to be caught when running a supervised task.
@@ -115,74 +103,26 @@ module Guard
115
103
  # @note If a Guard group is being run and it has the `:halt_on_fail`
116
104
  # option set, this method returns :no_catch as it will be caught at the
117
105
  # group level.
118
- # @see .scoped_guards
119
106
  #
120
- # @param [Guard::Guard] guard the Guard plugin to execute
107
+ # @param [Guard::Plugin] guard the Guard plugin to execute
121
108
  # @return [Symbol] the symbol to catch
122
109
  #
123
110
  def self.stopping_symbol_for(guard)
124
- return :task_has_failed if guard.group.class != Symbol
125
-
126
- group = ::Guard.groups(guard.group)
127
- group.options[:halt_on_fail] ? :no_catch : :task_has_failed
111
+ guard.group.options[:halt_on_fail] ? :no_catch : :task_has_failed
128
112
  end
129
113
 
130
- private
114
+ private
131
115
 
132
- # Tries to run the first implemented task by a given guard
133
- # from a collection of tasks.
134
- #
135
- # @param [Guard::Guard] guard the Guard plugin to run the first found task on
136
- # @param [Array<Symbol>] tasks the tasks to run the first among
137
- # @param [Object] task_param the param to pass to each task
138
- #
139
- def run_first_task_found(guard, tasks, task_param)
140
- tasks.each do |task|
141
- if guard.respond_to?(task)
142
- run_supervised_task(guard, task, task_param)
143
- break
144
- else
145
- ::Guard::UI.debug "Trying to run #{ guard.class.name }##{ task.to_s } with #{ task_param.inspect }"
116
+ def _run_group_plugins(plugins)
117
+ failed_plugin = nil
118
+ catch :task_has_failed do
119
+ plugins.each do |plugin|
120
+ failed_plugin = plugin
121
+ yield plugin
122
+ failed_plugin = nil
146
123
  end
147
124
  end
125
+ UI.info format(PLUGIN_FAILED, failed_plugin.class.name) if failed_plugin
148
126
  end
149
-
150
- # Loop through all groups and run the given task for each Guard plugin.
151
- #
152
- # Stop the task run for the all Guard plugins within a group if one Guard
153
- # throws `:task_has_failed`.
154
- #
155
- # @param [Hash] scopes hash with a Guard plugin or a group scope
156
- # @yield the task to run
157
- #
158
- def scoped_guards(scopes = {})
159
- if guard = scopes[:guard]
160
- yield(guard)
161
- else
162
- groups = scopes[:group] ? [scopes[:group]] : ::Guard.groups
163
- groups.each do |group|
164
- catch :task_has_failed do
165
- ::Guard.guards(:group => group.name).each do |guard|
166
- yield(guard)
167
- end
168
- end
169
- end
170
- end
171
- end
172
-
173
- # Logic to know if the UI can be cleared or not in the run_on_changes method
174
- # based on the guard and the changes.
175
- #
176
- # @param [Guard::Guard] guard the Guard plugin where run_on_changes is called
177
- # @param [Array<String>] modified_paths the modified paths.
178
- # @param [Array<String>] added_paths the added paths.
179
- # @param [Array<String>] removed_paths the removed paths.
180
- #
181
- def clearable?(guard, modified_paths, added_paths, removed_paths)
182
- (MODIFICATION_TASKS.any? { |task| guard.respond_to?(task) } && !modified_paths.empty?) ||
183
- (ADDITION_TASKS.any? { |task| guard.respond_to?(task) } && !added_paths.empty?) ||
184
- (REMOVAL_TASKS.any? { |task| guard.respond_to?(task) } && !removed_paths.empty?)
185
- end
186
-
187
127
  end
188
128
  end
@@ -1,2 +1,16 @@
1
1
  # A sample Guardfile
2
2
  # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ # directories %w(app lib config test spec features) \
6
+ # .select{|d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist")}
7
+
8
+ ## Note: if you are using the `directories` clause above and you are not
9
+ ## watching the project directory ('.'), then you will want to move
10
+ ## the Guardfile to a watched dir and symlink it back, e.g.
11
+ #
12
+ # $ mkdir config
13
+ # $ mv Guardfile config/
14
+ # $ ln -s config/Guardfile .
15
+ #
16
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
@@ -0,0 +1,13 @@
1
+ require "shellany/sheller"
2
+
3
+ module Guard
4
+ class Terminal
5
+ class << self
6
+ def clear
7
+ cmd = Gem.win_platform? ? "cls" : "printf '\33c\e[3J';"
8
+ exit_code, _, stderr = Shellany::Sheller.system(cmd)
9
+ fail Errno::ENOENT, stderr unless exit_code == 0
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,56 @@
1
+ module Guard
2
+ module UI
3
+ module Colors
4
+ # Brighten the color
5
+ ANSI_ESCAPE_BRIGHT = "1"
6
+
7
+ # Black foreground color
8
+ ANSI_ESCAPE_BLACK = "30"
9
+
10
+ # Red foreground color
11
+ ANSI_ESCAPE_RED = "31"
12
+
13
+ # Green foreground color
14
+ ANSI_ESCAPE_GREEN = "32"
15
+
16
+ # Yellow foreground color
17
+ ANSI_ESCAPE_YELLOW = "33"
18
+
19
+ # Blue foreground color
20
+ ANSI_ESCAPE_BLUE = "34"
21
+
22
+ # Magenta foreground color
23
+ ANSI_ESCAPE_MAGENTA = "35"
24
+
25
+ # Cyan foreground color
26
+ ANSI_ESCAPE_CYAN = "36"
27
+
28
+ # White foreground color
29
+ ANSI_ESCAPE_WHITE = "37"
30
+
31
+ # Black background color
32
+ ANSI_ESCAPE_BGBLACK = "40"
33
+
34
+ # Red background color
35
+ ANSI_ESCAPE_BGRED = "41"
36
+
37
+ # Green background color
38
+ ANSI_ESCAPE_BGGREEN = "42"
39
+
40
+ # Yellow background color
41
+ ANSI_ESCAPE_BGYELLOW = "43"
42
+
43
+ # Blue background color
44
+ ANSI_ESCAPE_BGBLUE = "44"
45
+
46
+ # Magenta background color
47
+ ANSI_ESCAPE_BGMAGENTA = "45"
48
+
49
+ # Cyan background color
50
+ ANSI_ESCAPE_BGCYAN = "46"
51
+
52
+ # White background color
53
+ ANSI_ESCAPE_BGWHITE = "47"
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,70 @@
1
+ require "guard/options"
2
+ require "guard/ui/logger"
3
+
4
+ module Guard
5
+ module UI
6
+ class Config < Guard::Options
7
+ DEFAULTS = {
8
+ only: nil,
9
+ except: nil,
10
+
11
+ # nil (will be whatever $stderr is later) or LumberJack device, e.g.
12
+ # $stderr or 'foo.log'
13
+ device: nil,
14
+ }.freeze
15
+
16
+ DEPRECATED_OPTS = %w(template time_format level progname).freeze
17
+
18
+ attr_reader :logger_config
19
+
20
+ def initialize(options = {})
21
+ opts = Guard::Options.new(options, DEFAULTS)
22
+
23
+ # migrate old options stored in UI config directly
24
+ deprecated_logger_opts = {}
25
+ DEPRECATED_OPTS.each do |option|
26
+ if opts.key?(option)
27
+ deprecated_logger_opts[option.to_sym] = opts.delete(option)
28
+ end
29
+ end
30
+
31
+ @logger_config = Logger::Config.new(deprecated_logger_opts)
32
+ super(opts.to_hash)
33
+ end
34
+
35
+ def device
36
+ # Use strings to work around Thor's indifferent Hash's bug
37
+ fetch("device") || $stderr
38
+ end
39
+
40
+ def only
41
+ fetch("only")
42
+ end
43
+
44
+ def except
45
+ fetch("except")
46
+ end
47
+
48
+ def [](name)
49
+ name = name.to_s
50
+
51
+ # TODO: remove in Guard 3.x
52
+ return logger_config[name] if DEPRECATED_OPTS.include?(name)
53
+ return device if name == "device"
54
+
55
+ # let Thor's Hash handle anything else
56
+ super(name.to_s)
57
+ end
58
+
59
+ def with_progname(name)
60
+ if Guard::UI.logger.respond_to?(:set_progname)
61
+ Guard::UI.logger.set_progname(name) do
62
+ yield if block_given?
63
+ end
64
+ elsif block_given?
65
+ yield
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,30 @@
1
+ require "guard/options"
2
+
3
+ module Guard
4
+ module UI
5
+ class Logger
6
+ class Config < Guard::Options
7
+ DEFAULTS = {
8
+ progname: "Guard",
9
+ level: :info,
10
+ template: ":time - :severity - :message",
11
+ time_format: "%H:%M:%S",
12
+ flush_seconds: 0,
13
+
14
+ # Other LumberJack device-specific options
15
+ # max_size: "5M",
16
+ # buffer_size: 0,
17
+ # additional_lines: nil,
18
+ }.freeze
19
+
20
+ def initialize(options = {})
21
+ super(options, DEFAULTS)
22
+ end
23
+
24
+ def level=(value)
25
+ self["level"] = value
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end