class RuboCop::Cop::Style::TrivialAccessors
end
attr_reader :baz
class << self
attr_writer :bar
attr_reader :foo
# good
end
@baz
def self.baz
end
@bar = val
def bar=(val)
end
@foo
def foo
# bad
@example
have been created with the attr_* family of functions automatically.
This cop looks for trivial reader/writer methods, that could
def accessor(kind, method_name)
def accessor(kind, method_name) "attr_#{kind} :#{method_name.to_s.chomp('=')}" end
def allow_dsl_writers?
def allow_dsl_writers? cop_config['AllowDSLWriters'] end
def allow_predicates?
def allow_predicates? cop_config['AllowPredicates'] end
def allowed_method?(node)
def allowed_method?(node) whitelist.include?(node.method_name) || exact_name_match? && !names_match?(node) end
def allowed_reader?(node)
def allowed_reader?(node) allow_predicates? && node.predicate_method? end
def allowed_writer?(method_name)
def allowed_writer?(method_name) allow_dsl_writers? && dsl_writer?(method_name) end
def autocorrect(node)
def autocorrect(node) parent = node.parent return if parent && parent.send_type? if node.def_type? autocorrect_instance(node) elsif node.defs_type? && node.children.first.self_type? autocorrect_class(node) end end
def autocorrect_class(node)
def autocorrect_class(node) kind = trivial_accessor_kind(node) return unless names_match?(node) && kind lambda do |corrector| indent = ' ' * node.loc.column corrector.replace( node.source_range, ['class << self', "#{indent} #{accessor(kind, node.method_name)}", "#{indent}end"].join("\n") ) end end
def autocorrect_instance(node)
def autocorrect_instance(node) kind = trivial_accessor_kind(node) return unless names_match?(node) && !node.predicate_method? && kind lambda do |corrector| corrector.replace(node.source_range, accessor(kind, node.method_name)) end end
def dsl_writer?(method_name)
def dsl_writer?(method_name) !method_name.to_s.end_with?('=') end
def exact_name_match?
def exact_name_match? cop_config['ExactNameMatch'] end
def ignore_class_methods?
def ignore_class_methods? cop_config['IgnoreClassMethods'] end
def in_module_or_instance_eval?(node)
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_name == :instance_eval end end false end
def looks_like_trivial_reader?(node)
def looks_like_trivial_reader?(node) !node.arguments? && node.body && node.body.ivar_type? end
def names_match?(node)
def names_match?(node) ivar_name, = *node.body node.method_name.to_s.sub(/[=?]$/, '') == ivar_name[1..-1] end
def on_def(node)
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
def on_method_def(node)
def on_method_def(node) kind = if trivial_reader?(node) 'reader' elsif trivial_writer?(node) 'writer' end return unless kind add_offense(node, location: :keyword, message: format(MSG, kind: kind)) end
def top_level_node?(node)
def top_level_node?(node) node.parent.nil? end
def trivial_accessor_kind(node)
def trivial_accessor_kind(node) if trivial_writer?(node) && !dsl_writer?(node.method_name) 'writer' elsif trivial_reader?(node) 'reader' end end
def trivial_reader?(node)
def trivial_reader?(node) looks_like_trivial_reader?(node) && !allowed_method?(node) && !allowed_reader?(node) end
def trivial_writer?(node)
def trivial_writer?(node) looks_like_trivial_writer?(node) && !allowed_method?(node) && !allowed_writer?(node.method_name) end
def whitelist
def whitelist whitelist = cop_config['Whitelist'] Array(whitelist).map(&:to_sym) + [:initialize] end