class RuboCop::Cop::Lint::NonDeterministicRequireOrder
Dir.glob(Rails.root.join(__dir__, ‘test’, ‘*.rb’), sort: false).each(&method(:require))
# good - Respect intent if ‘sort` keyword option is specified in Ruby 3.0 or higher.
Dir.glob(Rails.root.join(’test’, ‘*.rb’)).sort.each(&method(:require))
# good
Dir.glob(Rails.root.join(‘test’, ‘*.rb’), &method(:require))
# bad
Dir[‘./lib/*/.rb’].sort.each(&method(:require))
# good
Dir[‘./lib/*/.rb’].each(&method(:require))
# bad
end
require file
Dir.glob(Rails.root.join(__dir__, ‘test’, ‘*.rb’)).sort.each do |file|
# good
end
require file
Dir.glob(Rails.root.join(__dir__, ‘test’, ‘*.rb’)) do |file|
# bad
end
require file
Dir[“./lib/*/.rb”].sort.each do |file|
# good
end
require file
Dir[“./lib/*/.rb”].each do |file|
# bad
@example
expected behavior.
This cop is unsafe in the case where sorting files changes existing
@safety
NOTE: This cop will be deprecated and removed when supporting only Ruby 3.0 and higher.
So all bad cases are acceptable when Ruby 3.0 or higher are used.
‘Dir.glob` and `Dir[]` sort globbed results by default in Ruby 3.0.
always sort the list.
that are hard to debug. To ensure this doesn’t happen,
such as requiring files, can lead to intermittent failures
This means that using them in cases where the order matters,
determined by the operating system and file system.
the order in which files are returned. The final order is<br>‘Dir` and `Dir.glob(…)` do not make any guarantees about
def correct_block(corrector, node)
def correct_block(corrector, node) if unsorted_dir_block?(node) corrector.replace(node, "#{node.source}.sort.each") else source = node.receiver.source corrector.replace(node, "#{source}.sort.each") end end
def correct_block_pass(corrector, node)
def correct_block_pass(corrector, node) if unsorted_dir_glob_pass?(node) block_arg = node.arguments.last corrector.remove(last_arg_range(node)) corrector.insert_after(node, ".sort.each(#{block_arg.source})") else corrector.replace(node.loc.selector, 'sort.each') end end
def last_arg_range(node)
-
(Parser::Source::Range)
-
def last_arg_range(node) node.arguments.last.source_range.with( begin_pos: node.arguments[-2].source_range.end_pos ) end
def on_block(node)
def on_block(node) return if target_ruby_version >= 3.0 return unless node.body return unless unsorted_dir_loop?(node.send_node) loop_variable(node.arguments) do |var_name| return unless var_is_required?(node.body, var_name) add_offense(node.send_node) { |corrector| correct_block(corrector, node.send_node) } end end
def on_block_pass(node)
def on_block_pass(node) return if target_ruby_version >= 3.0 return unless method_require?(node) return unless unsorted_dir_pass?(node.parent) parent_node = node.parent add_offense(parent_node) do |corrector| if parent_node.arguments.last&.block_pass_type? correct_block_pass(corrector, parent_node) else correct_block(corrector, parent_node) end end end
def on_numblock(node)
def on_numblock(node) return if target_ruby_version >= 3.0 return unless node.body return unless unsorted_dir_loop?(node.send_node) node.argument_list .filter { |argument| var_is_required?(node.body, argument.name) } .each do add_offense(node.send_node) { |corrector| correct_block(corrector, node.send_node) } end end
def unsorted_dir_loop?(node)
def unsorted_dir_loop?(node) unsorted_dir_block?(node) || unsorted_dir_each?(node) end
def unsorted_dir_pass?(node)
def unsorted_dir_pass?(node) unsorted_dir_glob_pass?(node) || unsorted_dir_each_pass?(node) end