class RuboCop::Cop::Style::CommandLiteral

This cop enforces using “ or %x around command literals.

@example

# Good if EnforcedStyle is backticks or mixed, bad if percent_x.
folders = %x`find . -type d`.split

# Good if EnforcedStyle is percent_x, bad if backticks or mixed.
folders = %x(find . -type d).split

# Good if EnforcedStyle is backticks, bad if percent_x or mixed.
%x`
  ln -s foo.example.yml foo.example
  ln -s bar.example.yml bar.example
`

# Good if EnforcedStyle is percent_x or mixed, bad if backticks.
%x(
  ln -s foo.example.yml foo.example
  ln -s bar.example.yml bar.example
)

# Bad unless AllowInnerBackticks is true.
%x`echo \`ls\``

Constants

MSG_USE_BACKTICKS
MSG_USE_PERCENT_X

Public Instance Methods

on_xstr(node) click to toggle source
# File lib/rubocop/cop/style/command_literal.rb, line 35
def on_xstr(node)
  return if heredoc_literal?(node)

  if backtick_literal?(node)
    check_backtick_literal(node)
  else
    check_percent_x_literal(node)
  end
end

Private Instance Methods

allow_inner_backticks?() click to toggle source
# File lib/rubocop/cop/style/command_literal.rb, line 69
def allow_inner_backticks?
  cop_config['AllowInnerBackticks']
end
autocorrect(node) click to toggle source
# File lib/rubocop/cop/style/command_literal.rb, line 95
def autocorrect(node)
  return if contains_backtick?(node)

  replacement = if backtick_literal?(node)
                  ['%x', ''].zip(preferred_delimiters).map(&:join)
                else
                  %w(` `)
                end

  lambda do |corrector|
    corrector.replace(node.loc.begin, replacement.first)
    corrector.replace(node.loc.end, replacement.last)
  end
end
backtick_literal?(node) click to toggle source
# File lib/rubocop/cop/style/command_literal.rb, line 86
def backtick_literal?(node)
  node.loc.begin.source == '`'
end
check_backtick_literal(node) click to toggle source
# File lib/rubocop/cop/style/command_literal.rb, line 47
def check_backtick_literal(node)
  return if style == :backticks && !contains_disallowed_backtick?(node)
  return if style == :mixed &&
            node.single_line? &&
            !contains_disallowed_backtick?(node)

  add_offense(node, :expression, MSG_USE_PERCENT_X)
end
check_percent_x_literal(node) click to toggle source
# File lib/rubocop/cop/style/command_literal.rb, line 56
def check_percent_x_literal(node)
  return if style == :backticks && contains_disallowed_backtick?(node)
  return if style == :percent_x
  return if style == :mixed && node.multiline?
  return if style == :mixed && contains_disallowed_backtick?(node)

  add_offense(node, :expression, MSG_USE_BACKTICKS)
end
contains_backtick?(node) click to toggle source
# File lib/rubocop/cop/style/command_literal.rb, line 73
def contains_backtick?(node)
  node_body(node) =~ /`/
end
contains_disallowed_backtick?(node) click to toggle source
# File lib/rubocop/cop/style/command_literal.rb, line 65
def contains_disallowed_backtick?(node)
  !allow_inner_backticks? && contains_backtick?(node)
end
heredoc_literal?(node) click to toggle source
# File lib/rubocop/cop/style/command_literal.rb, line 82
def heredoc_literal?(node)
  node.loc.respond_to?(:heredoc_body)
end
node_body(node) click to toggle source
# File lib/rubocop/cop/style/command_literal.rb, line 77
def node_body(node)
  loc = node.loc
  loc.expression.source[loc.begin.length...-loc.end.length]
end
preferred_delimiters() click to toggle source
# File lib/rubocop/cop/style/command_literal.rb, line 90
def preferred_delimiters
  config.for_cop('Style/PercentLiteralDelimiters')              ['PreferredDelimiters']['%x'].split(//)
end