Class: RuboCop::Cop::Chef::Correctness::RubyGuardWithoutBlock

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Defined in:
lib/rubocop/cop/chef/correctness/ruby_guard_without_block.rb

Overview

A not_if/only_if guard takes either a string, which is run as a shell command, or a block, which is run as Ruby. Passing a Ruby expression directly gives the guard the expression's result rather than the expression, because it is evaluated while the recipe is compiled.

A guard that receives true or false raises at converge time:

ArgumentError: Invalid only_if/not_if command, expected a string: true (TrueClass)

Worse, an expression that happens to return a string is accepted and then run as a shell command, so the guard quietly tests something entirely different to what was intended.

Only expressions that clearly produce a boolean are flagged, so a shell command built in Ruby and held in a variable is left alone.

Examples:


# bad
not_if ::File.exist?('/etc/foo')
only_if node['foo']['version'] == '1.0'

# good
not_if { ::File.exist?('/etc/foo') }
only_if { node['foo']['version'] == '1.0' }

# good - a string guard runs as a shell command
not_if 'test -f /etc/foo'

Constant Summary collapse

MSG =
'A Ruby expression used as a resource guard has to be wrapped in a block. Passing it directly hands the guard the expression result, which raises at converge time or silently runs a shell command.'
RESTRICT_ON_SEND =
[:not_if, :only_if].freeze
BOOLEAN_OPERATORS =

comparison and negation operators always produce a boolean

%i(== != < > <= >= =~ !~ ! equal? eql?).freeze

Instance Method Summary collapse

Methods inherited from Base

#target_chef_version

Instance Method Details

#on_send(node) ⇒ Object



60
61
62
63
64
65
66
67
68
# File 'lib/rubocop/cop/chef/correctness/ruby_guard_without_block.rb', line 60

def on_send(node)
  guard_with_argument(node) do |argument|
    next unless boolean_expression?(argument)

    add_offense(node, severity: :refactor) do |corrector|
      corrector.replace(node, "#{node.method_name} { #{argument.source} }")
    end
  end
end