diff --git a/lib/rubocop-rspec.rb b/lib/rubocop-rspec.rb index 93b586449..de074801b 100644 --- a/lib/rubocop-rspec.rb +++ b/lib/rubocop-rspec.rb @@ -12,6 +12,7 @@ require_relative 'rubocop/rspec/top_level_describe' require_relative 'rubocop/rspec/wording' require_relative 'rubocop/rspec/language' +require_relative 'rubocop/rspec/language/runtime_macros' require_relative 'rubocop/rspec/language/node_pattern' require_relative 'rubocop/rspec/top_level_group' require_relative 'rubocop/rspec/concept' diff --git a/lib/rubocop/cop/rspec/cop.rb b/lib/rubocop/cop/rspec/cop.rb index 1c8cf0086..98e40aab7 100644 --- a/lib/rubocop/cop/rspec/cop.rb +++ b/lib/rubocop/cop/rspec/cop.rb @@ -20,6 +20,7 @@ module RSpec class Cop < ::RuboCop::Cop::Cop include RuboCop::RSpec::Language include RuboCop::RSpec::Language::NodePattern + extend RuboCop::RSpec::Language::RuntimeMacros DEFAULT_CONFIGURATION = RuboCop::RSpec::CONFIG.fetch('AllCops').fetch('RSpec') diff --git a/lib/rubocop/rspec/language/node_pattern.rb b/lib/rubocop/rspec/language/node_pattern.rb index de4c1da27..f0245ef58 100644 --- a/lib/rubocop/rspec/language/node_pattern.rb +++ b/lib/rubocop/rspec/language/node_pattern.rb @@ -6,6 +6,7 @@ module Language # Common node matchers used for matching against the rspec DSL module NodePattern extend RuboCop::NodePattern::Macros + extend RuntimeMacros def_node_matcher :example_group?, ExampleGroups::ALL.block_pattern def_node_matcher :shared_group?, SharedGroups::ALL.block_pattern diff --git a/lib/rubocop/rspec/language/runtime_macros.rb b/lib/rubocop/rspec/language/runtime_macros.rb new file mode 100644 index 000000000..cfd983aac --- /dev/null +++ b/lib/rubocop/rspec/language/runtime_macros.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module RuboCop + module RSpec + module Language + # RuntimeMacros `.def_node_matcher` and `.def_node_search` accept block + # that will be evaluated within cop context to get pattern pattern. + # It can be used to pattern match values from config because are available + # only during runtime. + module RuntimeMacros + def def_runtime_node_matcher(method_name, &pattern_block) + define_method method_name do |node, *args, &block| + pattern = RuboCop::NodePattern.new(instance_eval(&pattern_block)) + match = pattern.match(node, *args, &block) + + method_name.to_s.end_with?('?') ? !match.nil? : match + end + end + + def def_runtime_node_search(method_name, &pattern_block) + define_method method_name do |node, *args, &block| + pattern = RuboCop::NodePattern.new(instance_eval(&pattern_block)) + search_method = method_name.to_s.end_with?('?') ? :any? : :select + + node.each_node.public_method(search_method) + .call(&pattern.public_method(:match, *args, &block)) + end + end + end + end + end +end