lib/rubocop/cop/rails/root_pathname_methods.rb in rubocop-rails-2.16.0 vs lib/rubocop/cop/rails/root_pathname_methods.rb in rubocop-rails-2.16.1
- old
+ new
@@ -9,10 +9,14 @@
# so we can apply many IO methods directly.
#
# This cop works best when used together with
# `Style/FileRead`, `Style/FileWrite` and `Rails/RootJoinChain`.
#
+ # @safety
+ # This cop is unsafe for autocorrection because `Dir`'s `children`, `each_child`, `entries`, and `glob`
+ # methods return string element, but these methods of `Pathname` return `Pathname` element.
+ #
# @example
# # bad
# File.open(Rails.root.join('db', 'schema.rb'))
# File.open(Rails.root.join('db', 'schema.rb'), 'w')
# File.read(Rails.root.join('db', 'schema.rb'))
@@ -28,10 +32,11 @@
# Rails.root.join('db', 'schema.rb').write(content)
# Rails.root.join('db', 'schema.rb').binwrite(content)
#
class RootPathnameMethods < Base
extend AutoCorrector
+ include RangeHelp
MSG = '`%<rails_root>s` is a `Pathname` so you can just append `#%<method>s`.'
DIR_METHODS = %i[children delete each_child empty? entries exist? glob mkdir open rmdir unlink].to_set.freeze
@@ -136,10 +141,15 @@
(send (const {nil? cbase} :FileTest) $FILE_TEST_METHODS $_ $...)
(send (const {nil? cbase} :FileUtils) $FILE_UTILS_METHODS $_ $...)
}
PATTERN
+ def_node_matcher :dir_glob?, <<~PATTERN
+ (send
+ (const {cbase nil?} :Dir) :glob ...)
+ PATTERN
+
def_node_matcher :rails_root_pathname?, <<~PATTERN
{
$#rails_root?
(send $#rails_root? :join ...)
}
@@ -151,12 +161,16 @@
PATTERN
def on_send(node)
evidence(node) do |method, path, args, rails_root|
add_offense(node, message: format(MSG, method: method, rails_root: rails_root.source)) do |corrector|
- replacement = "#{path.source}.#{method}"
- replacement += "(#{args.map(&:source).join(', ')})" unless args.empty?
+ if dir_glob?(node)
+ replacement = build_path_glob(path, method)
+ else
+ replacement = "#{path.source}.#{method}"
+ replacement += "(#{args.map(&:source).join(', ')})" unless args.empty?
+ end
corrector.replace(node, replacement)
end
end
end
@@ -166,9 +180,34 @@
def evidence(node)
return if node.method?(:open) && node.parent&.send_type?
return unless (method, path, args = pathname_method(node)) && (rails_root = rails_root_pathname?(path))
yield(method, path, args, rails_root)
+ end
+
+ def build_path_glob(path, method)
+ receiver = range_between(path.loc.expression.begin_pos, path.children.first.loc.selector.end_pos).source
+
+ argument = if path.arguments.one?
+ path.first_argument.source
+ else
+ join_arguments(path.arguments)
+ end
+
+ "#{receiver}.#{method}(#{argument})"
+ end
+
+ def include_interpolation?(arguments)
+ arguments.any? do |argument|
+ argument.children.any? { |child| child.respond_to?(:begin_type?) && child.begin_type? }
+ end
+ end
+
+ def join_arguments(arguments)
+ quote = include_interpolation?(arguments) ? '"' : "'"
+ joined_arguments = arguments.map(&:value).join('/')
+
+ "#{quote}#{joined_arguments}#{quote}"
end
end
end
end
end