From f45b4e7d1a17625cf7c79a47377af006f18fdc87 Mon Sep 17 00:00:00 2001 From: Ryan Quanz Date: Sun, 29 Mar 2026 23:24:11 -0400 Subject: [PATCH] perf: cache RuboCop team and filter cop registry to enabled cops Cache the RuboCop cop team and registry in initialize rather than rebuilding them for every ERB tag. Previously, build_team and cop_classes were called per-node, creating ~500 cop instances and a new Team for each <%= %> tag. Also filter the cop registry to only include cops that are actually enabled in the merged config, and memoize target_ruby_version, the version check, and the global registry. --- lib/erb_lint/linters/rubocop.rb | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/erb_lint/linters/rubocop.rb b/lib/erb_lint/linters/rubocop.rb index abe8e3b6..bf33bf09 100644 --- a/lib/erb_lint/linters/rubocop.rb +++ b/lib/erb_lint/linters/rubocop.rb @@ -27,6 +27,11 @@ def initialize(file_loader, config) custom_config = config_from_path(@config.config_file_path) if @config.config_file_path custom_config ||= config_from_hash(@config.rubocop_config) @rubocop_config = ::RuboCop::ConfigLoader.merge_with_default(custom_config, "") + @rubocop_target_ruby_version = @rubocop_config.target_ruby_version + @rubocop_version_gte_138 = ::RuboCop::Version::STRING.to_f >= 1.38 + @rubocop_global_registry = RuboCop::Cop::Registry.global if @rubocop_version_gte_138 + @cop_classes = build_cop_classes + @team = build_team end def run(processed_source) @@ -65,7 +70,7 @@ def inspect_content(processed_source, erb_node) source = rubocop_processed_source(aligned_source, processed_source.filename) return unless source.valid_syntax? - activate_team(processed_source, source, offset, code_node, build_team) + activate_team(processed_source, source, offset, code_node, @team) end def activate_team(processed_source, source, offset, code_node, team) @@ -95,29 +100,34 @@ def tempfile_from(filename, content) def rubocop_processed_source(content, filename) source = ::RuboCop::ProcessedSource.new( content, - @rubocop_config.target_ruby_version, + @rubocop_target_ruby_version, filename, ) - if ::RuboCop::Version::STRING.to_f >= 1.38 - registry = RuboCop::Cop::Registry.global - source.registry = registry + if @rubocop_version_gte_138 + source.registry = @rubocop_global_registry source.config = @rubocop_config end source end - def cop_classes - if @only_cops.present? - selected_cops = ::RuboCop::Cop::Registry.all.select { |cop| cop.match?(@only_cops) } - ::RuboCop::Cop::Registry.new(selected_cops) + def build_cop_classes + all_cops = if @only_cops.present? + ::RuboCop::Cop::Registry.all.select { |cop| cop.match?(@only_cops) } else - ::RuboCop::Cop::Registry.new(::RuboCop::Cop::Registry.all) + ::RuboCop::Cop::Registry.all end + + # Filter to only cops that are enabled in the merged config + enabled_cops = all_cops.select do |cop| + @rubocop_config.for_cop(cop).fetch("Enabled") { true } != false + end + + ::RuboCop::Cop::Registry.new(enabled_cops) end def build_team ::RuboCop::Cop::Team.mobilize( - cop_classes, + @cop_classes, @rubocop_config, extra_details: true, display_cop_names: true,