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