创建一个在没有块的情况下调用方法时触发的 rubocop cop
create a rubocop cop that triggers when method is invoked without a block
我正在尝试开发一个新警察(基于 these guidelines) and am banging my head trying to get the correct node pattern。
我希望警察在呼叫 X.some_method
时记录违规行为 而没有提供阻止 。
即 X.some_method
是一种冒犯,但 X.some_method { blah }
不是。
我得到了识别 X.some_method
的正确模式,即 '(send (const nil? :X) :some_method ...'
。
但不确定如何为 "is not given a block" 创建模式?
显然,在解析的 AST 中,当给定一个节点一个块时,该节点然后表示为该块的 第一个子节点。
即
[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
我正在尝试开发一个新警察(基于 these guidelines) and am banging my head trying to get the correct node pattern。
我希望警察在呼叫 X.some_method
时记录违规行为 而没有提供阻止 。
即 X.some_method
是一种冒犯,但 X.some_method { blah }
不是。
我得到了识别 X.some_method
的正确模式,即 '(send (const nil? :X) :some_method ...'
。
但不确定如何为 "is not given a block" 创建模式?
显然,在解析的 AST 中,当给定一个节点一个块时,该节点然后表示为该块的 第一个子节点。
即
[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