|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +module RuboCop |
| 4 | + module RSpec |
| 5 | + module Language |
| 6 | + # RuntimeMacros `.def_node_matcher` and `.def_node_search` accept block |
| 7 | + # that will be evaluated within cop context to get pattern pattern. |
| 8 | + # It can be used to pattern match values from config because are available |
| 9 | + # only during runtime. |
| 10 | + module RuntimeMacros |
| 11 | + def def_runtime_node_matcher(method_name, &pattern_block) |
| 12 | + pattern_block_constant = |
| 13 | + set_pattern_block_constant(method_name, pattern_block) |
| 14 | + |
| 15 | + src = "def #{method_name}(node, *args, &block);" \ |
| 16 | + 'pattern = RuboCop::NodePattern.new' \ |
| 17 | + "(instance_exec(&#{pattern_block_constant}));" \ |
| 18 | + 'match = pattern.match(node, *args, &block);' \ |
| 19 | + "#{predicate_method?(method_name) ? '!match.nil?' : 'match'};" \ |
| 20 | + 'end' |
| 21 | + |
| 22 | + location = caller_locations(1, 1).first |
| 23 | + class_eval(src, location.path, location.lineno) |
| 24 | + end |
| 25 | + |
| 26 | + def def_runtime_node_search(method_name, &pattern_block) |
| 27 | + pattern_block_constant = |
| 28 | + set_pattern_block_constant(method_name, pattern_block) |
| 29 | + search_method = predicate_method?(method_name) ? ':any?' : ':select' |
| 30 | + |
| 31 | + src = "def #{method_name}(node, *args, &block);" \ |
| 32 | + 'pattern = RuboCop::NodePattern.new' \ |
| 33 | + "(instance_exec(&#{pattern_block_constant}));" \ |
| 34 | + "node.each_node.public_method(#{search_method})" \ |
| 35 | + '.call(&pattern.public_method(:match, *args, &block));end' |
| 36 | + |
| 37 | + location = caller_locations(1, 1).first |
| 38 | + class_eval(src, location.path, location.lineno) |
| 39 | + end |
| 40 | + |
| 41 | + protected |
| 42 | + |
| 43 | + def set_pattern_block_constant(method_name, pattern_block) |
| 44 | + pattern_block_constant = |
| 45 | + "#{method_name.to_s.upcase.sub('?', '_PREDICATE')}_PATTERN_BLOCK" |
| 46 | + const_set(pattern_block_constant, pattern_block) |
| 47 | + pattern_block_constant |
| 48 | + end |
| 49 | + |
| 50 | + def predicate_method?(method_name) |
| 51 | + method_name.to_s.end_with?('?') |
| 52 | + end |
| 53 | + end |
| 54 | + end |
| 55 | + end |
| 56 | +end |
0 commit comments