Class: RuboCop::Cop::Rails::HttpPositionalArguments

Inherits:
Cop
  • Object
show all
Extended by:
TargetRailsVersion
Defined in:
lib/rubocop/cop/rails/http_positional_arguments.rb

Overview

This cop is used to identify usages of http methods like get, post, put, patch without the usage of keyword arguments in your tests and change them to use keyword args. This cop only applies to Rails >= 5 . If you are running Rails < 5 you should disable the Rails/HttpPositionalArguments cop or set your TargetRailsVersion in your .rubocop.yml file to 4.0, etc.

Examples:

# bad
get :new, { user_id: 1}

# good
get :new, params: { user_id: 1 }

Constant Summary collapse

MSG =
'Use keyword arguments instead of ' \
'positional arguments for http call: `%<verb>s`.'.freeze
KEYWORD_ARGS =
%i[
  headers env params body flash as xhr session method
].freeze
HTTP_METHODS =
%i[get post put patch delete head].freeze

Constants included from Util

Util::ASGN_NODES, Util::BYTE_ORDER_MARK, Util::CONDITIONAL_NODES, Util::EQUALS_ASGN_NODES, Util::LITERAL_REGEX, Util::LOGICAL_OPERATOR_NODES, Util::MODIFIER_NODES, Util::OPERATOR_METHODS, Util::SHORTHAND_ASGN_NODES

Instance Attribute Summary

Attributes inherited from Cop

#config, #corrections, #offenses, #processed_source

Instance Method Summary collapse

Methods included from TargetRailsVersion

minimum_target_rails_version, support_target_rails_version?

Methods inherited from Cop

#add_offense, all, autocorrect_incompatible_with, badge, #config_to_allow_offenses, #config_to_allow_offenses=, #cop_config, cop_name, #cop_name, #correct, department, #duplicate_location?, #excluded_file?, #find_location, #highlights, inherited, #initialize, #join_force?, lint?, match?, #message, #messages, non_rails, #parse, qualified_cop_name, #relevant_file?, #target_rails_version, #target_ruby_version

Methods included from AST::Sexp

#s

Methods included from NodePattern::Macros

#def_node_matcher, #def_node_search, #node_search, #node_search_all, #node_search_body, #node_search_first

Methods included from AutocorrectLogic

#autocorrect?, #autocorrect_enabled?, #autocorrect_requested?, #support_autocorrect?

Methods included from IgnoredNode

#ignore_node, #ignored_node?, #part_of_ignored_node?

Methods included from Util

begins_its_line?, comment_line?, double_quotes_required?, effective_column, ends_its_line?, escape_string, first_part_of_call_chain, interpret_string_escapes, line_range, needs_escaping?, on_node, operator?, parentheses?, parenthesized_call?, precede?, range_between, range_by_whole_lines, range_with_surrounding_comma, range_with_surrounding_space, same_line?, source_range, strip_quotes, stripped_source_upto, symbol_without_quote?, to_string_literal, to_supported_styles, to_symbol_literal, within_node?

Methods included from PathUtil

absolute?, find_file_upwards, match_path?, pwd, relative_path, reset_pwd, smart_path

Constructor Details

This class inherits a constructor from RuboCop::Cop::Cop

Instance Method Details

#autocorrect(node) ⇒ Object

given a pre Rails 5 method: get :new, user_id: @user.id, {}

the result should look like:

get :new, params: { user_id: @user.id }, headers: {}

the http_method is the method used to call the controller the controller node can be a symbol, method, object or string that represents the path/action on the Rails controller the data is the http parameters and environment sent in the Rails 5 http call

Returns:

  • lambda of auto correct procedure



54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 54

def autocorrect(node)
  http_path, *data = *node.arguments

  controller_action = http_path.source
  params = convert_hash_data(data.first, 'params')
  headers = convert_hash_data(data.last, 'headers') if data.size > 1
  # the range of the text to replace, which is the whole line
  code_to_replace = node.loc.expression
  # what to replace with
  format = parentheses?(node) ? '%s(%s%s%s)' : '%s %s%s%s'
  new_code = format(format, node.method_name, controller_action,
                    params, headers)
  ->(corrector) { corrector.replace(code_to_replace, new_code) }
end

#convert_hash_data(data, type) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 86

def convert_hash_data(data, type)
  return '' if data.hash_type? && data.empty?

  hash_data = if data.hash_type?
                format('{ %s }', data.pairs.map(&:source).join(', '))
              else
                # user supplies an object,
                # no need to surround with braces
                data.source
              end

  format(', %s: %s', type, hash_data)
end

#format_arg?(node) ⇒ Boolean

Returns:

  • (Boolean)


82
83
84
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 82

def format_arg?(node)
  node.sym_type? && node.value == :format
end

#needs_conversion?(data) ⇒ Boolean

Returns:

  • (Boolean)


69
70
71
72
73
74
75
76
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 69

def needs_conversion?(data)
  return true unless data.hash_type?

  data.each_pair.none? do |pair|
    special_keyword_arg?(pair.key) ||
      format_arg?(pair.key) && data.pairs.one?
  end
end

#on_send(node) ⇒ Object



35
36
37
38
39
40
41
42
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 35

def on_send(node)
  http_request?(node) do |data|
    return unless needs_conversion?(data)

    add_offense(node, location: :selector,
                      message: format(MSG, verb: node.method_name))
  end
end

#special_keyword_arg?(node) ⇒ Boolean

Returns:

  • (Boolean)


78
79
80
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 78

def special_keyword_arg?(node)
  node.sym_type? && KEYWORD_ARGS.include?(node.value)
end