module RuboCop::Chef::CookbookHelpers

Common node helpers used for matching against Chef Infra Cookbooks

Public Instance Methods

match_property_in_resource?(resource_names, property_names, node) { |p| ... } click to toggle source

Match particular properties within a resource

@param [Symbol, Array<Symbol>] resource_names The name of the resources to match @param [String] property_names The name of the property to match (or action) @param [RuboCop::AST::Node] node The rubocop ast node to search

@yield

# File lib/rubocop/chef/cookbook_helpers.rb, line 49
def match_property_in_resource?(resource_names, property_names, node)
  return unless looks_like_resource?(node)
  # bail out if we're not in the resource we care about or nil was passed (all resources)
  return unless resource_names.nil? || Array(resource_names).include?(node.children.first.method_name) # see if we're in the right resource

  resource_block = node.children[2] # the 3rd child is the actual block in the resource
  return unless resource_block # nil would be an empty block

  if resource_block.begin_type? # if begin_type we need to iterate over the children
    resource_block.children.each do |resource_blk_child|
      extract_send_types(resource_blk_child) do |p|
        yield(p) if symbolized_property_types(property_names).include?(p.method_name)
      end
    end
  else # there's only a single property to check
    extract_send_types(resource_block) do |p|
      yield(p) if symbolized_property_types(property_names).include?(p.method_name)
    end
  end
end
match_resource_type?(resource_name, node) { |node| ... } click to toggle source

Match a particular resource

@param [String] resource_name The name of the resource to match @param [RuboCop::AST::Node] node The rubocop ast node to search

@yield

# File lib/rubocop/chef/cookbook_helpers.rb, line 35
def match_resource_type?(resource_name, node)
  return unless looks_like_resource?(node)
  # bail out if we're not in the resource we care about or nil was passed (all resources)
  yield(node) if node.children.first.method?(resource_name.to_sym)
end
method_arg_ast_to_string(ast) click to toggle source
# File lib/rubocop/chef/cookbook_helpers.rb, line 70
def method_arg_ast_to_string(ast)
  # a property without a value. This is totally bogus, but they exist
  return if ast.children[2].nil?
  # https://rubular.com/r/6uzOMd6WCHewOu
  m = ast.children[2].source.match(/^("|')(.*)("|')$/)
  return m[2] unless m.nil?
end
resource_block_name_if_string(node) click to toggle source
# File lib/rubocop/chef/cookbook_helpers.rb, line 22
def resource_block_name_if_string(node)
  if looks_like_resource?(node) && node.children.first.arguments.first.respond_to?(:value)
    node.children.first.arguments.first.value
  end
end

Private Instance Methods

extract_send_types(node) { |node| ... } click to toggle source
# File lib/rubocop/chef/cookbook_helpers.rb, line 109
def extract_send_types(node)
  return if node.nil? # there are cases we can be passed an empty node
  case node.type
  when :send
    yield(node) if node.receiver.nil? # if it's not nil then we're not in a property foo we're in bar.foo
  when :block # ie: not_if { ruby_foo }
    yield(node)
  when :while
    extract_send_types(node.body) { |t| yield(t) }
  when :if
    node.branches.each { |n| extract_send_types(n) { |t| yield(t) } }
  when :case
    node.when_branches.each { |n| extract_send_types(n.body) { |t| yield(t) } } # unless node.when_branches.nil?
    extract_send_types(node.else_branch) { |t| yield(t) } if node.else_branch
  end
end
looks_like_resource?(node) click to toggle source

given a node object does it look like a chef resource or not? warning: currently this requires a resource with properties since we key off blocks and property-less resources look like methods

@param [RuboCop::AST::Node] node AST object to test

@return [boolean]

# File lib/rubocop/chef/cookbook_helpers.rb, line 95
def looks_like_resource?(node)
  return false unless node.block_type? # resources are blocks if they have properties
  return false unless node.children.first.receiver.nil? # resource blocks don't have a receiver
  return false if node.send_node.arguments.first.is_a?(RuboCop::AST::SymbolNode) # resources have a string name. resource actions have symbols

  # bail if the block doesn't have a name a resource *generally* has a name.
  # This isn't 100% true with things like apt_update and build_essential, but we'll live
  # with that for now to avoid the false positives of getting stuck in generic blocks in resources
  return false if node.children.first.arguments.empty?

  # if we made it this far we're probably in a resource
  true
end
symbolized_property_types(property) click to toggle source

@param [String, Array] property

@return [Array]

# File lib/rubocop/chef/cookbook_helpers.rb, line 83
def symbolized_property_types(property)
  Array(property).map(&:to_sym)
end