lib/rubocop/cop/layout/class_structure.rb in rubocop-0.65.0 vs lib/rubocop/cop/layout/class_structure.rb in rubocop-0.66.0

- old
+ new

@@ -6,50 +6,65 @@ # Checks if the code style follows the ExpectedOrder configuration: # # `Categories` allows us to map macro names into a category. # # Consider an example of code style that covers the following order: + # - Module inclusion (include, prepend, extend) # - Constants # - Associations (has_one, has_many) - # - Attributes (attr_accessor, attr_writer, attr_reader) + # - Public attribute macros (attr_accessor, attr_writer, attr_reader) + # - Other macros (validates, validate) + # - Public class methods # - Initializer - # - Instance methods - # - Protected methods - # - Private methods + # - Public instance methods + # - Protected attribute macros (attr_accessor, attr_writer, attr_reader) + # - Protected instance methods + # - Private attribute macros (attr_accessor, attr_writer, attr_reader) + # - Private instance methods # # You can configure the following order: # # ```yaml # Layout/ClassStructure: - # Categories: - # module_inclusion: - # - include - # - prepend - # - extend # ExpectedOrder: - # - module_inclusion - # - constants - # - public_class_methods - # - initializer - # - public_methods - # - protected_methods - # - private_methods - # + # - module_inclusion + # - constants + # - association + # - public_attribute_macros + # - public_delegate + # - macros + # - public_class_methods + # - initializer + # - public_methods + # - protected_attribute_macros + # - protected_methods + # - private_attribute_macros + # - private_delegate + # - private_methods # ``` + # # Instead of putting all literals in the expected order, is also - # possible to group categories of macros. + # possible to group categories of macros. Visibility levels are handled + # automatically. # # ```yaml # Layout/ClassStructure: # Categories: # association: # - has_many # - has_one - # attribute: + # attribute_macros: # - attr_accessor # - attr_reader # - attr_writer + # macros: + # - validates + # - validate + # module_inclusion: + # - include + # - prepend + # - extend # ``` # # @example # # bad # # Expect extend be before constant @@ -71,16 +86,19 @@ # CustomError = Class.new(StandardError) # # # constants are next # SOME_CONSTANT = 20 # - # # afterwards we have attribute macros + # # afterwards we have public attribute macros # attr_reader :name # # # followed by other macros (if any) # validates :name # + # # then we have public delegate macros + # delegate :to_s, to: :name + # # # public class methods are next in line # def self.some_method # end # # # initialization goes between class methods and instance methods @@ -89,28 +107,37 @@ # # # followed by other public instance methods # def some_method # end # - # # protected and private methods are grouped near the end + # # protected attribute macros and methods go next # protected # + # attr_reader :protected_name + # # def some_protected_method # end # + # # private attribute macros, delegate macros and methods + # # are grouped near the end # private # + # attr_reader :private_name + # + # delegate :some_private_delegate, to: :name + # # def some_private_method # end # end # # @see https://github.com/rubocop-hq/ruby-style-guide#consistent-classes class ClassStructure < Cop HUMANIZED_NODE_TYPE = { casgn: :constants, defs: :class_methods, - def: :public_methods + def: :public_methods, + sclass: :class_singleton }.freeze VISIBILITY_SCOPES = %i[private protected public].freeze MSG = '`%<category>s` is supposed to appear before ' \ '`%<previous>s`.'.freeze @@ -165,22 +192,26 @@ case node.type when :block classify(node.send_node) when :send - find_category(node.method_name) + find_category(node) else humanize_node(node) end.to_s end - # Categorize a method_name according to the {expected_order} - # @param method_name try to match {categories} values + # Categorize a node according to the {expected_order} + # Try to match {categories} values against the node's method_name given + # also its visibility. + # @param node to be analysed. # @return [String] with the key category or the `method_name` as string - def find_category(method_name) - name = method_name.to_s + def find_category(node) + name = node.method_name.to_s category, = categories.find { |_, names| names.include?(name) } - category || name + key = category || name + visibility_key = "#{node_visibility(node)}_#{key}" + expected_order.include?(visibility_key) ? visibility_key : key end def walk_over_nested_class_definition(class_node) class_elements(class_node).each do |node| classification = classify(node)