guard 1.8.3 → 2.0.0.pre

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -10
  3. data/README.md +54 -33
  4. data/lib/guard.rb +133 -483
  5. data/lib/guard/cli.rb +78 -82
  6. data/lib/guard/commander.rb +121 -0
  7. data/lib/guard/commands/all.rb +1 -1
  8. data/lib/guard/commands/reload.rb +1 -1
  9. data/lib/guard/deprecated_methods.rb +59 -0
  10. data/lib/guard/deprecator.rb +107 -0
  11. data/lib/guard/dsl.rb +143 -329
  12. data/lib/guard/dsl_describer.rb +101 -57
  13. data/lib/guard/group.rb +27 -8
  14. data/lib/guard/guard.rb +25 -150
  15. data/lib/guard/guardfile.rb +35 -85
  16. data/lib/guard/guardfile/evaluator.rb +245 -0
  17. data/lib/guard/guardfile/generator.rb +89 -0
  18. data/lib/guard/interactor.rb +147 -163
  19. data/lib/guard/notifier.rb +83 -137
  20. data/lib/guard/notifiers/base.rb +220 -0
  21. data/lib/guard/notifiers/emacs.rb +39 -37
  22. data/lib/guard/notifiers/file_notifier.rb +29 -25
  23. data/lib/guard/notifiers/gntp.rb +68 -75
  24. data/lib/guard/notifiers/growl.rb +49 -52
  25. data/lib/guard/notifiers/growl_notify.rb +51 -56
  26. data/lib/guard/notifiers/libnotify.rb +41 -48
  27. data/lib/guard/notifiers/notifysend.rb +58 -38
  28. data/lib/guard/notifiers/rb_notifu.rb +54 -54
  29. data/lib/guard/notifiers/terminal_notifier.rb +48 -36
  30. data/lib/guard/notifiers/terminal_title.rb +23 -19
  31. data/lib/guard/notifiers/tmux.rb +110 -93
  32. data/lib/guard/options.rb +21 -0
  33. data/lib/guard/plugin.rb +66 -0
  34. data/lib/guard/plugin/base.rb +178 -0
  35. data/lib/guard/plugin/hooker.rb +123 -0
  36. data/lib/guard/plugin_util.rb +158 -0
  37. data/lib/guard/rake_task.rb +47 -0
  38. data/lib/guard/runner.rb +62 -82
  39. data/lib/guard/setuper.rb +248 -0
  40. data/lib/guard/ui.rb +24 -80
  41. data/lib/guard/ui/colors.rb +60 -0
  42. data/lib/guard/version.rb +1 -2
  43. data/lib/guard/watcher.rb +30 -30
  44. data/man/guard.1 +4 -4
  45. data/man/guard.1.html +6 -4
  46. metadata +25 -11
  47. data/lib/guard/hook.rb +0 -120
@@ -0,0 +1,245 @@
1
+ module Guard
2
+ module Guardfile
3
+
4
+ # This class is responsible for evaluating the Guardfile. It delegates
5
+ # to Guard::Dsl for the actual objects generation from the Guardfile content.
6
+ #
7
+ # @see Guard::Dsl
8
+ #
9
+ class Evaluator
10
+
11
+ attr_reader :options
12
+
13
+ # Initializes a new Guard::Guardfile::Evaluator object.
14
+ #
15
+ # @option opts [String] guardfile the path to a valid Guardfile
16
+ # @option opts [String] guardfile_contents a string representing the content of a valid Guardfile
17
+ #
18
+ def initialize(opts = {})
19
+ @options = ::Guard::Options.new([:guardfile, :guardfile_contents].reduce({}) { |h, key| h[key] = opts[key]; h })
20
+ end
21
+
22
+ # Evaluates the DSL methods in the `Guardfile`.
23
+ #
24
+ # @example Programmatically evaluate a Guardfile
25
+ # Guard::Guardfile::Evaluator.new.evaluate_guardfile
26
+ #
27
+ # @example Programmatically evaluate a Guardfile with a custom Guardfile path
28
+ # Guard::Guardfile::Evaluator.new(guardfile: '/Users/guardfile/MyAwesomeGuardfile').evaluate_guardfile
29
+ #
30
+ # @example Programmatically evaluate a Guardfile with an inline Guardfile
31
+ # Guard::Guardfile::Evaluator.new(guardfile_contents: 'guard :rspec').evaluate_guardfile
32
+ #
33
+ def evaluate_guardfile
34
+ _fetch_guardfile_contents
35
+ _instance_eval_guardfile(guardfile_contents)
36
+ end
37
+
38
+ # Re-evaluates the `Guardfile` to update
39
+ # the current Guard configuration.
40
+ #
41
+ def reevaluate_guardfile
42
+ _before_reevaluate_guardfile
43
+ evaluate_guardfile
44
+ _after_reevaluate_guardfile
45
+ end
46
+
47
+ # Tests if the current `Guardfile` contains a specific Guard plugin.
48
+ #
49
+ # @example Programmatically test if a Guardfile contains a specific Guard plugin
50
+ # File.read('Guardfile')
51
+ # #=> "guard :rspec"
52
+ #
53
+ # Guard::Guardfile::Evaluator.new.guardfile_include?('rspec)
54
+ # #=> true
55
+ #
56
+ # @param [String] plugin_name the name of the Guard
57
+ # @return [Boolean] whether the Guard plugin has been declared
58
+ #
59
+ def guardfile_include?(plugin_name)
60
+ _guardfile_contents_without_user_config.match(/^guard\s*\(?\s*['":]#{ plugin_name }['"]?/)
61
+ end
62
+
63
+ # Gets the file path to the project `Guardfile`.
64
+ #
65
+ # @example Gets the path of the currently evaluated Guardfile
66
+ # Dir.pwd
67
+ # #=> "/Users/remy/Code/github/guard"
68
+ #
69
+ # evaluator = Guard::Guardfile::Evaluator.new
70
+ # evaluator.evaluate_guardfile
71
+ # #=> nil
72
+ #
73
+ # evaluator.guardfile_path
74
+ # #=> "/Users/remy/Code/github/guard/Guardfile"
75
+ #
76
+ # @example Gets the "path" of an inline Guardfile
77
+ # > Guard::Guardfile::Evaluator.new(guardfile_contents: 'guard :rspec').evaluate_guardfile
78
+ # => nil
79
+ #
80
+ # > Guard::Guardfile::Evaluator.new.guardfile_path
81
+ # => "Inline Guardfile"
82
+ #
83
+ # @return [String] the path to the Guardfile or 'Inline Guardfile' if
84
+ # the Guardfile has been specified via the `:guardfile_contents` option.
85
+ #
86
+ def guardfile_path
87
+ options.guardfile_path || ''
88
+ end
89
+
90
+ # Gets the content of the `Guardfile` concatenated with the global
91
+ # user configuration file.
92
+ #
93
+ # @example Programmatically get the content of the current Guardfile
94
+ # Guard::Guardfile::Evaluator.new.guardfile_contents
95
+ # #=> "guard :rspec"
96
+ #
97
+ # @return [String] the Guardfile content
98
+ #
99
+ def guardfile_contents
100
+ config = File.read(_user_config_path) if File.exist?(_user_config_path)
101
+ [_guardfile_contents_without_user_config, config].compact.join("\n")
102
+ end
103
+
104
+ private
105
+
106
+ # Gets the default path of the `Guardfile`. This returns the `Guardfile`
107
+ # from the current directory when existing, or the global `~/.Guardfile`.
108
+ #
109
+ # @return [String] the path to the Guardfile
110
+ #
111
+ def _guardfile_default_path
112
+ File.exist?(_local_guardfile_path) ? _local_guardfile_path : _home_guardfile_path
113
+ end
114
+
115
+ # Gets the content of the `Guardfile`.
116
+ #
117
+ # @return [String] the Guardfile content
118
+ #
119
+ def _guardfile_contents_without_user_config
120
+ options.guardfile_contents || ''
121
+ end
122
+
123
+ # Evaluates the content of the `Guardfile`.
124
+ #
125
+ # @param [String] contents the content to evaluate.
126
+ #
127
+ def _instance_eval_guardfile(contents)
128
+ ::Guard::Dsl.new.instance_eval(contents, options.guardfile_path, 1)
129
+ rescue => ex
130
+ ::Guard::UI.error "Invalid Guardfile, original error is:\n#{ $! }"
131
+ raise ex
132
+ end
133
+
134
+ # Gets the content to evaluate and stores it into
135
+ # the options as `:guardfile_contents`.
136
+ #
137
+ def _fetch_guardfile_contents
138
+ if options.guardfile_contents
139
+ ::Guard::UI.info 'Using inline Guardfile.'
140
+ options.guardfile_path = 'Inline Guardfile'
141
+
142
+ elsif options.guardfile
143
+ if File.exist?(options.guardfile)
144
+ _read_guardfile(options.guardfile)
145
+ ::Guard::UI.info "Using Guardfile at #{ options.guardfile }."
146
+ else
147
+ ::Guard::UI.error "No Guardfile exists at #{ options.guardfile }."
148
+ exit 1
149
+ end
150
+
151
+ else
152
+ if File.exist?(_guardfile_default_path)
153
+ _read_guardfile(_guardfile_default_path)
154
+ else
155
+ ::Guard::UI.error 'No Guardfile found, please create one with `guard init`.'
156
+ exit 1
157
+ end
158
+ end
159
+
160
+ unless _guardfile_contents_usable?
161
+ ::Guard::UI.error 'No Guard plugins found in Guardfile, please add at least one.'
162
+ end
163
+ end
164
+
165
+ # Reads the current `Guardfile` content.
166
+ #
167
+ # @param [String] guardfile_path the path to the Guardfile
168
+ #
169
+ def _read_guardfile(guardfile_path)
170
+ options.guardfile_path = guardfile_path
171
+ options.guardfile_contents = File.read(guardfile_path)
172
+ rescue => ex
173
+ ::Guard::UI.error ex.inspect
174
+ ::Guard::UI.error("Error reading file #{ guardfile_path }")
175
+ exit 1
176
+ end
177
+
178
+ # Stops Guard and clear internal state
179
+ # before the Guardfile will be re-evaluated.
180
+ #
181
+ def _before_reevaluate_guardfile
182
+ ::Guard.runner.run(:stop)
183
+ ::Guard.reset_groups
184
+ ::Guard.reset_plugins
185
+ ::Guard::Notifier.clear_notifiers
186
+
187
+ options.guardfile_contents
188
+ end
189
+
190
+ # Starts Guard and notification and show a message
191
+ # after the Guardfile has been re-evaluated.
192
+ #
193
+ def _after_reevaluate_guardfile
194
+ ::Guard::Notifier.turn_on if ::Guard::Notifier.enabled?
195
+
196
+ if ::Guard.plugins.empty?
197
+ ::Guard::Notifier.notify('No plugins found in Guardfile, please add at least one.', title: 'Guard re-evaluate', image: :failed)
198
+ else
199
+ msg = 'Guardfile has been re-evaluated.'
200
+ ::Guard::UI.info(msg)
201
+ ::Guard::Notifier.notify(msg, title: 'Guard re-evaluate')
202
+
203
+ ::Guard.runner.run(:start)
204
+ end
205
+ end
206
+
207
+ # Tests if the current `Guardfile` content is usable.
208
+ #
209
+ # @return [Boolean] if the Guardfile is usable
210
+ #
211
+ def _guardfile_contents_usable?
212
+ guardfile_contents && guardfile_contents =~ /guard/m
213
+ end
214
+
215
+ # The path to the `Guardfile` that is located at
216
+ # the directory, where Guard has been started from.
217
+ #
218
+ # @return [String] the path to the local Guardfile
219
+ #
220
+ def _local_guardfile_path
221
+ File.join(Dir.pwd, 'Guardfile')
222
+ end
223
+
224
+ # The path to the `.Guardfile` that is located at
225
+ # the users home directory.
226
+ #
227
+ # @return [String] the path to `~/.Guardfile`
228
+ #
229
+ def _home_guardfile_path
230
+ File.expand_path(File.join('~', '.Guardfile'))
231
+ end
232
+
233
+ # The path to the user configuration `.guard.rb`
234
+ # that is located at the users home directory.
235
+ #
236
+ # @return [String] the path to `~/.guard.rb`
237
+ #
238
+ def _user_config_path
239
+ File.expand_path(File.join('~', '.guard.rb'))
240
+ end
241
+
242
+ end
243
+
244
+ end
245
+ end
@@ -0,0 +1,89 @@
1
+ module Guard
2
+ module Guardfile
3
+
4
+ # This class is responsible for generating the Guardfile and adding Guard'
5
+ # plugins' templates into it.
6
+ #
7
+ # @see Guard::CLI
8
+ #
9
+ class Generator
10
+
11
+ require 'guard'
12
+ require 'guard/ui'
13
+
14
+ attr_reader :options
15
+
16
+ # The Guardfile template for `guard init`
17
+ GUARDFILE_TEMPLATE = File.expand_path('../../../guard/templates/Guardfile', __FILE__)
18
+
19
+ # The location of user defined templates
20
+ HOME_TEMPLATES = File.expand_path('~/.guard/templates')
21
+
22
+ # Initialize a new `Guard::Guardfile::Generator` object.
23
+ #
24
+ # @param [Hash] options The options for creating a Guardfile
25
+ # @option options [Boolean] :abort_on_existence Whether to abort or not
26
+ # when a Guardfile already exists
27
+ #
28
+ def initialize(options = {})
29
+ @options = options
30
+ end
31
+
32
+ # Creates the initial Guardfile template when it does not
33
+ # already exist.
34
+ #
35
+ # @see Guard::CLI#init
36
+ #
37
+ def create_guardfile
38
+ if !File.exist?('Guardfile')
39
+ ::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile"
40
+ FileUtils.cp(GUARDFILE_TEMPLATE, 'Guardfile')
41
+ elsif options[:abort_on_existence]
42
+ ::Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
43
+ abort
44
+ end
45
+ end
46
+
47
+ # Adds the Guardfile template of a Guard plugin to an existing Guardfile.
48
+ #
49
+ # @see Guard::CLI#init
50
+ #
51
+ # @param [String] plugin_name the name of the Guard plugin or template to
52
+ # initialize
53
+ #
54
+ def initialize_template(plugin_name)
55
+ plugin_util = ::Guard::PluginUtil.new(plugin_name)
56
+ if plugin_util.plugin_class(fail_gracefully: true)
57
+ plugin_util.add_to_guardfile
58
+
59
+ @options[:guardfile] = File.read('Guardfile') if File.exists?('Guardfile')
60
+
61
+ elsif File.exist?(File.join(HOME_TEMPLATES, plugin_name))
62
+ content = File.read('Guardfile')
63
+
64
+ File.open('Guardfile', 'wb') do |f|
65
+ f.puts(content)
66
+ f.puts('')
67
+ f.puts(File.read(File.join(HOME_TEMPLATES, plugin_name)))
68
+ end
69
+
70
+ ::Guard::UI.info "#{ plugin_name } template added to Guardfile, feel free to edit it"
71
+ else
72
+ const_name = plugin_name.downcase.gsub('-', '')
73
+ UI.error "Could not load 'guard/#{ plugin_name.downcase }' or '~/.guard/templates/#{ plugin_name.downcase }' or find class Guard::#{ const_name.capitalize }"
74
+ end
75
+ end
76
+
77
+ # Adds the templates of all installed Guard implementations to an
78
+ # existing Guardfile.
79
+ #
80
+ # @see Guard::CLI#init
81
+ #
82
+ def initialize_all_templates
83
+ ::Guard::PluginUtil.plugin_names.each { |g| initialize_template(g) }
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+ end
@@ -1,3 +1,14 @@
1
+ require 'pry'
2
+
3
+ require 'guard/commands/all'
4
+ require 'guard/commands/change'
5
+ require 'guard/commands/notification'
6
+ require 'guard/commands/pause'
7
+ require 'guard/commands/reload'
8
+ require 'guard/commands/scope'
9
+ require 'guard/commands/show'
10
+ require 'guard/ui'
11
+
1
12
  module Guard
2
13
 
3
14
  # The Guard interactor is a Pry REPL with a Guard
@@ -5,80 +16,86 @@ module Guard
5
16
  #
6
17
  class Interactor
7
18
 
8
- require 'pry'
9
-
10
- require 'guard'
11
- require 'guard/ui'
12
-
13
- require 'guard/commands/all'
14
- require 'guard/commands/change'
15
- require 'guard/commands/notification'
16
- require 'guard/commands/pause'
17
- require 'guard/commands/reload'
18
- require 'guard/commands/scope'
19
- require 'guard/commands/show'
20
-
21
19
  # The default Ruby script to configure Guard Pry if the option `:guard_rc` is not defined.
22
- GUARD_RC = '~/.guardrc'
20
+ GUARD_RC = '~/.guardrc'
23
21
 
24
22
  # The default Guard Pry history file if the option `:history_file` is not defined.
25
23
  HISTORY_FILE = '~/.guard_history'
26
24
 
27
25
  # List of shortcuts for each interactor command
28
26
  SHORTCUTS = {
29
- :help => 'h',
30
- :all => 'a',
31
- :reload => 'r',
32
- :change => 'c',
33
- :show => 's',
34
- :scope => 'o',
35
- :notification => 'n',
36
- :pause => 'p',
37
- :exit => 'e',
38
- :quit => 'q'
27
+ help: 'h',
28
+ all: 'a',
29
+ reload: 'r',
30
+ change: 'c',
31
+ show: 's',
32
+ scope: 'o',
33
+ notification: 'n',
34
+ pause: 'p',
35
+ exit: 'e',
36
+ quit: 'q'
39
37
  }
40
38
 
41
39
  attr_accessor :thread
42
40
 
43
- class << self
41
+ # Get the interactor options
42
+ #
43
+ # @return [Hash] the options
44
+ #
45
+ def self.options
46
+ @options ||= {}
47
+ end
44
48
 
45
- # Get the interactor options
46
- #
47
- # @return [Hash] the options
48
- #
49
- def options
50
- @options ||= { }
51
- end
49
+ # Set the interactor options
50
+ #
51
+ # @param [Hash] options the interactor options
52
+ # @option options [String] :guard_rc the Ruby script to configure Guard Pry
53
+ # @option options [String] :history_file the file to write the Pry history to
54
+ #
55
+ def self.options=(options)
56
+ @options = options
57
+ end
52
58
 
53
- # Set the interactor options
54
- #
55
- # @param [Hash] options the interactor options
56
- # @option options [String] :guard_rc the Ruby script to configure Guard Pry
57
- # @option options [String] :history_file the file to write the Pry history to
58
- #
59
- def options=(options)
60
- @options = options
61
- end
59
+ # Is the interactor enabled?
60
+ #
61
+ # @return [Boolean] true if enabled
62
+ #
63
+ def self.enabled
64
+ @enabled || @enabled.nil?
65
+ end
62
66
 
63
- # Is the interactor enabled?
64
- #
65
- # @return [Boolean] true if enabled
66
- #
67
- def enabled
68
- @enabled.nil? ? true : @enabled
69
- end
67
+ # Set the enabled status for the interactor
68
+ #
69
+ # @param [Boolean] status true if enabled
70
+ #
71
+ def self.enabled=(status)
72
+ @enabled = status
73
+ end
74
+
75
+ # Converts and validates a plain text scope
76
+ # to a valid plugin or group scope.
77
+ #
78
+ # @param [Array<String>] entries the text scope
79
+ # @return [Hash, Array<String>] the plugin or group scope, the unknown entries
80
+ #
81
+ def self.convert_scope(entries)
82
+ scopes = { plugins: [], groups: [] }
83
+ unknown = []
70
84
 
71
- # Set the enabled status for the interactor
72
- #
73
- # @param [Boolean] status true if enabled
74
- #
75
- def enabled=(status)
76
- @enabled = status
85
+ entries.each do |entry|
86
+ if plugin = ::Guard.plugin(entry)
87
+ scopes[:plugins] << plugin
88
+ elsif group = ::Guard.group(entry)
89
+ scopes[:groups] << group
90
+ else
91
+ unknown << entry
92
+ end
77
93
  end
78
94
 
95
+ [scopes, unknown]
79
96
  end
80
97
 
81
- # Initialize the interactor. This configures
98
+ # Initializes the interactor. This configures
82
99
  # Pry and creates some custom commands and aliases
83
100
  # for Guard.
84
101
  #
@@ -90,24 +107,58 @@ module Guard
90
107
  Pry.config.history.file = File.expand_path(self.class.options[:history_file] || HISTORY_FILE)
91
108
 
92
109
  @stty_exists = nil
93
- add_hooks
110
+ _add_hooks
111
+
112
+ _replace_reset_command
113
+ _create_run_all_command
114
+ _create_command_aliases
115
+ _create_guard_commands
116
+ _create_group_commands
117
+
118
+ _configure_prompt
119
+ end
120
+
121
+ # Start the line reader in its own thread and
122
+ # stop Guard on Ctrl-D.
123
+ #
124
+ def start
125
+ return if ENV['GUARD_ENV'] == 'test'
126
+
127
+ _store_terminal_settings if _stty_exists?
128
+
129
+ if !@thread || !['sleep', 'run'].include?(@thread.status)
130
+ ::Guard::UI.debug 'Start interactor'
131
+
132
+ @thread = Thread.new do
133
+ Pry.start
134
+ ::Guard.stop
135
+ end
136
+ end
137
+ end
138
+
139
+ # Kill interactor thread if not current
140
+ #
141
+ def stop
142
+ return if !@thread || ENV['GUARD_ENV'] == 'test'
94
143
 
95
- replace_reset_command
96
- create_run_all_command
97
- create_command_aliases
98
- create_guard_commands
99
- create_group_commands
144
+ unless Thread.current == @thread
145
+ ::Guard::UI.reset_line
146
+ ::Guard::UI.debug 'Stop interactor'
147
+ @thread.kill
148
+ end
100
149
 
101
- configure_prompt
150
+ _restore_terminal_settings if _stty_exists?
102
151
  end
103
152
 
153
+ private
154
+
104
155
  # Add Pry hooks:
105
156
  #
106
157
  # * Load `~/.guardrc` within each new Pry session.
107
158
  # * Load project's `.guardrc` within each new Pry session.
108
159
  # * Restore prompt after each evaluation.
109
160
  #
110
- def add_hooks
161
+ def _add_hooks
111
162
  Pry.config.hooks.add_hook :when_started, :load_guard_rc do
112
163
  (self.class.options[:guard_rc] || GUARD_RC).tap do |p|
113
164
  load p if File.exist?(File.expand_path(p))
@@ -119,7 +170,7 @@ module Guard
119
170
  load project_guard_rc if File.exist?(project_guard_rc)
120
171
  end
121
172
 
122
- if stty_exists?
173
+ if _stty_exists?
123
174
  Pry.config.hooks.add_hook :after_eval, :restore_visibility do
124
175
  system("stty echo 2>#{ DEV_NULL }")
125
176
  end
@@ -128,8 +179,8 @@ module Guard
128
179
 
129
180
  # Replaces reset defined inside of Pry with a reset that
130
181
  # instead restarts guard.
131
-
132
- def replace_reset_command
182
+ #
183
+ def _replace_reset_command
133
184
  Pry.commands.command "reset", "Reset the Guard to a clean state." do
134
185
  output.puts "Guard reset."
135
186
  exec "guard"
@@ -140,7 +191,7 @@ module Guard
140
191
  # when the command is empty (just pressing enter on the
141
192
  # beginning of a line).
142
193
  #
143
- def create_run_all_command
194
+ def _create_run_all_command
144
195
  Pry.commands.block_command /^$/, 'Hit enter to run all' do
145
196
  Pry.run_command 'all'
146
197
  end
@@ -150,7 +201,7 @@ module Guard
150
201
  # `help`, `reload`, `change`, `scope`, `notification`, `pause`, `exit` and `quit`,
151
202
  # which will be the first letter of the command.
152
203
  #
153
- def create_command_aliases
204
+ def _create_command_aliases
154
205
  SHORTCUTS.each do |command, shortcut|
155
206
  Pry.commands.alias_command shortcut, command.to_s
156
207
  end
@@ -161,11 +212,9 @@ module Guard
161
212
  # when guard-rspec is available, then a command
162
213
  # `rspec` is created that runs `all rspec`.
163
214
  #
164
- def create_guard_commands
165
- ::Guard.guards.each do |guard|
166
- name = guard.class.to_s.downcase.sub('guard::', '')
167
-
168
- Pry.commands.create_command name, "Run all #{ name }" do
215
+ def _create_guard_commands
216
+ ::Guard.plugins.each do |guard_plugin|
217
+ Pry.commands.create_command guard_plugin.name, "Run all #{ guard_plugin.title }" do
169
218
  group 'Guard'
170
219
 
171
220
  def process
@@ -180,12 +229,11 @@ module Guard
180
229
  # when you have a group `frontend`, then a command
181
230
  # `frontend` is created that runs `all frontend`.
182
231
  #
183
- def create_group_commands
232
+ def _create_group_commands
184
233
  ::Guard.groups.each do |group|
185
- name = group.name.to_s
186
- next if name == 'default'
234
+ next if group.name == :default
187
235
 
188
- Pry.commands.create_command name, "Run all #{ name }" do
236
+ Pry.commands.create_command group.name.to_s, "Run all #{ group.title }" do
189
237
  group 'Guard'
190
238
 
191
239
  def process
@@ -198,71 +246,29 @@ module Guard
198
246
  # Configure the pry prompt to see `guard` instead of
199
247
  # `pry`.
200
248
  #
201
- def configure_prompt
202
- Pry.config.prompt = [
203
- proc do |target_self, nest_level, pry|
204
- history = pry.input_array.size
205
- process = ::Guard.listener.paused? ? 'pause' : 'guard'
206
- clip = Pry.view_clip(target_self)
207
- level = ":#{ nest_level }" unless nest_level.zero?
208
- scope = if !::Guard.scope[:plugins].empty?
209
- "{#{ ::Guard.scope[:plugins].join(',') }} "
210
- elsif !::Guard.scope[:groups].empty?
211
- "{#{ ::Guard.scope[:groups].join(',') }} "
212
- else
213
- ''
214
- end
215
-
216
- "[#{ history }] #{ scope }#{ process }(#{ clip })#{ level }> "
217
- end,
218
- proc do |target_self, nest_level, pry|
219
- history = pry.input_array.size
220
- process = ::Guard.listener.paused? ? 'pause' : 'guard'
221
- clip = Pry.view_clip(target_self)
222
- level = ":#{ nest_level }" unless nest_level.zero?
223
- scope = if !::Guard.scope[:plugins].empty?
224
- "{#{ ::Guard.scope[:plugins].join }} "
225
- elsif !::Guard.scope[:groups].empty?
226
- "{#{ ::Guard.scope[:groups].join }} "
227
- else
228
- ''
229
- end
230
-
231
- "[#{ history }] #{ scope }#{ process }(#{ clip })#{ level }* "
232
- end
233
- ]
234
- end
235
-
236
- # Start the line reader in its own thread and
237
- # stop Guard on Ctrl-D.
238
- #
239
- def start
240
- return if ENV['GUARD_ENV'] == 'test'
241
-
242
- store_terminal_settings if stty_exists?
243
-
244
- if !@thread || !['sleep', 'run'].include?(@thread.status)
245
- ::Guard::UI.debug 'Start interactor'
246
-
247
- @thread = Thread.new do
248
- Pry.start
249
- ::Guard.stop
250
- end
251
- end
249
+ def _configure_prompt
250
+ Pry.config.prompt = [_prompt('>'), _prompt('*')]
252
251
  end
253
252
 
254
- # Kill interactor thread if not current
253
+ # Returns a proc that will return itself a string ending with the given
254
+ # `ending_char` when called.
255
255
  #
256
- def stop
257
- return if !@thread || ENV['GUARD_ENV'] == 'test'
258
-
259
- unless Thread.current == @thread
260
- ::Guard::UI.reset_line
261
- ::Guard::UI.debug 'Stop interactor'
262
- @thread.kill
256
+ def _prompt(ending_char)
257
+ proc do |target_self, nest_level, pry|
258
+ history = pry.input_array.size
259
+ process = ::Guard.listener.paused? ? 'pause' : 'guard'
260
+ clip = Pry.view_clip(target_self)
261
+ level = ":#{ nest_level }" unless nest_level.zero?
262
+ scope = if !::Guard.scope[:plugins].empty?
263
+ "{#{ ::Guard.scope[:plugins].map(&:title).join(',') }} "
264
+ elsif !::Guard.scope[:groups].empty?
265
+ "{#{ ::Guard.scope[:groups].map(&:title).join(',') }} "
266
+ else
267
+ ''
268
+ end
269
+
270
+ "[#{ history }] #{ scope }#{ process }(#{ clip })#{ level }#{ending_char} "
263
271
  end
264
-
265
- restore_terminal_settings if stty_exists?
266
272
  end
267
273
 
268
274
  # Detects whether or not the stty command exists
@@ -270,7 +276,7 @@ module Guard
270
276
  #
271
277
  # @return [Boolean] the status of stty
272
278
  #
273
- def stty_exists?
279
+ def _stty_exists?
274
280
  @stty_exists ||= system('hash', 'stty') ? true : false if @stty_exists.nil?
275
281
  @stty_exists
276
282
  end
@@ -278,37 +284,15 @@ module Guard
278
284
  # Stores the terminal settings so we can resore them
279
285
  # when stopping.
280
286
  #
281
- def store_terminal_settings
287
+ def _store_terminal_settings
282
288
  @stty_save = `stty -g 2>#{ DEV_NULL }`.chomp
283
289
  end
284
290
 
285
291
  # Restore terminal settings
286
292
  #
287
- def restore_terminal_settings
293
+ def _restore_terminal_settings
288
294
  system("stty #{ @stty_save } 2>#{ DEV_NULL }") if @stty_save
289
295
  end
290
296
 
291
- # Converts and validates a plain text scope
292
- # to a valid plugin or group scope.
293
- #
294
- # @param [Array<String>] entries the text scope
295
- # @return [Hash, Array<String>] the plugin or group scope, the unknown entries
296
- #
297
- def self.convert_scope(entries)
298
- scopes = { :plugins => [], :groups => [] }
299
- unknown = []
300
-
301
- entries.each do |entry|
302
- if plugin = ::Guard.guards(entry)
303
- scopes[:plugins] << plugin
304
- elsif group = ::Guard.groups(entry)
305
- scopes[:groups] << group
306
- else
307
- unknown << entry
308
- end
309
- end
310
-
311
- [scopes, unknown]
312
- end
313
297
  end
314
298
  end