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

Inherits:
Cop
  • Object
show all
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, path without the usage of keyword arguments in your tests and change them to use keyword arguments.

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: `%s`.'.freeze
KEYWORD_ARGS =
[
  :headers, :env, :params, :body, :flash, :as,
  :xhr, :session, :method, :format
].freeze
HTTP_METHODS =
[:get, :post, :put, :patch, :delete, :head].freeze

Constants included from Util

Util::ASGN_NODES, Util::BYTE_ORDER_MARK, Util::EQUALS_ASGN_NODES, Util::LITERAL_REGEX, Util::OPERATOR_METHODS, Util::SHORTHAND_ASGN_NODES

Instance Attribute Summary

Attributes inherited from Cop

#config, #corrections, #offenses, #processed_source

Instance Method Summary collapse

Methods inherited from Cop

#add_offense, all, #config_to_allow_offenses, #config_to_allow_offenses=, #cop_config, cop_name, #cop_name, cop_type, #correct, #debug?, #details, #display_cop_names?, #display_style_guide?, #duplicate_location?, #excluded_file?, #extra_details?, #find_location, #highlights, inherited, #initialize, #join_force?, lint?, match?, #message, #messages, non_rails, #parse, qualified_cop_name, #reference_url, #relevant_file?, #style_guide_url, #target_ruby_version

Methods included from 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?, block_length, comment_line?, compatible_external_encoding_for?, directions, double_quotes_acceptable?, double_quotes_required?, effective_column, ends_its_line?, escape_string, first_part_of_call_chain, hard_to_type?, interpret_string_escapes, line_distance, line_range, move_pos, needs_escaping?, numeric_range_size, on_node, operator?, parentheses?, parenthesized_call?, preceed?, range_between, range_with_surrounding_comma, range_with_surrounding_space, same_line?, source_range, strip_quotes, stripped_source_upto, to_string_literal, to_symbol_literal, within_node?

Methods included from PathUtil

absolute?, match_path?, relative_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 use 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



77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 77

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

#convert_hash_data(data, type) ⇒ Object



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

def convert_hash_data(data, type)
  # empty hash or no hash return empty string
  return '' if data.nil? || data.children.count < 1
  hash_data = if data.hash_type?
                format('{ %s }', data.children.map(&:source).join(', '))
              else
                # user supplies an object,
                # no need to surround with braces
                data.source
              end
  format(', %s: %s', type, hash_data)
end

#needs_conversion?(data) ⇒ Boolean

Returns true if the line needs to be converted.

Returns:

  • (Boolean)

    true if the line needs to be converted



44
45
46
47
48
49
50
51
52
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 44

def needs_conversion?(data)
  # if the line has already been converted to use keyword args
  # then skip
  # ie. get :new, params: { user_id: 1 }  (looking for keyword arg)
  value = data.descendants.find do |d|
    KEYWORD_ARGS.include?(d.children.first) if d.type == :sym
  end
  value.nil?
end

#on_send(node) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 25

def on_send(node)
  receiver, http_method, http_path, data = *node
  # if the first word on the line is not an http method, then skip
  return unless HTTP_METHODS.include?(http_method)
  # if the data is nil then we don't need to add keyword arguments
  # because there is no data to put in params or headers, so skip
  return if data.nil?
  return unless needs_conversion?(data)
  # ensures this is the first method on the line
  # there is an edge case here where sometimes the http method is
  # wrapped into another method, but its just safer to skip those
  # cases and process manually
  return unless receiver.nil?
  # a http_method without a path?, must be something else
  return if http_path.nil?
  add_offense(node, node.loc.selector, format(MSG, node.method_name))
end