Class: RuboCop::Cop::Lint::NonDeterministicRequireOrder

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Defined in:
lib/rubocop/cop/lint/non_deterministic_require_order.rb

Overview

Dir[…​] and Dir.glob(…​) do not make any guarantees about the order in which files are returned. The final order is determined by the operating system and file system. This means that using them in cases where the order matters, such as requiring files, can lead to intermittent failures that are hard to debug. To ensure this doesn’t happen, always sort the list.

Dir.glob and Dir[] sort globbed results by default in Ruby 3.0. So all bad cases are acceptable when Ruby 3.0 or higher are used.

Note
This cop will be deprecated and removed when supporting only Ruby 3.0 and higher.

Examples:


# bad
Dir["./lib/**/*.rb"].each do |file|
  require file
end

# good
Dir["./lib/**/*.rb"].sort.each do |file|
  require file
end

# bad
Dir.glob(Rails.root.join(__dir__, 'test', '*.rb')) do |file|
  require file
end

# good
Dir.glob(Rails.root.join(__dir__, 'test', '*.rb')).sort.each do |file|
  require file
end

# bad
Dir['./lib/**/*.rb'].each(&method(:require))

# good
Dir['./lib/**/*.rb'].sort.each(&method(:require))

# bad
Dir.glob(Rails.root.join('test', '*.rb'), &method(:require))

# good
Dir.glob(Rails.root.join('test', '*.rb')).sort.each(&method(:require))

# good - Respect intent if `sort` keyword option is specified in Ruby 3.0 or higher.
Dir.glob(Rails.root.join(__dir__, 'test', '*.rb'), sort: false).each(&method(:require))

Cop Safety Information:

  • This cop is unsafe in the case where sorting files changes existing expected behavior.

Constant Summary collapse

MSG =
'Sort files before requiring them.'

Constants inherited from Base

Base::RESTRICT_ON_SEND

Instance Attribute Summary

Attributes inherited from Base

#config, #processed_source

Instance Method Summary collapse

Methods included from AutoCorrector

support_autocorrect?

Methods inherited from Base

#active_support_extensions_enabled?, #add_global_offense, #add_offense, autocorrect_incompatible_with, badge, #begin_investigation, callbacks_needed, #callbacks_needed, #config_to_allow_offenses, #config_to_allow_offenses=, #cop_config, cop_name, #cop_name, department, documentation_url, exclude_from_registry, #excluded_file?, #external_dependency_checksum, inherited, #initialize, #inspect, joining_forces, lint?, match?, #message, #offenses, #on_investigation_end, #on_new_investigation, #on_other_file, #parse, #ready, #relevant_file?, support_autocorrect?, support_multiple_source?, #target_rails_version, #target_ruby_version

Methods included from ExcludeLimit

#exclude_limit

Methods included from AutocorrectLogic

#autocorrect?, #autocorrect_enabled?, #autocorrect_requested?, #autocorrect_with_disable_uncorrectable?, #correctable?, #disable_uncorrectable?, #safe_autocorrect?

Methods included from IgnoredNode

#ignore_node, #ignored_node?, #part_of_ignored_node?

Methods included from Util

silence_warnings

Constructor Details

This class inherits a constructor from RuboCop::Cop::Base

Instance Method Details

#on_block(node) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/rubocop/cop/lint/non_deterministic_require_order.rb', line 65

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

#on_block_pass(node) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/rubocop/cop/lint/non_deterministic_require_order.rb', line 89

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

#on_numblock(node) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/rubocop/cop/lint/non_deterministic_require_order.rb', line 77

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