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
@@ -0,0 +1,336 @@
1
+ require "guard/commands/all"
2
+ require "guard/commands/change"
3
+ require "guard/commands/notification"
4
+ require "guard/commands/pause"
5
+ require "guard/commands/reload"
6
+ require "guard/commands/scope"
7
+ require "guard/commands/show"
8
+ require "shellany/sheller"
9
+
10
+ require "guard/jobs/base"
11
+
12
+ module Guard
13
+ module Jobs
14
+ class TerminalSettings
15
+ def initialize
16
+ @settings = nil
17
+ @works = Shellany::Sheller.run("hash", "stty") || false
18
+ end
19
+
20
+ def restore
21
+ return unless configurable? && @settings
22
+ Shellany::Sheller.run("stty #{ @setting } 2>#{IO::NULL}")
23
+ end
24
+
25
+ def save
26
+ return unless configurable?
27
+ @settings = Shellany::Sheller.stdout("stty -g 2>#{IO::NULL}").chomp
28
+ end
29
+
30
+ def echo
31
+ return unless configurable?
32
+ Shellany::Sheller.run("stty echo 2>#{IO::NULL}")
33
+ end
34
+
35
+ def configurable?
36
+ @works
37
+ end
38
+ end
39
+
40
+ class PryWrapper < Base
41
+ # The default Ruby script to configure Guard Pry if the option `:guard_rc`
42
+ # is not defined.
43
+
44
+ GUARD_RC = if ENV["XDG_CONFIG_HOME"] && File.exist?(ENV["XDG_CONFIG_HOME"] + "/guard/guardrc")
45
+ ENV["XDG_CONFIG_HOME"] + "/guard/guardrc"
46
+ else
47
+ "~/.guardrc"
48
+ end
49
+
50
+ # The default Guard Pry history file if the option `:history_file` is not
51
+ # defined.
52
+
53
+ HISTORY_FILE = if ENV["XDG_DATA_HOME"] && File.exist?(ENV["XDG_DATA_HOME"] + "/guard/history")
54
+ ENV["XDG_DATA_HOME"] + "/guard/history"
55
+ else
56
+ "~/.guard_history"
57
+ end
58
+
59
+ # List of shortcuts for each interactor command
60
+ SHORTCUTS = {
61
+ help: "h",
62
+ all: "a",
63
+ reload: "r",
64
+ change: "c",
65
+ show: "s",
66
+ scope: "o",
67
+ notification: "n",
68
+ pause: "p",
69
+ exit: "e",
70
+ quit: "q"
71
+ }
72
+
73
+ def initialize(options)
74
+ @mutex = Mutex.new
75
+ @thread = nil
76
+ @terminal_settings = TerminalSettings.new
77
+
78
+ _setup(options)
79
+ end
80
+
81
+ def foreground
82
+ UI.debug "Start interactor"
83
+ @terminal_settings.save
84
+
85
+ _switch_to_pry
86
+ # TODO: rename :stopped to continue
87
+ _killed? ? :stopped : :exit
88
+ ensure
89
+ UI.reset_line
90
+ UI.debug "Interactor was stopped or killed"
91
+ @terminal_settings.restore
92
+ end
93
+
94
+ def background
95
+ _kill_pry
96
+ end
97
+
98
+ def handle_interrupt
99
+ thread = @thread
100
+ fail Interrupt unless thread
101
+ thread.raise Interrupt
102
+ end
103
+
104
+ private
105
+
106
+ attr_reader :thread
107
+
108
+ def _pry_config
109
+ Pry.config
110
+ end
111
+
112
+ def _pry_commands
113
+ Pry.commands
114
+ end
115
+
116
+ def _switch_to_pry
117
+ th = nil
118
+ @mutex.synchronize do
119
+ unless @thread
120
+ @thread = Thread.new { Pry.start }
121
+ @thread.join(0.5) # give pry a chance to start
122
+ th = @thread
123
+ end
124
+ end
125
+ # check for nill, because it might've been killed between the mutex and
126
+ # now
127
+ th.join unless th.nil?
128
+ end
129
+
130
+ def _killed?
131
+ th = nil
132
+ @mutex.synchronize { th = @thread }
133
+ th.nil?
134
+ end
135
+
136
+ def _kill_pry
137
+ @mutex.synchronize do
138
+ unless @thread.nil?
139
+ @thread.kill
140
+ @thread = nil # set to nil so we know we were killed
141
+ end
142
+ end
143
+ end
144
+
145
+ def _setup(options)
146
+ _pry_config.should_load_rc = false
147
+ _pry_config.should_load_local_rc = false
148
+
149
+ _configure_history_file(options[:history_file] || HISTORY_FILE)
150
+ _add_hooks(options)
151
+
152
+ Commands::All.import
153
+ Commands::Change.import
154
+ Commands::Notification.import
155
+ Commands::Pause.import
156
+ Commands::Reload.import
157
+ Commands::Show.import
158
+ Commands::Scope.import
159
+
160
+ _setup_commands
161
+ _configure_prompt
162
+ end
163
+
164
+ def _configure_history_file(history_file)
165
+ history_file_path = File.expand_path(history_file)
166
+
167
+ # Pry >= 0.13
168
+ if _pry_config.respond_to?(:history_file=)
169
+ _pry_config.history_file = history_file_path
170
+ else
171
+ _pry_config.history.file = history_file_path
172
+ end
173
+ end
174
+
175
+ # Add Pry hooks:
176
+ #
177
+ # * Load `~/.guardrc` within each new Pry session.
178
+ # * Load project's `.guardrc` within each new Pry session.
179
+ # * Restore prompt after each evaluation.
180
+ #
181
+ def _add_hooks(options)
182
+ _add_load_guard_rc_hook(Pathname(options[:guard_rc] || GUARD_RC))
183
+ _add_load_project_guard_rc_hook(Pathname.pwd + ".guardrc")
184
+ _add_restore_visibility_hook if @terminal_settings.configurable?
185
+ end
186
+
187
+ # Add a `when_started` hook that loads a global .guardrc if it exists.
188
+ #
189
+ def _add_load_guard_rc_hook(guard_rc)
190
+ _pry_config.hooks.add_hook :when_started, :load_guard_rc do
191
+ guard_rc.expand_path.tap { |p| load p if p.exist? }
192
+ end
193
+ end
194
+
195
+ # Add a `when_started` hook that loads a project .guardrc if it exists.
196
+ #
197
+ def _add_load_project_guard_rc_hook(guard_rc)
198
+ _pry_config.hooks.add_hook :when_started, :load_project_guard_rc do
199
+ load guard_rc if guard_rc.exist?
200
+ end
201
+ end
202
+
203
+ # Add a `after_eval` hook that restores visibility after a command is
204
+ # eval.
205
+ def _add_restore_visibility_hook
206
+ _pry_config.hooks.add_hook :after_eval, :restore_visibility do
207
+ @terminal_settings.echo
208
+ end
209
+ end
210
+
211
+ def _setup_commands
212
+ _replace_reset_command
213
+ _create_run_all_command
214
+ _create_command_aliases
215
+ _create_guard_commands
216
+ _create_group_commands
217
+ end
218
+
219
+ # Replaces reset defined inside of Pry with a reset that
220
+ # instead restarts guard.
221
+ #
222
+ def _replace_reset_command
223
+ _pry_commands.command "reset", "Reset the Guard to a clean state." do
224
+ output.puts "Guard reset."
225
+ exec "guard"
226
+ end
227
+ end
228
+
229
+ # Creates a command that triggers the `:run_all` action
230
+ # when the command is empty (just pressing enter on the
231
+ # beginning of a line).
232
+ #
233
+ def _create_run_all_command
234
+ _pry_commands.block_command(/^$/, "Hit enter to run all") do
235
+ Pry.run_command "all"
236
+ end
237
+ end
238
+
239
+ # Creates command aliases for the commands: `help`, `reload`, `change`,
240
+ # `scope`, `notification`, `pause`, `exit` and `quit`, which will be the
241
+ # first letter of the command.
242
+ #
243
+ def _create_command_aliases
244
+ SHORTCUTS.each do |command, shortcut|
245
+ _pry_commands.alias_command shortcut, command.to_s
246
+ end
247
+ end
248
+
249
+ # Create a shorthand command to run the `:run_all`
250
+ # action on a specific Guard plugin. For example,
251
+ # when guard-rspec is available, then a command
252
+ # `rspec` is created that runs `all rspec`.
253
+ #
254
+ def _create_guard_commands
255
+ Guard.state.session.plugins.all.each do |guard_plugin|
256
+ cmd = "Run all #{guard_plugin.title}"
257
+ _pry_commands.create_command guard_plugin.name, cmd do
258
+ group "Guard"
259
+
260
+ def process
261
+ Pry.run_command "all #{ match }"
262
+ end
263
+ end
264
+ end
265
+ end
266
+
267
+ # Create a shorthand command to run the `:run_all`
268
+ # action on a specific Guard group. For example,
269
+ # when you have a group `frontend`, then a command
270
+ # `frontend` is created that runs `all frontend`.
271
+ #
272
+ def _create_group_commands
273
+ Guard.state.session.groups.all.each do |group|
274
+ next if group.name == :default
275
+
276
+ cmd = "Run all #{group.title}"
277
+ _pry_commands.create_command group.name.to_s, cmd do
278
+ group "Guard"
279
+
280
+ def process
281
+ Pry.run_command "all #{ match }"
282
+ end
283
+ end
284
+ end
285
+ end
286
+
287
+ # Configures the pry prompt to see `guard` instead of
288
+ # `pry`.
289
+ #
290
+ def _configure_prompt
291
+ prompt_procs = [_prompt(">"), _prompt("*")]
292
+ prompt =
293
+ if Pry::Prompt.is_a?(Class)
294
+ Pry::Prompt.new("Guard", "Guard Pry prompt", prompt_procs)
295
+ else
296
+ prompt_procs
297
+ end
298
+
299
+ _pry_config.prompt = prompt
300
+ end
301
+
302
+ # Returns the plugins scope, or the groups scope ready for display in the
303
+ # prompt.
304
+ #
305
+ def _scope_for_prompt
306
+ titles = Guard.state.scope.titles.join(",")
307
+ titles == "all" ? "" : titles + " "
308
+ end
309
+
310
+ # Returns a proc that will return itself a string ending with the given
311
+ # `ending_char` when called.
312
+ #
313
+ def _prompt(ending_char)
314
+ proc do |target_self, nest_level, pry|
315
+ process = Guard.listener.paused? ? "pause" : "guard"
316
+ level = ":#{ nest_level }" unless nest_level.zero?
317
+
318
+ "[#{ _history(pry) }] #{ _scope_for_prompt }#{ process }"\
319
+ "(#{ _clip_name(target_self) })#{ level }#{ ending_char } "
320
+ end
321
+ end
322
+
323
+ def _clip_name(target)
324
+ Pry.view_clip(target)
325
+ end
326
+
327
+ def _history(pry)
328
+ if pry.respond_to?(:input_ring)
329
+ pry.input_ring.size
330
+ else
331
+ pry.input_array.size
332
+ end
333
+ end
334
+ end
335
+ end
336
+ end
@@ -0,0 +1,26 @@
1
+ require "guard/jobs/base"
2
+ require "guard/ui"
3
+
4
+ module Guard
5
+ module Jobs
6
+ class Sleep < Base
7
+ def foreground
8
+ UI.debug "Guards jobs done. Sleeping..."
9
+ sleep
10
+ UI.debug "Sleep interrupted by events."
11
+ :stopped
12
+ rescue Interrupt
13
+ UI.debug "Sleep interrupted by user."
14
+ :exit
15
+ end
16
+
17
+ def background
18
+ Thread.main.wakeup
19
+ end
20
+
21
+ def handle_interrupt
22
+ Thread.main.raise Interrupt
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,237 +1,71 @@
1
- require 'yaml'
2
- require 'rbconfig'
3
- require 'pathname'
1
+ require "notiffany/notifier"
2
+ require "guard/ui"
4
3
 
5
4
  module Guard
6
-
7
- # The notifier handles sending messages to different notifiers. Currently the following
8
- # libraries are supported:
9
- #
10
- # * Ruby GNTP
11
- # * Growl
12
- # * GrowlNotify
13
- # * Libnotify
14
- # * rb-notifu
15
- # * emacs
16
- # * Terminal Notifier
17
- # * Tmux
18
- #
19
- # Please see the documentation of each notifier for more information about the requirements
20
- # and configuration possibilities.
21
- #
22
- # Guard knows four different notification types:
23
- #
24
- # * success
25
- # * pending
26
- # * failed
27
- # * notify
28
- #
29
- # The notification type selection is based on the image option that is
30
- # sent to {#notify}. Each image type has its own notification type, and
31
- # notifications with custom images goes all sent as type `notify`. The
32
- # `gntp` and `growl_notify` notifiers are able to register these types
33
- # at Growl and allows customization of each notification type.
34
- #
35
- # Guard can be configured to make use of more than one notifier at once, @see Guard::Dsl
36
- #
37
- module Notifier
38
-
39
- require 'guard'
40
- require 'guard/ui'
41
- require 'guard/notifiers/gntp'
42
- require 'guard/notifiers/growl'
43
- require 'guard/notifiers/growl_notify'
44
- require 'guard/notifiers/libnotify'
45
- require 'guard/notifiers/notifysend'
46
- require 'guard/notifiers/rb_notifu'
47
- require 'guard/notifiers/emacs'
48
- require 'guard/notifiers/terminal_notifier'
49
- require 'guard/notifiers/tmux'
50
-
51
- extend self
52
-
53
- # List of available notifiers. It needs to be a nested hash instead of
54
- # a simpler Hash, because it maintains its order on Ruby 1.8.7 also.
55
- NOTIFIERS = [
56
- [:growl, ::Guard::Notifier::Growl],
57
- [:gntp, ::Guard::Notifier::GNTP],
58
- [:growl_notify, ::Guard::Notifier::GrowlNotify],
59
- [:libnotify, ::Guard::Notifier::Libnotify],
60
- [:notifysend, ::Guard::Notifier::NotifySend],
61
- [:notifu, ::Guard::Notifier::Notifu],
62
- [:emacs, ::Guard::Notifier::Emacs],
63
- [:terminal_notifier, ::Guard::Notifier::TerminalNotifier],
64
- [:tmux, ::Guard::Notifier::Tmux]
65
- ]
66
-
67
- # Get the available notifications.
68
- #
69
- # @return [Hash] the notifications
70
- #
71
- def notifications
72
- ENV['GUARD_NOTIFICATIONS'] ? YAML::load(ENV['GUARD_NOTIFICATIONS']) : []
73
- end
74
-
75
- # Set the available notifications.
76
- #
77
- # @param [Array<Hash>] notifications the notifications
78
- #
79
- def notifications=(notifications)
80
- ENV['GUARD_NOTIFICATIONS'] = YAML::dump(notifications)
5
+ class Notifier
6
+ def self.connect(options = {})
7
+ @notifier ||= nil
8
+ fail "Already connected!" if @notifier
9
+ begin
10
+ opts = options.merge(namespace: "guard", logger: UI)
11
+ @notifier = Notiffany.connect(opts)
12
+ rescue Notiffany::Notifier::Detected::UnknownNotifier => e
13
+ UI.error "Failed to setup notification: #{e.message}"
14
+ fail
15
+ end
81
16
  end
82
17
 
83
- # Clear available notifications.
84
- #
85
- def clear_notifications
86
- ENV['GUARD_NOTIFICATIONS'] = nil
18
+ def self.disconnect
19
+ @notifier && @notifier.disconnect
20
+ @notifier = nil
87
21
  end
88
22
 
89
- # Turn notifications on. If no notifications are defined
90
- # in the `Guardfile` Guard auto detects the first available
91
- # library.
92
- #
93
- def turn_on
94
- auto_detect_notification if notifications.empty? && (!::Guard.options || ::Guard.options[:notify])
95
-
96
- if notifications.empty?
97
- ENV['GUARD_NOTIFY'] = 'false'
98
- else
99
- notifications.each do |notification|
100
- ::Guard::UI.info "Guard uses #{ get_notifier_module(notification[:name]).to_s.split('::').last } to send notifications."
101
- end
23
+ DEPRECATED_IMPLICIT_CONNECT = "Calling Notiffany::Notifier.notify()"\
24
+ " without a prior Notifier.connect() is"\
25
+ " deprecated"
102
26
 
103
- ENV['GUARD_NOTIFY'] = 'true'
27
+ def self.notify(message, options = {})
28
+ unless @notifier
29
+ # TODO: reenable again?
30
+ # UI.deprecation(DEPRECTED_IMPLICIT_CONNECT)
31
+ connect(notify: true)
104
32
  end
105
- end
106
33
 
107
- # Turn notifications off.
108
- #
109
- def turn_off
110
- ENV['GUARD_NOTIFY'] = 'false'
34
+ @notifier.notify(message, options)
35
+ rescue RuntimeError => e
36
+ UI.error "Notification failed for #{@notifier.class.name}: #{e.message}"
37
+ UI.debug e.backtrace.join("\n")
111
38
  end
112
39
 
113
- # Test if the notifications are on.
114
- #
115
- # @return [Boolean] whether the notifications are on
116
- #
117
- def enabled?
118
- ENV['GUARD_NOTIFY'] == 'true'
40
+ def self.turn_on
41
+ @notifier.turn_on
119
42
  end
120
43
 
121
- # Add a notification library to be used.
122
- #
123
- # @param [Symbol] name the name of the notifier to use
124
- # @param [Boolean] silent disable any error message
125
- # @param [Hash] options the notifier options
126
- # @return [Boolean] if the notification could be added
127
- #
128
- def add_notification(name, options = { }, silent = false)
129
- return turn_off if name == :off
130
-
131
- notifier = get_notifier_module(name)
132
-
133
- if notifier && notifier.available?(silent)
134
- self.notifications = notifications << { :name => name, :options => options }
135
- true
136
- else
137
- false
44
+ def self.toggle
45
+ unless @notifier.enabled?
46
+ UI.error NOTIFICATIONS_DISABLED
47
+ return
138
48
  end
139
- end
140
-
141
- # Show a system notification with all configured notifiers.
142
- #
143
- # @param [String] message the message to show
144
- # @option options [Symbol, String] image the image symbol or path to an image
145
- # @option options [String] title the notification title
146
- #
147
- def notify(message, options = { })
148
- if enabled?
149
- type = notification_type(options[:image] || :success)
150
- image = image_path(options.delete(:image) || :success)
151
- title = options.delete(:title) || 'Guard'
152
49
 
153
- notifications.each do |notification|
154
- begin
155
- get_notifier_module(notification[:name]).notify(type, title, message, image, options.merge(notification[:options]))
156
- rescue Exception => e
157
- ::Guard::UI.error "Error sending notification with #{ notification[:name] }: #{ e.message }"
158
- end
159
- end
50
+ if @notifier.active?
51
+ UI.info "Turn off notifications"
52
+ @notifier.turn_off
53
+ return
160
54
  end
161
- end
162
-
163
- private
164
55
 
165
- # Get the notifier module for the given name.
166
- #
167
- # @param [Symbol] the notifier name
168
- # @return [Module] the notifier module
169
- #
170
- def get_notifier_module(name)
171
- notifier = NOTIFIERS.detect { |n| n.first == name }
172
- notifier ? notifier.last : notifier
56
+ @notifier.turn_on
173
57
  end
174
58
 
175
- # Auto detect the available notification library. This goes through
176
- # the list of supported notification gems and picks the first that
177
- # is available.
178
- #
179
- def auto_detect_notification
180
- available = NOTIFIERS.map { |n| n.first }.any? { |notifier| add_notification(notifier, { }, true) }
181
- ::Guard::UI.info('Guard could not detect any of the supported notification libraries.') unless available
59
+ # Used by dsl describer
60
+ def self.supported
61
+ Notiffany::Notifier::SUPPORTED.inject(:merge)
182
62
  end
183
63
 
184
- # Get the image path for an image symbol for the following
185
- # known image types:
186
- #
187
- # - failed
188
- # - pending
189
- # - success
190
- #
191
- # If the image is not a known symbol, it will be returned unmodified.
192
- #
193
- # @param [Symbol, String] image the image symbol or path to an image
194
- # @return [String] the image path
195
- #
196
- def image_path(image)
197
- case image
198
- when :failed
199
- images_path.join('failed.png').to_s
200
- when :pending
201
- images_path.join('pending.png').to_s
202
- when :success
203
- images_path.join('success.png').to_s
204
- else
205
- image
206
- end
207
- end
208
-
209
- # Paths where all Guard images are located
210
- #
211
- # @return [Pathname] the path to the images directory
212
- #
213
- def images_path
214
- @images_path ||= Pathname.new(File.dirname(__FILE__)).join('../../images')
215
- end
216
-
217
- # Get the notification type depending on the
218
- # image that has been selected for the notification.
219
- #
220
- # @param [Symbol, String] image the image symbol or path to an image
221
- # @return [String] the notification type
222
- #
223
- def notification_type(image)
224
- case image
225
- when :failed
226
- 'failed'
227
- when :pending
228
- 'pending'
229
- when :success
230
- 'success'
231
- else
232
- 'notify'
64
+ # Used by dsl describer
65
+ def self.detected
66
+ @notifier.available.map do |mod|
67
+ { name: mod.name.to_sym, options: mod.options }
233
68
  end
234
69
  end
235
70
  end
236
-
237
71
  end
@@ -0,0 +1,22 @@
1
+ require "thor/core_ext/hash_with_indifferent_access"
2
+
3
+ module Guard
4
+ # A class that holds options. Can be instantiated with default options.
5
+ #
6
+ class Options < Thor::CoreExt::HashWithIndifferentAccess
7
+ # Initializes an Guard::Options object. `default_opts` is merged into
8
+ # `opts`.
9
+ #
10
+ # @param [Hash] opts the options
11
+ # @param [Hash] default_opts the default options
12
+ #
13
+ def initialize(opts = {}, default_opts = {})
14
+ super(default_opts.merge(opts || {}))
15
+ end
16
+
17
+ # workaround for: https://github.com/erikhuda/thor/issues/504
18
+ def fetch(name)
19
+ super(name.to_s)
20
+ end
21
+ end
22
+ end