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, patch 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
].freeze
HTTP_METHODS =
[: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 inherited from Cop

#add_offense, all, 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_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?, 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_supported_styles, 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



82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 82

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.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, http_method, controller_action,
                    params, headers)
  ->(corrector) { corrector.replace(code_to_replace, new_code) }
end

#convert_hash_data(data, type) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 59

def convert_hash_data(data, type)
  # empty hash or no hash return empty string
  return '' if data.nil? || data.children.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)


55
56
57
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 55

def format_arg?(node)
  node.children.first == :format if node.type == :sym
end

#needs_conversion?(data) ⇒ Boolean

Returns true if the line needs to be converted.

Returns:

  • (Boolean)

    true if the line needs to be converted



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 39

def needs_conversion?(data)
  return true unless data.hash_type?
  children = data.child_nodes

  value = children.find do |d|
    special_keyword_arg?(d.children.first) ||
      (format_arg?(d.children.first) && children.size == 1)
  end

  value.nil?
end

#on_send(node) ⇒ Object



28
29
30
31
32
33
34
35
36
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 28

def on_send(node)
  data = http_request?(node)
  # 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)

  add_offense(node, node.loc.selector, format(MSG, node.method_name))
end

#special_keyword_arg?(node) ⇒ Boolean

Returns:

  • (Boolean)


51
52
53
# File 'lib/rubocop/cop/rails/http_positional_arguments.rb', line 51

def special_keyword_arg?(node)
  KEYWORD_ARGS.include?(node.children.first) if node.type == :sym
end