# frozen_string_literal: true module RuboCop module RSpec # Wrapper for RSpec hook class Hook < Concept # @!method extract_metadata(node) def_node_matcher :extract_metadata, <<~PATTERN (block (send _ _ #valid_scope? ? $...) ... ) PATTERN def name node.method_name end def knowable_scope? scope_argument.nil? || scope_argument.sym_type? || scope_argument.hash_type? end def example? scope.equal?(:each) end def scope return :each if scope_argument&.hash_type? case scope_name when nil, :each, :example then :each when :context, :all then :context when :suite then :suite end end def metadata (extract_metadata(node) || []) .map { |meta| transform_metadata(meta) } .flatten .inject(&:merge) end private def valid_scope?(node) node&.sym_type? && Language::HookScopes.all(node.value) end def transform_metadata(meta) if meta.sym_type? { meta => true } else # This check is to be able to compare those two hooks: # # before(:example, :special) { ... } # before(:example, special: true) { ... } # # In the second case it's a node with a pair that has a value # of a `true_type?`. meta.pairs.map { |pair| { pair.key => transform_true(pair.value) } } end end def transform_true(node) node.true_type? ? true : node end def scope_name scope_argument.to_a.first end def scope_argument node.send_node.first_argument end end end end