2

我正在尝试开发一个新警察(基于这些准则)并且正在努力获得正确的节点模式

我希望警察在没有提供阻止的情况下X.some_method被召唤时登记犯罪。 即是一种冒犯,但不是。
X.some_methodX.some_method { blah }

我得到了正确的识别模式X.some_method,即'(send (const nil? :X) :some_method ...'.
但不确定如何为“没有给定块”创建模式?

4

1 回答 1

1

显然,在解析的 AST 中,当一个节点被赋予一个块时,该节点就被表示为该块的第一个子节点。
IE

[92] pry(RuboCop)> node # `X.some_method(something) { do_something }`
=> s(:block,
  s(:send,
    s(:const, nil, :X), :some_method,
    s(:send, nil, :something)),
  s(:args),
  s(:send, nil, :do_something))

我们可以使用Rubocop::AST实例进行检查。
这是完整的实现(包括多个方法名称的选项):

  MSG = 'Avoid using `X.%<method>s` without providing a block.'

  def_node_matcher :x_method, '(send (const nil? :X) ${:some_method :another_method} ...)'

  def on_send(node)
      x_method(node) do |method_name|
        return if !method_name || first_child_of_block?(node)
        add_offense(node, location: :selector, message: format(MSG, method: method_name))
      end

    end

  private

    # checks if the given node's parent is a block, and the given node is its first child,
    # which would mean that the block is supplied to the given node (i.e `node { block }`)
    def first_child_of_block?(node)
      return false unless (parent = node.parent)
      return false unless parent.type == :block
      parent.children.first == node
    end
于 2019-04-03T16:17:17.707 回答