guard 2.8.2 → 2.9.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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -7
  3. data/lib/guard.rb +220 -152
  4. data/lib/guard.rb.orig +213 -155
  5. data/lib/guard/aruba_adapter.rb +2 -2
  6. data/lib/guard/cli.rb +8 -13
  7. data/lib/guard/cli.rb.orig +12 -10
  8. data/lib/guard/commander.rb +15 -7
  9. data/lib/guard/commands/all.rb +3 -0
  10. data/lib/guard/commands/change.rb +3 -0
  11. data/lib/guard/commands/pause.rb +2 -0
  12. data/lib/guard/commands/reload.rb +4 -0
  13. data/lib/guard/commands/scope.rb +3 -0
  14. data/lib/guard/config.rb +24 -0
  15. data/lib/guard/deprecated/dsl.rb +45 -0
  16. data/lib/guard/deprecated/guard.rb +166 -0
  17. data/lib/guard/deprecated/guardfile.rb +84 -0
  18. data/lib/guard/dsl.rb +24 -13
  19. data/lib/guard/dsl.rb.orig +378 -0
  20. data/lib/guard/dsl_describer.rb +8 -2
  21. data/lib/guard/dsl_describer.rb.orig +11 -3
  22. data/lib/guard/guardfile.rb +32 -44
  23. data/lib/guard/guardfile/evaluator.rb +13 -6
  24. data/lib/guard/guardfile/generator.rb +4 -3
  25. data/lib/guard/interactor.rb +7 -3
  26. data/lib/guard/internals/debugging.rb +1 -0
  27. data/lib/guard/internals/environment.rb +93 -0
  28. data/lib/guard/internals/helpers.rb +13 -0
  29. data/lib/guard/internals/traps.rb +10 -0
  30. data/lib/guard/jobs/pry_wrapper.rb +4 -3
  31. data/lib/guard/jobs/sleep.rb +2 -0
  32. data/lib/guard/metadata.rb +190 -0
  33. data/lib/guard/notifier.rb +124 -99
  34. data/lib/guard/notifier.rb.orig +124 -99
  35. data/lib/guard/notifier/detected.rb +83 -0
  36. data/lib/guard/notifiers/emacs.rb +2 -1
  37. data/lib/guard/notifiers/tmux.rb +173 -177
  38. data/lib/guard/plugin/base.rb +2 -0
  39. data/lib/guard/plugin_util.rb +26 -32
  40. data/lib/guard/reevaluator.rb +3 -3
  41. data/lib/guard/reevaluator.rb.orig +22 -0
  42. data/lib/guard/runner.rb +1 -0
  43. data/lib/guard/session.rb +5 -0
  44. data/lib/guard/sheller.rb +2 -2
  45. data/lib/guard/templates/Guardfile +4 -0
  46. data/lib/guard/templates/Guardfile.orig +2 -0
  47. data/lib/guard/terminal.rb +1 -0
  48. data/lib/guard/ui.rb +4 -1
  49. data/lib/guard/version.rb +1 -1
  50. data/lib/guard/version.rb.orig +1 -1
  51. data/lib/guard/watcher.rb +3 -1
  52. data/lib/guard/watcher.rb.orig +122 -0
  53. data/man/guard.1 +1 -4
  54. data/man/guard.1.html +1 -4
  55. metadata +17 -25
  56. data/lib/guard/commander.rb.orig +0 -103
  57. data/lib/guard/commands/all.rb.orig +0 -36
  58. data/lib/guard/commands/reload.rb.orig +0 -34
  59. data/lib/guard/commands/scope.rb.orig +0 -36
  60. data/lib/guard/deprecated_methods.rb +0 -72
  61. data/lib/guard/deprecated_methods.rb.orig +0 -71
  62. data/lib/guard/deprecator.rb +0 -133
  63. data/lib/guard/deprecator.rb.orig +0 -206
  64. data/lib/guard/guard.rb +0 -100
  65. data/lib/guard/guard.rb.orig +0 -42
  66. data/lib/guard/guardfile.rb.orig +0 -43
  67. data/lib/guard/guardfile/evaluator.rb.orig +0 -275
  68. data/lib/guard/internals/debugging.rb.orig +0 -0
  69. data/lib/guard/internals/environment.rb.orig +0 -0
  70. data/lib/guard/internals/tracing.rb.orig +0 -0
  71. data/lib/guard/notifiers/base.rb.orig +0 -221
  72. data/lib/guard/notifiers/tmux.rb.orig +0 -339
  73. data/lib/guard/plugin_util.rb.orig +0 -186
  74. data/lib/guard/runner.rb.orig +0 -210
  75. data/lib/guard/setuper.rb +0 -359
  76. data/lib/guard/setuper.rb.orig +0 -395
  77. data/lib/guard/ui.rb.orig +0 -278
@@ -0,0 +1,83 @@
1
+ require "guard/internals/environment"
2
+
3
+ require_relative "../notifiers/emacs"
4
+ require_relative "../notifiers/file_notifier"
5
+ require_relative "../notifiers/gntp"
6
+ require_relative "../notifiers/growl"
7
+ require_relative "../notifiers/libnotify"
8
+ require_relative "../notifiers/notifysend"
9
+ require_relative "../notifiers/rb_notifu"
10
+ require_relative "../notifiers/terminal_notifier"
11
+ require_relative "../notifiers/terminal_title"
12
+ require_relative "../notifiers/tmux"
13
+
14
+ module Guard
15
+ module Notifier
16
+ # @private api
17
+ class Detected
18
+ NO_SUPPORTED_NOTIFIERS = "Guard could not detect any of the supported" +
19
+ " notification libraries."
20
+
21
+ class NoneAvailableError < RuntimeError
22
+ end
23
+
24
+ def initialize(supported)
25
+ @supported = supported
26
+ @environment = Internals::Environment.new("GUARD").tap do |env|
27
+ env.create_method(:notifiers=) { |data| YAML::dump(data) }
28
+ env.create_method(:notifiers) { |data| data ? YAML::load(data) : [] }
29
+ end
30
+ end
31
+
32
+ def reset
33
+ @environment.notifiers = nil
34
+ end
35
+
36
+ def detect
37
+ return unless _data.empty?
38
+ @supported.each do |group|
39
+ group.detect { |name, _| add(name, silent: true) }
40
+ end
41
+
42
+ fail NoneAvailableError, NO_SUPPORTED_NOTIFIERS if _data.empty?
43
+ end
44
+
45
+ def available
46
+ _data.map { |entry| [_to_module(entry[:name]), entry[:options]] }
47
+ end
48
+
49
+ def add(name, opts)
50
+ klass = _to_module(name)
51
+ return false unless klass
52
+
53
+ all = @environment.notifiers
54
+
55
+ # Silently skip if it's already available, because otherwise
56
+ # we'd have to do :turn_off, then configure, then :turn_on
57
+ names = all.map(&:first).map(&:last)
58
+ unless names.include?(name)
59
+ return false unless klass.available?(opts)
60
+ @environment.notifiers = all << { name: name, options: opts }
61
+ true
62
+ end
63
+
64
+ # Just overwrite the options (without turning the notifier off or on),
65
+ # so those options will be passed in next calls to notify()
66
+ all.each { |item| item[:options] = opts if item[:name] == name }
67
+ true
68
+ end
69
+
70
+ def _to_module(name)
71
+ @supported.each do |group|
72
+ next unless (notifier = group.detect { |n, _| n == name })
73
+ return notifier.last
74
+ end
75
+ nil
76
+ end
77
+
78
+ def _data
79
+ @environment.notifiers || []
80
+ end
81
+ end
82
+ end
83
+ end
@@ -1,4 +1,5 @@
1
1
  require "guard/notifiers/base"
2
+ require "guard/sheller"
2
3
 
3
4
  module Guard
4
5
  module Notifier
@@ -21,7 +22,7 @@ module Guard
21
22
  return false unless super
22
23
 
23
24
  client_name = opts.fetch(:client, DEFAULTS[:client])
24
- cmd = "#{client_name} --eval '1' 2> #{DEV_NULL} || echo 'N/A'"
25
+ cmd = "#{client_name} --eval '1' 2> #{IO::NULL} || echo 'N/A'"
25
26
  stdout = Sheller.stdout(cmd)
26
27
  return false if stdout.nil?
27
28
  !%w(N/A 'N/A').include?(stdout.chomp)
@@ -1,4 +1,5 @@
1
1
  require "guard/notifiers/base"
2
+ require "guard/sheller"
2
3
 
3
4
  module Guard
4
5
  module Notifier
@@ -15,60 +16,152 @@ module Guard
15
16
  # notification :tmux, color_location: 'status-right-bg'
16
17
  #
17
18
  class Tmux < Base
19
+ @@session = nil
20
+
18
21
  # Default options for the tmux notifications.
19
- DEFAULTS = {
20
- client: "tmux",
21
- tmux_environment: "TMUX",
22
- success: "green",
23
- failed: "red",
24
- pending: "yellow",
25
- default: "green",
26
- timeout: 5,
27
- display_message: false,
28
- default_message_format: "%s - %s",
29
- default_message_color: "white",
30
- display_on_all_clients: false,
31
- display_title: false,
32
- default_title_format: "%s - %s",
33
- line_separator: " - ",
34
- change_color: true,
35
- color_location: "status-left-bg"
36
- }
37
-
38
- ERROR_NOT_INSIDE_SESSION = "The :tmux notifier runs only on when Guard"\
39
- " is executed inside of a tmux session."
22
+ class Defaults
23
+ DEFAULTS = {
24
+ tmux_environment: "TMUX",
25
+ success: "green",
26
+ failed: "red",
27
+ pending: "yellow",
28
+ default: "green",
29
+ timeout: 5,
30
+ display_message: false,
31
+ default_message_format: "%s - %s",
32
+ default_message_color: "white",
33
+ display_on_all_clients: false,
34
+ display_title: false,
35
+ default_title_format: "%s - %s",
36
+ line_separator: " - ",
37
+ change_color: true,
38
+ color_location: "status-left-bg"
39
+ }
40
+
41
+ def self.option(opts, name)
42
+ opts.fetch(name, DEFAULTS[name])
43
+ end
40
44
 
41
- def self.available?(opts = {})
42
- super && _register!(opts)
45
+ def self.[](name)
46
+ DEFAULTS[name]
47
+ end
43
48
  end
44
49
 
45
- # @private
46
- #
47
- # @return [Boolean] whether or not a TMUX environment is available
48
- #
49
- def self._tmux_environment_available?(opts)
50
- !ENV[opts.fetch(:tmux_environment, DEFAULTS[:tmux_environment])].nil?
50
+ class Client
51
+ CLIENT = "tmux"
52
+ class << self
53
+ def version
54
+ Float(_capture("-V")[/\d+\.\d+/])
55
+ end
56
+
57
+ def clients
58
+ ttys = _capture("list-clients", "-F", "'\#{client_tty}'")
59
+ ttys = ttys.split(/\n/)
60
+
61
+ # if user is running 'tmux -C' remove this client from list
62
+ ttys.delete("(null)")
63
+ ttys
64
+ end
65
+
66
+ def set(client, key, value)
67
+ case client
68
+ when :all, true
69
+ # call ourself
70
+ clients.each { |cl| Client.set(cl, key, value) }
71
+ else
72
+ args = client ? ["-t", client.strip] : nil
73
+ _run("set", "-q", *args, key, value)
74
+ end
75
+ end
76
+
77
+ def display(client, message)
78
+ case client
79
+ when :all, true
80
+ # call ourself
81
+ clients.each { |cl| Client.display(cl, message) }
82
+ else
83
+ args += ["-c", client.strip] if client
84
+ _run("display", *args, message)
85
+ end
86
+ end
87
+
88
+ def unset(client, key, value)
89
+ return set(client, key, value) if value
90
+ args = client ? ["-t", client.strip] : []
91
+ _run("set", "-q", "-u", *args, key)
92
+ end
93
+
94
+ def parse_options(client)
95
+ output = _capture("show", "-t", client)
96
+ Hash[output.lines.map { |line| _parse_option(line) }]
97
+ end
98
+
99
+ def _parse_option(line)
100
+ line.partition(" ").map(&:strip).reject(&:empty?)
101
+ end
102
+
103
+ def _capture(*args)
104
+ Sheller.stdout(([CLIENT] + args).join(" "))
105
+ end
106
+
107
+ def _run(*args)
108
+ Sheller.run(([CLIENT] + args).join(" "))
109
+ end
110
+ end
51
111
  end
52
112
 
53
- # @private
54
- #
55
- # Detects if a TMUX environment is available and if not,
56
- # displays an error message unless `opts[:silent]` is true.
57
- #
58
- # @return [Boolean] whether or not a TMUX environment is available
59
- #
60
- def self._register!(opts)
61
- @options_stored = false
62
- if _tmux_environment_available?(opts)
63
- true
64
- else
65
- unless opts[:silent]
66
- ::Guard::UI.error ERROR_NOT_INSIDE_SESSION
113
+ class Session
114
+ def initialize(_tmux)
115
+ @options_store = {}
116
+
117
+ Client.clients.each do |client|
118
+ @options_store[client] = {
119
+ "status-left-bg" => nil,
120
+ "status-right-bg" => nil,
121
+ "status-left-fg" => nil,
122
+ "status-right-fg" => nil,
123
+ "message-bg" => nil,
124
+ "message-fg" => nil,
125
+ "display-time" => nil
126
+ }.merge(Client.parse_options(client))
127
+ end
128
+ end
129
+
130
+ def close
131
+ @options_store.each do |client, options|
132
+ options.each do |key, value|
133
+ Client.unset(client, key, value)
134
+ end
67
135
  end
68
- false
136
+ @options_store = nil
69
137
  end
70
138
  end
71
139
 
140
+ class Error < RuntimeError
141
+ end
142
+
143
+ ERROR_NOT_INSIDE_TMUX = "The :tmux notifier runs only on when Guard"\
144
+ " is executed inside of a tmux session."
145
+
146
+ ERROR_ANCIENT_TMUX = "Your tmux version is way too old!"
147
+
148
+ def self.available?(opts = {})
149
+ return unless super
150
+
151
+ fail "PREVIOUS TMUX SESSION NOT CLEARED!" if @@session || nil
152
+
153
+ var_name = Defaults.option(opts, :tmux_environment)
154
+ fail Error, ERROR_NOT_INSIDE_TMUX unless ENV.key?(var_name)
155
+
156
+ version = Client.version
157
+ fail Error, format(ERROR_ANCIENT_TMUX, version) if version < 1.7
158
+
159
+ true
160
+ rescue Error => e
161
+ ::Guard::UI.error e.message unless opts[:silent]
162
+ false
163
+ end
164
+
72
165
  # Shows a system notification.
73
166
  #
74
167
  # By default, the Tmux notifier only makes
@@ -99,25 +192,21 @@ module Guard
99
192
  super
100
193
  opts.delete(:image)
101
194
 
102
- if opts.fetch(:change_color, DEFAULTS[:change_color])
103
- options = opts.fetch(:color_location, DEFAULTS[:color_location])
104
- color_locations = Array(options)
105
- color = tmux_color(opts[:type], opts)
106
-
107
- color_locations.each do |color_location|
108
- _run_client "set", "#{self.class._quiet_option}"\
109
- "#{color_location} #{color}"
110
- end
111
- end
112
-
195
+ change_color = Defaults.option(opts, :change_color)
196
+ options = Array(Defaults.option(opts, :color_location))
197
+ display_the_title = Defaults.option(opts, :display_title)
198
+ display_message = Defaults.option(opts, :display_message)
113
199
  type = opts.delete(:type).to_s
114
200
  title = opts.delete(:title)
115
201
 
116
- if opts.fetch(:display_title, DEFAULTS[:display_title])
117
- display_title(type, title, message, opts)
202
+ if change_color
203
+ color = tmux_color(type, opts)
204
+ options.each { |location| Client.set(_all?, location, color) }
118
205
  end
119
206
 
120
- return unless opts.fetch(:display_message, DEFAULTS[:display_message])
207
+ display_title(type, title, message, opts) if display_the_title
208
+
209
+ return unless display_message
121
210
  display_message(type, title, message, opts)
122
211
  end
123
212
 
@@ -137,14 +226,12 @@ module Guard
137
226
  #
138
227
  def display_title(type, title, message, opts = {})
139
228
  format = "#{type}_title_format".to_sym
140
- defaults = DEFAULTS[:default_title_format]
141
- options = opts.fetch(:default_title_format, defaults)
229
+ options = Defaults.option(opts, :default_title_format)
142
230
  title_format = opts.fetch(format, options)
143
231
  teaser_message = message.split("\n").first
144
232
  display_title = title_format % [title, teaser_message]
145
233
 
146
- _run_client "set-option", "#{self.class._quiet_option}"\
147
- "set-titles-string '#{display_title}'"
234
+ Client.set(_all?, "set-titles-string", "'#{display_title}'")
148
235
  end
149
236
 
150
237
  # Displays a message in the status bar of tmux.
@@ -176,32 +263,25 @@ module Guard
176
263
  # line-break.
177
264
  #
178
265
  def display_message(type, title, message, opts = {})
179
- default_format = DEFAULTS[:default_message_format]
180
- default_format = opts.fetch(:default_message_format, default_format)
266
+ default_format = Defaults.option(opts, :default_message_format)
267
+ default_color = Defaults.option(opts, :default_message_color)
268
+ display_time = Defaults.option(opts, :timeout)
269
+ separator = Defaults.option(opts, :line_separator)
270
+
181
271
  format = "#{type}_message_format".to_sym
182
272
  message_format = opts.fetch(format, default_format)
183
273
 
184
- default_color = DEFAULTS[:default_message_color]
185
- default_color = opts.fetch(:default_message_color, default_color)
186
274
  color = "#{type}_message_color".to_sym
187
275
  message_color = opts.fetch(color, default_color)
188
276
 
189
- display_time = opts.fetch(:timeout, DEFAULTS[:timeout])
190
- separator = opts.fetch(:line_separator, DEFAULTS[:line_separator])
191
-
192
- color = tmux_color type, opts
277
+ color = tmux_color(type, opts)
193
278
  formatted_message = message.split("\n").join(separator)
194
279
  display_message = message_format % [title, formatted_message]
195
280
 
196
- _run_client(
197
- "set",
198
- "#{self.class._quiet_option}display-time #{display_time * 1000}")
199
-
200
- _run_client "set", "#{self.class._quiet_option}"\
201
- "message-fg #{message_color}"
202
- _run_client "set", "#{self.class._quiet_option}"\
203
- "message-bg #{color}"
204
- _run_client "display-message", "'#{display_message}'"
281
+ Client.set(_all?, "display-time", display_time * 1000)
282
+ Client.set(_all?, "message-fg", message_color)
283
+ Client.set(_all?, "message-bg", color)
284
+ Client.display(_all?, "'#{display_message}'")
205
285
  end
206
286
 
207
287
  # Get the Tmux color for the notification type.
@@ -212,23 +292,14 @@ module Guard
212
292
  #
213
293
  def tmux_color(type, opts = {})
214
294
  type = type.to_sym
215
-
216
- opts[type] || DEFAULTS[type] || opts[:default] || DEFAULTS[:default]
295
+ opts[type] || Defaults[type] || Defaults.option(opts, :default)
217
296
  end
218
297
 
219
298
  # Notification starting, save the current Tmux settings
220
299
  # and quiet the Tmux output.
221
300
  #
222
301
  def self.turn_on
223
- unless @options_stored
224
- _reset_options_store
225
-
226
- _clients.each do |client|
227
- @options_store[client].merge!(_options_for_client(client))
228
- end
229
-
230
- @options_stored = true
231
- end
302
+ _start_session
232
303
  end
233
304
 
234
305
  # Notification stopping. Restore the previous Tmux state
@@ -236,103 +307,28 @@ module Guard
236
307
  # are unset) and unquiet the Tmux output.
237
308
  #
238
309
  def self.turn_off
239
- if @options_stored
240
- @options_store.each do |client, options|
241
- options.each do |key, value|
242
- args = [
243
- DEFAULTS[:client], "set", "-t",
244
- client, _quiet_option.strip
245
- ]
246
- args << "-u" unless value
247
- args << key
248
- args << value if value
249
- Sheller.run(args.join(" "))
250
- end
251
- end
252
- _reset_options_store
253
- end
254
- end
255
-
256
- def self.options_store
257
- @options_store ||= {}
310
+ _end_session
258
311
  end
259
312
 
260
313
  private
261
314
 
262
- def self._clients
263
- args = [DEFAULTS[:client], "list-clients", "-F", "'\#{client_tty}'"]
264
- ttys = Sheller.stdout(args.join(" "))
265
- ttys = ttys.split(/\n/)
266
-
267
- # if user is running 'tmux -C' remove this client from list
268
- ttys.delete("(null)")
269
-
270
- ttys
271
- end
272
-
273
- def self._options_for_client(client)
274
- options = {}
275
-
276
- lines = Sheller.stdout("#{DEFAULTS[:client]} show -t #{client}")
277
-
278
- lines.each_line do |line|
279
- option, _, setting = line.chomp.partition(" ")
280
- options[option] = setting
281
- end
282
-
283
- options
315
+ def self._start_session
316
+ fail "Already turned on!" if @@session
317
+ @@session = Session.new(self)
284
318
  end
285
319
 
286
- def _clients
287
- self.class._clients
288
- end
289
-
290
- def _run_client(cmd, args)
291
- default = DEFAULTS[:display_on_all_clients]
292
- all_clients = @options.fetch(:display_on_all_clients, default)
293
- clients = all_clients ? _clients : [nil]
294
- clients.each do |client|
295
- cmd_args = if client
296
- "#{_client_cmd_flag(cmd)} #{client.strip} #{args}"
297
- else
298
- args
299
- end
300
- Sheller.run("#{DEFAULTS[:client]} #{cmd} #{cmd_args}")
301
- end
302
- end
303
-
304
- def _client_cmd_flag(cmd)
305
- case cmd
306
- when "set", "set-option" then "-t"
307
- when "display-message" then "-c"
308
- end
309
- end
310
-
311
- # Reset the internal Tmux options store defaults.
312
- #
313
- def self._reset_options_store
314
- @options_stored = false
315
- @options_store = {}
316
-
317
- _clients.each do |client|
318
- @options_store[client] = {
319
- "status-left-bg" => nil,
320
- "status-right-bg" => nil,
321
- "status-left-fg" => nil,
322
- "status-right-fg" => nil,
323
- "message-bg" => nil,
324
- "message-fg" => nil,
325
- "display-time" => nil
326
- }
327
- end
320
+ def self._end_session
321
+ fail "Already turned off!" unless @@session || nil
322
+ @@session.close
323
+ @@session = nil
328
324
  end
329
325
 
330
- def self._tmux_version
331
- @@tmux_version ||= Float(Sheller.stdout("tmux -V")[/\d+\.\d+/])
326
+ def self._session
327
+ @@session
332
328
  end
333
329
 
334
- def self._quiet_option
335
- "-q " if _tmux_version >= 1.7
330
+ def _all?
331
+ Defaults.option(options, :display_on_all_clients)
336
332
  end
337
333
  end
338
334
  end