class RuboCop::Cop::Style::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/style/file_name.rb, line 19
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, range, msg)
  end
end

Private Instance Methods

expect_matching_definition?() click to toggle source
# File lib/rubocop/cop/style/file_name.rb, line 64
def expect_matching_definition?
  cop_config['ExpectMatchingDefinition']
end
filename_good?(basename) click to toggle source
# File lib/rubocop/cop/style/file_name.rb, line 72
def filename_good?(basename)
  basename = basename.sub(/\.[^\.]+$/, '')
  basename =~ (regex || SNAKE_CASE)
end
find_class_or_module(node, namespace) click to toggle source
# File lib/rubocop/cop/style/file_name.rb, line 77
def find_class_or_module(node, namespace)
  return nil if node.nil?
  name = namespace.pop

  on_node([:class, :module, :casgn], node) do |child|
    next unless (const = child.defined_module)

    const_namespace, const_name = *const
    next unless name == const_name

    return node if namespace.empty?
    return node if match_namespace(child, const_namespace, namespace)
  end
  nil
end
first_line() click to toggle source
# File lib/rubocop/cop/style/file_name.rb, line 46
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/style/file_name.rb, line 30
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 cop_config['IgnoreExecutableScripts'] &&
                    shebang?(first_line)
          other_message(basename)
        end

  yield source_range(processed_source.buffer, 1, 0), msg
end
match_namespace(node, namespace, expected) click to toggle source
# File lib/rubocop/cop/style/file_name.rb, line 93
def match_namespace(node, namespace, expected)
  expected = expected.dup

  match_partial = lambda do |ns|
    next if ns.nil?
    while ns
      return expected.empty? || expected == [:Object] if ns.cbase_type?
      ns, name = *ns
      name == expected.last ? expected.pop : (return false)
    end
  end

  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

  expected.empty? || expected == [:Object]
end
no_definition_message(basename, file_path) click to toggle source
# File lib/rubocop/cop/style/file_name.rb, line 50
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/style/file_name.rb, line 56
def other_message(basename)
  regex ? format(MSG_REGEX, basename, regex) : MSG_SNAKE_CASE
end
regex() click to toggle source
# File lib/rubocop/cop/style/file_name.rb, line 68
def regex
  cop_config['Regex']
end
shebang?(line) click to toggle source
# File lib/rubocop/cop/style/file_name.rb, line 60
def shebang?(line)
  line && line.start_with?('#!')
end
to_module_name(basename) click to toggle source
# File lib/rubocop/cop/style/file_name.rb, line 130
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/style/file_name.rb, line 115
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)
  if components.find { |c| start.include?(c) }
    components = components.drop_while { |c| !start.include?(c) }
    components.drop(1).map { |fn| to_module_name(fn) }
  else
    [to_module_name(components.last)]
  end
end