class RuboCop::Cop::Naming::FileName
This cop makes sure that Ruby source files have snake_case names. Ruby scripts (i.e. source files with a shebang in the first line) are ignored.
Constants
- MSG_NO_DEFINITION
- MSG_REGEX
- MSG_SNAKE_CASE
- SNAKE_CASE
Public Instance Methods
investigate(processed_source)
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 20 def investigate(processed_source) file_path = processed_source.buffer.name return if config.file_to_include?(file_path) for_bad_filename(file_path) do |range, msg| add_offense(nil, location: range, message: msg) end end
Private Instance Methods
allowed_acronyms()
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 81 def allowed_acronyms cop_config['AllowedAcronyms'] || [] end
expect_matching_definition?()
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 73 def expect_matching_definition? cop_config['ExpectMatchingDefinition'] end
filename_good?(basename)
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 85 def filename_good?(basename) basename = basename.sub(/\.[^\.]+$/, '') basename =~ (regex || SNAKE_CASE) end
find_class_or_module(node, namespace)
click to toggle source
rubocop:disable Metrics/CyclomaticComplexity
# File lib/rubocop/cop/naming/file_name.rb, line 91 def find_class_or_module(node, namespace) return nil unless node name = namespace.pop on_node(%i[class module casgn], node) do |child| next unless (const = child.defined_module) const_namespace, const_name = *const next if name != const_name && !match_acronym?(name, const_name) next unless namespace.empty? || match_namespace(child, const_namespace, namespace) return node end nil end
first_line()
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 47 def first_line processed_source.lines.first end
for_bad_filename(file_path) { |source_range(buffer, 1, 0), msg| ... }
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 31 def for_bad_filename(file_path) basename = File.basename(file_path) msg = if filename_good?(basename) return unless expect_matching_definition? return if find_class_or_module(processed_source.ast, to_namespace(file_path)) no_definition_message(basename, file_path) else return if ignore_executable_scripts? && shebang?(first_line) other_message(basename) end yield source_range(processed_source.buffer, 1, 0), msg end
ignore_executable_scripts?()
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 69 def ignore_executable_scripts? cop_config['IgnoreExecutableScripts'] end
match?(expected)
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 140 def match?(expected) expected.empty? || expected == [:Object] end
match_acronym?(expected, name)
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 144 def match_acronym?(expected, name) expected = expected.to_s name = name.to_s allowed_acronyms.any? do |acronym| expected.gsub(acronym.capitalize, acronym) == name end end
match_namespace(node, namespace, expected)
click to toggle source
rubocop:enable Metrics/CyclomaticComplexity
# File lib/rubocop/cop/naming/file_name.rb, line 111 def match_namespace(node, namespace, expected) match_partial = partial_matcher!(expected) match_partial.call(namespace) node.each_ancestor(:class, :module, :sclass, :casgn) do |ancestor| return false if ancestor.sclass_type? match_partial.call(ancestor.defined_module) end match?(expected) end
no_definition_message(basename, file_path)
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 51 def no_definition_message(basename, file_path) format(MSG_NO_DEFINITION, basename, to_namespace(file_path).join('::')) end
other_message(basename)
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 57 def other_message(basename) if regex format(MSG_REGEX, basename, regex) else format(MSG_SNAKE_CASE, basename) end end
partial_matcher!(expected)
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 124 def partial_matcher!(expected) lambda do |namespace| while namespace return match?(expected) if namespace.cbase_type? namespace, name = *namespace if name == expected.last || match_acronym?(expected.last, name) expected.pop end end false end end
regex()
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 77 def regex cop_config['Regex'] end
shebang?(line)
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 65 def shebang?(line) line && line.start_with?('#!') end
to_module_name(basename)
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 180 def to_module_name(basename) words = basename.sub(/\..*/, '').split('_') words.map(&:capitalize).join.to_sym end
to_namespace(path)
click to toggle source
# File lib/rubocop/cop/naming/file_name.rb, line 153 def to_namespace(path) components = Pathname(path).each_filename.to_a # To convert a pathname to a Ruby namespace, we need a starting point # But RC can be run from any working directory, and can check any path # We can't assume that the working directory, or any other, is the # "starting point" to build a namespace start = %w[lib spec test src] start_index = nil # To find the closest namespace root take the path components, and # then work through them backwards until we find a candidate. This # makes sure we work from the actual root in the case of a path like # /home/user/src/project_name/lib. components.reverse.each_with_index do |c, i| if start.include?(c) start_index = components.size - i break end end if start_index.nil? [to_module_name(components.last)] else components[start_index..-1].map { |c| to_module_name(c) } end end