guard 2.9.0 → 2.9.1

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.
@@ -5,7 +5,7 @@ if Guard::Config.new.strict?
5
5
  else
6
6
  require "guard/deprecated/guardfile"
7
7
 
8
- # TODO: deprecate this whole file
8
+ # TODO: remove this file in next major version
9
9
 
10
10
  module Guard
11
11
  unless Guard::Config.new.silence_deprecations?
@@ -1,12 +1,11 @@
1
1
  require "guard/config"
2
+
2
3
  require "guard/options"
3
4
  require "guard/plugin"
4
5
 
5
- # TODO: this class shouldn't use notify directly
6
- require "guard/notifier"
7
-
8
6
  require "guard/dsl"
9
- require "guard/metadata"
7
+
8
+ require "guard/deprecated/evaluator" unless Guard::Config.new.strict?
10
9
 
11
10
  module Guard
12
11
  module Guardfile
@@ -15,9 +14,30 @@ module Guard
15
14
  #
16
15
  # @see Guard::Dsl
17
16
  #
17
+ # TODO: rename this to a Locator or Loader or something
18
18
  class Evaluator
19
+ Deprecated::Evaluator.add_deprecated(self) unless Config.new.strict?
20
+
21
+ ERROR_NO_GUARDFILE = "No Guardfile found,"\
22
+ " please create one with `guard init`."
23
+
19
24
  attr_reader :options, :guardfile_path
20
25
 
26
+ ERROR_NO_PLUGINS = "No Guard plugins found in Guardfile,"\
27
+ " please add at least one."
28
+
29
+ class Error < RuntimeError
30
+ end
31
+
32
+ class NoGuardfileError < Error
33
+ end
34
+
35
+ class NoCustomGuardfile < Error
36
+ end
37
+
38
+ class NoPluginsError < Error
39
+ end
40
+
21
41
  def guardfile_source
22
42
  @source
23
43
  end
@@ -25,53 +45,50 @@ module Guard
25
45
  # Initializes a new Guard::Guardfile::Evaluator object.
26
46
  #
27
47
  # @option opts [String] guardfile the path to a valid Guardfile
28
- # @option opts [String] guardfile_contents a string representing the
48
+ # @option opts [String] contents a string representing the
29
49
  # content of a valid Guardfile
30
50
  #
31
51
  def initialize(opts = {})
32
- @evaluated = false
33
- @source = nil
34
- @guardfile_path = nil
52
+ @type = nil
53
+ @path = nil
54
+ @user_config = nil
35
55
 
36
- valid_options = opts.select do |k, _|
37
- [:guardfile, :guardfile_contents].include?(k.to_sym)
38
- end
56
+ opts = _from_deprecated(opts)
39
57
 
40
- @options = ::Guard::Options.new(valid_options)
58
+ if opts[:contents]
59
+ @type = :inline
60
+ @contents = opts[:contents]
61
+ else
62
+ if opts[:guardfile]
63
+ @type = :custom
64
+ @path = Pathname(opts[:guardfile]) # may be updated by _read
65
+ end
66
+ end
41
67
  end
42
68
 
43
69
  # Evaluates the DSL methods in the `Guardfile`.
44
70
  #
45
71
  # @example Programmatically evaluate a Guardfile
46
- # Guard::Guardfile::Evaluator.new.evaluate_guardfile
72
+ # Guard::Guardfile::Evaluator.new.evaluate
47
73
  #
48
74
  # @example Programmatically evaluate a Guardfile with a custom Guardfile
49
75
  # path
50
76
  #
51
77
  # options = { guardfile: '/Users/guardfile/MyAwesomeGuardfile' }
52
- # Guard::Guardfile::Evaluator.new(options).evaluate_guardfile
78
+ # Guard::Guardfile::Evaluator.new(options).evaluate
53
79
  #
54
80
  # @example Programmatically evaluate a Guardfile with an inline Guardfile
55
81
  #
56
- # options = { guardfile_contents: 'guard :rspec' }
57
- # Guard::Guardfile::Evaluator.new(options).evaluate_guardfile
82
+ # options = { contents: 'guard :rspec' }
83
+ # Guard::Guardfile::Evaluator.new(options).evaluate
58
84
  #
59
- def evaluate_guardfile
60
- _fetch_guardfile_contents
61
- _instance_eval_guardfile(guardfile_contents)
62
- Guard.add_builtin_plugins(guardfile_path)
63
- end
85
+ def evaluate
86
+ inline? || _use_provided || _use_default!
64
87
 
65
- # Re-evaluates the `Guardfile` to update
66
- # the current Guard configuration.
67
- #
68
- def reevaluate_guardfile
69
- # Don't re-evaluate inline Guardfile
70
- return if @source == :inline
88
+ contents = _guardfile_contents
89
+ fail NoPluginsError, ERROR_NO_PLUGINS unless /guard/m =~ contents
71
90
 
72
- _before_reevaluate_guardfile
73
- evaluate_guardfile
74
- _after_reevaluate_guardfile
91
+ Dsl.new.evaluate(contents, @path || "", 1)
75
92
  end
76
93
 
77
94
  # Tests if the current `Guardfile` contains a specific Guard plugin.
@@ -89,8 +106,13 @@ module Guard
89
106
  # @return [Boolean] whether the Guard plugin has been declared
90
107
  #
91
108
  def guardfile_include?(plugin_name)
92
- /^\s*guard\s*\(?\s*['":]#{ plugin_name }['"]?/.
93
- match _guardfile_contents_without_user_config
109
+ /^\s*guard\s*\(?\s*['":]#{plugin_name}['"]?/.match(@contents)
110
+ end
111
+
112
+ attr_reader :path
113
+
114
+ def custom?
115
+ @type == :custom
94
116
  end
95
117
 
96
118
  # Gets the content of the `Guardfile` concatenated with the global
@@ -107,41 +129,32 @@ module Guard
107
129
  [_guardfile_contents_without_user_config, config].compact.join("\n")
108
130
  end
109
131
 
132
+ def inline?
133
+ @type == :inline
134
+ end
135
+
110
136
  private
111
137
 
112
- # Gets the content of the `Guardfile`.
113
- #
114
- # @return [String] the Guardfile content
115
- #
116
138
  def _guardfile_contents_without_user_config
117
- fail "BUG: no data - Guardfile wasn't evaluated" unless @evaluated
118
139
  @guardfile_contents || ""
119
140
  end
120
141
 
121
- # Evaluates the content of the `Guardfile`.
122
- #
123
- # @param [String] contents the content to evaluate.
124
- #
125
142
  def _instance_eval_guardfile(contents)
126
- ::Guard::Dsl.new.instance_eval(contents, @guardfile_path || "", 1)
143
+ Dsl.new.evaluate(contents, @guardfile_path || "", 1)
127
144
  rescue => ex
128
145
  ::Guard::UI.error "Invalid Guardfile, original error is:\n#{ $! }"
129
146
  raise ex
130
147
  end
131
148
 
132
- # Gets the content to evaluate and stores it into @guardfile_contents.
133
- #
134
149
  def _fetch_guardfile_contents
135
150
  _use_inline || _use_provided || _use_default
136
151
  @evaluated = true
137
152
 
138
153
  return if _guardfile_contents_usable?
139
- ::Guard::UI.error "No Guard plugins found in Guardfile,"\
154
+ UI.error "No Guard plugins found in Guardfile,"\
140
155
  " please add at least one."
141
156
  end
142
157
 
143
- # Use the provided inline Guardfile if provided.
144
- #
145
158
  def _use_inline
146
159
  source_from_option = @source.nil? && options[:guardfile_contents]
147
160
  inline = @source == :inline
@@ -155,130 +168,55 @@ module Guard
155
168
  true
156
169
  end
157
170
 
158
- # Try to use the provided Guardfile. Exits Guard if the Guardfile cannot
159
- # be found.
160
- #
161
171
  def _use_provided
162
- source_from_file = @source.nil? && options[:guardfile]
163
- return false unless source_from_file || (@source == :custom)
164
-
165
- @source = :custom
166
-
167
- options[:guardfile] = File.expand_path(options[:guardfile])
168
- if File.exist?(options[:guardfile])
169
- _read_guardfile(options[:guardfile])
170
- ::Guard::UI.info "Using Guardfile at #{ options[:guardfile] }."
171
- true
172
- else
173
- ::Guard::UI.error "No Guardfile exists at #{ options[:guardfile] }."
174
- exit 1
175
- end
176
-
172
+ return unless custom?
173
+ @path, @contents = _read(@path)
177
174
  true
178
- end
179
-
180
- # Try to use one of the default Guardfiles (local or home Guardfile).
181
- # Exits Guard if no Guardfile is found.
182
- #
183
- def _use_default
184
- if guardfile_path = _find_default_guardfile
185
- @source = :default
186
- _read_guardfile(guardfile_path)
187
- else
188
- ::Guard::UI.error \
189
- "No Guardfile found, please create one with `guard init`."
190
- exit 1
175
+ rescue Errno::ENOENT
176
+ fail NoCustomGuardfile, "No Guardfile exists at #{ @path }."
177
+ end
178
+
179
+ def _use_default!
180
+ @path, @contents = _read("Guardfile")
181
+ @type = :default
182
+ rescue Errno::ENOENT
183
+ begin
184
+ @path, @contents = _read("~/.Guardfile")
185
+ @type = :default
186
+ rescue Errno::ENOENT
187
+ fail NoGuardfileError, ERROR_NO_GUARDFILE
191
188
  end
192
189
  end
193
190
 
194
- # Returns the first default Guardfile (either local or home Guardfile)
195
- # or nil otherwise.
196
- #
197
- def _find_default_guardfile
198
- [_local_guardfile_path, _home_guardfile_path].detect do |path|
199
- File.exist?(path)
200
- end
201
- end
202
-
203
- # Reads the current `Guardfile` content.
204
- #
205
- # @param [String] guardfile_path the path to the Guardfile
206
- #
207
- def _read_guardfile(guardfile_path)
208
- @guardfile_path = guardfile_path
209
- @guardfile_contents = File.read(guardfile_path)
210
- rescue => ex
211
- ::Guard::UI.error "Error reading file #{ guardfile_path }:"
212
- ::Guard::UI.error ex.inspect
213
- ::Guard::UI.error ex.backtrace
214
- exit 1
215
- end
216
-
217
- # Stops Guard and clear internal state
218
- # before the Guardfile will be re-evaluated.
219
- #
220
- def _before_reevaluate_guardfile
221
- Guard::Runner.new.run(:stop)
222
- ::Guard.reset_groups
223
- ::Guard.reset_plugins
224
- ::Guard.reset_scope
225
- ::Guard::Notifier.disconnect
191
+ def _read(path)
192
+ full_path = Pathname(path).expand_path
193
+ [full_path, full_path.read]
194
+ rescue Errno::ENOENT
195
+ fail
196
+ rescue SystemCallError => e
197
+ ::Guard::UI.error "Error reading file #{full_path}:"
198
+ ::Guard::UI.error e.inspect
199
+ ::Guard::UI.error e.backtrace
200
+ abort
226
201
  end
227
202
 
228
- # Starts Guard and notification and show a message
229
- # after the Guardfile has been re-evaluated.
230
- #
231
- def _after_reevaluate_guardfile
232
- ::Guard::Notifier.connect(::Guard.options)
233
-
234
- if ::Guard.send(:_pluginless_guardfile?)
235
- ::Guard::Notifier.notify(
236
- "No plugins found in Guardfile, please add at least one.",
237
- title: "Guard re-evaluate",
238
- image: :failed)
239
- else
240
- msg = "Guardfile has been re-evaluated."
241
- ::Guard::UI.info(msg)
242
- ::Guard::Notifier.notify(msg, title: "Guard re-evaluate")
243
-
244
- ::Guard.setup_scope
245
- Guard::Runner.new.run(:start)
246
- end
203
+ def _guardfile_contents
204
+ @user_config ||= Pathname("~/.guard.rb").expand_path.read
205
+ [@contents, @user_config].compact.join("\n")
206
+ rescue Errno::ENOENT
207
+ @contents || ""
247
208
  end
248
209
 
249
- # Tests if the current `Guardfile` content is usable.
250
- #
251
- # @return [Boolean] if the Guardfile is usable
252
- #
253
210
  def _guardfile_contents_usable?
254
211
  guardfile_contents && guardfile_contents =~ /guard/m
255
212
  end
256
213
 
257
- # The path to the `Guardfile` that is located at
258
- # the directory, where Guard has been started from.
259
- #
260
- # @return [String] the path to the local Guardfile
261
- #
262
- def _local_guardfile_path
263
- File.expand_path(File.join(Dir.pwd, "Guardfile"))
264
- end
265
-
266
- # The path to the `.Guardfile` that is located at
267
- # the users home directory.
268
- #
269
- # @return [String] the path to `~/.Guardfile`
270
- #
271
- def _home_guardfile_path
272
- File.expand_path(File.join("~", ".Guardfile"))
273
- end
274
-
275
- # The path to the user configuration `.guard.rb`
276
- # that is located at the users home directory.
277
- #
278
- # @return [String] the path to `~/.guard.rb`
279
- #
280
- def _user_config_path
281
- File.expand_path(File.join("~", ".guard.rb"))
214
+ def _from_deprecated(opts)
215
+ res = opts.dup
216
+ if opts.key?(:guardfile_contents)
217
+ res[:contents] = opts[:guardfile_contents]
218
+ end
219
+ res
282
220
  end
283
221
  end
284
222
  end
@@ -1,6 +1,15 @@
1
1
  require "guard/ui"
2
2
  require "guard/plugin_util"
3
3
 
4
+ # Add Pathname#binwrite to 1.9.3
5
+ unless Pathname.instance_methods.include?(:binwrite)
6
+ class Pathname
7
+ def binwrite(*args)
8
+ IO.binwrite(to_s, *args)
9
+ end
10
+ end
11
+ end
12
+
4
13
  module Guard
5
14
  module Guardfile
6
15
  # This class is responsible for generating the Guardfile and adding Guard'
@@ -9,7 +18,11 @@ module Guard
9
18
  # @see Guard::CLI
10
19
  #
11
20
  class Generator
12
- attr_reader :options
21
+ require "guard"
22
+ require "guard/ui"
23
+
24
+ INFO_TEMPLATE_ADDED =
25
+ "%s template added to Guardfile, feel free to edit it"
13
26
 
14
27
  # The Guardfile template for `guard init`
15
28
  GUARDFILE_TEMPLATE = File.expand_path(
@@ -18,21 +31,11 @@ module Guard
18
31
 
19
32
  # The location of user defined templates
20
33
  begin
21
- HOME_TEMPLATES = File.expand_path("~/.guard/templates")
34
+ HOME_TEMPLATES = Pathname("~/.guard/templates").expand_path
22
35
  rescue ArgumentError
23
36
  # home isn't defined. Set to the root of the drive. Trust that there
24
37
  # won't be user defined templates there
25
- HOME_TEMPLATES = File.expand_path("/")
26
- end
27
-
28
- # Initialize a new `Guard::Guardfile::Generator` object.
29
- #
30
- # @param [Hash] options The options for creating a Guardfile
31
- # @option options [Boolean] :abort_on_existence Whether to abort or not
32
- # when a Guardfile already exists
33
- #
34
- def initialize(options = {})
35
- @options = options
38
+ HOME_TEMPLATES = Pathname("/").expand_path
36
39
  end
37
40
 
38
41
  # Creates the initial Guardfile template when it does not
@@ -41,13 +44,14 @@ module Guard
41
44
  # @see Guard::CLI#init
42
45
  #
43
46
  def create_guardfile
44
- if !File.exist?("Guardfile")
45
- ::Guard::UI.info "Writing new Guardfile to #{ Dir.pwd }/Guardfile"
46
- FileUtils.cp(GUARDFILE_TEMPLATE, "Guardfile")
47
- elsif options[:abort_on_existence]
48
- ::Guard::UI.error "Guardfile already exists at #{ Dir.pwd }/Guardfile"
47
+ path = Pathname("Guardfile").expand_path
48
+ if path.exist?
49
+ _ui(:error, "Guardfile already exists at #{path}")
49
50
  abort
50
51
  end
52
+
53
+ _ui(:info, "Writing new Guardfile to #{path}")
54
+ FileUtils.cp(GUARDFILE_TEMPLATE, path.to_s)
51
55
  end
52
56
 
53
57
  # Adds the Guardfile template of a Guard plugin to an existing Guardfile.
@@ -58,33 +62,27 @@ module Guard
58
62
  # initialize
59
63
  #
60
64
  def initialize_template(plugin_name)
65
+ guardfile = Pathname("Guardfile")
66
+
61
67
  plugin_util = ::Guard::PluginUtil.new(plugin_name)
62
- # TODO: change to "plugin_class?" method
68
+ # TODO: change to "valid?" method
63
69
  if plugin_util.plugin_class(fail_gracefully: true)
64
70
  plugin_util.add_to_guardfile
65
-
66
- begin
67
- @options[:guardfile] = IO.read("Guardfile")
68
- rescue Errno::ENOENT
69
- end
70
-
71
- elsif File.exist?(File.join(HOME_TEMPLATES, plugin_name))
72
- content = File.read("Guardfile")
73
-
74
- File.open("Guardfile", "wb") do |f|
75
- f.puts(content)
76
- f.puts("")
77
- f.puts(File.read(File.join(HOME_TEMPLATES, plugin_name)))
78
- end
79
-
80
- ::Guard::UI.info \
81
- "#{ plugin_name } template added to Guardfile, feel free to edit it"
82
- else
83
- const_name = plugin_name.downcase.gsub("-", "")
84
- UI.error "Could not load 'guard/#{ plugin_name.downcase }'"\
85
- " or '~/.guard/templates/#{ plugin_name.downcase }'"\
86
- " or find class Guard::#{ const_name.capitalize }"
71
+ return
87
72
  end
73
+
74
+ template_code = (HOME_TEMPLATES + plugin_name).read
75
+ guardfile.binwrite(format("\n%s\n", template_code), open_args: ["a"])
76
+
77
+ _ui(:info, format(INFO_TEMPLATE_ADDED, plugin_name))
78
+
79
+ rescue Errno::ENOENT
80
+
81
+ name = plugin_name.downcase
82
+ class_name = name.gsub("-", "").capitalize
83
+ _ui(:error, "Could not load 'guard/#{name}'"\
84
+ " or '~/.guard/templates/#{name}'"\
85
+ " or find class Guard::#{class_name}")
88
86
  end
89
87
 
90
88
  # Adds the templates of all installed Guard implementations to an
@@ -95,6 +93,12 @@ module Guard
95
93
  def initialize_all_templates
96
94
  ::Guard::PluginUtil.plugin_names.each { |g| initialize_template(g) }
97
95
  end
96
+
97
+ private
98
+
99
+ def _ui(*args)
100
+ ::Guard::UI.send(*args)
101
+ end
98
102
  end
99
103
  end
100
104
  end