guard 1.8.3 → 2.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
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