123456789_123456789_123456789_123456789_123456789_

Class: RuboCop::Cop::Style::TrivialAccessors

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, ::RuboCop::Cop::AutoCorrector, ::RuboCop::Cop::Base, ::RuboCop::ExcludeLimit, NodePattern::Macros, RuboCop::AST::Sexp
Instance Chain:
Inherits: RuboCop::Cop::Base
Defined in: lib/rubocop/cop/style/trivial_accessors.rb

Overview

Looks for trivial reader/writer methods, that could have been created with the attr_* family of functions automatically. to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, and to_sym methods are allowed by default. These are customizable with AllowedMethods option.

Examples:

# bad
def foo
  @foo
end

def bar=(val)
  @bar = val
end

def self.baz
  @baz
end

# good
attr_reader :foo
attr_writer :bar

class << self
  attr_reader :baz
end

ExactNameMatch: true (default)

# good
def name
  @other_name
end

ExactNameMatch: false

# bad
def name
  @other_name
end

AllowPredicates: true (default)

# good
def foo?
  @foo
end

AllowPredicates: false

# bad
def foo?
  @foo
end

# good
attr_reader :foo

AllowDSLWriters: true (default)

# good
def on_exception(action)
  @on_exception=action
end

AllowDSLWriters: false

# bad
def on_exception(action)
  @on_exception=action
end

# good
attr_writer :on_exception

IgnoreClassMethods: false (default)

# bad
def self.foo
  @foo
end

# good
class << self
  attr_reader :foo
end

IgnoreClassMethods: true

# good
def self.foo
  @foo
end

AllowedMethods: ['allowed_method']

# good
def allowed_method
  @foo
end

Constant Summary

::RuboCop::Cop::Base - Inherited

EMPTY_OFFENSES, RESTRICT_ON_SEND

Class Attribute Summary

::RuboCop::Cop::AutoCorrector - Extended

::RuboCop::Cop::Base - Inherited

.gem_requirements, .lint?,
.support_autocorrect?

Returns if class supports autocorrect.

.support_multiple_source?

Override if your cop should be called repeatedly for multiple investigations Between calls to on_new_investigation and on_investigation_end, the result of processed_source will remain constant.

.builtin?

Class Method Summary

::RuboCop::Cop::Base - Inherited

.autocorrect_incompatible_with

List of cops that should not try to autocorrect at the same time as this cop.

.badge

Naming.

.callbacks_needed, .cop_name, .department,
.documentation_url

Cops (other than builtin) are encouraged to implement this.

.exclude_from_registry

Call for abstract Cop classes.

.inherited,
.joining_forces

Override and return the Force class(es) you need to join.

.match?

Returns true if the cop name or the cop namespace matches any of the given names.

.new,
.requires_gem

Register a version requirement for the given gem name.

.restrict_on_send

::RuboCop::ExcludeLimit - Extended

exclude_limit

Sets up a configuration option to have an exclude limit tracked.

transform

Instance Attribute Summary

Instance Method Summary

::RuboCop::Cop::AllowedMethods - Included

::RuboCop::Cop::Base - Inherited

#add_global_offense

Adds an offense that has no particular location.

#add_offense

Adds an offense on the specified range (or node with an expression) Unless that offense is disabled for this range, a corrector will be yielded to provide the cop the opportunity to autocorrect the offense.

#begin_investigation

Called before any investigation.

#callbacks_needed,
#cop_config

Configuration Helpers.

#cop_name, #excluded_file?,
#external_dependency_checksum

This method should be overridden when a cop’s behavior depends on state that lives outside of these locations:

#inspect,
#message

Gets called if no message is specified when calling add_offense or add_global_offense Cops are discouraged to override this; instead pass your message directly.

#name

Alias for Base#cop_name.

#offenses,
#on_investigation_end

Called after all on_…​

#on_new_investigation

Called before all on_…​

#on_other_file

Called instead of all on_…​

#parse

There should be very limited reasons for a Cop to do it’s own parsing.

#parser_engine,
#ready

Called between investigations.

#relevant_file?, #target_rails_version, #target_ruby_version, #annotate, #apply_correction, #attempt_correction,
#callback_argument

Reserved for Cop::Cop.

#complete_investigation

Called to complete an investigation.

#correct, #current_corrector,
#current_offense_locations

Reserved for Commissioner:

#current_offenses, #currently_disabled_lines, #custom_severity, #default_severity, #disable_uncorrectable, #enabled_line?, #file_name_matches_any?, #find_message, #find_severity, #range_for_original, #range_from_node_or_range, #reset_investigation, #use_corrector

::RuboCop::Cop::AutocorrectLogic - Included

::RuboCop::Cop::IgnoredNode - Included

Constructor Details

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

Instance Attribute Details

#allow_dsl_writers?Boolean (readonly, private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 161

def allow_dsl_writers?
  cop_config['AllowDSLWriters']
end

#allow_predicates?Boolean (readonly, private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 157

def allow_predicates?
  cop_config['AllowPredicates']
end

#exact_name_match?Boolean (readonly, private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 153

def exact_name_match?
  cop_config['ExactNameMatch']
end

#ignore_class_methods?Boolean (readonly, private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 165

def ignore_class_methods?
  cop_config['IgnoreClassMethods']
end

Instance Method Details

#accessor(kind, method_name) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 222

def accessor(kind, method_name)
  "attr_#{kind} :#{method_name.to_s.chomp('=')}"
end

#allowed_method_name?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 195

def allowed_method_name?(node)
  allowed_method_names.include?(node.method_name) ||
    (exact_name_match? && !names_match?(node))
end

#allowed_method_names (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 169

def allowed_method_names
  allowed_methods.map(&:to_sym) + [:initialize]
end

#allowed_reader?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 204

def allowed_reader?(node)
  allow_predicates? && node.predicate_method?
end

#allowed_writer?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 200

def allowed_writer?(node)
  allow_dsl_writers? && dsl_writer?(node)
end

#autocorrect(corrector, node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 142

def autocorrect(corrector, node)
  parent = node.parent
  return if parent&.send_type?

  if node.def_type?
    autocorrect_instance(corrector, node)
  elsif node.defs_type? && node.children.first.self_type?
    autocorrect_class(corrector, node)
  end
end

#autocorrect_class(corrector, node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 234

def autocorrect_class(corrector, node)
  kind = trivial_accessor_kind(node)

  return unless names_match?(node) && kind

  indent = ' ' * node.loc.column
  corrector.replace(
    node,
    ['class << self',
     "#{indent}  #{accessor(kind, node.method_name)}",
     "#{indent}end"].join("\n")
  )
end

#autocorrect_instance(corrector, node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 226

def autocorrect_instance(corrector, node)
  kind = trivial_accessor_kind(node)

  return unless names_match?(node) && !node.predicate_method? && kind

  corrector.replace(node, accessor(kind, node.method_name))
end

#dsl_writer?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 173

def dsl_writer?(node)
  !node.assignment_method?
end

#in_module_or_instance_eval?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 115

def in_module_or_instance_eval?(node)
  node.each_ancestor(:block, :class, :sclass, :module).each do |pnode|
    case pnode.type
    when :class, :sclass
      return false
    when :module
      return true
    else
      return true if pnode.method?(:instance_eval)
    end
  end
  false
end

#looks_like_trivial_reader?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 181

def looks_like_trivial_reader?(node)
  !node.arguments? && node.body && node.body.ivar_type?
end

#looks_like_trivial_writer?(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 190

def_node_matcher :looks_like_trivial_writer?, <<~PATTERN
  {(def    _ (args (arg ...)) (ivasgn _ (lvar _)))
   (defs _ _ (args (arg ...)) (ivasgn _ (lvar _)))}
PATTERN

#names_match?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 208

def names_match?(node)
  ivar_name, = *node.body

  node.method_name.to_s.sub(/[=?]$/, '') == ivar_name[1..]
end

#on_def(node) Also known as: #on_defs

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 104

def on_def(node)
  return if top_level_node?(node)
  return if in_module_or_instance_eval?(node)
  return if ignore_class_methods? && node.defs_type?

  on_method_def(node)
end

#on_defs(node)

Alias for #on_def.

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 111

alias on_defs on_def

#on_method_def(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 129

def on_method_def(node)
  kind = if trivial_reader?(node)
           'reader'
         elsif trivial_writer?(node)
           'writer'
         end
  return unless kind

  add_offense(node.loc.keyword, message: format(MSG, kind: kind)) do |corrector|
    autocorrect(corrector, node)
  end
end

#top_level_node?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 248

def top_level_node?(node)
  node.parent.nil?
end

#trivial_accessor_kind(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 214

def trivial_accessor_kind(node)
  if trivial_writer?(node) && !dsl_writer?(node)
    'writer'
  elsif trivial_reader?(node)
    'reader'
  end
end

#trivial_reader?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 177

def trivial_reader?(node)
  looks_like_trivial_reader?(node) && !allowed_method_name?(node) && !allowed_reader?(node)
end

#trivial_writer?(node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/style/trivial_accessors.rb', line 185

def trivial_writer?(node)
  looks_like_trivial_writer?(node) && !allowed_method_name?(node) && !allowed_writer?(node)
end