Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial Pry integration.

  • Loading branch information...
commit 455489ca8a697c8641e64531c20fb082b152a71f 1 parent 76a849c
@netzpirat netzpirat authored
Showing with 297 additions and 1,122 deletions.
  1. +2 −7 Gemfile
  2. +0 −2  Guardfile
  3. +22 −83 README.md
  4. +1 −0  guard.gemspec
  5. +1 −1  lib/guard.rb
  6. +34 −0 lib/guard/commands/all.rb
  7. +33 −0 lib/guard/commands/change.rb
  8. +27 −0 lib/guard/commands/notification.rb
  9. +28 −0 lib/guard/commands/pause.rb
  10. +35 −0 lib/guard/commands/reload.rb
  11. +27 −0 lib/guard/commands/show.rb
  12. +13 −3 lib/guard/dsl.rb
  13. +43 −236 lib/guard/interactor.rb
  14. +0 −64 lib/guard/interactors/coolline.rb
  15. +0 −32 lib/guard/interactors/helpers/completion.rb
  16. +0 −46 lib/guard/interactors/helpers/terminal.rb
  17. +0 −94 lib/guard/interactors/readline.rb
  18. +0 −19 lib/guard/interactors/simple.rb
  19. +13 −2 lib/guard/notifier.rb
  20. +0 −302 spec/guard/interactor_spec.rb
  21. +0 −49 spec/guard/interactors/coolline_spec.rb
  22. +0 −51 spec/guard/interactors/helpers/completion_spec.rb
  23. +0 −51 spec/guard/interactors/helpers/terminal_spec.rb
  24. +0 −53 spec/guard/interactors/readline_spec.rb
  25. +0 −25 spec/guard/interactors/simple_spec.rb
  26. +16 −0 spec/guard/notifier_spec.rb
  27. +2 −2 spec/support/guard_helper.rb
View
9 Gemfile
@@ -10,25 +10,20 @@ gem 'listen', :github => 'guard/listen'
#
group :development do
- gem 'pry'
-
gem 'guard-ronn'
gem 'yard'
gem 'redcarpet'
- platform :ruby_19 do
- gem 'coolline'
- end
-
require 'rbconfig'
if RbConfig::CONFIG['target_os'] =~ /darwin/i
- gem 'growl', :require => false
gem 'rb-fsevent', :require => false
if `uname`.strip == 'Darwin' && `sw_vers -productVersion`.strip >= '10.8'
gem 'terminal-notifier-guard', '~> 1.5.3', :require => false
+ else
+ gem 'growl', :require => false
end rescue Errno::ENOENT
elsif RbConfig::CONFIG['target_os'] =~ /linux/i
View
2  Guardfile
@@ -1,5 +1,3 @@
-notification :off
-
group :specs do
guard :rspec, :cli => '--fail-fast --format doc' do
watch(%r{^spec/.+_spec\.rb$})
View
105 README.md
@@ -420,82 +420,37 @@ read more about these files in the shared configuration section below.
Interactions
------------
-You can interact with Guard and enter commands when Guard has nothing to do. Guard understands the following commands:
+Guard shows a [Pry](http://pryrepl.org/) console whenever it has nothing to do and comes with some Guard specific Pry
+commands:
-* `↩`: Run all plugins.
-* `h`, `help`: Show a help of the available interactor commands.
-* `r`, `reload`: Reload all plugins.
-* `c`, `change`: Trigger a file change to the plugins.
-* `s`, `show`: Show the plugin configurations.
-* `n`, `notification`: Toggle system notifications on and off.
-* `p`, `pause`: Toggles the file modification listener. The prompt will change to `p>` when paused.
- This is useful when switching Git branches, rebase Git or change whitespace.
-* `e`, `exit`: Stop all plugins and quit Guard.
+ * `all` Run all plugins.
+ * `change` Trigger a file change.
+ * `notification` Toggles the notifications.
+ * `pause` Toggles the file listener.
+ * `reload` Reload all plugins.
+ * `show` Show all Guard plugins.
-Instead of running all plugins with the `↩` key, you can also run a single plugin by entering its name:
+The `all` and `reload` commands supports an optional scope, so you limit the Guard action to either a Guard plugin or
+a Guard group like:
```bash
-> rspec
+[1] guard(main)> all rspec
+[2] guard(main)> all frontend
```
-It's also possible to run all plugins within a group by entering the group name:
+Remember, you can always use `help` on the Pry command line to see all available commands and `help <command>` for
+more detailed information.
-```bash
-> frontend
-```
-
-The same applies to reloading. You can reload a plugin with the following command:
-
-```bash
-> ronn reload
-```
-
-This will reload only the Ronn plugin. You can also reload all plugins within a group:
-
-```bash
-> backend reload
-```
+Pry supports the Ruby built-in Readline, [rb-readline](https://github.com/luislavena/rb-readline) and
+[Coolline](https://github.com/Mon-Ouie/coolline). Just install the readline implementation of your choice by adding it
+to your `Gemfile.
-The action and plugin/group name can have any order, so you can also write:
+You can also disable the interactions completely by running Guard with the `--no-interactions` option.
-```bash
-> reload backend
-```
-
-You can pass a list of filenames to the `change` command to trigger manually a file modification:
-
-```bash
-> change spec/guard_spec.rb
-```
-
-### Readline support
-
-With Readline enabled, you'll see a command prompt `>` when Guard is ready to accept a command. The command line
-supports history navigation with the `↑` and `↓` arrow keys, and command auto-completion with the `⇥` key.
-
-Unfortunately Readline [does not work on MRI](http://bugs.ruby-lang.org/issues/5539) on Mac OS X by default. You can
-work around the issue by installing a pure Ruby implementation:
-
-```ruby
-platforms :ruby do
- gem 'rb-readline'
-end
-```
-
-Guard will automatically enable Readline support if your environment supports it, but you can disable Readline with the
-`interactor` DSL method or turn off completely with the `--no-interactions` option.
-
-### Coolline support
-
-With Ruby 1.9.3 you can use a [Coolline](https://github.com/Mon-Ouie/coolline) based interactor, which uses the new
-`io/console` from stdlib. Just add it to your `Gemfile`
-
-```ruby
-gem 'coolline'
-```
-
-Guard will automatically enable Coolline support if your environment supports it, but you can disable Coolline with the
-`interactor` DSL method or turn off completely with the `--no-interactions` option.
+Further Guard specific customizations can be made in `~/.guardrc` that will be evaluated prior the Pry session is
+started. This allows you to make use of the Pry plugin architecture to provide custom commands and extend Guard for
+your own needs and distribute as a gem. Please have a look at the [Pry Wiki](https://github.com/pry/pry/wiki) for more
+information.
### Signals
@@ -644,22 +599,6 @@ or using the cli switch `-n`:
notification :off
```
-### interactor
-
-You can disable the interactor auto detection and select a specific implementation:
-
-```ruby
-interactor :coolline
-interactor :readline
-interactor :simple
-```
-
-If you do not need the keyboard interactions with Guard at all, you can turn them off:
-
-```ruby
-interactor :off
-```
-
### callback
The `callback` method allows you to execute arbitrary code before or after any of the `start`, `stop`, `reload`,
View
1  guard.gemspec
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
s.add_dependency 'thor', '>= 0.14.6'
s.add_dependency 'listen', '>= 0.4.2'
+ s.add_dependency 'pry'
s.add_development_dependency 'bundler'
s.add_development_dependency 'rspec', '~> 2.11.0'
View
2  lib/guard.rb
@@ -130,7 +130,7 @@ def setup_notifier
#
def setup_interactor
unless options[:no_interactions]
- @interactor = ::Guard::Interactor.fabricate
+ @interactor = ::Guard::Interactor.new
end
end
View
34 lib/guard/commands/all.rb
@@ -0,0 +1,34 @@
+module Guard
+ class Interactor
+
+ ALL = Pry::CommandSet.new do
+ create_command 'all' do
+
+ group 'Guard'
+ description 'Run all plugins.'
+
+ banner <<-BANNER
+ Usage: all <scope>
+
+ Run the Guard plugin `run_all` action.
+
+ You may want to specify an optional scope to the action,
+ either the name of a Guard plugin or a plugin group.
+ BANNER
+
+ def process(*entries)
+ scopes, rest = ::Guard::Interactor.convert_scope(entries)
+
+ if rest.length == 0
+ ::Guard.run_all scopes
+ else
+ puts "Unkown scope #{ rest.join(', ') }"
+ end
+ end
+ end
+ end
+
+ end
+end
+
+Pry.commands.import ::Guard::Interactor::ALL
View
33 lib/guard/commands/change.rb
@@ -0,0 +1,33 @@
+module Guard
+ class Interactor
+
+ CHANGE = Pry::CommandSet.new do
+ create_command 'change' do
+
+ group 'Guard'
+ description 'Trigger a file change.'
+
+ banner <<-BANNER
+ Usage: change <scope>
+
+ Runs the Guard plugin `run_on_changes` action.
+
+ You may want to specify an optional scope to the action,
+ either the name of a Guard plugin or a plugin group.
+ BANNER
+
+ def process(*files)
+ scopes, rest = ::Guard::Interactor.convert_scope(entries)
+
+ ::Guard.within_preserved_state do
+ ::Guard.runner.run_on_changes(rest, [], [])
+ end
+ end
+
+ end
+ end
+
+ end
+end
+
+Pry.commands.import ::Guard::Interactor::CHANGE
View
27 lib/guard/commands/notification.rb
@@ -0,0 +1,27 @@
+require 'guard/notifier'
+
+module Guard
+ class Interactor
+
+ NOTIFICATION = Pry::CommandSet.new do
+ create_command 'notification' do
+
+ group 'Guard'
+ description 'Toggles the notifications.'
+
+ banner <<-BANNER
+ Usage: notification
+
+ Toggles the notifications on and off.
+ BANNER
+
+ def process
+ ::Guard::Notifier.toggle
+ end
+ end
+ end
+
+ end
+end
+
+Pry.commands.import ::Guard::Interactor::NOTIFICATION
View
28 lib/guard/commands/pause.rb
@@ -0,0 +1,28 @@
+module Guard
+ class Interactor
+
+ PAUSE = Pry::CommandSet.new do
+ create_command 'pause' do
+
+ group 'Guard'
+ description 'Toggles the file listener.'
+
+ banner <<-BANNER
+ Usage: pause
+
+ Toggles the file listener on and off.
+
+ When the file listener is paused, the default Guard Pry
+ prompt will show the pause sign `[p]`.
+ BANNER
+
+ def process
+ ::Guard.pause
+ end
+ end
+ end
+
+ end
+end
+
+Pry.commands.import ::Guard::Interactor::PAUSE
View
35 lib/guard/commands/reload.rb
@@ -0,0 +1,35 @@
+module Guard
+ class Interactor
+
+ RELOAD = Pry::CommandSet.new do
+ create_command 'reload' do
+
+ group 'Guard'
+ description 'Reload all plugins.'
+
+ banner <<-BANNER
+ Usage: reload <scope>
+
+ Run the Guard plugin `reload` action.
+
+ You may want to specify an optional scope to the action,
+ either the name of a Guard plugin or a plugin group.
+ BANNER
+
+ def process(*entries)
+ scopes, rest = ::Guard::Interactor.convert_scope(entries)
+
+ if rest.length == 0
+ ::Guard.reload scopes
+ else
+ puts "Unkown scope #{ rest.join(', ') }"
+ end
+ end
+
+ end
+ end
+
+ end
+end
+
+Pry.commands.import ::Guard::Interactor::RELOAD
View
27 lib/guard/commands/show.rb
@@ -0,0 +1,27 @@
+require 'guard/dsl_describer'
+
+module Guard
+ class Interactor
+
+ SHOW = Pry::CommandSet.new do
+ create_command 'show' do
+
+ group 'Guard'
+ description 'Show all Guard plugins.'
+
+ banner <<-BANNER
+ Usage: show <scope>
+
+ Show all defined Guard plugins and their options.
+ BANNER
+
+ def process
+ ::Guard::DslDescriber.show(::Guard.options)
+ end
+ end
+ end
+
+ end
+end
+
+Pry.commands.import ::Guard::Interactor::SHOW
View
16 lib/guard/dsl.rb
@@ -16,7 +16,7 @@ module Guard
#
# A more advanced DSL use is the `callback` keyword that allows you to execute arbitrary
# code before or after any of the `start`, `stop`, `reload`, `run_all`, `run_on_changes`,
- # `run_on_additions`, `run_on_modifications` and `run_on_removals` Guard plugins method.
+ # `run_on_additions`, `run_on_modifications` and `run_on_removals` Guard plugins method.
# You can even insert more hooks inside these methods.
# Please [checkout the Wiki page](https://github.com/guard/guard/wiki/Hooks-and-callbacks) for more details.
#
@@ -93,12 +93,20 @@ class Dsl
# Deprecation message for the `ignore_paths` method
IGNORE_PATHS_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
- Starting with Guard v1.1 the use of the 'ignore_paths' Guardfile dsl method is deprecated.
+ Starting with Guard v1.1 the use of the 'ignore_paths' Guardfile DSL method is deprecated.
Please replace that method with the better 'ignore' or/and 'filter' methods.
Documentation on the README: https://github.com/guard/guard#guardfile-dsl-ignore
EOS
+ # Deprecation message for the `ignore_paths` method
+ INTERACTOR_DEPRECATION = <<-EOS.gsub(/^\s*/, '')
+ Starting with Guard v1.4 the use of the 'interactor' Guardfile DSL method is deprecated.
+
+ Please make use of the Pry plugin architecture to customize the interactions and place them
+ either in your `~/.guardrc` or the `Guardfile`.
+ EOS
+
class << self
@@options = nil
@@ -324,8 +332,10 @@ def notification(notifier, options = {})
# @example Turn off interactions
# interactor :off
#
+ # @deprecated
+ #
def interactor(interactor)
- ::Guard::Interactor.interactor = interactor.to_sym
+ ::Guard::UI.deprecation(IINTERACTOR_DEPRECATION)
end
# Declares a group of Guard plugins to be run with `guard start --group group_name`.
View
279 lib/guard/interactor.rb
@@ -1,110 +1,34 @@
module Guard
- # The interactor triggers specific action from input
- # read by a interactor implementation.
- #
- # Currently the following actions are implemented:
- #
- # - h, help => Show help
- # - e, exit,
- # q. quit => Exit Guard
- # - r, reload => Reload Guard
- # - p, pause => Toggle file modification listener
- # - n, notification => Toggle notifications
- # - s, show => Show Guard plugin configuration
- # - c, change => Trigger a file change
- # - <enter> => Run all
- #
- # It's also possible to scope `reload` and `run all` actions to only a specified group or a guard.
- #
- # @example Reload backend group
- # backend reload
- # reload backend
- #
- # @example Reload rspec guard
- # spork reload
- # reload spork
- #
- # @example Run all jasmine specs
- # jasmine
- #
- # @abstract
+ # The Guard interactor is a Pry REPL with a Guard
+ # specific command set.
#
class Interactor
+ require 'pry'
+
require 'guard'
require 'guard/ui'
- require 'guard/dsl_describer'
- require 'guard/notifier'
- require 'guard/interactors/readline'
- require 'guard/interactors/coolline'
- require 'guard/interactors/simple'
-
- ACTIONS = {
- :help => %w[help h],
- :reload => %w[reload r],
- :stop => %w[exit e quit q],
- :pause => %w[pause p],
- :notification => %w[notification n],
- :show => %w[show s],
- :change => %w[change c]
- }
-
- # Set the interactor implementation
- #
- # @param [Symbol] interactor the name of the interactor
- #
- def self.interactor=(interactor)
- @interactor = interactor
- end
-
- # Get an instance of the currently configured
- # interactor implementation.
- #
- # @return [Interactor] an interactor implementation
- #
- def self.fabricate
- case @interactor
- when :coolline
- ::Guard::CoollineInteractor.new if ::Guard::CoollineInteractor.available?
- when :readline
- ::Guard::ReadlineInteractor.new if ::Guard::ReadlineInteractor.available?
- when :simple
- ::Guard::SimpleInteractor.new
- when :off
- nil
- else
- auto_detect
- end
- end
- # Tries to detect an optimal interactor for the
- # current environment.
- #
- # It returns the Readline implementation when:
- #
- # * rb-readline is installed
- # * The Ruby implementation is JRuby
- # * The current OS is not Mac OS X
- #
- # Otherwise the plain gets interactor is returned.
- #
- # @return [Interactor] an interactor implementation
- #
- def self.auto_detect
- [::Guard::CoollineInteractor, ::Guard::ReadlineInteractor, ::Guard::SimpleInteractor].detect do |interactor|
- interactor.available?(true)
- end.new
- end
-
- # Template method for checking if the Interactor is
- # available in the current environment?
- #
- # @param [Boolean] silent true if no error messages should be shown
- # @return [Boolean] the availability status
- #
- def self.available?(silent = false)
- true
+ require 'guard/commands/all'
+ require 'guard/commands/change'
+ require 'guard/commands/notification'
+ require 'guard/commands/pause'
+ require 'guard/commands/reload'
+ require 'guard/commands/show'
+
+ def initialize
+ Pry::RC_FILES << '~/.guardrc'
+ Pry.config.history.file = '~/.guard_history'
+
+ Pry.config.prompt = [
+ proc do |target_self, nest_level, pry|
+ "[#{pry.input_array.size}] #{ ::Guard.listener.paused? ? '[p]' : '' } guard(#{Pry.view_clip(target_self)})#{":#{nest_level}" unless nest_level.zero?}> "
+ end,
+ proc do |target_self, nest_level, pry|
+ "[#{pry.input_array.size}] #{ ::Guard.listener.paused? ? '[p]' : '' } guard(#{Pry.view_clip(target_self)})#{":#{nest_level}" unless nest_level.zero?}* "
+ end
+ ]
end
# Start the line reader in its own thread.
@@ -112,8 +36,15 @@ def self.available?(silent = false)
def start
return if ENV['GUARD_ENV'] == 'test'
- ::Guard::UI.debug 'Start interactor'
- @thread = Thread.new { read_line } if !@thread || !@thread.alive?
+ if !@thread || !@thread.alive?
+ ::Guard::UI.debug 'Start interactor'
+
+ @thread = Thread.new do
+ Pry.start
+ ::Guard.stop
+ exit
+ end
+ end
end
# Kill interactor thread if not current
@@ -121,157 +52,33 @@ def start
def stop
return if !@thread || ENV['GUARD_ENV'] == 'test'
- ::Guard::UI.debug 'Stop interactor'
unless Thread.current == @thread
+ ::Guard::UI.debug 'Stop interactor'
@thread.kill
end
end
- # Read the user input. This method must be implemented
- # by each interactor implementation.
- #
- # @abstract
- #
- def read_line
- raise NotImplementedError
- end
-
- # Process the input from readline.
- #
- # @param [String] line the input line
- #
- def process_input(line)
- scopes, action, rest = extract_scopes_and_action(line)
-
- case action
- when :help
- help
- when :show
- ::Guard::DslDescriber.show(::Guard.options)
- when :stop
- ::Guard.stop
- exit
- when :pause
- ::Guard.pause
- when :reload
- ::Guard.reload(scopes)
- when :change
- ::Guard.within_preserved_state do
- ::Guard.runner.run_on_changes(rest, [], [])
- end
- when :run_all
- ::Guard.run_all(scopes)
- when :notification
- toggle_notification
- else
- ::Guard::UI.error "Unknown command #{ line }"
- end
- end
-
- # Toggle the system notifications on/off
- #
- def toggle_notification
- if ENV['GUARD_NOTIFY'] == 'true'
- ::Guard::UI.info 'Turn off notifications'
- ::Guard::Notifier.turn_off
- else
- ::Guard::Notifier.turn_on
- end
- end
-
- # Show the help.
- #
- def help
- puts ''
- puts '[e]xit, [q]uit Exit Guard'
- puts '[p]ause Toggle file modification listener'
- puts '[r]eload Reload Guard'
- puts '[n]otification Toggle notifications'
- puts '[s]how Show available Guard plugins'
- puts '[c]hange <file> Trigger a file change'
- puts '<enter> Run all Guard plugins'
- puts ''
- puts 'You can scope the reload action to a specific guard or group:'
- puts ''
- puts 'rspec reload Reload the RSpec Guard'
- puts 'backend reload Reload the backend group'
- puts ''
- puts 'You can also run only a specific Guard or all Guard plugins in a specific group:'
- puts ''
- puts 'jasmine Run the jasmine Guard'
- puts 'frontend Run all Guard plugins in the frontend group'
- puts ''
- end
-
- # Extract the Guard or group scope and action from the
- # input line. There's no strict order for scopes and
- # actions.
+ # Converts and validates a plain text scope
+ # to a valid plugin or group scope.
#
- # @example `spork reload` will only reload rspec
- # @example `jasmine` will only run all jasmine specs
+ # @param [String] entries the text scope
+ # @return [Array<Hash}, Array] the plugin or group scope, the unknown entries
#
- # @param [String] line the readline input
- # @return [Array] the group or guard scope, the action and the rest
- #
- def extract_scopes_and_action(line)
- entries = line.split(' ')
-
- scopes = extract_scopes(entries)
- action = extract_action(entries)
+ def self.convert_scope(entries)
+ scopes = { }
+ unknown = []
- action = :run_all if !action && (!scopes.empty? || entries.empty?)
-
- [scopes, action, entries]
- end
-
- private
-
- # Extract a guard or group scope from entry if valid.
- # Any entry found will be removed from the entries.
- #
- # @param [Array<String>] entries the user entries
- # @return [Hash] a hash with a Guard or a group scope
- #
- def extract_scopes(entries)
- scopes = { }
-
- entries.delete_if do |entry|
+ entries.each do |entry|
if guard = ::Guard.guards(entry)
scopes[:guard] ||= guard
- true
-
elsif group = ::Guard.groups(entry)
scopes[:group] ||= group
- true
-
else
- false
+ unknown << entry
end
end
- scopes
+ [scopes, unknown]
end
-
- # Find the action for the given input entry.
- # Any action found will be removed from the entries.
- #
- # @param [Array<String>] entries the user entries
- # @return [Symbol] a Guard action
- #
- def extract_action(entries)
- action = nil
-
- entries.delete_if do |entry|
- if command = ACTIONS.detect { |k, list| list.include?(entry) }
- action ||= command.first
- true
- else
- false
- end
- end
-
- action
- end
-
end
end
View
64 lib/guard/interactors/coolline.rb
@@ -1,64 +0,0 @@
-require 'guard'
-require 'guard/ui'
-require 'guard/interactor'
-require 'guard/interactors/helpers/terminal'
-require 'guard/interactors/helpers/completion'
-
-module Guard
-
- # Interactor that uses coolline for getting the user input.
- # This enables history support and auto-completion,
- #
- class CoollineInteractor < ::Guard::Interactor
- include ::Guard::CompletionHelper
- include ::Guard::TerminalHelper
-
- # Test if the Interactor is
- # available in the current environment?
- #
- # @param [Boolean] silent true if no error messages should be shown
- # @return [Boolean] the availability status
- #
- def self.available?(silent = false)
- if RbConfig::CONFIG['RUBY_PROGRAM_VERSION'] == '1.9.3'
- require 'coolline'
- true
- else
- ::Guard::UI.error 'The :coolline interactor runs only on Ruby 1.9.3.' unless silent
- false
- end
-
- rescue LoadError => e
- ::Guard::UI.error "Please add \"gem 'coolline'\" to your Gemfile and run Guard with \"bundle exec\"." unless silent
- false
- end
-
- # Read a line from stdin with Readline.
- #
- def read_line
- coolline = Coolline.new do |cool|
- cool.transform_proc = proc do
- cool.line
- end
-
- cool.completion_proc = proc do
- word = cool.completed_word
- auto_complete(word)
- end
- end
-
- while line = coolline.readline(prompt)
- process_input(line)
- end
- end
-
- # The current interactor prompt
- #
- # @return [String] the prompt to show
- #
- def prompt
- ::Guard.listener.paused? ? 'p> ' : '>> '
- end
-
- end
-end
View
32 lib/guard/interactors/helpers/completion.rb
@@ -1,32 +0,0 @@
-require 'guard'
-
-module Guard
-
- # Module for providing word completion to an interactor.
- #
- module CompletionHelper
-
- COMPLETION_ACTIONS = %w[help reload exit pause notification show]
-
- # Auto complete the given word.
- #
- # @param [String] word the partial word
- # @return [Array<String>] the matching words
- #
- def auto_complete(word)
- completion_list.grep(/^#{ Regexp.escape(word) }/)
- end
-
- # Get the auto completion list.
- #
- # @return [Array<String>] the list of words
- #
- def completion_list
- groups = ::Guard.groups.map { |group| group.name.to_s }
- guards = ::Guard.guards.map { |guard| guard.class.to_s.downcase.sub('guard::', '') }
-
- COMPLETION_ACTIONS + groups + guards - ['default']
- end
-
- end
-end
View
46 lib/guard/interactors/helpers/terminal.rb
@@ -1,46 +0,0 @@
-module Guard
-
- # Module for resetting terminal options for an interactor.
- #
- module TerminalHelper
-
- # Start the interactor.
- #
- def start
- store_terminal_settings if stty_exists?
- super
- end
-
- # Stop the interactor.
- #
- def stop
- super
- restore_terminal_settings if stty_exists?
- end
-
- private
-
- # Detects whether or not the stty command exists
- # on the user machine.
- #
- # @return [Boolean] the status of stty
- #
- def stty_exists?
- @stty_exists ||= system('hash', 'stty')
- end
-
- # Stores the terminal settings so we can resore them
- # when stopping.
- #
- def store_terminal_settings
- @stty_save = `stty -g 2>/dev/null`.chomp
- end
-
- # Restore terminal settings
- #
- def restore_terminal_settings
- system("stty #{ @stty_save } 2>/dev/null") if @stty_save
- end
-
- end
-end
View
94 lib/guard/interactors/readline.rb
@@ -1,94 +0,0 @@
-require 'guard'
-require 'guard/ui'
-require 'guard/interactor'
-require 'guard/interactors/helpers/terminal'
-require 'guard/interactors/helpers/completion'
-
-module Guard
-
- # Interactor that used readline for getting the user input.
- # This enables history support and auto-completion, but is
- # broken on OS X without installing `rb-readline` or using JRuby.
- #
- # @see http://bugs.ruby-lang.org/issues/5539
- #
- class ReadlineInteractor < ::Guard::Interactor
- include ::Guard::CompletionHelper
- include ::Guard::TerminalHelper
-
- # Test if the Interactor is
- # available in the current environment?
- #
- # @param [Boolean] silent true if no error messages should be shown
- # @return [Boolean] the availability status
- #
- def self.available?(silent = false)
- require 'readline'
-
- if defined?(RbReadline) || defined?(JRUBY_VERSION) || RbConfig::CONFIG['target_os'] =~ /linux/i
- true
- else
- ::Guard::UI.error 'The :readline interactor runs only fine on JRuby, Linux or with the gem \'rb-readline\' installed.' unless silent
- false
- end
-
- rescue LoadError => e
- ::Guard::UI.error "Please install Ruby Readline support or add \"gem 'rb-readline'\" to your Gemfile and run Guard with \"bundle exec\"." unless silent
- false
- end
-
- # Initialize the interactor.
- #
- def initialize
- require 'readline'
-
- Readline.completion_proc = proc { |word| auto_complete(word) }
-
- begin
- Readline.completion_append_character = ' '
- rescue NotImplementedError
- # Ignore, we just don't support it then
- end
- end
-
- # Stop the interactor.
- #
- def stop
- # Erase the current line for Ruby Readline
- if Readline.respond_to?(:refresh_line) && !defined?(::JRUBY_VERSION)
- Readline.refresh_line
- end
-
- # Erase the current line for Rb-Readline
- if defined?(RbReadline) && RbReadline.rl_outstream
- RbReadline._rl_erase_entire_line
- end
-
- super
- end
-
- # Read a line from stdin with Readline.
- #
- def read_line
- require 'readline'
-
- while line = Readline.readline(prompt, true)
- line.gsub!(/^\W*/, '')
- if line =~ /^\s*$/ or Readline::HISTORY.to_a[-2] == line
- Readline::HISTORY.pop
- end
-
- process_input(line)
- end
- end
-
- # The current interactor prompt
- #
- # @return [String] the prompt to show
- #
- def prompt
- ::Guard.listener.paused? ? 'p> ' : '> '
- end
-
- end
-end
View
19 lib/guard/interactors/simple.rb
@@ -1,19 +0,0 @@
-require 'guard/interactor'
-
-module Guard
-
- # Simple interactor that that reads user
- # input from standard input.
- #
- class SimpleInteractor < ::Guard::Interactor
-
- # Read a line from stdin with Readline.
- #
- def read_line
- while line = $stdin.gets
- process_input(line.gsub(/^\W*/, '').chomp)
- end
- end
-
- end
-end
View
15 lib/guard/notifier.rb
@@ -105,6 +105,17 @@ def turn_off
ENV['GUARD_NOTIFY'] = 'false'
end
+ # Toggle the system notifications on/off
+ #
+ def toggle
+ if ENV['GUARD_NOTIFY'] == 'true'
+ ::Guard::UI.info 'Turn off notifications'
+ turn_off
+ else
+ turn_on
+ end
+ end
+
# Test if the notifications are on.
#
# @return [Boolean] whether the notifications are on
@@ -124,7 +135,7 @@ def add_notification(name, options = { }, silent = false)
return turn_off if name == :off
notifier = get_notifier_module(name)
-
+
if notifier && notifier.available?(silent)
self.notifications = notifications << { :name => name, :options => options }
true
@@ -166,7 +177,7 @@ def get_notifier_module(name)
notifier = NOTIFIERS.detect { |n| n.first == name }
notifier ? notifier.last : notifier
end
-
+
# Auto detect the available notification library. This goes through
# the list of supported notification gems and picks the first that
# is available.
View
302 spec/guard/interactor_spec.rb
@@ -3,306 +3,4 @@
describe Guard::Interactor do
subject { Guard::Interactor.new }
- describe '#readline' do
- it 'must be implemented by a subclass' do
- expect { subject.read_line }.to raise_error(NotImplementedError)
- end
- end
-
- describe '.fabricate' do
- context 'with coolline available' do
- before { Guard::CoollineInteractor.stub(:available?).and_return true }
-
- it 'returns the Coolline interactor for a :coolline symbol' do
- Guard::Interactor.interactor = :coolline
- Guard::Interactor.fabricate.should be_an_instance_of(Guard::CoollineInteractor)
- end
- end
-
- context 'with coolline unavailable' do
- before { Guard::CoollineInteractor.stub(:available?).and_return false }
-
- it 'returns nil' do
- Guard::Interactor.interactor = :coolline
- Guard::Interactor.fabricate.should be_nil
- end
- end
-
- context 'with readline available' do
- before { Guard::ReadlineInteractor.stub(:available?).and_return true }
-
- it 'returns the Readline interactor for a :readline symbol' do
- Guard::Interactor.interactor = :readline
- Guard::Interactor.fabricate.should be_an_instance_of(Guard::ReadlineInteractor)
- end
- end
-
- context 'with readline unavailable' do
- before { Guard::ReadlineInteractor.stub(:available?).and_return false }
-
- it 'returns nil' do
- Guard::Interactor.interactor = :readline
- Guard::Interactor.fabricate.should be_nil
- end
- end
-
- it 'returns the Gets interactor for a :simple symbol' do
- Guard::Interactor.interactor = :simple
- Guard::Interactor.fabricate.should be_an_instance_of(Guard::SimpleInteractor)
- end
-
- it 'returns nil for an :off symbol' do
- Guard::Interactor.interactor = :off
- Guard::Interactor.fabricate.should be_nil
- end
-
- it 'auto detects the interactor when unspecified' do
- Guard::Interactor.interactor = nil
- Guard::Interactor.should_receive(:auto_detect)
- Guard::Interactor.fabricate
- end
- end
-
- describe '.auto_detect' do
- context 'when all interactors are available' do
- before do
- Guard::CoollineInteractor.stub(:available?).and_return true
- Guard::ReadlineInteractor.stub(:available?).and_return true
- end
-
- it 'chooses the coolline interactor ' do
- Guard::Interactor.auto_detect.should be_an_instance_of(Guard::CoollineInteractor)
- end
- end
-
- context 'when only the coolline interactor is unavailable available' do
- before do
- Guard::CoollineInteractor.stub(:available?).and_return false
- Guard::ReadlineInteractor.stub(:available?).and_return true
- end
-
- it 'chooses the readline interactor ' do
- Guard::Interactor.auto_detect.should be_an_instance_of(Guard::ReadlineInteractor)
- end
- end
-
- context 'when coolline and readline interactors are unavailable available' do
- before do
- Guard::CoollineInteractor.stub(:available?).and_return false
- Guard::ReadlineInteractor.stub(:available?).and_return false
- end
-
- it 'chooses the simple interactor ' do
- Guard::Interactor.auto_detect.should be_an_instance_of(Guard::SimpleInteractor)
- end
- end
- end
-
- describe '#process_input' do
- before do
- ::Guard.stub(:within_preserved_state).and_yield
- ::Guard.runner = stub('runner')
- end
-
- it 'shows the help on help action' do
- subject.should_receive(:extract_scopes_and_action).with('help').and_return [{ }, :help, []]
- subject.should_receive(:help)
- subject.process_input 'help'
- end
-
- it 'describes the DSL on show action' do
- subject.should_receive(:extract_scopes_and_action).with('show').and_return [{ }, :show, []]
- ::Guard::DslDescriber.should_receive(:show)
- subject.process_input 'show'
- end
-
- it 'stops Guard on stop action and exit' do
- subject.should_receive(:extract_scopes_and_action).with('stop').and_return [{ }, :stop, []]
- ::Guard.should_receive(:stop)
-
- begin
- subject.process_input 'stop'
- raise 'Guard did not exit!'
- rescue SystemExit => e
- e.status.should eq(0)
- end
- end
-
- it 'pauses Guard on pause action' do
- subject.should_receive(:extract_scopes_and_action).with('pause').and_return [{ }, :pause, []]
- ::Guard.should_receive(:pause)
- subject.process_input 'pause'
- end
-
- it 'reloads Guard on reload action' do
- subject.should_receive(:extract_scopes_and_action).with('reload').and_return [{ }, :reload, []]
- ::Guard.should_receive(:reload).with({ })
- subject.process_input 'reload'
- end
-
- it 'runs an empty file change on change action' do
- subject.should_receive(:extract_scopes_and_action).with('change spec/guard_spec.rb').and_return [{ }, :change, ['spec/guard_spec.rb']]
- ::Guard.runner.should_receive(:run_on_changes).with(['spec/guard_spec.rb'], [], [])
- subject.process_input 'change spec/guard_spec.rb'
- end
-
- it 'runs all Guard on run_all action' do
- subject.should_receive(:extract_scopes_and_action).with('').and_return [{ }, :run_all, []]
- ::Guard.should_receive(:run_all).with({ })
- subject.process_input ''
- end
-
- it 'toggles the notifications on notification action' do
- subject.should_receive(:extract_scopes_and_action).with('notification').and_return [{ }, :notification, []]
- subject.should_receive(:toggle_notification)
- subject.process_input 'notification'
- end
-
- it 'shows an error on unknown action' do
- subject.should_receive(:extract_scopes_and_action).with('foo').and_return [{ }, :unknown, []]
- ::Guard::UI.should_receive(:error).with 'Unknown command foo'
- subject.process_input 'foo'
- end
- end
-
- describe 'toggle_notification' do
- before { ::Guard::UI.stub(:info) }
-
- it 'disables the notifications when enabled' do
- ENV['GUARD_NOTIFY'] = 'true'
- ::Guard::Notifier.should_receive(:turn_off)
- subject.toggle_notification
- end
-
- it 'enables the notifications when disabled' do
- ENV['GUARD_NOTIFY'] = 'false'
- ::Guard::Notifier.should_receive(:turn_on)
- subject.toggle_notification
- end
- end
-
- describe '#extract_scopes_and_action' do
- before(:all) do
- class Guard::Foo < Guard::Guard; end
- class Guard::FooBar < Guard::Guard; end
- end
-
- before(:each) do
- guard = ::Guard.setup
- @backend_group = guard.add_group(:backend)
- @frontend_group = guard.add_group(:frontend)
- @foo_guard1 = guard.add_guard(:foo, [], [], { :group => :backend })
- @foo_guard2 = guard.add_guard(:foo, [], [], { :group => :backend })
- @foo_bar_guard = guard.add_guard('foo-bar', [], [], { :group => :frontend })
- end
-
- after(:all) do
- ::Guard.instance_eval do
- remove_const(:Foo)
- remove_const(:FooBar)
- end
- end
-
- context 'for blank command' do
- it 'returns :run_all action' do
- subject.extract_scopes_and_action('').should == [{ }, :run_all, []]
- end
- end
-
- context 'for an action command' do
- it 'returns the action if the command contains only a action' do
- subject.extract_scopes_and_action('exit').should == [{ }, :stop, []]
- end
-
- it 'returns the first action if the command contains multiple actions, removes all other actions' do
- subject.extract_scopes_and_action('change reload').should == [{ }, :change, []]
- end
- end
-
- context 'for a scope command' do
- it 'returns guard scope and run_all action if entry is only a guard scope' do
- subject.extract_scopes_and_action('foo-bar').should == [{ :guard => @foo_bar_guard }, :run_all, []]
- end
-
- it 'returns group scope and run_all action if entry is only a group scope' do
- subject.extract_scopes_and_action('backend').should == [{ :group => @backend_group }, :run_all, []]
- end
-
- it 'returns group scope and run_all action if entry is a group scope and not a action' do
- subject.extract_scopes_and_action('frontend x').should == [{ :group => @frontend_group }, :run_all, ['x']]
- end
-
- it 'returns the first group scope and drop the other scopes' do
- subject.extract_scopes_and_action('backend frontend').should == [{ :group => @backend_group }, :run_all, []]
- subject.extract_scopes_and_action('frontend backend').should == [{ :group => @frontend_group }, :run_all, []]
- end
- end
-
- context 'for an action and scope command' do
- it 'returns guard scope and action if entry is a guard scope and a action' do
- subject.extract_scopes_and_action('foo r').should == [{ :guard => @foo_guard1 }, :reload, []]
- subject.extract_scopes_and_action('r foo').should == [{ :guard => @foo_guard1 }, :reload, []]
- end
-
- it 'returns group scope and action if entry is a group scope and a action' do
- subject.extract_scopes_and_action('frontend r').should == [{ :group => @frontend_group }, :reload, []]
- subject.extract_scopes_and_action('r frontend').should == [{ :group => @frontend_group }, :reload, []]
- end
- end
-
- context 'for an invalid scope or command' do
- it 'returns no action if entry is not a scope or action' do
- subject.extract_scopes_and_action('x').should == [{ }, nil, ['x']]
- end
-
- it 'returns no action if entry is not a scope and not a action' do
- subject.extract_scopes_and_action('x x').should == [{ }, nil, ['x', 'x']]
- end
- end
-
- describe 'extracting actions' do
- it 'returns :help action for the help entry and for its shortcut' do
- %w{help h}.each do |e|
- subject.extract_scopes_and_action(e).should == [{ }, :help , []]
- end
- end
-
- it 'returns :reload action for the reload entry and for its shortcut' do
- %w{reload r}.each do |e|
- subject.extract_scopes_and_action(e).should == [{ }, :reload, []]
- end
- end
-
- it 'returns :stop action for exit or quit entry and for their shortcuts' do
- %w{exit e quit q}.each do |e|
- subject.extract_scopes_and_action(e).should == [{ }, :stop, []]
- end
- end
-
- it 'returns :pause action for the pause entry and for its shortcut' do
- %w{pause p}.each do |e|
- subject.extract_scopes_and_action(e).should == [{ }, :pause, []]
- end
- end
-
- it 'returns :notification action for the notification entry and for its shortcut' do
- %w{notification n}.each do |e|
- subject.extract_scopes_and_action(e).should == [{ }, :notification, []]
- end
- end
-
- it 'returns :show action for the show entry and for its shortcut' do
- %w{show s}.each do |e|
- subject.extract_scopes_and_action(e).should == [{ }, :show, []]
- end
- end
-
- it 'returns :change action for the show entry and for its shortcut' do
- %w{change c}.each do |e|
- subject.extract_scopes_and_action(e).should == [{ }, :change, []]
- end
- end
- end
- end
-
end
View
49 spec/guard/interactors/coolline_spec.rb
@@ -1,49 +0,0 @@
-require 'spec_helper'
-require 'guard/interactors/readline'
-
-describe Guard::CoollineInteractor do
- subject { Guard::CoollineInteractor.new }
-
- describe '#readline' do
- let(:coolline) { mock('coolline') }
-
- before do
- class Coolline
- end
- ::Coolline.stub(:new) { coolline }
- end
-
- before do
- Guard.listener = mock('listener')
- Guard.listener.stub(:paused?).and_return false
- end
-
- it 'reads all lines for processing' do
- coolline.should_receive(:readline).and_return 'First line'
- coolline.should_receive(:readline).and_return 'Second line'
- coolline.should_receive(:readline).and_return 'Control line'
- coolline.should_receive(:readline).and_return nil
- subject.should_receive(:process_input).with('First line').and_return
- subject.should_receive(:process_input).with('Second line').and_return
- subject.should_receive(:process_input).with('Control line').and_return
- subject.read_line
- end
- end
-
- describe "#prompt" do
- before do
- ::Guard.listener = stub('Listener')
- end
-
- it 'returns >> when listener is active' do
- ::Guard.listener.should_receive(:paused?).and_return false
- subject.prompt.should == '>> '
- end
-
- it 'returns p> when listener is paused' do
- ::Guard.listener.should_receive(:paused?).and_return true
- subject.prompt.should == 'p> '
- end
- end
-
-end
View
51 spec/guard/interactors/helpers/completion_spec.rb
@@ -1,51 +0,0 @@
-require 'spec_helper'
-require 'guard/interactors/helpers/completion'
-
-describe Guard::CompletionHelper do
- subject do
- Class.new(::Guard::Interactor) { include Guard::CompletionHelper }.new
- end
-
-
- describe '#auto_complete' do
- it 'returns the matching list of words' do
- subject.should_receive(:completion_list).any_number_of_times.and_return %w[help reload exit pause notification backend frontend foo foobar]
- subject.auto_complete('f').should =~ ['frontend', 'foo', 'foobar']
- subject.auto_complete('foo').should =~ ['foo', 'foobar']
- subject.auto_complete('he').should =~ ['help']
- subject.auto_complete('re').should =~ ['reload']
- end
- end
-
- describe "#completion_list" do
- before(:all) do
- class Guard::Foo < Guard::Guard; end
- class Guard::FooBar < Guard::Guard; end
- end
-
- before(:each) do
- guard = ::Guard
- guard.setup_guards
- guard.setup_groups
- @backend_group = guard.add_group(:backend)
- @frontend_group = guard.add_group(:frontend)
- @foo_guard = guard.add_guard(:foo, [], [], { :group => :backend })
- @foo_bar_guard = guard.add_guard('foo-bar', [], [], { :group => :frontend })
- end
-
- after(:all) do
- ::Guard.instance_eval do
- remove_const(:Foo)
- remove_const(:FooBar)
- end
- end
-
- it 'creates the list of string to auto complete' do
- subject.completion_list.should =~ %w[help reload exit pause notification backend frontend foo foobar show]
- end
-
- it 'does not include the default scope' do
- subject.completion_list.should_not include('default')
- end
- end
-end
View
51 spec/guard/interactors/helpers/terminal_spec.rb
@@ -1,51 +0,0 @@
-require 'spec_helper'
-require 'guard/interactors/helpers/terminal'
-
-describe Guard::TerminalHelper do
- subject do
- Class.new(::Guard::Interactor) { include Guard::TerminalHelper }.new
- end
-
- describe '#start' do
- context 'when running on a system that has stty' do
- before { subject.should_receive(:stty_exists?).and_return(true) }
-
- it 'stores the terminal settings' do
- subject.should_receive(:store_terminal_settings)
- subject.start
- end
- end
-
- context 'when running on a system without stty' do
- before { subject.should_receive(:stty_exists?).and_return(false) }
-
- it 'does not store the terminal settings' do
- subject.should_not_receive(:store_terminal_settings)
- subject.start
- end
- end
- end
-
- describe '#stop' do
- before { subject.instance_variable_set(:@thread, Thread.current) }
-
- context 'when running on a system that has stty' do
- before { subject.should_receive(:stty_exists?).and_return(true) }
-
- it 'restores the terminal settings' do
- subject.should_receive(:restore_terminal_settings)
- subject.stop
- end
- end
-
- context 'when running on a system without stty' do
- before { subject.should_receive(:stty_exists?).and_return(false) }
-
- it 'does not store the terminal settings' do
- subject.should_not_receive(:restore_terminal_settings)
- subject.stop
- end
- end
- end
-
-end
View
53 spec/guard/interactors/readline_spec.rb
@@ -1,53 +0,0 @@
-require 'spec_helper'
-require 'guard/interactors/readline'
-require 'readline'
-
-describe Guard::ReadlineInteractor do
- subject { Guard::ReadlineInteractor.new }
-
- describe "#initialize" do
- # completion_proc getter is not implemented in JRuby
- # see https://github.com/jruby/jruby/blob/master/src/org/jruby/ext/Readline.java#L349
- if RUBY_PLATFORM != 'java'
- it 'sets the Readline completion proc' do
- subject
- Readline.completion_proc.should be_a Proc
- end
- end
- end
-
- describe '#readline' do
- before do
- Guard.listener = mock('listener')
- Guard.listener.stub(:paused?).and_return false
- end
-
- it 'reads all lines for processing' do
- Readline.should_receive(:readline).and_return 'First line'
- Readline.should_receive(:readline).and_return 'Second line'
- Readline.should_receive(:readline).and_return "\x00 \tControl line"
- Readline.should_receive(:readline).and_return nil
- subject.should_receive(:process_input).with('First line').and_return
- subject.should_receive(:process_input).with('Second line').and_return
- subject.should_receive(:process_input).with('Control line').and_return
- subject.read_line
- end
- end
-
- describe "#prompt" do
- before do
- ::Guard.listener = stub('Listener')
- end
-
- it 'returns > when listener is active' do
- ::Guard.listener.should_receive(:paused?).and_return false
- subject.prompt.should == '> '
- end
-
- it 'returns p> when listener is paused' do
- ::Guard.listener.should_receive(:paused?).and_return true
- subject.prompt.should == 'p> '
- end
- end
-
-end
View
25 spec/guard/interactors/simple_spec.rb
@@ -1,25 +0,0 @@
-require 'spec_helper'
-require 'guard/interactors/simple'
-
-describe Guard::SimpleInteractor do
- subject { Guard::SimpleInteractor.new }
-
- describe '#readline' do
- before do
- subject.stub(:process_input)
- end
-
- it 'reads all lines for processing' do
- $stdin.should_receive(:gets).and_return "First line\n"
- $stdin.should_receive(:gets).and_return "Second line\n"
- $stdin.should_receive(:gets).and_return "\x00 \tControl line\n"
- $stdin.should_receive(:gets).and_return nil
-
- subject.should_receive(:process_input).with('First line')
- subject.should_receive(:process_input).with('Second line')
- subject.should_receive(:process_input).with('Control line')
- subject.read_line
- end
- end
-
-end
View
16 spec/guard/notifier_spec.rb
@@ -82,6 +82,22 @@
end
end
+ describe 'toggle_notification' do
+ before { ::Guard::UI.stub(:info) }
+
+ it 'disables the notifications when enabled' do
+ ENV['GUARD_NOTIFY'] = 'true'
+ ::Guard::Notifier.should_receive(:turn_off)
+ subject.toggle
+ end
+
+ it 'enables the notifications when disabled' do
+ ENV['GUARD_NOTIFY'] = 'false'
+ ::Guard::Notifier.should_receive(:turn_on)
+ subject.toggle
+ end
+ end
+
describe '.enabled?' do
context 'when enabled' do
before { ENV['GUARD_NOTIFY'] = 'true' }
View
4 spec/support/guard_helper.rb
@@ -1,13 +1,13 @@
shared_examples_for 'interactor enabled' do
it 'enables the notifier' do
- described_class::Interactor.should_receive(:fabricate)
+ described_class::Interactor.should_receive(:new)
described_class.setup_interactor
end
end
shared_examples_for 'interactor disabled' do
it 'enables the notifier' do
- described_class::Interactor.should_not_receive(:fabricate)
+ described_class::Interactor.should_not_receive(:new)
described_class.setup_interactor
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.