class RuboCop::Cop::DarkFinger::ModelStructure

Constants

ASSOCIATION
ATTRIBUTES
CALLBACK
CLASS_METHOD
CONSTANT
CONSTRUCTOR
DEFAULT_MISC_METHOD_NAMES
DEFAULT_REQUIRED_COMMENTS
DEFAULT_REQUIRED_ORDER
ENUM
INCLUDE
INSTANCE_METHOD
KNOWN_ELEMENTS
MISC
MODULE
SCOPE
VALIDATION

Attributes

class_elements_seen[R]
misc_method_names[R]
required_comments[R]
required_order[R]

Public Class Methods

new(*args, options) click to toggle source
Calls superclass method
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 71
def initialize(*args, options)
  super
  @class_elements_seen = []
  @required_order = options[:required_order] || cop_config['required_order'] || DEFAULT_REQUIRED_ORDER
  @required_comments = options[:required_comments] || cop_config['required_comments'] || DEFAULT_REQUIRED_COMMENTS
  @misc_method_names = options[:misc_method_names] || cop_config['misc_method_names'] || DEFAULT_MISC_METHOD_NAMES

  # symbolize configs
  @required_order.map!(&:to_sym)
  @required_comments = Hash[ @required_comments.map {|k,v| [k.to_sym, v]} ]
  @misc_method_names.map!(&:to_sym)

  validate_config!
end

Public Instance Methods

on_casgn(node) click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 90
def on_casgn(node)
  process_node(node, seen_element: CONSTANT)
end
on_def(node) click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 98
def on_def(node)
  seen_element = if node.method_name == :initialize
                   CONSTRUCTOR
                 else
                   INSTANCE_METHOD
                 end
  process_node(node, seen_element: seen_element)
end
on_defs(node) click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 107
def on_defs(node)
  process_node(node, seen_element: CLASS_METHOD)
end
on_module(node) click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 94
def on_module(node)
  process_node(node, seen_element: MODULE)
end
on_send(node) click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 86
def on_send(node)
  process_node(node)
end

Private Instance Methods

detect_comment_violation(node, class_element) click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 149
def detect_comment_violation(node, class_element)
  return false unless required_comments[class_element]

  comment = node.preceeding_comment(processed_source)
  unless comment && comment.strip == required_comments[class_element]
    add_offense(node, message: "Expected preceeding comment: \"#{required_comments[class_element]}\"")
  end
end
detect_order_violation(node) click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 158
def detect_order_violation(node)
  if order_violation_detected?
    @order_violation_reported = true
    message = "Model elements must appear in order:#{to_bullet_list(required_order)}\n"
    message << "Observed order:#{to_bullet_list(class_elements_seen)}"

    add_offense(node, message: message)
  end
end
first_time_seeing?(class_element) click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 145
def first_time_seeing?(class_element)
  !class_elements_seen.include?(class_element)
end
order_violation_detected?() click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 172
def order_violation_detected?
  required_order_for_elements_seen != class_elements_seen
end
process_node(node, seen_element: nil) click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 115
def process_node(node, seen_element: nil)
  return if @order_violation_reported
  return if @seen_private_declaration

  node = ActiveModelNodeDecorator.new(node, misc_method_names: misc_method_names)

  if node.private_declaration?
    @seen_private_declaration = true
    return
  end

  seen_element ||= node.node_type
  return unless seen_element

  return if node.ignore_due_to_nesting?

  if first_time_seeing?(seen_element)
    detect_comment_violation(node, seen_element)
  end

  seen(seen_element)
  detect_order_violation(node)
end
required_order_for_elements_seen() click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 176
def required_order_for_elements_seen
  class_elements_seen.sort do |class_elem_1, class_elem_2|
    required_order.index(class_elem_1) <=> required_order.index(class_elem_2)
  end
end
seen(class_element) click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 139
def seen(class_element)
  return unless required_order.include?(class_element)
  class_elements_seen << class_element
  class_elements_seen.compact!
end
to_bullet_list(array) click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 168
def to_bullet_list(array)
  "\n* #{array.join("\n* ")}\n"
end
validate_config!() click to toggle source
# File lib/rubocop/cop/dark_finger/model_structure.rb, line 182
def validate_config!
  required_order.each do |i|
    if !KNOWN_ELEMENTS.include?(i)
      raise(InvalidConfigError, "Unknown 'required_order' model element: #{i}")
    end
  end

  required_comments.keys.each do |i|
    if !KNOWN_ELEMENTS.include?(i)
      raise(InvalidConfigError, "Unknown 'required_comments' model element: #{i}")
    end
  end
end