Class: RuboCop::Cop::Metrics::Utils::CodeLengthCalculator
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
Macros
|
|
Instance Chain:
|
|
Inherits: | Object |
Defined in: | lib/rubocop/cop/metrics/utils/code_length_calculator.rb |
Overview
Helps to calculate code length for the provided node.
Constant Summary
-
CLASSLIKE_TYPES =
private
# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 13%i[class module].freeze
-
FOLDABLE_TYPES =
private
# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 12%i[array hash heredoc method_call].freeze
::RuboCop::PathUtil
- Included
HIDDEN_FILE_PATTERN, SMART_PATH_CACHE
::RuboCop::Cop::Util
- Included
LINE_BEGINS_REGEX_CACHE, LITERAL_REGEX, MAX_LINE_BEGINS_REGEX_INDEX
Class Method Summary
Instance Attribute Summary
- #count_comments? ⇒ Boolean readonly private
Instance Method Summary
- #calculate
- #another_args?(node) ⇒ Boolean private
- #build_foldable_checks(types) private
- #classlike_code_length(node) private
- #classlike_node?(node) ⇒ Boolean private
- #code_length(node) private
- #each_top_level_descendant(node, types, &block) private
- #extract_body(node) private
- #foldable_node?(node) ⇒ Boolean private
- #heredoc_length(node) private
- #heredoc_node?(node) ⇒ Boolean private
-
#irrelevant_line?(source_line) ⇒ Boolean
private
Returns true for lines that shall not be included in the count.
- #line_numbers_of_inner_nodes(node, *types) private
- #namespace_module?(node) ⇒ Boolean private
- #node_with_heredoc?(node) ⇒ Boolean private
- #normalize_foldable_types(types) private
- #omit_length(descendant) private
- #parenthesized?(node) ⇒ Boolean private
- #source_from_node_with_heredoc(node) private
::RuboCop::Cop::Util
- Included
#add_parentheses | Metrics/MethodLength. |
#any_descendant? | Metrics/MethodLength. |
#args_begin, #args_end, #begins_its_line?, | |
#comment_line? | This is a bad API. |
#comment_lines?, #compatible_external_encoding_for?, | |
#double_quotes_required? | If converting a string to Ruby string literal source code, must double quotes be used? |
#escape_string, | |
#first_part_of_call_chain | Returns, for example, a bare |
#include_or_equal?, #indent, #interpret_string_escapes, #line, #line_range, #needs_escaping?, #on_node, #parentheses?, #parse_regexp, #same_line?, #to_string_literal, #to_supported_styles, #trim_string_interpolation_escape_character |
::RuboCop::PathUtil
- Included
#absolute? | Returns true for an absolute Unix or Windows path. |
#glob? | Returns true for a glob. |
#hidden_dir?, #hidden_file?, #hidden_file_in_not_hidden_dir?, | |
#match_path? | Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity. |
#maybe_hidden_file? | Loose check to reduce memory allocations. |
#relative_path, #smart_path |
Constructor Details
.new(node, processed_source, count_comments: false, foldable_types: []) ⇒ CodeLengthCalculator
# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 16
def initialize(node, processed_source, count_comments: false, foldable_types: []) @node = node @processed_source = processed_source @count_comments = count_comments @foldable_checks = build_foldable_checks(foldable_types) @foldable_types = normalize_foldable_types(foldable_types) end
Instance Attribute Details
#count_comments? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 162
def count_comments? @count_comments end
Instance Method Details
#another_args?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 181
def another_args?(node) node.call_type? && node.arguments.count > 1 end
#build_foldable_checks(types) (private)
[ GitHub ]# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 42
def build_foldable_checks(types) # rubocop:disable Metrics/MethodLength types.map do |type| case type when :array lambda(&:array_type?) when :hash lambda(&:hash_type?) when :heredoc ->(node) { heredoc_node?(node) } when :method_call lambda(&:call_type?) else raise Warning, "Unknown foldable type: #{type.inspect}. " \ "Valid foldable types are: #{FOLDABLE_TYPES.join(', ')}." end end end
#calculate
[ GitHub ]# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 24
def calculate length = code_length(@node) return length if @foldable_types.empty? each_top_level_descendant(@node, @foldable_types) do |descendant| next unless foldable_node?(descendant) descendant_length = code_length(descendant) length = length - descendant_length + 1 # Subtract length of opening and closing brace if method argument omits hash braces. length -= omit_length(descendant) if descendant.hash_type? && !descendant.braces? end length end
#classlike_code_length(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 90
def classlike_code_length(node) return 0 if namespace_module?(node) body_line_numbers = line_range(node).to_a[1...-1] target_line_numbers = body_line_numbers - line_numbers_of_inner_nodes(node, :module, :class) target_line_numbers.reduce(0) do |length, line_number| source_line = @processed_source[line_number] next length if irrelevant_line?(source_line) length + 1 end end
#classlike_node?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 138
def classlike_node?(node) CLASSLIKE_TYPES.include?(node&.type) end
#code_length(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 66
def code_length(node) # rubocop:disable Metrics/MethodLength if classlike_node?(node) classlike_code_length(node) elsif heredoc_node?(node) heredoc_length(node) else body = extract_body(node) return 0 unless body source = if node_with_heredoc?(body) source_from_node_with_heredoc(body) else body.source.lines end source.count { |line| !irrelevant_line?(line) } end end
#each_top_level_descendant(node, types, &block) (private)
[ GitHub ]# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 126
def each_top_level_descendant(node, types, &block) node.each_child_node do |child| next if classlike_node?(child) if types.include?(child.type) yield child else each_top_level_descendant(child, types, &block) end end end
#extract_body(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 146
def extract_body(node) case node.type when :class, :module, :sclass, :block, :numblock, :def, :defs node.body when :casgn extract_body(node.expression) else node end end
#foldable_node?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 142
def foldable_node?(node) @foldable_checks.any? { |check| check.call(node) } end
#heredoc_length(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 121
def heredoc_length(node) lines = node.loc.heredoc_body.source.lines lines.count { |line| !irrelevant_line?(line) } + 2 end
#heredoc_node?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 86
def heredoc_node?(node) node.respond_to?(:heredoc?) && node.heredoc? end
#irrelevant_line?(source_line) ⇒ Boolean
(private)
Returns true for lines that shall not be included in the count.
# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 158
def irrelevant_line?(source_line) source_line.blank? || (!count_comments? && comment_line?(source_line)) end
#line_numbers_of_inner_nodes(node, *types) (private)
[ GitHub ]# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 110
def line_numbers_of_inner_nodes(node, *types) line_numbers = Set.new node.each_descendant(*types) do |inner_node| line_range = line_range(inner_node) line_numbers.merge(line_range) end line_numbers.to_a end
#namespace_module?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 106
def namespace_module?(node) classlike_node?(node.body) end
#node_with_heredoc?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 185
def node_with_heredoc?(node) node.each_descendant(:str, :dstr).any? { |descendant| heredoc_node?(descendant) } end
#normalize_foldable_types(types) (private)
[ GitHub ]# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 60
def normalize_foldable_types(types) types.push(:str, :dstr) if types.delete(:heredoc) types.push(:send, :csend) if types.delete(:method_call) types end
#omit_length(descendant) (private)
[ GitHub ]# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 166
def omit_length(descendant) parent = descendant.parent return 0 if another_args?(parent) return 0 unless parenthesized?(parent) [ parent.loc.begin.end_pos != descendant.source_range.begin_pos, parent.loc.end.begin_pos != descendant.source_range.end_pos ].count(true) end
#parenthesized?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 177
def parenthesized?(node) node.call_type? && node.parenthesized? end
#source_from_node_with_heredoc(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/metrics/utils/code_length_calculator.rb', line 189
def source_from_node_with_heredoc(node) last_line = -1 node.each_descendant do |descendant| next unless descendant.source descendant_last_line = if heredoc_node?(descendant) descendant.loc.heredoc_end.line else descendant.last_line end last_line = [last_line, descendant_last_line].max end @processed_source[(node.first_line - 1)..(last_line - 1)] end