guard 2.9.0 → 2.9.1

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