rubocop 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +75 -16
  4. data/lib/rubocop.rb +5 -0
  5. data/lib/rubocop/cli.rb +5 -1
  6. data/lib/rubocop/cli/command/execute_runner.rb +26 -11
  7. data/lib/rubocop/cli/command/suggest_extensions.rb +67 -0
  8. data/lib/rubocop/config_loader.rb +12 -4
  9. data/lib/rubocop/config_loader_resolver.rb +5 -1
  10. data/lib/rubocop/config_obsoletion.rb +21 -3
  11. data/lib/rubocop/config_regeneration.rb +1 -1
  12. data/lib/rubocop/config_validator.rb +8 -1
  13. data/lib/rubocop/cop/autocorrect_logic.rb +21 -6
  14. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
  15. data/lib/rubocop/cop/generator.rb +2 -9
  16. data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
  17. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +1 -1
  18. data/lib/rubocop/cop/layout/class_structure.rb +15 -3
  19. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +80 -10
  20. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +6 -1
  21. data/lib/rubocop/cop/layout/end_of_line.rb +5 -5
  22. data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -2
  23. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  24. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +2 -1
  25. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +4 -1
  26. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  27. data/lib/rubocop/cop/lint/missing_super.rb +7 -4
  28. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +1 -1
  29. data/lib/rubocop/cop/lint/to_enum_arguments.rb +6 -15
  30. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +85 -0
  31. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +20 -6
  32. data/lib/rubocop/cop/metrics/abc_size.rb +25 -1
  33. data/lib/rubocop/cop/metrics/block_length.rb +13 -7
  34. data/lib/rubocop/cop/metrics/method_length.rb +7 -2
  35. data/lib/rubocop/cop/metrics/parameter_lists.rb +64 -1
  36. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +20 -10
  37. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +146 -0
  38. data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +6 -1
  39. data/lib/rubocop/cop/mixin/configurable_numbering.rb +4 -3
  40. data/lib/rubocop/cop/mixin/enforce_superclass.rb +9 -1
  41. data/lib/rubocop/cop/mixin/ignored_methods.rb +36 -3
  42. data/lib/rubocop/cop/mixin/method_complexity.rb +6 -0
  43. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  44. data/lib/rubocop/cop/mixin/visibility_help.rb +1 -3
  45. data/lib/rubocop/cop/style/and_or.rb +10 -0
  46. data/lib/rubocop/cop/style/class_and_module_children.rb +8 -3
  47. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +8 -1
  48. data/lib/rubocop/cop/style/documentation.rb +12 -1
  49. data/lib/rubocop/cop/style/format_string.rb +8 -3
  50. data/lib/rubocop/cop/style/if_with_semicolon.rb +39 -4
  51. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -2
  52. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -2
  53. data/lib/rubocop/cop/style/negated_if_else_condition.rb +3 -1
  54. data/lib/rubocop/cop/style/numeric_literals.rb +14 -11
  55. data/lib/rubocop/cop/style/redundant_argument.rb +75 -0
  56. data/lib/rubocop/cop/style/redundant_condition.rb +2 -1
  57. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  58. data/lib/rubocop/cop/style/sole_nested_conditional.rb +49 -3
  59. data/lib/rubocop/cop/style/symbol_proc.rb +5 -3
  60. data/lib/rubocop/cop/util.rb +1 -1
  61. data/lib/rubocop/cop/variable_force/branch.rb +1 -1
  62. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  63. data/lib/rubocop/core_ext/hash.rb +20 -0
  64. data/lib/rubocop/ext/regexp_node.rb +5 -10
  65. data/lib/rubocop/ext/regexp_parser.rb +2 -9
  66. data/lib/rubocop/formatter/disabled_config_formatter.rb +21 -6
  67. data/lib/rubocop/options.rb +5 -0
  68. data/lib/rubocop/rake_task.rb +2 -2
  69. data/lib/rubocop/runner.rb +1 -1
  70. data/lib/rubocop/target_finder.rb +1 -1
  71. data/lib/rubocop/target_ruby.rb +12 -4
  72. data/lib/rubocop/version.rb +1 -1
  73. metadata +12 -10
  74. data/bin/console +0 -10
  75. data/bin/rubocop-profile +0 -32
  76. data/bin/setup +0 -7
@@ -51,7 +51,7 @@ module RuboCop
51
51
  alias on_csend on_send
52
52
 
53
53
  def on_const(node)
54
- return unless node.loc.double_colon
54
+ return unless node.loc.respond_to?(:double_colon) && node.loc.double_colon
55
55
 
56
56
  check_space_after_double_colon(node)
57
57
  end
@@ -53,7 +53,8 @@ module RuboCop
53
53
  def find_offense_node(node, regexp_receiver)
54
54
  return node unless node.parent
55
55
 
56
- if node.parent.send_type? || method_chain_to_regexp_receiver?(node, regexp_receiver)
56
+ if (node.parent.send_type? && node.receiver) ||
57
+ method_chain_to_regexp_receiver?(node, regexp_receiver)
57
58
  node = find_offense_node(node.parent, regexp_receiver)
58
59
  end
59
60
 
@@ -50,8 +50,11 @@ module RuboCop
50
50
  # end
51
51
  # end
52
52
  #
53
- # @example AllowedMethods: ['enums']
53
+ # @example AllowedMethods: ['enums'] (default)
54
54
  # # good
55
+ #
56
+ # # `enums` for Typed Enums via `T::Enum` in Sorbet.
57
+ # # https://sorbet.org/docs/tenum
55
58
  # class TestEnum < T::Enum
56
59
  # enums do
57
60
  # Foo = new("foo")
@@ -95,7 +95,7 @@ module RuboCop
95
95
  def autocorrected_value_for_array(node)
96
96
  return node.source.gsub('"', '\"') unless node.percent_literal?
97
97
 
98
- contents_range(node).source.split(' ').to_s.gsub('"', '\"')
98
+ contents_range(node).source.split.to_s.gsub('"', '\"')
99
99
  end
100
100
 
101
101
  # Does node print its own source when converted to a string?
@@ -6,6 +6,11 @@ module RuboCop
6
6
  # This cop checks for the presence of constructors and lifecycle callbacks
7
7
  # without calls to `super`.
8
8
  #
9
+ # This cop does not consider `method_missing` (and `respond_to_missing?`)
10
+ # because in some cases it makes sense to overtake what is considered a
11
+ # missing method. In other cases, the theoretical ideal handling could be
12
+ # challenging or verbose for no actual gain.
13
+ #
9
14
  # @example
10
15
  # # bad
11
16
  # class Employee < Person
@@ -43,15 +48,13 @@ module RuboCop
43
48
 
44
49
  STATELESS_CLASSES = %w[BasicObject Object].freeze
45
50
 
46
- OBJECT_LIFECYCLE_CALLBACKS = %i[method_missing respond_to_missing?].freeze
47
51
  CLASS_LIFECYCLE_CALLBACKS = %i[inherited].freeze
48
52
  METHOD_LIFECYCLE_CALLBACKS = %i[method_added method_removed method_undefined
49
53
  singleton_method_added singleton_method_removed
50
54
  singleton_method_undefined].freeze
51
55
 
52
- CALLBACKS = (OBJECT_LIFECYCLE_CALLBACKS +
53
- CLASS_LIFECYCLE_CALLBACKS +
54
- METHOD_LIFECYCLE_CALLBACKS).to_set.freeze
56
+ CALLBACKS = (CLASS_LIFECYCLE_CALLBACKS +
57
+ METHOD_LIFECYCLE_CALLBACKS).to_set.freeze
55
58
 
56
59
  def on_def(node)
57
60
  return unless offender?(node)
@@ -40,7 +40,7 @@ module RuboCop
40
40
  # do_something
41
41
  # end
42
42
  #
43
- class NoReturnInBeginEndBlocks < Cop
43
+ class NoReturnInBeginEndBlocks < Base
44
44
  MSG = 'Do not `return` in `begin..end` blocks in assignment contexts.'
45
45
 
46
46
  def on_lvasgn(node)
@@ -8,23 +8,14 @@ module RuboCop
8
8
  #
9
9
  # @example
10
10
  # # bad
11
- # def method(x, y = 1)
12
- # return to_enum(__method__, x) # `y` is missing
11
+ # def foo(x, y = 1)
12
+ # return to_enum(__callee__, x) # `y` is missing
13
13
  # end
14
14
  #
15
15
  # # good
16
- # def method(x, y = 1)
17
- # return to_enum(__method__, x, y)
18
- # end
19
- #
20
- # # bad
21
- # def method(required:)
22
- # return to_enum(:method, required: something) # `required` has incorrect value
23
- # end
24
- #
25
- # # good
26
- # def method(required:)
27
- # return to_enum(:method, required: required)
16
+ # def foo(x, y = 1)
17
+ # return to_enum(__callee__, x, y)
18
+ # # alternatives to `__callee__` are `__method__` and `:foo`
28
19
  # end
29
20
  #
30
21
  class ToEnumArguments < Base
@@ -37,7 +28,7 @@ module RuboCop
37
28
  PATTERN
38
29
 
39
30
  def_node_matcher :method_name?, <<~PATTERN
40
- {(send nil? :__method__) (sym %1)}
31
+ {(send nil? {:__method__ :__callee__}) (sym %1)}
41
32
  PATTERN
42
33
 
43
34
  def_node_matcher :passing_keyword_arg?, <<~PATTERN
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for a block that is known to need more positional
7
+ # block arguments than are given (by default this is configured for
8
+ # `Enumerable` methods needing 2 arguments). Optional arguments are allowed,
9
+ # although they don't generally make sense as the default value will
10
+ # be used. Blocks that have no receiver, or take splatted arguments
11
+ # (ie. `*args`) are always accepted.
12
+ #
13
+ # Keyword arguments (including `**kwargs`) do not get counted towards
14
+ # this, as they are not used by the methods in question.
15
+ #
16
+ # NOTE: This cop matches for method names only and hence cannot tell apart
17
+ # methods with same name in different classes.
18
+ #
19
+ # Method names and their expected arity can be configured like this:
20
+ #
21
+ # Methods:
22
+ # inject: 2
23
+ # reduce: 2
24
+ #
25
+ # @example
26
+ # # bad
27
+ # values.reduce {}
28
+ # values.min { |a| a }
29
+ # values.sort { |a; b| a + b }
30
+ #
31
+ # # good
32
+ # values.reduce { |memo, obj| memo << obj }
33
+ # values.min { |a, b| a <=> b }
34
+ # values.sort { |*x| x[0] <=> x[1] }
35
+ #
36
+ class UnexpectedBlockArity < Base
37
+ MSG = '`%<method>s` expects at least %<expected>i positional arguments, got %<actual>i.'
38
+
39
+ def on_block(node)
40
+ return if acceptable?(node)
41
+
42
+ expected = expected_arity(node.method_name)
43
+ actual = arg_count(node)
44
+ return if actual >= expected
45
+
46
+ message = format(MSG, method: node.method_name, expected: expected, actual: actual)
47
+ add_offense(node, message: message)
48
+ end
49
+
50
+ alias on_numblock on_block
51
+
52
+ private
53
+
54
+ def methods
55
+ cop_config.fetch('Methods', [])
56
+ end
57
+
58
+ def acceptable?(node)
59
+ !(included_method?(node.method_name) && node.receiver)
60
+ end
61
+
62
+ def included_method?(name)
63
+ methods.key?(name.to_s)
64
+ end
65
+
66
+ def expected_arity(method)
67
+ cop_config['Methods'][method.to_s]
68
+ end
69
+
70
+ def arg_count(node)
71
+ return node.children[1] if node.numblock_type? # the maximum numbered param for the block
72
+
73
+ # Only `arg`, `optarg` and `mlhs` (destructuring) count as arguments that
74
+ # can be used. Keyword arguments are not used for these methods so are
75
+ # ignored.
76
+ node.arguments.count do |arg|
77
+ return Float::INFINITY if arg.restarg_type?
78
+
79
+ arg.arg_type? || arg.optarg_type? || arg.mlhs_type?
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -54,6 +54,9 @@ module RuboCop
54
54
  # value
55
55
  # end
56
56
  #
57
+ # # good, recursive
58
+ # keys.reduce(self) { |result, key| result[key] }
59
+ #
57
60
  # # ignored as the return value cannot be determined
58
61
  # enum.reduce do |acc, el|
59
62
  # x = foo(acc, el)
@@ -64,7 +67,10 @@ module RuboCop
64
67
  MSG_INDEX = 'Do not return an element of the accumulator in `%<method>s`.'
65
68
 
66
69
  def_node_matcher :reduce_with_block?, <<~PATTERN
67
- (block (send _recv {:reduce :inject} ...) (args arg+) ...)
70
+ {
71
+ (block (send _recv {:reduce :inject} ...) args ...)
72
+ (numblock (send _recv {:reduce :inject} ...) ...)
73
+ }
68
74
  PATTERN
69
75
 
70
76
  def_node_matcher :accumulator_index?, <<~PATTERN
@@ -103,9 +109,11 @@ module RuboCop
103
109
 
104
110
  def on_block(node)
105
111
  return unless reduce_with_block?(node)
112
+ return unless node.argument_list.length >= 2
106
113
 
107
114
  check_return_values(node)
108
115
  end
116
+ alias on_numblock on_block
109
117
 
110
118
  private
111
119
 
@@ -131,7 +139,7 @@ module RuboCop
131
139
  element_name = block_arg_name(block_node, 1)
132
140
  message_opts = { method: block_node.method_name, accum: accumulator_name }
133
141
 
134
- if (node = returned_accumulator_index(return_values, accumulator_name))
142
+ if (node = returned_accumulator_index(return_values, accumulator_name, element_name))
135
143
  add_offense(node, message: format(MSG_INDEX, message_opts))
136
144
  elsif potential_offense?(return_values, block_node.body, element_name, accumulator_name)
137
145
  return_values.each do |return_val|
@@ -143,14 +151,20 @@ module RuboCop
143
151
  end
144
152
 
145
153
  def block_arg_name(node, index)
146
- node.arguments[index].node_parts[0]
154
+ node.argument_list[index].name
147
155
  end
148
156
 
149
- # Look for an index of the accumulator being returned
157
+ # Look for an index of the accumulator being returned, except where the index
158
+ # is the element.
150
159
  # This is always an offense, in order to try to catch potential exceptions
151
160
  # due to type mismatches
152
- def returned_accumulator_index(return_values, accumulator_name)
153
- return_values.detect { |val| accumulator_index?(val, accumulator_name) }
161
+ def returned_accumulator_index(return_values, accumulator_name, element_name)
162
+ return_values.detect do |val|
163
+ next unless accumulator_index?(val, accumulator_name)
164
+ next true if val.method?(:[]=)
165
+
166
+ val.arguments.none? { |arg| lvar_used?(arg, element_name) }
167
+ end
154
168
  end
155
169
 
156
170
  def potential_offense?(return_values, block_body, element_name, accumulator_name)
@@ -7,6 +7,27 @@ module RuboCop
7
7
  # configured maximum. The ABC size is based on assignments, branches
8
8
  # (method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric
9
9
  # and https://en.wikipedia.org/wiki/ABC_Software_Metric.
10
+ #
11
+ # You can have repeated "attributes" calls count as a single "branch".
12
+ # For this purpose, attributes are any method with no argument; no attempt
13
+ # is meant to distinguish actual `attr_reader` from other methods.
14
+ #
15
+ # @example CountRepeatedAttributes: false (default is true)
16
+ #
17
+ # # `model` and `current_user`, refenced 3 times each,
18
+ # # are each counted as only 1 branch each if
19
+ # # `CountRepeatedAttributes` is set to 'false'
20
+ #
21
+ # def search
22
+ # @posts = model.active.visible_by(current_user)
23
+ # .search(params[:q])
24
+ # @posts = model.some_process(@posts, current_user)
25
+ # @posts = model.another_process(@posts, current_user)
26
+ #
27
+ # render 'pages/search/page'
28
+ # end
29
+ #
30
+ # This cop also takes into account `IgnoredMethods` (defaults to `[]`)
10
31
  class AbcSize < Base
11
32
  include MethodComplexity
12
33
 
@@ -16,7 +37,10 @@ module RuboCop
16
37
  private
17
38
 
18
39
  def complexity(node)
19
- Utils::AbcSizeCalculator.calculate(node)
40
+ Utils::AbcSizeCalculator.calculate(
41
+ node,
42
+ discount_repeated_attributes: !cop_config['CountRepeatedAttributes']
43
+ )
20
44
  end
21
45
  end
22
46
  end
@@ -12,6 +12,10 @@ module RuboCop
12
12
  # Available are: 'array', 'hash', and 'heredoc'. Each literal
13
13
  # will be counted as one line regardless of its actual size.
14
14
  #
15
+ #
16
+ # NOTE: The `ExcludedMethods` configuration is deprecated and only kept
17
+ # for backwards compatibility. Please use `IgnoredMethods` instead.
18
+ #
15
19
  # @example CountAsOne: ['array', 'heredoc']
16
20
  #
17
21
  # something do
@@ -33,11 +37,15 @@ module RuboCop
33
37
  # NOTE: This cop does not apply for `Struct` definitions.
34
38
  class BlockLength < Base
35
39
  include CodeLength
40
+ include IgnoredMethods
41
+
42
+ ignored_methods deprecated_key: 'ExcludedMethods'
36
43
 
37
44
  LABEL = 'Block'
38
45
 
39
46
  def on_block(node)
40
- return if excluded_method?(node)
47
+ return if ignored_method?(node.method_name)
48
+ return if method_receiver_excluded?(node)
41
49
  return if node.class_constructor? || node.struct_constructor?
42
50
 
43
51
  check_code_length(node)
@@ -45,11 +53,13 @@ module RuboCop
45
53
 
46
54
  private
47
55
 
48
- def excluded_method?(node)
56
+ def method_receiver_excluded?(node)
49
57
  node_receiver = node.receiver&.source&.gsub(/\s+/, '')
50
58
  node_method = String(node.method_name)
51
59
 
52
- excluded_methods.any? do |config|
60
+ ignored_methods.any? do |config|
61
+ next unless config.is_a?(String)
62
+
53
63
  receiver, method = config.split('.')
54
64
 
55
65
  unless method
@@ -61,10 +71,6 @@ module RuboCop
61
71
  end
62
72
  end
63
73
 
64
- def excluded_methods
65
- cop_config['ExcludedMethods'] || []
66
- end
67
-
68
74
  def cop_label
69
75
  LABEL
70
76
  end
@@ -11,6 +11,9 @@ module RuboCop
11
11
  # Available are: 'array', 'hash', and 'heredoc'. Each literal
12
12
  # will be counted as one line regardless of its actual size.
13
13
  #
14
+ # NOTE: The `ExcludedMethods` configuration is deprecated and only kept
15
+ # for backwards compatibility. Please use `IgnoredMethods` instead.
16
+ #
14
17
  # @example CountAsOne: ['array', 'heredoc']
15
18
  #
16
19
  # def m
@@ -31,12 +34,14 @@ module RuboCop
31
34
  #
32
35
  class MethodLength < Base
33
36
  include CodeLength
37
+ include IgnoredMethods
38
+
39
+ ignored_methods deprecated_key: 'ExcludedMethods'
34
40
 
35
41
  LABEL = 'Method'
36
42
 
37
43
  def on_def(node)
38
- excluded_methods = cop_config['ExcludedMethods']
39
- return if excluded_methods.include?(String(node.method_name))
44
+ return if ignored_method?(node.method_name)
40
45
 
41
46
  check_code_length(node)
42
47
  end
@@ -4,17 +4,76 @@ module RuboCop
4
4
  module Cop
5
5
  module Metrics
6
6
  # This cop checks for methods with too many parameters.
7
+ #
7
8
  # The maximum number of parameters is configurable.
8
- # Keyword arguments can optionally be excluded from the total count.
9
+ # Keyword arguments can optionally be excluded from the total count,
10
+ # as they add less complexity than positional or optional parameters.
11
+ #
12
+ # @example Max: 3
13
+ # # good
14
+ # def foo(a, b, c = 1)
15
+ # end
16
+ #
17
+ # @example Max: 2
18
+ # # bad
19
+ # def foo(a, b, c = 1)
20
+ # end
21
+ #
22
+ # @example CountKeywordArgs: true (default)
23
+ # # counts keyword args towards the maximum
24
+ #
25
+ # # bad (assuming Max is 3)
26
+ # def foo(a, b, c, d: 1)
27
+ # end
28
+ #
29
+ # # good (assuming Max is 3)
30
+ # def foo(a, b, c: 1)
31
+ # end
32
+ #
33
+ # @example CountKeywordArgs: false
34
+ # # don't count keyword args towards the maximum
35
+ #
36
+ # # good (assuming Max is 3)
37
+ # def foo(a, b, c, d: 1)
38
+ # end
39
+ #
40
+ # This cop also checks for the maximum number of optional parameters.
41
+ # This can be configured using the `MaxOptionalParameters` config option.
42
+ #
43
+ # @example MaxOptionalParameters: 3 (default)
44
+ # # good
45
+ # def foo(a = 1, b = 2, c = 3)
46
+ # end
47
+ #
48
+ # @example MaxOptionalParameters: 2
49
+ # # bad
50
+ # def foo(a = 1, b = 2, c = 3)
51
+ # end
52
+ #
9
53
  class ParameterLists < Base
10
54
  include ConfigurableMax
11
55
 
12
56
  MSG = 'Avoid parameter lists longer than %<max>d parameters. ' \
13
57
  '[%<count>d/%<max>d]'
58
+ OPTIONAL_PARAMETERS_MSG = 'Method has too many optional parameters. [%<count>d/%<max>d]'
14
59
 
15
60
  NAMED_KEYWORD_TYPES = %i[kwoptarg kwarg].freeze
16
61
  private_constant :NAMED_KEYWORD_TYPES
17
62
 
63
+ def on_def(node)
64
+ optargs = node.arguments.select(&:optarg_type?)
65
+ return if optargs.count <= max_optional_parameters
66
+
67
+ message = format(
68
+ OPTIONAL_PARAMETERS_MSG,
69
+ max: max_optional_parameters,
70
+ count: optargs.count
71
+ )
72
+
73
+ add_offense(node, message: message)
74
+ end
75
+ alias on_defs on_def
76
+
18
77
  def on_args(node)
19
78
  count = args_count(node)
20
79
  return unless count > max_params
@@ -44,6 +103,10 @@ module RuboCop
44
103
  cop_config['Max']
45
104
  end
46
105
 
106
+ def max_optional_parameters
107
+ cop_config['MaxOptionalParameters']
108
+ end
109
+
47
110
  def count_keyword_args?
48
111
  cop_config['CountKeywordArgs']
49
112
  end