guard 2.10.2 → 2.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/guard.rb +29 -29
- data/lib/guard/cli.rb +11 -78
- data/lib/guard/cli/environments/bundler.rb +22 -0
- data/lib/guard/cli/environments/evaluate_only.rb +35 -0
- data/lib/guard/cli/environments/valid.rb +59 -0
- data/lib/guard/commander.rb +7 -9
- data/lib/guard/commands/all.rb +1 -2
- data/lib/guard/commands/reload.rb +1 -2
- data/lib/guard/commands/scope.rb +1 -1
- data/lib/guard/config.rb +10 -16
- data/lib/guard/deprecated/evaluator.rb +4 -1
- data/lib/guard/deprecated/guard.rb +92 -2
- data/lib/guard/dsl_describer.rb +2 -0
- data/lib/guard/guardfile/evaluator.rb +1 -2
- data/lib/guard/interactor.rb +0 -29
- data/lib/guard/internals/plugins.rb +2 -0
- data/lib/guard/internals/scope.rb +5 -1
- data/lib/guard/internals/session.rb +25 -6
- data/lib/guard/internals/state.rb +9 -4
- data/lib/guard/notifier.rb +10 -12
- data/lib/guard/notifier/detected.rb +9 -5
- data/lib/guard/plugin.rb +3 -0
- data/lib/guard/templates/Guardfile +23 -1
- data/lib/guard/ui.rb +0 -7
- data/lib/guard/version.rb +1 -1
- data/lib/guard/watcher.rb +2 -2
- metadata +19 -11
- data/lib/guard.rb.orig +0 -174
- data/lib/guard/compat/test/helper.rb.orig +0 -0
- data/lib/guard/dsl.rb.orig +0 -432
- data/lib/guard/internals/environment.rb +0 -93
- data/lib/guard/internals/session.rb.orig +0 -148
- data/lib/guard/plugin_util.rb.orig +0 -182
- data/lib/guard/reevaluator.rb +0 -61
- data/lib/guard/ui.rb.orig +0 -268
- data/lib/guard/version.rb.orig +0 -3
@@ -1,93 +0,0 @@
|
|
1
|
-
module Guard
|
2
|
-
# @private api
|
3
|
-
module Internals
|
4
|
-
class Environment
|
5
|
-
class Error < ArgumentError
|
6
|
-
end
|
7
|
-
|
8
|
-
class MethodError < Error
|
9
|
-
def initialize(meth)
|
10
|
-
@meth = meth
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class NoMethodError < MethodError
|
15
|
-
def message
|
16
|
-
format("No such method %s", @meth.inspect)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class AlreadyExistsError < MethodError
|
21
|
-
def message
|
22
|
-
format("Method %s already exists", @meth.inspect)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class Loader
|
27
|
-
def initialize(meth)
|
28
|
-
@bool = meth.to_s.end_with?("?")
|
29
|
-
end
|
30
|
-
|
31
|
-
def load(raw_value, &callback)
|
32
|
-
return callback.call(raw_value) if callback
|
33
|
-
@bool ? _to_bool(raw_value) : raw_value
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def _to_bool(raw_value)
|
39
|
-
case raw_value
|
40
|
-
when nil
|
41
|
-
nil
|
42
|
-
when ""
|
43
|
-
fail ArgumentError, "Can't convert empty string into Bool"
|
44
|
-
when "0", "false"
|
45
|
-
false
|
46
|
-
else
|
47
|
-
true
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
class Dumper
|
53
|
-
def initialize
|
54
|
-
end
|
55
|
-
|
56
|
-
def dump(raw_value, &callback)
|
57
|
-
return callback.call(raw_value) if callback
|
58
|
-
raw_value.nil? ? nil : raw_value.to_s
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def initialize(namespace)
|
63
|
-
@namespace = namespace
|
64
|
-
@methods = {}
|
65
|
-
end
|
66
|
-
|
67
|
-
def create_method(meth, &block)
|
68
|
-
fail AlreadyExistsError, meth if @methods.key?(meth)
|
69
|
-
@methods[meth] = block
|
70
|
-
end
|
71
|
-
|
72
|
-
def method_missing(*args)
|
73
|
-
meth, raw_value = *args
|
74
|
-
fail NoMethodError, meth unless @methods.key?(meth)
|
75
|
-
|
76
|
-
callback = @methods[meth]
|
77
|
-
env_name = format("%s_%s", @namespace, _sanitize(meth))
|
78
|
-
|
79
|
-
if args.size == 2
|
80
|
-
ENV[env_name] = Dumper.new.dump(raw_value, &callback)
|
81
|
-
else
|
82
|
-
Loader.new(meth).load(ENV[env_name], &callback)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
private
|
87
|
-
|
88
|
-
def _sanitize(meth)
|
89
|
-
meth[/^([^=?]*)[=?]?$/, 1].upcase
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
@@ -1,148 +0,0 @@
|
|
1
|
-
require "guard/internals/plugins"
|
2
|
-
require "guard/internals/groups"
|
3
|
-
|
4
|
-
require "guard/options"
|
5
|
-
|
6
|
-
module Guard
|
7
|
-
# @private api
|
8
|
-
module Internals
|
9
|
-
# TODO: split into a commandline class and session (plugins, groups)
|
10
|
-
# TODO: swap session and metadata
|
11
|
-
# This class contains variables set during
|
12
|
-
# evaluation of the guardfile (and are reset
|
13
|
-
# before reevaluation)
|
14
|
-
class Session
|
15
|
-
attr_reader :options
|
16
|
-
attr_reader :plugins
|
17
|
-
attr_reader :groups
|
18
|
-
|
19
|
-
DEFAULT_OPTIONS = {
|
20
|
-
clear: false,
|
21
|
-
debug: false,
|
22
|
-
no_bundler_warning: false,
|
23
|
-
|
24
|
-
# User defined scopes
|
25
|
-
group: [],
|
26
|
-
plugin: [],
|
27
|
-
|
28
|
-
# Notifier
|
29
|
-
notify: true,
|
30
|
-
|
31
|
-
# Interactor
|
32
|
-
no_interactions: false,
|
33
|
-
|
34
|
-
# Guardfile options:
|
35
|
-
# guardfile_contents
|
36
|
-
guardfile: nil,
|
37
|
-
|
38
|
-
# Listener options
|
39
|
-
# TODO: rename to watchdirs?
|
40
|
-
watchdir: Dir.pwd,
|
41
|
-
latency: nil,
|
42
|
-
force_polling: false,
|
43
|
-
wait_for_delay: nil,
|
44
|
-
listen_on: nil
|
45
|
-
}
|
46
|
-
|
47
|
-
def cmdline_groups
|
48
|
-
@cmdline_groups.dup.freeze
|
49
|
-
end
|
50
|
-
|
51
|
-
def cmdline_plugins
|
52
|
-
@cmdline_plugins.dup.freeze
|
53
|
-
end
|
54
|
-
|
55
|
-
def initialize(new_options)
|
56
|
-
@options = Options.new(new_options, DEFAULT_OPTIONS)
|
57
|
-
|
58
|
-
@plugins = Internals::Plugins.new
|
59
|
-
@groups = Internals::Groups.new
|
60
|
-
|
61
|
-
@cmdline_groups = @options[:group]
|
62
|
-
@cmdline_plugins = @options[:plugin]
|
63
|
-
|
64
|
-
@clear = @options[:clear]
|
65
|
-
@debug = @options[:debug]
|
66
|
-
@watchdirs = Array(@options[:watchdir])
|
67
|
-
@notify = @options[:notify]
|
68
|
-
@interactor_name = @options[:no_interactions] ? :sleep : :pry_wrapper
|
69
|
-
|
70
|
-
@guardfile_plugin_scope = []
|
71
|
-
@guardfile_group_scope = []
|
72
|
-
end
|
73
|
-
|
74
|
-
def guardfile_scope(scope)
|
75
|
-
opts = scope.dup
|
76
|
-
@guardfile_plugin_scope = Array(opts.delete(:plugins))
|
77
|
-
@guardfile_group_scope = Array(opts.delete(:groups))
|
78
|
-
fail "Unknown options: #{opts.inspect}" unless opts.empty?
|
79
|
-
end
|
80
|
-
|
81
|
-
attr_reader :guardfile_group_scope
|
82
|
-
attr_reader :guardfile_plugin_scope
|
83
|
-
|
84
|
-
def guardfile_ignore
|
85
|
-
fail NotImplementedError
|
86
|
-
end
|
87
|
-
|
88
|
-
def guardfile_ignore_bang
|
89
|
-
fail NotImplementedError
|
90
|
-
end
|
91
|
-
|
92
|
-
def clearing(on)
|
93
|
-
@clear = on
|
94
|
-
end
|
95
|
-
|
96
|
-
def clearing?
|
97
|
-
@clear
|
98
|
-
end
|
99
|
-
|
100
|
-
alias :clear? :clearing?
|
101
|
-
|
102
|
-
def debug?
|
103
|
-
@debug
|
104
|
-
end
|
105
|
-
|
106
|
-
def watchdirs
|
107
|
-
@watchdirs_from_guardfile ||= nil
|
108
|
-
@watchdirs_from_guardfile || @watchdirs
|
109
|
-
end
|
110
|
-
|
111
|
-
# set by Dsl with :directories() command
|
112
|
-
def watchdirs=(dirs)
|
113
|
-
dirs = [Dir.pwd] if dirs.empty?
|
114
|
-
@watchdirs_from_guardfile = dirs.map { |dir| File.expand_path dir }
|
115
|
-
end
|
116
|
-
|
117
|
-
def listener_args
|
118
|
-
if options[:listen_on]
|
119
|
-
[:on, options[:listen_on]]
|
120
|
-
else
|
121
|
-
listener_options = {}
|
122
|
-
[:latency, :force_polling, :wait_for_delay].each do |option|
|
123
|
-
listener_options[option] = options[option] if options[option]
|
124
|
-
end
|
125
|
-
expanded_watchdirs = watchdirs.map { |dir| File.expand_path dir }
|
126
|
-
[:to, *expanded_watchdirs, listener_options]
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def evaluator_options
|
131
|
-
opts = { guardfile: options[:guardfile] }
|
132
|
-
# TODO: deprecate :guardfile_contents
|
133
|
-
if options[:guardfile_contents]
|
134
|
-
opts[:contents] = options[:guardfile_contents]
|
135
|
-
end
|
136
|
-
opts
|
137
|
-
end
|
138
|
-
|
139
|
-
def notify_options
|
140
|
-
{ notify: @options[:notify] }
|
141
|
-
end
|
142
|
-
|
143
|
-
def interactor_name
|
144
|
-
@interactor_name
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
@@ -1,182 +0,0 @@
|
|
1
|
-
require "guard/ui"
|
2
|
-
|
3
|
-
module Guard
|
4
|
-
# This class contains useful methods to:
|
5
|
-
#
|
6
|
-
# * Fetch all the Guard plugins names;
|
7
|
-
# * Initialize a plugin, get its location;
|
8
|
-
# * Return its class name;
|
9
|
-
# * Add its template to the Guardfile.
|
10
|
-
#
|
11
|
-
class PluginUtil
|
12
|
-
ERROR_NO_GUARD_OR_CLASS = "Could not load 'guard/%s' or'\
|
13
|
-
' find class Guard::%s"
|
14
|
-
|
15
|
-
INFO_ADDED_GUARD_TO_GUARDFILE = "%s guard added to Guardfile,"\
|
16
|
-
" feel free to edit it"
|
17
|
-
|
18
|
-
attr_accessor :name
|
19
|
-
|
20
|
-
# Returns a list of Guard plugin Gem names installed locally.
|
21
|
-
#
|
22
|
-
# @return [Array<String>] a list of Guard plugin gem names
|
23
|
-
#
|
24
|
-
def self.plugin_names
|
25
|
-
valid = Gem::Specification.find_all.select do |gem|
|
26
|
-
_gem_valid?(gem)
|
27
|
-
end
|
28
|
-
|
29
|
-
valid.map { |x| x.name.sub(/^guard-/, "") }.uniq
|
30
|
-
end
|
31
|
-
|
32
|
-
# Initializes a new `Guard::PluginUtil` object.
|
33
|
-
#
|
34
|
-
# @param [String] name the name of the Guard plugin
|
35
|
-
#
|
36
|
-
def initialize(name)
|
37
|
-
@name = name.to_s.sub(/^guard-/, "")
|
38
|
-
end
|
39
|
-
|
40
|
-
# Initializes a new `Guard::Plugin` with the given `options` hash. This
|
41
|
-
# methods handles plugins that inherit from the deprecated `Guard::Guard`
|
42
|
-
# class as well as plugins that inherit from `Guard::Plugin`.
|
43
|
-
#
|
44
|
-
# @see Guard::Plugin
|
45
|
-
# @see https://github.com/guard/guard/wiki/Upgrading-to-Guard-2.0 How to
|
46
|
-
# upgrade for Guard 2.0
|
47
|
-
#
|
48
|
-
# @return [Guard::Plugin] the initialized plugin
|
49
|
-
# @return [Guard::Guard] the initialized plugin. This return type is
|
50
|
-
# deprecated and the plugin's maintainer should update it to be
|
51
|
-
# compatible with Guard 2.0. For more information on how to upgrade for
|
52
|
-
# Guard 2.0, please head over to:
|
53
|
-
# https://github.com/guard/guard/wiki/Upgrading-to-Guard-2.0
|
54
|
-
#
|
55
|
-
def initialize_plugin(options)
|
56
|
-
klass = plugin_class
|
57
|
-
fail "Could not load class: #{_constant_name.inspect}" unless klass
|
58
|
-
if klass.superclass.to_s == "Guard::Guard"
|
59
|
-
klass.new(options.delete(:watchers), options)
|
60
|
-
else
|
61
|
-
begin
|
62
|
-
klass.new(options)
|
63
|
-
rescue ArgumentError => e
|
64
|
-
fail "Failed to call #{klass}.new(options): #{e}"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Locates a path to a Guard plugin gem.
|
70
|
-
#
|
71
|
-
# @return [String] the full path to the plugin gem
|
72
|
-
#
|
73
|
-
def plugin_location
|
74
|
-
@plugin_location ||= _full_gem_path("guard-#{name}")
|
75
|
-
rescue Gem::LoadError
|
76
|
-
::Guard::UI.error "Could not find 'guard-#{ name }' gem path."
|
77
|
-
end
|
78
|
-
|
79
|
-
# Tries to load the Guard plugin main class. This transforms the supplied
|
80
|
-
# plugin name into a class name:
|
81
|
-
#
|
82
|
-
# * `guardname` will become `Guard::Guardname`
|
83
|
-
# * `dashed-guard-name` will become `Guard::DashedGuardName`
|
84
|
-
# * `underscore_guard_name` will become `Guard::UnderscoreGuardName`
|
85
|
-
#
|
86
|
-
# When no class is found with the strict case sensitive rules, another
|
87
|
-
# try is made to locate the class without matching case:
|
88
|
-
#
|
89
|
-
# * `rspec` will find a class `Guard::RSpec`
|
90
|
-
#
|
91
|
-
# @option options [Boolean] fail_gracefully whether error messages should
|
92
|
-
# not be printed
|
93
|
-
#
|
94
|
-
# @return [Class, nil] the loaded class
|
95
|
-
#
|
96
|
-
def plugin_class(options = {})
|
97
|
-
options = { fail_gracefully: false }.merge(options)
|
98
|
-
|
99
|
-
const = _plugin_constant
|
100
|
-
fail TypeError, "no constant: #{_constant_name}" unless const
|
101
|
-
@plugin_class ||= Guard.const_get(const)
|
102
|
-
|
103
|
-
rescue TypeError
|
104
|
-
begin
|
105
|
-
require "guard/#{ name.downcase }"
|
106
|
-
const = _plugin_constant
|
107
|
-
@plugin_class ||= Guard.const_get(const)
|
108
|
-
|
109
|
-
rescue TypeError => error
|
110
|
-
UI.error "Could not find class Guard::#{ _constant_name }"
|
111
|
-
UI.error error.backtrace.join("\n")
|
112
|
-
rescue LoadError => error
|
113
|
-
unless options[:fail_gracefully]
|
114
|
-
UI.error ERROR_NO_GUARD_OR_CLASS % [name.downcase, _constant_name]
|
115
|
-
UI.error "Error is: #{error}"
|
116
|
-
UI.error error.backtrace.join("\n")
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
# Adds a plugin's template to the Guardfile.
|
122
|
-
#
|
123
|
-
def add_to_guardfile
|
124
|
-
klass = plugin_class # call here to avoid failing later
|
125
|
-
|
126
|
-
require "guard/guardfile/evaluator"
|
127
|
-
# TODO: move this to Generator?
|
128
|
-
options = Guard.state.session.evaluator_options
|
129
|
-
evaluator = Guardfile::Evaluator.new(options)
|
130
|
-
evaluator.evaluate
|
131
|
-
if evaluator.guardfile_include?(name)
|
132
|
-
UI.info "Guardfile already includes #{ name } guard"
|
133
|
-
else
|
134
|
-
content = File.read("Guardfile")
|
135
|
-
File.open("Guardfile", "wb") do |f|
|
136
|
-
f.puts(content)
|
137
|
-
f.puts("")
|
138
|
-
f.puts(klass.template(plugin_location))
|
139
|
-
end
|
140
|
-
|
141
|
-
UI.info INFO_ADDED_GUARD_TO_GUARDFILE % name
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
private
|
146
|
-
|
147
|
-
# Returns the constant for the current plugin.
|
148
|
-
#
|
149
|
-
# @example Returns the constant for a plugin
|
150
|
-
# > Guard::PluginUtil.new('rspec').send(:_plugin_constant)
|
151
|
-
# => Guard::RSpec
|
152
|
-
#
|
153
|
-
def _plugin_constant
|
154
|
-
@_plugin_constant ||= Guard.constants.detect do |c|
|
155
|
-
c.to_s.downcase == _constant_name.downcase
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
# Guesses the most probable name for the current plugin based on its name.
|
160
|
-
#
|
161
|
-
# @example Returns the most probable name for a plugin
|
162
|
-
# > Guard::PluginUtil.new('rspec').send(:_constant_name)
|
163
|
-
# => "Rspec"
|
164
|
-
#
|
165
|
-
def _constant_name
|
166
|
-
@_constant_name ||= name.gsub(/\/(.?)/) { "::#{ $1.upcase }" }.
|
167
|
-
gsub(/(?:^|[_-])(.)/) { $1.upcase }
|
168
|
-
end
|
169
|
-
|
170
|
-
def self._gem_valid?(gem)
|
171
|
-
return false if gem.name == 'guard-compat'
|
172
|
-
return true if gem.name =~ /^guard-/
|
173
|
-
full_path = gem.full_gem_path
|
174
|
-
file = File.join(full_path, "lib", "guard", "#{gem.name}.rb")
|
175
|
-
File.exist?(file)
|
176
|
-
end
|
177
|
-
|
178
|
-
def _full_gem_path(name)
|
179
|
-
Gem::Specification.find_by_name(name).full_gem_path
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
data/lib/guard/reevaluator.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
require "guard/plugin"
|
2
|
-
require "guard/guardfile/evaluator"
|
3
|
-
require "guard/runner"
|
4
|
-
require "guard/internals/helpers"
|
5
|
-
|
6
|
-
module Guard
|
7
|
-
class Reevaluator < Plugin
|
8
|
-
include Internals::Helpers
|
9
|
-
|
10
|
-
def run_on_modifications(files)
|
11
|
-
# TODO: this is messed up, because reevaluator adds itself
|
12
|
-
# anyway, so it know what the path is
|
13
|
-
evaluator = _evaluator
|
14
|
-
path = evaluator.path
|
15
|
-
return unless files.any? { |file| path == Pathname(file) }
|
16
|
-
reevaluate
|
17
|
-
rescue Dsl::Error, Guardfile::Evaluator::Error => e
|
18
|
-
UI.warning("Failed to reevaluate file: #{e}")
|
19
|
-
_add_self_to_plugins
|
20
|
-
throw :task_has_failed
|
21
|
-
end
|
22
|
-
|
23
|
-
def reevaluate
|
24
|
-
evaluator = _evaluator
|
25
|
-
return if evaluator.inline?
|
26
|
-
|
27
|
-
Runner.new.run(:stop)
|
28
|
-
|
29
|
-
Guard.state.reset_session
|
30
|
-
|
31
|
-
Notifier.disconnect
|
32
|
-
evaluator.evaluate
|
33
|
-
Notifier.connect(Guard.state.session.notify_options)
|
34
|
-
|
35
|
-
if Guard.send(:_pluginless_guardfile?)
|
36
|
-
Notifier.notify(
|
37
|
-
"No plugins found in Guardfile, please add at least one.",
|
38
|
-
title: "Guard re-evaluate",
|
39
|
-
image: :failed)
|
40
|
-
else
|
41
|
-
msg = "Guardfile has been re-evaluated."
|
42
|
-
UI.info(msg)
|
43
|
-
Notifier.notify(msg, title: "Guard re-evaluate")
|
44
|
-
Runner.new.run(:start)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def _evaluator
|
51
|
-
Guardfile::Evaluator.new(Guard.state.session.evaluator_options)
|
52
|
-
end
|
53
|
-
|
54
|
-
def _add_self_to_plugins
|
55
|
-
# TODO: do this on reload as well
|
56
|
-
pattern = _relative_pathname(_evaluator.path).to_s
|
57
|
-
options = { watchers: [Watcher.new(pattern)], group: :common }
|
58
|
-
Guard.state.session.plugins.add(:reevaluator, options)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|