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,128 @@
1
+ require "guard/ui"
2
+ require "guard/plugin_util"
3
+
4
+ # Add Pathname#binwrite to 1.9.3
5
+ unless Pathname.instance_methods.include?(:binwrite)
6
+ class Pathname
7
+ def binwrite(*args)
8
+ IO.binwrite(to_s, *args)
9
+ end
10
+ end
11
+ end
12
+
13
+ module Guard
14
+ module Guardfile
15
+ # This class is responsible for generating the Guardfile and adding Guard'
16
+ # plugins' templates into it.
17
+ #
18
+ # @see Guard::CLI
19
+ #
20
+ class Generator
21
+ require "guard"
22
+ require "guard/ui"
23
+
24
+ INFO_TEMPLATE_ADDED =
25
+ "%s template added to Guardfile, feel free to edit it"
26
+
27
+ # The Guardfile template for `guard init`
28
+ GUARDFILE_TEMPLATE = File.expand_path(
29
+ "../../../guard/templates/Guardfile",
30
+ __FILE__
31
+ )
32
+
33
+ # The location of user defined templates
34
+ begin
35
+ HOME_TEMPLATES = Pathname.new("~/.guard/templates").expand_path
36
+ rescue ArgumentError
37
+ # home isn't defined. Set to the root of the drive. Trust that there
38
+ # won't be user defined templates there
39
+ HOME_TEMPLATES = Pathname.new("/").expand_path
40
+ end
41
+
42
+ class Error < RuntimeError
43
+ end
44
+
45
+ class NoSuchPlugin < Error
46
+ attr_reader :plugin_name, :class_name
47
+
48
+ def initialize(plugin_name)
49
+ @plugin_name = plugin_name
50
+ @class_name = plugin_name.delete("-").capitalize
51
+ end
52
+
53
+ def message
54
+ "Could not load 'guard/#{plugin_name}'"\
55
+ " or '~/.guard/templates/#{plugin_name}'"\
56
+ " or find class Guard::#{class_name}\n"
57
+ end
58
+ end
59
+
60
+ # Creates the initial Guardfile template when it does not
61
+ # already exist.
62
+ #
63
+ # @see Guard::CLI#init
64
+ #
65
+ def create_guardfile
66
+ path = Pathname.new("Guardfile").expand_path
67
+ if path.exist?
68
+ _ui(:error, "Guardfile already exists at #{path}")
69
+ abort
70
+ end
71
+
72
+ _ui(:info, "Writing new Guardfile to #{path}")
73
+ FileUtils.cp(GUARDFILE_TEMPLATE, path.to_s)
74
+ end
75
+
76
+ # Adds the Guardfile template of a Guard plugin to an existing Guardfile.
77
+ #
78
+ # @see Guard::CLI#init
79
+ #
80
+ # @param [String] plugin_name the name of the Guard plugin or template to
81
+ # initialize
82
+ #
83
+ def initialize_template(plugin_name)
84
+ guardfile = Pathname.new("Guardfile")
85
+
86
+ plugin_util = PluginUtil.new(plugin_name)
87
+ # TODO: change to "valid?" method
88
+ plugin_class = plugin_util.plugin_class(fail_gracefully: true)
89
+ if plugin_class
90
+ begin
91
+ plugin_util.add_to_guardfile
92
+ rescue Errno::ENOENT => error
93
+ # TODO: refactor
94
+ template = plugin_class.template(plugin_util.plugin_location)
95
+ _ui(:error, "Found class #{plugin_class} but loading it's template"\
96
+ "failed: '#{template}'")
97
+ _ui(:error, "Error is: #{error}")
98
+ return
99
+ end
100
+ return
101
+ end
102
+
103
+ template_code = (HOME_TEMPLATES + plugin_name).read
104
+ guardfile.binwrite(format("\n%s\n", template_code), open_args: ["a"])
105
+
106
+ _ui(:info, format(INFO_TEMPLATE_ADDED, plugin_name))
107
+
108
+ rescue Errno::ENOENT
109
+ fail NoSuchPlugin, plugin_name.downcase
110
+ end
111
+
112
+ # Adds the templates of all installed Guard implementations to an
113
+ # existing Guardfile.
114
+ #
115
+ # @see Guard::CLI#init
116
+ #
117
+ def initialize_all_templates
118
+ PluginUtil.plugin_names.each { |g| initialize_template(g) }
119
+ end
120
+
121
+ private
122
+
123
+ def _ui(*args)
124
+ UI.send(*args)
125
+ end
126
+ end
127
+ end
128
+ end
@@ -1,73 +1,37 @@
1
- module Guard
1
+ require "guard/config"
2
2
 
3
- # The Guardfile is responsible for generating the Guardfile
4
- # and adding guards' template into it.
5
- #
6
- # @see Guard::CLI
7
- #
8
- class Guardfile
3
+ if Guard::Config.new.strict?
4
+ abort "Error: Deprecated file #{__FILE__} is being used"
5
+ else
6
+ require "guard/deprecated/guardfile"
9
7
 
10
- require 'guard'
11
- require 'guard/ui'
8
+ # TODO: remove this file in next major version
12
9
 
13
- class << self
10
+ module Guard
11
+ unless Guard::Config.new.silence_deprecations?
12
+ UPGRADE_WIKI_URL =
13
+ "https://github.com/guard/guard/wiki/Upgrading-to-Guard-2.0"
14
14
 
15
- # Creates the initial Guardfile template when it does not
16
- # already exist.
17
- #
18
- # @see Guard::CLI.init
19
- #
20
- # @param [Hash] options The options for creating a Guardfile
21
- # @option options [Boolean] :abort_on_existence Whether to abort or not when a Guardfile already exists
22
- #
23
- def create_guardfile(options = {})
24
- if !File.exist?('Guardfile')
25
- ::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile"
26
- FileUtils.cp(GUARDFILE_TEMPLATE, 'Guardfile')
27
- elsif options[:abort_on_existence]
28
- ::Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
29
- abort
30
- end
31
- end
15
+ STDERR.puts <<-EOS
16
+ (guard/guardfile.rb message)
32
17
 
33
- # Adds the Guardfile template of a Guard implementation
34
- # to an existing Guardfile.
35
- #
36
- # @see Guard::CLI.init
37
- #
38
- # @param [String] guard_name the name of the Guard or template to initialize
39
- #
40
- def initialize_template(guard_name)
41
- guard_class = ::Guard.get_guard_class(guard_name, true)
18
+ You are including "guard/guardfile.rb", which has been deprecated
19
+ since 2013 ... and will be removed.
42
20
 
43
- if guard_class
44
- guard_class.init(guard_name)
45
- elsif File.exist?(File.join(HOME_TEMPLATES, guard_name))
46
- content = File.read('Guardfile')
47
- template = File.read(File.join(HOME_TEMPLATES, guard_name))
21
+ Migration is easy, see: #{UPGRADE_WIKI_URL}
48
22
 
49
- File.open('Guardfile', 'wb') do |f|
50
- f.puts(content)
51
- f.puts('')
52
- f.puts(template)
53
- end
23
+ This file was included from:
24
+ #{caller[0..10] * "\n >"}
54
25
 
55
- ::Guard::UI.info "#{ guard_name } template added to Guardfile, feel free to edit it"
56
- else
57
- const_name = guard_name.downcase.gsub('-', '')
58
- UI.error "Could not load 'guard/#{ guard_name.downcase }' or '~/.guard/templates/#{ guard_name.downcase }' or find class Guard::#{ const_name.capitalize }"
59
- end
60
- end
26
+ Sorry for the inconvenience and have a nice day!
61
27
 
62
- # Adds the templates of all installed Guard implementations
63
- # to an existing Guardfile.
64
- #
65
- # @see Guard::CLI.init
66
- #
67
- def initialize_all_templates
68
- ::Guard.guard_gem_names.each { |g| initialize_template(g) }
69
- end
28
+ (end of guard/guardfile.rb message)
70
29
 
30
+
31
+ EOS
32
+ end
33
+ module Guardfile
34
+ extend Deprecated::Guardfile::ClassMethods
71
35
  end
72
36
  end
73
37
  end
@@ -1,277 +1,53 @@
1
- module Guard
1
+ require "forwardable"
2
2
 
3
- # The interactor triggers specific action from input
4
- # read by a interactor implementation.
5
- #
6
- # Currently the following actions are implemented:
7
- #
8
- # - h, help => Show help
9
- # - e, exit,
10
- # q. quit => Exit Guard
11
- # - r, reload => Reload Guard
12
- # - p, pause => Toggle file modification listener
13
- # - n, notification => Toggle notifications
14
- # - s, show => Show Guard plugin configuration
15
- # - c, change => Trigger a file change
16
- # - <enter> => Run all
17
- #
18
- # It's also possible to scope `reload` and `run all` actions to only a specified group or a guard.
19
- #
20
- # @example Reload backend group
21
- # backend reload
22
- # reload backend
23
- #
24
- # @example Reload rspec guard
25
- # spork reload
26
- # reload spork
27
- #
28
- # @example Run all jasmine specs
29
- # jasmine
30
- #
31
- # @abstract
32
- #
3
+ module Guard
33
4
  class Interactor
34
-
35
- require 'guard'
36
- require 'guard/ui'
37
- require 'guard/dsl_describer'
38
- require 'guard/notifier'
39
- require 'guard/interactors/readline'
40
- require 'guard/interactors/coolline'
41
- require 'guard/interactors/simple'
42
-
43
- ACTIONS = {
44
- :help => %w[help h],
45
- :reload => %w[reload r],
46
- :stop => %w[exit e quit q],
47
- :pause => %w[pause p],
48
- :notification => %w[notification n],
49
- :show => %w[show s],
50
- :change => %w[change c]
51
- }
52
-
53
- # Set the interactor implementation
54
- #
55
- # @param [Symbol] interactor the name of the interactor
5
+ # Initializes the interactor. This configures
6
+ # Pry and creates some custom commands and aliases
7
+ # for Guard.
56
8
  #
57
- def self.interactor=(interactor)
58
- @interactor = interactor
59
- end
9
+ def initialize(no_interaction = false)
10
+ @interactive = !no_interaction && self.class.enabled?
60
11
 
61
- # Get an instance of the currently configured
62
- # interactor implementation.
63
- #
64
- # @return [Interactor] an interactor implementation
65
- #
66
- def self.fabricate
67
- case @interactor
68
- when :coolline
69
- ::Guard::CoollineInteractor.new if ::Guard::CoollineInteractor.available?
70
- when :readline
71
- ::Guard::ReadlineInteractor.new if ::Guard::ReadlineInteractor.available?
72
- when :simple
73
- ::Guard::SimpleInteractor.new
74
- when :off
75
- nil
76
- else
77
- auto_detect
78
- end
79
- end
80
-
81
- # Tries to detect an optimal interactor for the
82
- # current environment.
83
- #
84
- # It returns the Readline implementation when:
85
- #
86
- # * rb-readline is installed
87
- # * The Ruby implementation is JRuby
88
- # * The current OS is not Mac OS X
89
- #
90
- # Otherwise the plain gets interactor is returned.
91
- #
92
- # @return [Interactor] an interactor implementation
93
- #
94
- def self.auto_detect
95
- [::Guard::CoollineInteractor, ::Guard::ReadlineInteractor, ::Guard::SimpleInteractor].detect do |interactor|
96
- interactor.available?(true)
97
- end.new
98
- end
12
+ # TODO: only require the one used
13
+ require "guard/jobs/sleep"
14
+ require "guard/jobs/pry_wrapper"
99
15
 
100
- # Template method for checking if the Interactor is
101
- # available in the current environment?
102
- #
103
- # @param [Boolean] silent true if no error messages should be shown
104
- # @return [Boolean] the availability status
105
- #
106
- def self.available?(silent = false)
107
- true
16
+ job_klass = interactive? ? Jobs::PryWrapper : Jobs::Sleep
17
+ @idle_job = job_klass.new(self.class.options)
108
18
  end
109
19
 
110
- # Start the line reader in its own thread.
111
- #
112
- def start
113
- return if ENV['GUARD_ENV'] == 'test'
114
-
115
- ::Guard::UI.debug 'Start interactor'
116
- @thread = Thread.new { read_line } if !@thread || !@thread.alive?
20
+ def interactive?
21
+ @interactive
117
22
  end
118
23
 
119
- # Kill interactor thread if not current
120
- #
121
- def stop
122
- return if !@thread || ENV['GUARD_ENV'] == 'test'
24
+ extend Forwardable
25
+ delegate [:foreground, :background, :handle_interrupt] => :idle_job
123
26
 
124
- ::Guard::UI.debug 'Stop interactor'
125
- unless Thread.current == @thread
126
- @thread.kill
27
+ # TODO: everything below is just so the DSL can set options
28
+ # before setup() is called, which makes it useless for when
29
+ # Guardfile is reevaluated
30
+ class << self
31
+ def options
32
+ @options ||= {}
127
33
  end
128
- end
129
34
 
130
- # Read the user input. This method must be implemented
131
- # by each interactor implementation.
132
- #
133
- # @abstract
134
- #
135
- def read_line
136
- raise NotImplementedError
137
- end
138
-
139
- # Process the input from readline.
140
- #
141
- # @param [String] line the input line
142
- #
143
- def process_input(line)
144
- scopes, action, rest = extract_scopes_and_action(line)
35
+ # Pass options to interactor's job when it's created
36
+ attr_writer :options
145
37
 
146
- case action
147
- when :help
148
- help
149
- when :show
150
- ::Guard::DslDescriber.show(::Guard.options)
151
- when :stop
152
- ::Guard.stop
153
- exit
154
- when :pause
155
- ::Guard.pause
156
- when :reload
157
- ::Guard.reload(scopes)
158
- when :change
159
- ::Guard.within_preserved_state do
160
- ::Guard.runner.run_on_changes(rest, [], [])
161
- end
162
- when :run_all
163
- ::Guard.run_all(scopes)
164
- when :notification
165
- toggle_notification
166
- else
167
- ::Guard::UI.error "Unknown command #{ line }"
38
+ # TODO: allow custom user idle jobs, e.g. [:pry, :sleep, :exit, ...]
39
+ def enabled?
40
+ @enabled || @enabled.nil?
168
41
  end
169
- end
170
42
 
171
- # Toggle the system notifications on/off
172
- #
173
- def toggle_notification
174
- if ENV['GUARD_NOTIFY'] == 'true'
175
- ::Guard::UI.info 'Turn off notifications'
176
- ::Guard::Notifier.turn_off
177
- else
178
- ::Guard::Notifier.turn_on
179
- end
180
- end
43
+ alias_method :enabled, :enabled?
181
44
 
182
- # Show the help.
183
- #
184
- def help
185
- puts ''
186
- puts '[e]xit, [q]uit Exit Guard'
187
- puts '[p]ause Toggle file modification listener'
188
- puts '[r]eload Reload Guard'
189
- puts '[n]otification Toggle notifications'
190
- puts '[s]how Show available Guard plugins'
191
- puts '[c]hange <file> Trigger a file change'
192
- puts '<enter> Run all Guard plugins'
193
- puts ''
194
- puts 'You can scope the reload action to a specific guard or group:'
195
- puts ''
196
- puts 'rspec reload Reload the RSpec Guard'
197
- puts 'backend reload Reload the backend group'
198
- puts ''
199
- puts 'You can also run only a specific Guard or all Guard plugins in a specific group:'
200
- puts ''
201
- puts 'jasmine Run the jasmine Guard'
202
- puts 'frontend Run all Guard plugins in the frontend group'
203
- puts ''
204
- end
205
-
206
- # Extract the Guard or group scope and action from the
207
- # input line. There's no strict order for scopes and
208
- # actions.
209
- #
210
- # @example `spork reload` will only reload rspec
211
- # @example `jasmine` will only run all jasmine specs
212
- #
213
- # @param [String] line the readline input
214
- # @return [Array] the group or guard scope, the action and the rest
215
- #
216
- def extract_scopes_and_action(line)
217
- entries = line.split(' ')
218
-
219
- scopes = extract_scopes(entries)
220
- action = extract_action(entries)
221
-
222
- action = :run_all if !action && (!scopes.empty? || entries.empty?)
223
-
224
- [scopes, action, entries]
45
+ # TODO: handle switching interactors during runtime?
46
+ attr_writer :enabled
225
47
  end
226
48
 
227
49
  private
228
50
 
229
- # Extract a guard or group scope from entry if valid.
230
- # Any entry found will be removed from the entries.
231
- #
232
- # @param [Array<String>] entries the user entries
233
- # @return [Hash] a hash with a Guard or a group scope
234
- #
235
- def extract_scopes(entries)
236
- scopes = { }
237
-
238
- entries.delete_if do |entry|
239
- if guard = ::Guard.guards(entry)
240
- scopes[:guard] ||= guard
241
- true
242
-
243
- elsif group = ::Guard.groups(entry)
244
- scopes[:group] ||= group
245
- true
246
-
247
- else
248
- false
249
- end
250
- end
251
-
252
- scopes
253
- end
254
-
255
- # Find the action for the given input entry.
256
- # Any action found will be removed from the entries.
257
- #
258
- # @param [Array<String>] entries the user entries
259
- # @return [Symbol] a Guard action
260
- #
261
- def extract_action(entries)
262
- action = nil
263
-
264
- entries.delete_if do |entry|
265
- if command = ACTIONS.detect { |k, list| list.include?(entry) }
266
- action ||= command.first
267
- true
268
- else
269
- false
270
- end
271
- end
272
-
273
- action
274
- end
275
-
51
+ attr_reader :idle_job
276
52
  end
277
53
  end
@@ -0,0 +1,68 @@
1
+ # Because it's used by Sheller
2
+ require "open3"
3
+ require "logger"
4
+
5
+ require "guard/ui"
6
+
7
+ require "guard/internals/tracing"
8
+
9
+ module Guard
10
+ # @private api
11
+ module Internals
12
+ class Debugging
13
+ class << self
14
+ TRACES = [
15
+ [Kernel, :system],
16
+ [Kernel, :spawn],
17
+ [Kernel, :`],
18
+ [Open3, :popen3]
19
+ ]
20
+
21
+ # Sets up debugging:
22
+ #
23
+ # * aborts on thread exceptions
24
+ # * Set the logging level to `:debug`
25
+ # * traces execution of Kernel.system and backtick calls
26
+ def start
27
+ return if @started ||= false
28
+ @started = true
29
+
30
+ Thread.abort_on_exception = true
31
+
32
+ UI.level = Logger::DEBUG
33
+
34
+ TRACES.each { |mod, meth| _trace(mod, meth, &method(:_notify)) }
35
+ @traced = true
36
+ end
37
+
38
+ def stop
39
+ return unless @started ||= false
40
+ UI.level = Logger::INFO
41
+ _reset
42
+ end
43
+
44
+ private
45
+
46
+ def _notify(*args)
47
+ UI.debug "Command execution: #{args.join(' ')}"
48
+ end
49
+
50
+ # reset singleton - called by tests
51
+ def _reset
52
+ @started = false
53
+ return unless @traced
54
+ TRACES.each { |mod, meth| _untrace(mod, meth) }
55
+ @traced = false
56
+ end
57
+
58
+ def _trace(mod, meth, &block)
59
+ Tracing.trace(mod, meth, &block)
60
+ end
61
+
62
+ def _untrace(mod, meth)
63
+ Tracing.untrace(mod, meth)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,40 @@
1
+ require "guard/group"
2
+
3
+ module Guard
4
+ # @private api
5
+ module Internals
6
+ class Groups
7
+ DEFAULT_GROUPS = [:common, :default]
8
+
9
+ def initialize
10
+ @groups = DEFAULT_GROUPS.map { |name| Group.new(name) }
11
+ end
12
+
13
+ def all(filter = nil)
14
+ return @groups if filter.nil?
15
+ matcher = matcher_for(filter)
16
+ @groups.select { |group| matcher.call(group) }
17
+ end
18
+
19
+ def add(name, options = {})
20
+ all(name).first || Group.new(name, options).tap do |group|
21
+ fail if name == :specs && options.empty?
22
+ @groups << group
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def matcher_for(filter)
29
+ case filter
30
+ when String, Symbol
31
+ ->(group) { group.name == filter.to_sym }
32
+ when Regexp
33
+ ->(group) { group.name.to_s =~ filter }
34
+ else
35
+ fail "Invalid filter: #{filter.inspect}"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,13 @@
1
+ module Guard
2
+ # @private api
3
+ module Internals
4
+ module Helpers
5
+ def _relative_pathname(path)
6
+ full_path = Pathname(path)
7
+ full_path.relative_path_from(Pathname.pwd)
8
+ rescue ArgumentError
9
+ full_path
10
+ end
11
+ end
12
+ end
13
+ end