123456789_123456789_123456789_123456789_123456789_

Module: RuboCop::AST::NodePattern::MethodDefiner

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Included In:
Defined in: lib/rubocop/ast/node_pattern/method_definer.rb

Overview

Functionality to turn #match_code into methods/lambda

Instance Method Summary

Instance Method Details

#as_lambda

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 37

def as_lambda
  eval(compile_as_lambda) # rubocop:disable Security/Eval
end

#compile_as_lambda

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 27

def compile_as_lambda
  <<~RUBY
    ->(#{emit_params('param0')}, block: nil) do
      #{VAR} = param0
      #{compile_init}
      #{emit_lambda_code}
    end
  RUBY
end

#compile_init (private)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 139

def compile_init
  "captures = Array.new(#{captures})" if captures.positive?
end

#def_helper(base, method_name, **defaults) (private)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 50

def def_helper(base, method_name, **defaults)
  location = caller_locations(3, 1).first
  unless defaults.empty?
    call = :"without_defaults_#{method_name}"
    base.send :define_method, method_name, &wrapping_block(call, **defaults)
    method_name = call
  end
  src = yield method_name
  base.class_eval(src, location.path, location.lineno)

  method_name
end

#def_node_matcher(base, method_name, **defaults)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 8

def def_node_matcher(base, method_name, **defaults)
  def_helper(base, method_name, **defaults) do |name|
    params = emit_params('param0 = self')
    <<~RUBY
      def #{name}(#{params})
        #{VAR} = param0
        #{compile_init}
        #{emit_method_code}
      end
    RUBY
  end
end

#def_node_search(base, method_name, **defaults)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 21

def def_node_search(base, method_name, **defaults)
  def_helper(base, method_name, **defaults) do |name|
    emit_node_search(name)
  end
end

#emit_keyword_list(forwarding: false) (private)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 114

def emit_keyword_list(forwarding: false)
  pattern = "%<keyword>s: #{'%<keyword>s' if forwarding}"
  named_parameters.map { |k| format(pattern, keyword: k) }.join(',')
end

#emit_lambda_code (private)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 132

def emit_lambda_code
  <<~RUBY
    return unless #{match_code}
    block ? #{emit_yield_capture(yield_with: 'block.call')} : (return #{emit_retval})
  RUBY
end

#emit_method_code (private)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 125

def emit_method_code
  <<~RUBY
    return unless #{match_code}
    block_given? ? #{emit_yield_capture} : (return #{emit_retval})
  RUBY
end

#emit_node_search(method_name) (private)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 63

def emit_node_search(method_name)
  if method_name.to_s.end_with?('?')
    on_match = 'return true'
  else
    args = emit_params(":#{method_name}", 'param0', forwarding: true)
    prelude = "return enum_for(#{args}) unless block_given?\n"
    on_match = emit_yield_capture(VAR)
  end
  emit_node_search_body(method_name, prelude: prelude, on_match: on_match)
end

#emit_node_search_body(method_name, prelude:, on_match:) (private)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 74

def emit_node_search_body(method_name, prelude:, on_match:)
  <<~RUBY
    def #{method_name}(#{emit_params('param0')})
      #{compile_init}
      #{prelude}
      param0.each_node do |#{VAR}|
        if #{match_code}
          #{on_match}
        end
      end
      nil
    end
  RUBY
end

#emit_param_list (private)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 110

def emit_param_list
  (1..positional_parameters).map { |n| "param#{n}" }.join(',')
end

#emit_params(*first, forwarding: false) (private)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 119

def emit_params(*first, forwarding: false)
  params = emit_param_list
  keywords = emit_keyword_list(forwarding: forwarding)
  [*first, params, keywords].reject(&:empty?).join(',')
end

#emit_retval (private)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 100

def emit_retval
  if captures.zero?
    'true'
  elsif captures == 1
    'captures[0]'
  else
    'captures'
  end
end

#emit_yield_capture(when_no_capture = '', yield_with: 'yield') (private)

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 89

def emit_yield_capture(when_no_capture = '', yield_with: 'yield')
  yield_val = if captures.zero?
                when_no_capture
              elsif captures == 1
                'captures[0]' # Circumvent https://github.com/jruby/jruby/issues/5710
              else
                '*captures'
              end
  "#{yield_with}(#{yield_val})"
end

#wrapping_block(method_name, **defaults) (private)

This method minimizes the closure for our method

[ GitHub ]

  
# File 'lib/rubocop/ast/node_pattern/method_definer.rb', line 44

def wrapping_block(method_name, **defaults)
  proc do |*args, **values|
    send method_name, *args, **defaults, **values
  end
end