Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Scope plugins and groups #378

Merged
merged 6 commits into from

3 participants

@netzpirat
Owner

This adds setting an initial plugin scope from the cli (in addition to the already existing group scope), shows the current scope in the interactor and let it change at runtime with the new scope (or o as shortcut).

But let's see it in action instead of this boring description:

$ bundle exec guard help start 
  -g, [--group=Run only the passed groups]                                                                    
  -P, [--plugin=Run only the passed plugins]  

Yeah I know, but -p is already for polling. So now you can pass a plugin to scope the actions to, like

$ bundle exec guard -P ronn
[1] {Ronn} guard(main)>

As you can see, the current scope is visible within the mustaches {ronn}. This means that the change, run_all and reload actions are globally scoped to ronn and no other plugins are triggered:

[1] {Ronn} guard(main)> r
15:54:53 - INFO - Reload ronn
[2] {Ronn} guard(main)> 

but you can overwrite the global scope by providing a local scope:

[2] {Ronn} guard(main)> r rspec
15:55:20 - INFO - Reload rspec
[3] {Ronn} guard(main)>

To change the scope, use the scope command or its shorthand o:

[3] {Ronn} guard(main)> o rspec
[4] {Rspec} guard(main)>

To clear the scope, just call it without parameter:

[4] {Rspec} guard(main)> o
[5] guard(main)> 

The same is true for groups:

$ bundle exec guard -g docs
[1] {Docs} guard(main)> 

That's all. Happy scoping!

@rymai
Owner

That's totally awesome @netzpirat, I love you so much!! :heart:

@thibaudgg
Owner

Really nice! Thanks!

@netzpirat netzpirat merged commit c4ebdd1 into from
@netzpirat netzpirat deleted the branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
12 README.md
@@ -374,7 +374,7 @@ Notifications can also be disabled globally by setting a `GUARD_NOTIFY` environm
#### `-g`/`--group` option
-Only certain plugin groups can be run:
+Scope Guard to certain plugin groups on start:
```bash
$ guard --group group_name another_group_name
@@ -383,6 +383,15 @@ $ guard -g group_name another_group_name # shortcut
See the Guardfile DSL below for creating groups.
+#### `-P`/`--plugins` option
+
+Scope Guard to certain plugins on start:
+
+```bash
+$ guard --plugins plugin_name another_plugin_name
+$ guard -p plugin_name another_plugin_name # shortcut
+```
+
#### `-d`/`--debug` option
Guard can display debug information which can be very usefull for plugins
@@ -499,6 +508,7 @@ commands:
* `n`, `notification`: Toggles the notifications.
* `p`, `pause`: Toggles the file listener.
* `r`, `reload`: Reload all plugins.
+ * `o`, `scope`: Scope Guard actions to plugins or groups.
* `s`, `show`: Show all Guard plugins.
* `e`, `exit`: Stop all plugins and quit Guard
View
2  guard.gemspec
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
s.add_development_dependency 'bundler'
s.add_development_dependency 'rspec', '~> 2.12.0'
- s.add_development_dependency 'guard-rspec', '~> 2.1.0'
+ s.add_development_dependency 'guard-rspec', '~> 2.3.0'
s.files = Dir.glob('{bin,images,lib}/**/*') + %w[CHANGELOG.md LICENSE man/guard.1 man/guard.1.html README.md]
s.executable = 'guard'
View
36 lib/guard.rb
@@ -26,7 +26,7 @@ module Guard
DEV_NULL = WINDOWS ? "NUL" : "/dev/null"
class << self
- attr_accessor :options, :interactor, :runner, :listener, :lock
+ attr_accessor :options, :interactor, :runner, :listener, :lock, :scope
# Initialize the Guard singleton:
#
@@ -48,8 +48,9 @@ def setup(options = {})
@options = options
@watchdir = (options[:watchdir] && File.expand_path(options[:watchdir])) || Dir.pwd
@runner = ::Guard::Runner.new
+ @scope = { :plugins => [], :groups => []}
- if @options[:debug]
+ if options[:debug]
Thread.abort_on_exception = true
::Guard::UI.options[:level] = :debug
debug_command_execution
@@ -66,6 +67,14 @@ def setup(options = {})
::Guard::Dsl.evaluate_guardfile(options)
::Guard::UI.error 'No guards found in Guardfile, please add at least one.' if @guards.empty?
+ if options[:group]
+ @scope[:groups] = options[:group].map { |g| ::Guard.groups(g) }
+ end
+
+ if options[:plugin]
+ @scope[:plugins] = options[:plugin].map { |p| ::Guard.guards(p) }
+ end
+
runner.deprecation_warning if @options[:show_deprecations]
setup_notifier
@@ -189,6 +198,8 @@ def stop
# @param [Hash] scopes hash with a Guard plugin or a group scope
#
def reload(scopes = {})
+ scopes = convert_scopes(scopes)
+
within_preserved_state do
::Guard::UI.clear(:force => true)
::Guard::UI.action_with_scopes('Reload', scopes)
@@ -206,6 +217,8 @@ def reload(scopes = {})
# @param [Hash] scopes hash with a Guard plugin or a group scope
#
def run_all(scopes = {})
+ scopes = convert_scopes(scopes)
+
within_preserved_state do
::Guard::UI.clear(:force => true)
::Guard::UI.action_with_scopes('Run', scopes)
@@ -455,5 +468,24 @@ def deprecated_options_warning
::Guard::UI.deprecation(NO_VENDOR_DEPRECATION) if options[:no_vendor]
end
+ # Convert the old scope format to the new scope format.
+ #
+ # @example Convert old scopes
+ # convert_scopes({ :guard => :rspec, :group => :backend })
+ # => { :plugins => [:rspec], :groups => [:backend] }
+ #
+ def convert_scopes(scopes)
+ if scopes[:guard]
+ scopes[:plugins] = [scopes[:guard]]
+ scopes.delete(:guard)
+ end
+
+ if scopes[:group]
+ scopes[:groups] = [scopes[:group]]
+ scopes.delete(:group)
+ end
+
+ scopes
+ end
end
end
View
6 lib/guard/cli.rb
@@ -41,6 +41,12 @@ class CLI < Thor
:aliases => '-g',
:banner => 'Run only the passed groups'
+ method_option :plugin,
+ :type => :array,
+ :default => [],
+ :aliases => '-P',
+ :banner => 'Run only the passed plugins'
+
method_option :watchdir,
:type => :string,
:aliases => '-w',
View
32 lib/guard/commands/scope.rb
@@ -0,0 +1,32 @@
+module Guard
+ class Interactor
+
+ SCOPE = Pry::CommandSet.new do
+ create_command 'scope' do
+
+ group 'Guard'
+ description 'Scope Guard actions to groups and plugins.'
+
+ banner <<-BANNER
+ Usage: scope <scope>
+
+ Set the global Guard scope.
+ BANNER
+
+ def process(*entries)
+ scope, rest = ::Guard::Interactor.convert_scope(entries)
+
+ if rest.length == 0
+ ::Guard.scope = scope
+ else
+ output.puts "Unkown scope #{ rest.join(', ') }"
+ end
+ end
+
+ end
+ end
+
+ end
+end
+
+Pry.commands.import ::Guard::Interactor::SCOPE
View
3  lib/guard/dsl.rb
@@ -361,10 +361,9 @@ def interactor(options)
# @see Guard::DslDescriber
#
def group(name, options = {})
- @groups = @@options[:group] || []
name = name.to_sym
- if block_given? && (@groups.empty? || @groups.map(&:to_sym).include?(name))
+ if block_given?
::Guard.add_group(name.to_s.downcase, options)
@current_group = name
View
2  lib/guard/group.rb
@@ -37,7 +37,7 @@ def initialize(name, options = {})
# @return [String] the group name
#
def to_s
- "#{@name} group"
+ @name.to_s.capitalize
end
end
View
13 lib/guard/guard.rb
@@ -60,13 +60,13 @@ def initialize(watchers = [], options = {})
# Specify the source for the Guardfile template.
# Each Guard plugin can redefine this method to add its own logic.
- #
+ #
# @param [String] The plugin name
- #
+ #
def self.template(name)
File.read("#{ ::Guard.locate_guard(name) }/lib/guard/#{ name }/templates/Guardfile")
end
-
+
# Initialize the Guard plugin. This will copy the Guardfile template inside the Guard plugin gem.
# The template Guardfile must be located within the Gem at `lib/guard/guard-name/templates/Guardfile`.
#
@@ -152,12 +152,13 @@ def self.init(name)
# @!method run_on_removals(paths)
# Convert plugin to string representation. The
- # default just uses the plugin class name.
- #
+ # default just uses the plugin class name and
+ # removes the Guard module name.
+ #
# @return [String] the string representation
#
def to_s
- self.class.to_s
+ self.class.to_s.downcase.sub('guard::', '').capitalize
end
end
View
69 lib/guard/interactor.rb
@@ -15,14 +15,29 @@ class Interactor
require 'guard/commands/notification'
require 'guard/commands/pause'
require 'guard/commands/reload'
+ require 'guard/commands/scope'
require 'guard/commands/show'
# The default Ruby script to configure Guard Pry if the option `:guard_rc` is not defined.
- GUARD_RC = '~/.guardrc'
+ GUARD_RC = '~/.guardrc'
# The default Guard Pry history file if the option `:history_file` is not defined.
HISTORY_FILE = '~/.guard_history'
+ # List of shortcuts for each interactor command
+ SHORTCUTS = {
+ :help => 'h',
+ :all => 'a',
+ :reload => 'r',
+ :change => 'c',
+ :show => 's',
+ :scope => 'o',
+ :notification => 'n',
+ :pause => 'p',
+ :exit => 'e',
+ :quit => 'q'
+ }
+
class << self
# Get the interactor options
@@ -30,7 +45,7 @@ class << self
# @return [Hash] the options
#
def options
- @options ||= {}
+ @options ||= { }
end
# Set the interactor options
@@ -68,9 +83,9 @@ def enabled=(status)
def initialize
return if ENV['GUARD_ENV'] == 'test'
- Pry.config.should_load_rc = false
+ Pry.config.should_load_rc = false
Pry.config.should_load_local_rc = false
- Pry.config.history.file = self.class.options[:history_file] || HISTORY_FILE
+ Pry.config.history.file = self.class.options[:history_file] || HISTORY_FILE
load_guard_rc
@@ -101,12 +116,12 @@ def create_run_all_command
end
# Creates command aliases for the commands
- # `help`, `reload`, `change`, `show`, `notification`, `pause`, `exit` and `quit`,
+ # `help`, `reload`, `change`, `scope`, `notification`, `pause`, `exit` and `quit`,
# which will be the first letter of the command.
#
def create_command_aliases
- %w(help all reload change show notification pause exit quit).each do |command|
- Pry.commands.alias_command command[0].chr, command
+ SHORTCUTS.each do |command, shortcut|
+ Pry.commands.alias_command shortcut, command
end
end
@@ -155,10 +170,34 @@ def process
def configure_prompt
Pry.config.prompt = [
proc do |target_self, nest_level, pry|
- "[#{ pry.input_array.size }] #{ ::Guard.listener.paused? ? 'pause' : 'guard' }(#{ Pry.view_clip(target_self) })#{":#{ nest_level }" unless nest_level.zero? }> "
+ history = pry.input_array.size
+ process = ::Guard.listener.paused? ? 'pause' : 'guard'
+ clip = Pry.view_clip(target_self)
+ level = ":#{ nest_level }" unless nest_level.zero?
+ scope = if !::Guard.scope[:plugins].empty?
+ "{#{ ::Guard.scope[:plugins].join }} "
+ elsif !::Guard.scope[:groups].empty?
+ "{#{ ::Guard.scope[:groups].join }} "
+ else
+ ''
+ end
+
+ "[#{ history }] #{ scope }#{ process }(#{ clip })#{ level }> "
end,
proc do |target_self, nest_level, pry|
- "[#{ pry.input_array.size }] #{ ::Guard.listener.paused? ? 'pause' : 'guard' }(#{ Pry.view_clip(target_self) })#{":#{ nest_level }" unless nest_level.zero? }* "
+ history = pry.input_array.size
+ process = ::Guard.listener.paused? ? 'pause' : 'guard'
+ clip = Pry.view_clip(target_self)
+ level = ":#{ nest_level }" unless nest_level.zero?
+ scope = if !::Guard.scope[:plugins].empty?
+ "{#{ ::Guard.scope[:plugins].join }} "
+ elsif !::Guard.scope[:groups].empty?
+ "{#{ ::Guard.scope[:groups].join }} "
+ else
+ ''
+ end
+
+ "[#{ history }] #{ scope }#{ process }(#{ clip })#{ level }* "
end
]
end
@@ -208,13 +247,13 @@ def stty_exists?
# when stopping.
#
def store_terminal_settings
- @stty_save = `stty -g 2>#{DEV_NULL}`.chomp
+ @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
+ system("stty #{ @stty_save } 2>#{ DEV_NULL }") if @stty_save
end
# Converts and validates a plain text scope
@@ -224,14 +263,14 @@ def restore_terminal_settings
# @return [Hash, Array<String>] the plugin or group scope, the unknown entries
#
def self.convert_scope(entries)
- scopes = { }
+ scopes = { :plugins => [], :groups => [] }
unknown = []
entries.each do |entry|
- if guard = ::Guard.guards(entry)
- scopes[:guard] ||= guard
+ if plugin = ::Guard.guards(entry)
+ scopes[:plugins] << plugin
elsif group = ::Guard.groups(entry)
- scopes[:group] ||= group
+ scopes[:groups] << group
else
unknown << entry
end
View
54 lib/guard/runner.rb
@@ -7,7 +7,7 @@ class Runner
require 'guard'
require 'guard/ui'
require 'guard/watcher'
-
+
require 'lumberjack'
# Deprecation message for the `run_on_change` method
@@ -153,18 +153,23 @@ def run_first_task_found(guard, tasks, task_param)
# Loop through all groups and run the given task for each Guard plugin.
#
+ # If no scope is supplied, the global Guard scope is taken into account.
+ # If both a plugin and a group scope is given, then only the plugin scope
+ # is used.
+ #
# Stop the task run for the all Guard plugins within a group if one Guard
# throws `:task_has_failed`.
#
- # @param [Hash] scopes hash with a Guard plugin or a group scope
+ # @param [Hash] scopes hash with plugins or a groups scope
# @yield the task to run
#
def scoped_guards(scopes = {})
- if guard = scopes[:guard]
- yield(guard)
+ if guards = current_plugins_scope(scopes)
+ guards.each do |guard|
+ yield(guard)
+ end
else
- groups = scopes[:group] ? [scopes[:group]] : ::Guard.groups
- groups.each do |group|
+ current_groups_scope(scopes).each do |group|
catch :task_has_failed do
::Guard.guards(:group => group.name).each do |guard|
yield(guard)
@@ -188,5 +193,42 @@ def clearable?(guard, modified_paths, added_paths, removed_paths)
(REMOVAL_TASKS.any? { |task| guard.respond_to?(task) } && !removed_paths.empty?)
end
+ # Returns the current plugins scope.
+ # Local plugins scope wins over global plugins scope.
+ # If no plugins scope is found, then NO plugins are returned.
+ #
+ # @param [Hash] scopes hash with a local plugins or a groups scope
+ # @return [Array<Guard::Guard>] the plugins to scope to
+ #
+ def current_plugins_scope(scopes)
+ if scopes[:plugins] && !scopes[:plugins].empty?
+ scopes[:plugins]
+
+ elsif !::Guard.scope[:plugins].empty?
+ ::Guard.scope[:plugins]
+
+ else
+ nil
+ end
+ end
+
+ # Returns the current groups scope.
+ # Local groups scope wins over global groups scope.
+ # If no groups scope is found, then ALL groups are returned.
+ #
+ # @param [Hash] scopes hash with a local plugins or a groups scope
+ # @return [Array<Guard::Group>] the groups to scope to
+ #
+ def current_groups_scope(scopes)
+ if scopes[:groups] && !scopes[:groups].empty?
+ scopes[:groups]
+
+ elsif !::Guard.scope[:groups].empty?
+ ::Guard.scope[:groups]
+
+ else
+ ::Guard.groups
+ end
+ end
end
end
View
24 lib/guard/ui.rb
@@ -10,7 +10,7 @@ module Guard
# processing, please just write it to STDOUT with `puts`.
#
module UI
-
+
class << self
# Get the Guard::UI logger instance
@@ -18,7 +18,7 @@ class << self
def logger
@logger ||= Lumberjack::Logger.new($stderr, self.options)
end
-
+
# Get the logger options
#
# @return [Hash] the logger options
@@ -131,27 +131,35 @@ def clearable
# @param [Hash] scopes hash with a guard or a group scope
#
def action_with_scopes(action, scopes)
- scope_message ||= scopes[:guard]
- scope_message ||= scopes[:group]
+ plugins = scopes[:plugins] || []
+ groups = scopes[:groups] || []
+
+ if plugins.empty? && groups.empty?
+ plugins = ::Guard.scope[:plugins] || []
+ groups = ::Guard.scope[:groups] || []
+ end
+
+ scope_message ||= plugins.join(',') unless plugins.empty?
+ scope_message ||= groups.join(',') unless groups.empty?
scope_message ||= 'all'
- info "#{action} #{scope_message}"
+ info "#{ action } #{ scope_message }"
end
private
-
+
# Filters log messages depending on either the
# `:only`` or `:except` option.
#
# @param [String] plugin the calling plugin name
# @yield When the message should be logged
- # @yieldparam [String] param the calling plugin name
+ # @yieldparam [String] param the calling plugin name
#
def filter(plugin)
only = self.options[:only]
except = self.options[:except]
plugin = plugin || calling_plugin_name
-
+
if (!only && !except) || (only && only.match(plugin)) || (except && !except.match(plugin))
yield plugin
end
View
6 spec/guard/commands/all_spec.rb
@@ -16,21 +16,21 @@
describe '#perform' do
context 'without scope' do
it 'runs the :run_all action' do
- Guard.should_receive(:run_all).with({})
+ Guard.should_receive(:run_all).with({ :groups => [], :plugins => [] })
Pry.run_command 'all'
end
end
context 'with a valid Guard group scope' do
it 'runs the :run_all action with the given scope' do
- Guard.should_receive(:run_all).with({ :group => foo_group })
+ Guard.should_receive(:run_all).with({ :groups => [foo_group], :plugins => [] })
Pry.run_command 'all foo'
end
end
context 'with a valid Guard plugin scope' do
it 'runs the :run_all action with the given scope' do
- Guard.should_receive(:run_all).with({ :guard => bar_guard })
+ Guard.should_receive(:run_all).with({ :plugins => [bar_guard], :groups => [] })
Pry.run_command 'all bar'
end
end
View
6 spec/guard/commands/reload_spec.rb
@@ -16,21 +16,21 @@
describe '#perform' do
context 'without scope' do
it 'runs the :reload action' do
- Guard.should_receive(:reload).with({})
+ Guard.should_receive(:reload).with({ :groups => [], :plugins => [] })
Pry.run_command 'reload'
end
end
context 'with a valid Guard group scope' do
it 'runs the :reload action with the given scope' do
- Guard.should_receive(:reload).with({ :group => foo_group })
+ Guard.should_receive(:reload).with({ :groups => [foo_group], :plugins => [] })
Pry.run_command 'reload foo'
end
end
context 'with a valid Guard plugin scope' do
it 'runs the :reload action with the given scope' do
- Guard.should_receive(:reload).with({ :guard => bar_guard })
+ Guard.should_receive(:reload).with({ :plugins => [bar_guard], :groups => [] })
Pry.run_command 'reload bar'
end
end
View
32 spec/guard/dsl_spec.rb
@@ -422,37 +422,7 @@ def self.disable_user_config
describe "#group" do
disable_user_config
- it "evaluates only the specified string group" do
- ::Guard.should_receive(:add_guard).with('pow', [], [], { :group => :default })
- ::Guard.should_receive(:add_guard).with('test', [], [], { :group => :w })
-
- described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string, :group => [:w])
- end
-
- it "evaluates only the specified symbol group" do
- ::Guard.should_receive(:add_guard).with('pow', [], [], { :group => :default })
- ::Guard.should_receive(:add_guard).with('test', [], [], { :group => :w })
-
- described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string, :group => [:w])
- end
-
- it "evaluates only the specified groups (with their options)" do
- ::Guard.should_receive(:add_guard).with('pow', [], [], { :group => :default })
- ::Guard.should_receive(:add_guard).with('rspec', [], [], { :group => :x })
- ::Guard.should_receive(:add_guard).with('ronn', [], [], { :group => :x })
- ::Guard.should_receive(:add_guard).with('less', [], [], { :group => :y })
-
- described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string, :group => [:x, :y])
- end
-
- it "evaluates always guard outside any group (even when a group is given)" do
- ::Guard.should_receive(:add_guard).with('pow', [], [], { :group => :default })
- ::Guard.should_receive(:add_guard).with('test', [], [], { :group => :w })
-
- described_class.evaluate_guardfile(:guardfile_contents => valid_guardfile_string, :group => [:w])
- end
-
- it "evaluates all groups when no group option is specified (with their options)" do
+ it "evaluates all groups" do
::Guard.should_receive(:add_guard).with('pow', [], [], { :group => :default })
::Guard.should_receive(:add_guard).with('test', [], [], { :group => :w })
::Guard.should_receive(:add_guard).with('rspec', [], [], { :group => :x })
View
2  spec/guard/group_spec.rb
@@ -19,7 +19,7 @@
describe '#to_s' do
it "output Group properly" do
group = described_class.new(:foo)
- group.to_s.should eq "foo group"
+ group.to_s.should eq "Foo"
end
end
View
4 spec/guard/guard_spec.rb
@@ -61,9 +61,9 @@
describe '#to_s' do
before(:all) { class Guard::Dummy < Guard::Guard; end }
- it "output Guard properly" do
+ it "output the short plugin name" do
guard = Guard::Dummy.new
- guard.to_s.should eq "Guard::Dummy"
+ guard.to_s.should eq "Dummy"
end
end
View
23 spec/guard/interactor_spec.rb
@@ -17,16 +17,31 @@
it 'returns a group scope' do
scopes, _ = Guard::Interactor.convert_scope %w(backend)
- scopes.should eql({ :group => @backend_group })
+ scopes.should eql({ :groups => [@backend_group], :plugins => [] })
scopes, _ = Guard::Interactor.convert_scope %w(frontend)
- scopes.should eql({ :group => @frontend_group })
+ scopes.should eql({ :groups => [@frontend_group], :plugins => [] })
end
it 'returns a plugin scope' do
scopes, _ = Guard::Interactor.convert_scope %w(foo)
- scopes.should eql({ :guard => @foo_guard })
+ scopes.should eql({ :plugins => [@foo_guard], :groups => [] })
scopes, _ = Guard::Interactor.convert_scope %w(bar)
- scopes.should eql({ :guard => @bar_guard })
+ scopes.should eql({ :plugins => [@bar_guard], :groups => [] })
+ end
+
+ it 'returns multiple group scopes' do
+ scopes, _ = Guard::Interactor.convert_scope %w(backend frontend)
+ scopes.should eql({ :groups => [@backend_group, @frontend_group], :plugins => [] })
+ end
+
+ it 'returns multiple plugin scopes' do
+ scopes, _ = Guard::Interactor.convert_scope %w(foo bar)
+ scopes.should eql({ :plugins => [@foo_guard, @bar_guard], :groups => [] })
+ end
+
+ it 'returns a plugin and group scope' do
+ scopes, _ = Guard::Interactor.convert_scope %w(foo backend)
+ scopes.should eql({ :plugins => [@foo_guard], :groups => [@backend_group] })
end
it 'returns the unkown scopes' do
View
12 spec/guard/runner_spec.rb
@@ -90,8 +90,8 @@
end
end
- context 'within the scope of a specified guard' do
- let(:scopes) { { :guard => bar1_guard } }
+ context 'within the scope of a specified local guard' do
+ let(:scopes) { { :plugins => [bar1_guard] } }
it 'executes the supervised task on the specified guard only' do
subject.should_receive(:run_supervised_task).with(bar1_guard, :my_task)
@@ -103,8 +103,8 @@
end
end
- context 'within the scope of a specified group' do
- let(:scopes) { { :group => foo_group } }
+ context 'within the scope of a specified local group' do
+ let(:scopes) { { :groups => [foo_group] } }
it 'executes the task on each guard in the specified group only' do
subject.should_receive(:run_supervised_task).with(foo_guard, :my_task)
@@ -121,11 +121,11 @@
let(:changes) { [ [], [], [] ] }
let(:watcher_module) { ::Guard::Watcher }
- before {
+ before do
subject.stub(:scoped_guards).and_yield(foo_guard)
subject.stub(:clearable?) { false }
watcher_module.stub(:match_files) { [] }
- }
+ end
it "always calls UI.clearable" do
Guard::UI.should_receive(:clearable)
View
34 spec/guard/ui_spec.rb
@@ -276,4 +276,38 @@
end
end
+ describe '.action_with_scopes' do
+ context 'with a plugins scope' do
+ it 'shows the plugin scoped action' do
+ Guard::UI.should_receive(:info).with('Reload rspec,jasmine')
+ Guard::UI.action_with_scopes('Reload', { :plugins => [:rspec, :jasmine] })
+ end
+ end
+
+ context 'with a groups scope' do
+ it 'shows the group scoped action' do
+ Guard::UI.should_receive(:info).with('Reload frontend')
+ Guard::UI.action_with_scopes('Reload', { :groups => [:frontend] })
+ end
+ end
+
+ context 'without a scope' do
+ context 'with a global plugin scope' do
+ it 'shows the global plugin scoped action' do
+ Guard.scope = { :groups => [:test] }
+ Guard::UI.should_receive(:info).with('Reload test')
+ Guard::UI.action_with_scopes('Reload', {})
+ end
+ end
+
+ context 'with a global group scope' do
+ it 'shows the global group scoped action' do
+ Guard.scope = { :groups => [:backend] }
+ Guard::UI.should_receive(:info).with('Reload backend')
+ Guard::UI.action_with_scopes('Reload', {})
+ end
+ end
+ end
+ end
+
end
View
145 spec/guard_spec.rb
@@ -13,13 +13,13 @@
subject.should be ::Guard
end
- it "initializes @guards" do
+ it "initializes the plugins" do
subject.guards.should eq []
end
- it "initializes @groups" do
+ it "initializes the groups" do
subject.groups[0].name.should eq :default
- subject.groups[0].options.should == {}
+ subject.groups[0].options.should == { }
end
it "initializes the options" do
@@ -61,6 +61,46 @@
subject
end
+ context 'without the group or plugin option' do
+ it "initializes the empty scope" do
+ subject.scope.should == { :groups => [], :plugins => [] }
+ end
+ end
+
+ context 'with the group option' do
+ let(:options) { {
+ :group => ['backend', 'frontend'],
+ :guardfile_contents => "group :backend do; end; group :frontend do; end; group :excluded do; end"
+ } }
+
+ it "initializes the group scope" do
+ subject.scope[:plugins].should be_empty
+ subject.scope[:groups].count.should be 2
+ subject.scope[:groups][0].name.should eql :backend
+ subject.scope[:groups][1].name.should eql :frontend
+ end
+ end
+
+ context 'with the plugin option' do
+ let(:options) { {
+ :plugin => ['cucumber', 'jasmine'],
+ :guardfile_contents => "guard :jasmine do; end; guard :cucumber do; end; guard :coffeescript do; end"
+ } }
+
+ before do
+ stub_const 'Guard::Jasmine', Class.new(Guard::Guard)
+ stub_const 'Guard::Cucumber', Class.new(Guard::Guard)
+ stub_const 'Guard::CoffeeScript', Class.new(Guard::Guard)
+ end
+
+ it "initializes the plugin scope" do
+ subject.scope[:groups].should be_empty
+ subject.scope[:plugins].count.should be 2
+ subject.scope[:plugins][0].class.should eql ::Guard::Cucumber
+ subject.scope[:plugins][1].class.should eql ::Guard::Jasmine
+ end
+ end
+
context 'when deprecations should be shown' do
let(:options) { { :show_deprecations => true, :guardfile => File.join(@fixture_path, "Guardfile") } }
subject { ::Guard.setup(options) }
@@ -270,7 +310,7 @@
describe ".setup_interactor" do
context 'with CLI options' do
before do
- @enabled = ::Guard::Interactor.enabled
+ @enabled = ::Guard::Interactor.enabled
::Guard::Interactor.enabled = true
end
@@ -330,18 +370,30 @@
subject.reload
end
- context 'with a scope' do
+ context 'with a old scope format' do
it 'does not re-evaluate the Guardfile' do
::Guard::Dsl.should_not_receive(:reevaluate_guardfile)
subject.reload({ :group => :frontend })
end
it 'reloads Guard' do
- ::Guard.should_receive(:reload).with({ :group => :frontend })
+ runner.should_receive(:run).with(:reload, { :groups => [:frontend] })
subject.reload({ :group => :frontend })
end
end
+ context 'with a new scope format' do
+ it 'does not re-evaluate the Guardfile' do
+ ::Guard::Dsl.should_not_receive(:reevaluate_guardfile)
+ subject.reload({ :groups => [:frontend] })
+ end
+
+ it 'reloads Guard' do
+ runner.should_receive(:run).with(:reload, { :groups => [:frontend] })
+ subject.reload({ :groups => [:frontend] })
+ end
+ end
+
context 'with an empty scope' do
it 'does re-evaluate the Guardfile' do
::Guard::Dsl.should_receive(:reevaluate_guardfile)
@@ -349,7 +401,7 @@
end
it 'does not reload Guard' do
- ::Guard.should_not_receive(:reload).with({ })
+ runner.should_not_receive(:run).with(:reload, { })
subject.reload
end
end
@@ -357,8 +409,10 @@
describe ".guards" do
before(:all) do
- class Guard::FooBar < Guard::Guard; end
- class Guard::FooBaz < Guard::Guard; end
+ class Guard::FooBar < Guard::Guard;
+ end
+ class Guard::FooBaz < Guard::Guard;
+ end
end
after(:all) do
@@ -369,7 +423,7 @@ class Guard::FooBaz < Guard::Guard; end
end
subject do
- guard = ::Guard.setup
+ guard = ::Guard.setup
@guard_foo_bar_backend = Guard::FooBar.new([], { :group => 'backend' })
@guard_foo_bar_frontend = Guard::FooBar.new([], { :group => 'frontend' })
@guard_foo_baz_backend = Guard::FooBaz.new([], { :group => 'backend' })
@@ -385,7 +439,7 @@ class Guard::FooBaz < Guard::Guard; end
subject.guards.should == subject.instance_variable_get("@guards")
end
- describe "find a guard by as string/symbol" do
+ context "find a guard by as string/symbol" do
it "find a guard by a string" do
subject.guards('foo-bar').should == @guard_foo_bar_backend
end
@@ -399,7 +453,7 @@ class Guard::FooBaz < Guard::Guard; end
end
end
- describe "find guards matching a regexp" do
+ context "find guards matching a regexp" do
it "with matches" do
subject.guards(/^foobar/).should == [@guard_foo_bar_backend, @guard_foo_bar_frontend]
end
@@ -409,7 +463,7 @@ class Guard::FooBaz < Guard::Guard; end
end
end
- describe "find guards by their group" do
+ context "find guards by their group" do
it "group name is a string" do
subject.guards(:group => 'backend').should == [@guard_foo_bar_backend, @guard_foo_baz_backend]
end
@@ -423,7 +477,7 @@ class Guard::FooBaz < Guard::Guard; end
end
end
- describe "find guards by their group & name" do
+ context "find guards by their group & name" do
it "group name is a string" do
subject.guards(:group => 'backend', :name => 'foo-bar').should == [@guard_foo_bar_backend]
end
@@ -440,17 +494,19 @@ class Guard::FooBaz < Guard::Guard; end
describe ".groups" do
subject do
- guard = ::Guard.setup
+ guard = ::Guard.setup
@group_backend = guard.add_group(:backend)
@group_backflip = guard.add_group(:backflip)
guard
end
- it "return @groups without any argument" do
- subject.groups.should == subject.instance_variable_get("@groups")
+ context 'without any argument' do
+ it "return all groups" do
+ subject.groups.should == subject.instance_variable_get("@groups")
+ end
end
- describe "find a group by as string/symbol" do
+ context "find a group by as string/symbol" do
it "find a group by a string" do
subject.groups('backend').should == @group_backend
end
@@ -464,7 +520,7 @@ class Guard::FooBaz < Guard::Guard; end
end
end
- describe "find groups matching a regexp" do
+ context "find groups matching a regexp" do
it "with matches" do
subject.groups(/^back/).should == [@group_backend, @group_backflip]
end
@@ -477,32 +533,32 @@ class Guard::FooBaz < Guard::Guard; end
describe ".setup_groups" do
subject do
- guard = ::Guard.setup(:guardfile => File.join(@fixture_path, "Guardfile"))
+ guard = ::Guard.setup(:guardfile => File.join(@fixture_path, "Guardfile"))
@group_backend = guard.add_group(:backend)
@group_backflip = guard.add_group(:backflip)
guard
end
- it "return @groups without any argument" do
- subject.groups.should have(3).items
-
+ it "initializes a default group" do
subject.setup_groups
subject.groups.should have(1).item
subject.groups[0].name.should eq :default
- subject.groups[0].options.should == {}
+ subject.groups[0].options.should == { }
end
end
describe ".setup_guards" do
- before(:all) { class Guard::FooBar < Guard::Guard; end }
+ before(:all) {
+ class Guard::FooBar < Guard::Guard;
+ end }
after(:all) do
::Guard.instance_eval { remove_const(:FooBar) }
end
subject do
- guard = ::Guard.setup(:guardfile => File.join(@fixture_path, "Guardfile"))
+ guard = ::Guard.setup(:guardfile => File.join(@fixture_path, "Guardfile"))
@group_backend = guard.add_guard(:foo_bar)
guard
end
@@ -554,7 +610,7 @@ class Guard::FooBaz < Guard::Guard; end
describe ".add_guard" do
before do
@guard_rspec_class = double('Guard::RSpec')
- @guard_rspec = double('Guard::RSpec', :is_a? => true)
+ @guard_rspec = double('Guard::RSpec', :is_a? => true)
::Guard.stub!(:get_guard_class) { @guard_rspec_class }
@@ -585,7 +641,7 @@ class Guard::FooBaz < Guard::Guard; end
context "with no watchers given" do
it "gives an empty array of watchers" do
- @guard_rspec_class.should_receive(:new).with([], {}).and_return(@guard_rspec)
+ @guard_rspec_class.should_receive(:new).with([], { }).and_return(@guard_rspec)
::Guard.add_guard(:rspec, [])
end
@@ -593,7 +649,7 @@ class Guard::FooBaz < Guard::Guard; end
context "with watchers given" do
it "give the watchers array" do
- @guard_rspec_class.should_receive(:new).with([:foo], {}).and_return(@guard_rspec)
+ @guard_rspec_class.should_receive(:new).with([:foo], { }).and_return(@guard_rspec)
::Guard.add_guard(:rspec, [:foo])
end
@@ -601,9 +657,9 @@ class Guard::FooBaz < Guard::Guard; end
context "with no options given" do
it "gives an empty hash of options" do
- @guard_rspec_class.should_receive(:new).with([], {}).and_return(@guard_rspec)
+ @guard_rspec_class.should_receive(:new).with([], { }).and_return(@guard_rspec)
- ::Guard.add_guard(:rspec, [], [], {})
+ ::Guard.add_guard(:rspec, [], [], { })
end
end
@@ -636,18 +692,18 @@ class Guard::FooBaz < Guard::Guard; end
it "accepts options" do
::Guard.add_group(:backend, { :halt_on_fail => true })
- ::Guard.groups[0].options.should eq({})
+ ::Guard.groups[0].options.should eq({ })
::Guard.groups[1].options.should eq({ :halt_on_fail => true })
end
end
describe '.within_preserved_state' do
subject { ::Guard.setup }
- before { subject.interactor = stub('interactor').as_null_object }
+ before { subject.interactor = stub('interactor').as_null_object }
it 'disallows running the block concurrently to avoid inconsistent states' do
subject.lock.should_receive(:synchronize)
- subject.within_preserved_state &Proc.new {}
+ subject.within_preserved_state &Proc.new { }
end
it 'runs the passed block' do
@@ -660,7 +716,7 @@ class Guard::FooBaz < Guard::Guard; end
it 'stops the interactor before running the block and starts it again when done' do
subject.interactor.should_receive(:stop)
subject.interactor.should_receive(:start)
- subject.within_preserved_state &Proc.new {}
+ subject.within_preserved_state &Proc.new { }
end
end
@@ -668,7 +724,7 @@ class Guard::FooBaz < Guard::Guard; end
it 'stops the interactor before running the block' do
subject.interactor.should_receive(:stop)
subject.interactor.should__not_receive(:start)
- subject.within_preserved_state &Proc.new {}
+ subject.within_preserved_state &Proc.new { }
end
end
end
@@ -691,7 +747,8 @@ class Guard::FooBaz < Guard::Guard; end
it "resolves the Guard class from string" do
Guard.should_receive(:require) { |classname|
classname.should eq 'guard/classname'
- class Guard::Classname; end
+ class Guard::Classname;
+ end
}
Guard.get_guard_class('classname').should == Guard::Classname
end
@@ -699,7 +756,8 @@ class Guard::Classname; end
it "resolves the Guard class from symbol" do
Guard.should_receive(:require) { |classname|
classname.should eq 'guard/classname'
- class Guard::Classname; end
+ class Guard::Classname;
+ end
}
Guard.get_guard_class(:classname).should == Guard::Classname
end
@@ -711,7 +769,8 @@ class Guard::Classname; end
it "returns the Guard class" do
Guard.should_receive(:require) { |classname|
classname.should eq 'guard/dashed-class-name'
- class Guard::DashedClassName; end
+ class Guard::DashedClassName;
+ end
}
Guard.get_guard_class('dashed-class-name').should == Guard::DashedClassName
end
@@ -723,7 +782,8 @@ class Guard::DashedClassName; end
it "returns the Guard class" do
Guard.should_receive(:require) { |classname|
classname.should eq 'guard/underscore_class_name'
- class Guard::UnderscoreClassName; end
+ class Guard::UnderscoreClassName;
+ end
}
Guard.get_guard_class('underscore_class_name').should == Guard::UnderscoreClassName
end
@@ -735,7 +795,8 @@ class Guard::UnderscoreClassName; end
it "returns the Guard class" do
Guard.should_receive(:require) { |classname|
classname.should eq 'guard/vspec'
- class Guard::VSpec; end
+ class Guard::VSpec;
+ end
}
Guard.get_guard_class('vspec').should == Guard::VSpec
end
@@ -801,7 +862,7 @@ class Inline < Guard
before do
Guard.unstub(:debug_command_execution)
- @original_system = Kernel.method(:system)
+ @original_system = Kernel.method(:system)
@original_command = Kernel.method(:"`")
end
View
2  spec/spec_helper.rb
@@ -44,6 +44,8 @@
if ::Guard.options
::Guard.options[:debug] = false
end
+
+ Guard.scope = { :plugins => [], :groups => [] }
end
config.after(:all) do
Something went wrong with that request. Please try again.