rubocop 1.84.2 → 1.86.2
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.
- checksums.yaml +4 -4
- data/config/default.yml +99 -16
- data/config/obsoletion.yml +5 -0
- data/lib/rubocop/cache_config.rb +1 -1
- data/lib/rubocop/cli/command/auto_generate_config.rb +28 -2
- data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
- data/lib/rubocop/cli/command/mcp.rb +19 -0
- data/lib/rubocop/cli/command/show_cops.rb +2 -2
- data/lib/rubocop/cli/command/show_docs_url.rb +4 -8
- data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
- data/lib/rubocop/cli.rb +7 -7
- data/lib/rubocop/comment_config.rb +12 -15
- data/lib/rubocop/config.rb +14 -10
- data/lib/rubocop/config_finder.rb +1 -1
- data/lib/rubocop/config_loader_resolver.rb +2 -1
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
- data/lib/rubocop/config_store.rb +1 -1
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +2 -1
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors.rb +28 -0
- data/lib/rubocop/cop/documentation.rb +2 -3
- data/lib/rubocop/cop/exclude_limit.rb +31 -5
- data/lib/rubocop/cop/gemspec/require_mfa.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +9 -2
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +12 -2
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
- data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
- data/lib/rubocop/cop/layout/end_alignment.rb +6 -3
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +5 -3
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +53 -3
- data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +3 -1
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -0
- data/lib/rubocop/cop/lint/constant_reassignment.rb +59 -9
- data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
- data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +55 -8
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +6 -1
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
- data/lib/rubocop/cop/lint/empty_when.rb +8 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +0 -9
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +23 -6
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +2 -0
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
- data/lib/rubocop/cop/lint/syntax.rb +25 -1
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -0
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
- data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
- data/lib/rubocop/cop/lint/useless_assignment.rb +4 -9
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +35 -9
- data/lib/rubocop/cop/lint/void.rb +32 -12
- data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
- data/lib/rubocop/cop/migration/department_name.rb +12 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
- data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
- data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
- data/lib/rubocop/cop/mixin.rb +85 -0
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +8 -0
- data/lib/rubocop/cop/registry.rb +39 -37
- data/lib/rubocop/cop/security/eval.rb +15 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +14 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
- data/lib/rubocop/cop/style/alias.rb +4 -1
- data/lib/rubocop/cop/style/and_or.rb +1 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
- data/lib/rubocop/cop/style/array_join.rb +4 -2
- data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
- data/lib/rubocop/cop/style/attr.rb +5 -2
- data/lib/rubocop/cop/style/bare_percent_literals.rb +3 -1
- data/lib/rubocop/cop/style/begin_block.rb +3 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +25 -33
- data/lib/rubocop/cop/style/case_equality.rb +4 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +10 -2
- data/lib/rubocop/cop/style/collection_compact.rb +36 -16
- data/lib/rubocop/cop/style/colon_method_call.rb +3 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +2 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +0 -4
- data/lib/rubocop/cop/style/copyright.rb +22 -11
- data/lib/rubocop/cop/style/date_time.rb +2 -2
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +2 -0
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_class_definition.rb +43 -20
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/encoding.rb +7 -1
- data/lib/rubocop/cop/style/end_block.rb +3 -1
- data/lib/rubocop/cop/style/endless_method.rb +8 -3
- data/lib/rubocop/cop/style/file_open.rb +84 -0
- data/lib/rubocop/cop/style/for.rb +3 -0
- data/lib/rubocop/cop/style/format_string_token.rb +29 -2
- data/lib/rubocop/cop/style/global_vars.rb +5 -2
- data/lib/rubocop/cop/style/guard_clause.rb +9 -6
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +21 -5
- data/lib/rubocop/cop/style/hash_lookup_method.rb +19 -7
- data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
- data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
- data/lib/rubocop/cop/style/if_inside_else.rb +16 -7
- data/lib/rubocop/cop/style/if_unless_modifier.rb +14 -3
- data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
- data/lib/rubocop/cop/style/inline_comment.rb +4 -1
- data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
- data/lib/rubocop/cop/style/magic_comment_format.rb +2 -2
- data/lib/rubocop/cop/style/map_join.rb +123 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -3
- data/lib/rubocop/cop/style/module_member_existence_check.rb +7 -14
- data/lib/rubocop/cop/style/multiline_if_then.rb +3 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
- data/lib/rubocop/cop/style/nil_comparison.rb +2 -3
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
- data/lib/rubocop/cop/style/not.rb +2 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
- data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +4 -3
- data/lib/rubocop/cop/style/parallel_assignment.rb +4 -0
- data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
- data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
- data/lib/rubocop/cop/style/proc.rb +3 -2
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/reduce_to_hash.rb +200 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +3 -3
- data/lib/rubocop/cop/style/redundant_each.rb +3 -3
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
- data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +25 -22
- data/lib/rubocop/cop/style/redundant_percent_q.rb +4 -1
- data/lib/rubocop/cop/style/redundant_return.rb +3 -1
- data/lib/rubocop/cop/style/redundant_self.rb +2 -2
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +114 -0
- data/lib/rubocop/cop/style/regexp_literal.rb +29 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +7 -7
- data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
- data/lib/rubocop/cop/style/select_by_range.rb +197 -0
- data/lib/rubocop/cop/style/select_by_regexp.rb +51 -21
- data/lib/rubocop/cop/style/semicolon.rb +2 -0
- data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
- data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +7 -6
- data/lib/rubocop/cop/style/tally_method.rb +181 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
- data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
- data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
- data/lib/rubocop/cop/team.rb +86 -35
- data/lib/rubocop/cop/variable_force/branch.rb +2 -2
- data/lib/rubocop/directive_comment.rb +2 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +5 -2
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
- data/lib/rubocop/formatter.rb +22 -21
- data/lib/rubocop/lsp/diagnostic.rb +1 -0
- data/lib/rubocop/lsp/routes.rb +10 -3
- data/lib/rubocop/lsp/runtime.rb +1 -2
- data/lib/rubocop/mcp/server.rb +200 -0
- data/lib/rubocop/options.rb +17 -4
- data/lib/rubocop/path_util.rb +14 -2
- data/lib/rubocop/plugin/loader.rb +1 -1
- data/lib/rubocop/result_cache.rb +22 -10
- data/lib/rubocop/rspec/cop_helper.rb +8 -0
- data/lib/rubocop/rspec/shared_contexts.rb +32 -2
- data/lib/rubocop/runner.rb +78 -51
- data/lib/rubocop/server/cache.rb +5 -7
- data/lib/rubocop/server/core.rb +2 -0
- data/lib/rubocop/target_finder.rb +14 -7
- data/lib/rubocop/target_ruby.rb +18 -12
- data/lib/rubocop/version.rb +2 -2
- data/lib/rubocop.rb +21 -96
- metadata +25 -5
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Checks for `File.open` without a block, which can leak file descriptors.
|
|
7
|
+
#
|
|
8
|
+
# When `File.open` is called without a block, the caller is responsible
|
|
9
|
+
# for closing the file descriptor. If it is not explicitly closed, it
|
|
10
|
+
# will only be closed when the garbage collector runs, which may lead
|
|
11
|
+
# to resource exhaustion. Using the block form ensures the file is
|
|
12
|
+
# automatically closed when the block exits.
|
|
13
|
+
#
|
|
14
|
+
# This cop only registers an offense when the result of `File.open` is
|
|
15
|
+
# assigned to a variable or has a method chained on it, as those are the
|
|
16
|
+
# clearest indicators that the block form should be used instead. When
|
|
17
|
+
# `File.open` is used as a return value or passed as an argument, the
|
|
18
|
+
# caller is likely managing the file descriptor intentionally.
|
|
19
|
+
#
|
|
20
|
+
# @safety
|
|
21
|
+
# This cop is unsafe because it relies on syntax heuristics and cannot
|
|
22
|
+
# verify whether the file descriptor is safely managed. For example, it
|
|
23
|
+
# still flags intentional one-shot reads (`File.open("f").read`) where
|
|
24
|
+
# the file descriptor is closed by the garbage collector.
|
|
25
|
+
#
|
|
26
|
+
# @example
|
|
27
|
+
# # bad
|
|
28
|
+
# f = File.open('file')
|
|
29
|
+
#
|
|
30
|
+
# # bad
|
|
31
|
+
# File.open('file').read
|
|
32
|
+
#
|
|
33
|
+
# # good
|
|
34
|
+
# File.open('file') do |f|
|
|
35
|
+
# f.read
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# # good
|
|
39
|
+
# File.open('file', &:read)
|
|
40
|
+
#
|
|
41
|
+
# # good - pass an open file object to an API that manages its lifecycle
|
|
42
|
+
# process(io: File.open('file'))
|
|
43
|
+
#
|
|
44
|
+
# # good - return an open file object for the caller to manage
|
|
45
|
+
# def json_key_io
|
|
46
|
+
# File.open('file')
|
|
47
|
+
# end
|
|
48
|
+
#
|
|
49
|
+
# # good - use File.read for one-shot reads
|
|
50
|
+
# File.read('file')
|
|
51
|
+
#
|
|
52
|
+
class FileOpen < Base
|
|
53
|
+
MSG = '`File.open` without a block may leak a file descriptor; use the block form.'
|
|
54
|
+
RESTRICT_ON_SEND = %i[open].freeze
|
|
55
|
+
|
|
56
|
+
# @!method file_open?(node)
|
|
57
|
+
def_node_matcher :file_open?, <<~PATTERN
|
|
58
|
+
(send (const {nil? cbase} :File) :open ...)
|
|
59
|
+
PATTERN
|
|
60
|
+
|
|
61
|
+
def on_send(node)
|
|
62
|
+
return unless file_open?(node)
|
|
63
|
+
return if node.block_argument?
|
|
64
|
+
return unless offensive_usage?(node)
|
|
65
|
+
|
|
66
|
+
add_offense(node)
|
|
67
|
+
end
|
|
68
|
+
alias on_csend on_send
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def offensive_usage?(node)
|
|
73
|
+
return true unless node.value_used?
|
|
74
|
+
|
|
75
|
+
node.parent.lvasgn_type? || receiver_of_chained_call?(node)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def receiver_of_chained_call?(node)
|
|
79
|
+
node.parent.receiver == node
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -8,6 +8,9 @@ module RuboCop
|
|
|
8
8
|
# parameter. An `each` call with a block on a single line is always
|
|
9
9
|
# allowed.
|
|
10
10
|
#
|
|
11
|
+
# NOTE: `each` is preferred in idiomatic Ruby because `for` leaks
|
|
12
|
+
# its loop variable into the surrounding scope.
|
|
13
|
+
#
|
|
11
14
|
# @example EnforcedStyle: each (default)
|
|
12
15
|
# # bad
|
|
13
16
|
# def foo
|
|
@@ -18,6 +18,11 @@ module RuboCop
|
|
|
18
18
|
# of `EnforcedStyle`) are only considered if used in the format string argument to the
|
|
19
19
|
# methods `printf`, `sprintf`, `format` and `%`.
|
|
20
20
|
#
|
|
21
|
+
# NOTE: In `aggressive` mode, offenses are registered for all strings containing tokens,
|
|
22
|
+
# but autocorrection is only applied when the string appears in a known formatting context
|
|
23
|
+
# (`format`, `sprintf`, `printf`, or `%`). This is done in order to prevent false
|
|
24
|
+
# autocorrections for strings that are not actually format strings.
|
|
25
|
+
#
|
|
21
26
|
# NOTE: Tokens in the `unannotated` style (eg. `%s`) are always treated as if
|
|
22
27
|
# configured with `Conservative: true`. This is done in order to prevent false positives,
|
|
23
28
|
# because this format is very similar to encoded URLs or Date/Time formatting strings.
|
|
@@ -90,9 +95,25 @@ module RuboCop
|
|
|
90
95
|
# # good
|
|
91
96
|
# redirect('foo/%{bar_id}')
|
|
92
97
|
#
|
|
98
|
+
# @example Mode: aggressive (default), EnforcedStyle: annotated
|
|
99
|
+
#
|
|
100
|
+
# # bad
|
|
101
|
+
# "%{greeting}"
|
|
102
|
+
# foo("%{greeting}")
|
|
103
|
+
#
|
|
104
|
+
# # bad
|
|
105
|
+
# format("%{greeting}", greeting: 'Hello')
|
|
106
|
+
# printf("%{greeting}", greeting: 'Hello')
|
|
107
|
+
# sprintf("%{greeting}", greeting: 'Hello')
|
|
108
|
+
# "%{greeting}" % { greeting: 'Hello' }
|
|
109
|
+
#
|
|
110
|
+
# # good
|
|
111
|
+
# format("%<greeting>s", greeting: 'Hello')
|
|
112
|
+
# printf("%<greeting>s", greeting: 'Hello')
|
|
113
|
+
# sprintf("%<greeting>s", greeting: 'Hello')
|
|
114
|
+
# "%<greeting>s" % { greeting: 'Hello' }
|
|
115
|
+
#
|
|
93
116
|
# @example Mode: conservative, EnforcedStyle: annotated
|
|
94
|
-
# # In `conservative` mode, offenses are only registered for strings
|
|
95
|
-
# # given to a known formatting method.
|
|
96
117
|
#
|
|
97
118
|
# # good
|
|
98
119
|
# "%{greeting}"
|
|
@@ -104,6 +125,12 @@ module RuboCop
|
|
|
104
125
|
# sprintf("%{greeting}", greeting: 'Hello')
|
|
105
126
|
# "%{greeting}" % { greeting: 'Hello' }
|
|
106
127
|
#
|
|
128
|
+
# # good
|
|
129
|
+
# format("%<greeting>s", greeting: 'Hello')
|
|
130
|
+
# printf("%<greeting>s", greeting: 'Hello')
|
|
131
|
+
# sprintf("%<greeting>s", greeting: 'Hello')
|
|
132
|
+
# "%<greeting>s" % { greeting: 'Hello' }
|
|
133
|
+
#
|
|
107
134
|
class FormatStringToken < Base
|
|
108
135
|
include ConfigurableEnforcedStyle
|
|
109
136
|
include AllowedMethods
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Looks for uses of global variables.
|
|
6
|
+
# Looks for uses of global variables. Global variables introduce
|
|
7
|
+
# shared mutable state that makes code harder to test, debug,
|
|
8
|
+
# and reason about, since any part of the program can read or modify them.
|
|
9
|
+
#
|
|
7
10
|
# It does not report offenses for built-in global variables.
|
|
8
11
|
# Built-in global variables are allowed by default. Additionally
|
|
9
12
|
# users can allow additional variables via the AllowedVariables option.
|
|
@@ -54,7 +57,7 @@ module RuboCop
|
|
|
54
57
|
].map(&:to_sym)
|
|
55
58
|
|
|
56
59
|
def user_vars
|
|
57
|
-
cop_config['AllowedVariables'].map(&:to_sym)
|
|
60
|
+
@user_vars ||= cop_config['AllowedVariables'].map(&:to_sym).freeze
|
|
58
61
|
end
|
|
59
62
|
|
|
60
63
|
def allowed_var?(global_var)
|
|
@@ -224,15 +224,18 @@ module RuboCop
|
|
|
224
224
|
end
|
|
225
225
|
|
|
226
226
|
def find_heredoc_argument(node)
|
|
227
|
-
return unless node
|
|
227
|
+
return unless node
|
|
228
228
|
|
|
229
|
-
|
|
229
|
+
node = node.children.first while node.begin_type?
|
|
230
|
+
return node if heredoc?(node)
|
|
231
|
+
return unless node.call_type?
|
|
230
232
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
find_heredoc_argument(last_arg)
|
|
233
|
+
node.arguments.reverse_each do |argument|
|
|
234
|
+
heredoc_argument = find_heredoc_argument(argument)
|
|
235
|
+
return heredoc_argument if heredoc_argument
|
|
235
236
|
end
|
|
237
|
+
|
|
238
|
+
find_heredoc_argument(node.receiver)
|
|
236
239
|
end
|
|
237
240
|
|
|
238
241
|
def autocorrect_heredoc_argument(corrector, node, heredoc_node, leave_branch, guard)
|
|
@@ -6,8 +6,13 @@ module RuboCop
|
|
|
6
6
|
# Checks for presence or absence of braces around hash literal as a last
|
|
7
7
|
# array item depending on configuration.
|
|
8
8
|
#
|
|
9
|
-
# NOTE: This cop will ignore arrays where
|
|
10
|
-
# EnforcedStyle
|
|
9
|
+
# NOTE: This cop will ignore arrays where multiple items are all hashes,
|
|
10
|
+
# regardless of `EnforcedStyle`.
|
|
11
|
+
#
|
|
12
|
+
# [source,ruby]
|
|
13
|
+
# ----
|
|
14
|
+
# [{ one: 1 }, { two: 2 }]
|
|
15
|
+
# ----
|
|
11
16
|
#
|
|
12
17
|
# @example EnforcedStyle: braces (default)
|
|
13
18
|
# # bad
|
|
@@ -16,8 +21,11 @@ module RuboCop
|
|
|
16
21
|
# # good
|
|
17
22
|
# [1, 2, { one: 1, two: 2 }]
|
|
18
23
|
#
|
|
24
|
+
# # bad
|
|
25
|
+
# [one: 1, two: 2]
|
|
26
|
+
#
|
|
19
27
|
# # good
|
|
20
|
-
# [{ one: 1
|
|
28
|
+
# [{ one: 1, two: 2 }]
|
|
21
29
|
#
|
|
22
30
|
# @example EnforcedStyle: no_braces
|
|
23
31
|
# # bad
|
|
@@ -26,8 +34,11 @@ module RuboCop
|
|
|
26
34
|
# # good
|
|
27
35
|
# [1, 2, one: 1, two: 2]
|
|
28
36
|
#
|
|
37
|
+
# # bad
|
|
38
|
+
# [{ one: 1, two: 2 }]
|
|
39
|
+
#
|
|
29
40
|
# # good
|
|
30
|
-
# [
|
|
41
|
+
# [one: 1, two: 2]
|
|
31
42
|
class HashAsLastArrayItem < Base
|
|
32
43
|
include RangeHelp
|
|
33
44
|
include ConfigurableEnforcedStyle
|
|
@@ -69,7 +80,12 @@ module RuboCop
|
|
|
69
80
|
return if node.braces?
|
|
70
81
|
|
|
71
82
|
add_offense(node, message: 'Wrap hash in `{` and `}`.') do |corrector|
|
|
72
|
-
|
|
83
|
+
if node.single_line? || same_line?(node, node.parent)
|
|
84
|
+
corrector.wrap(node, '{', '}')
|
|
85
|
+
else
|
|
86
|
+
indent = indent(node)
|
|
87
|
+
corrector.wrap(node, "{\n#{indent}", "\n#{indent}}")
|
|
88
|
+
end
|
|
73
89
|
end
|
|
74
90
|
end
|
|
75
91
|
|
|
@@ -41,8 +41,13 @@ module RuboCop
|
|
|
41
41
|
# # good
|
|
42
42
|
# hash.fetch(key)
|
|
43
43
|
#
|
|
44
|
+
# @example AllowedReceivers: ['Rails.cache']
|
|
45
|
+
# # good
|
|
46
|
+
# Rails.cache.fetch(name, options) { block }
|
|
47
|
+
#
|
|
44
48
|
class HashLookupMethod < Base
|
|
45
49
|
include ConfigurableEnforcedStyle
|
|
50
|
+
include AllowedReceivers
|
|
46
51
|
extend AutoCorrector
|
|
47
52
|
|
|
48
53
|
BRACKET_MSG = 'Use `Hash#[]` instead of `Hash#fetch`.'
|
|
@@ -51,6 +56,8 @@ module RuboCop
|
|
|
51
56
|
RESTRICT_ON_SEND = %i[[] fetch].freeze
|
|
52
57
|
|
|
53
58
|
def on_send(node)
|
|
59
|
+
return if (receiver = node.receiver) && allowed_receiver?(receiver)
|
|
60
|
+
|
|
54
61
|
if offense_for_brackets?(node)
|
|
55
62
|
add_offense(node.loc.selector, message: BRACKET_MSG) do |corrector|
|
|
56
63
|
correct_fetch_to_brackets(corrector, node)
|
|
@@ -75,18 +82,23 @@ module RuboCop
|
|
|
75
82
|
end
|
|
76
83
|
|
|
77
84
|
def correct_fetch_to_brackets(corrector, node)
|
|
78
|
-
receiver = node.receiver.source
|
|
79
85
|
key = node.first_argument.source
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
86
|
+
|
|
87
|
+
if node.csend_type?
|
|
88
|
+
corrector.replace(node, "(#{node.receiver.source}[#{key}])")
|
|
89
|
+
else
|
|
90
|
+
corrector.replace(node.loc.dot.join(node.source_range.end), "[#{key}]")
|
|
91
|
+
end
|
|
83
92
|
end
|
|
84
93
|
|
|
85
94
|
def correct_brackets_to_fetch(corrector, node)
|
|
86
|
-
receiver = node.receiver.source
|
|
87
95
|
key = node.first_argument.source
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
|
|
97
|
+
if node.csend_type?
|
|
98
|
+
corrector.replace(node.loc.dot.join(node.source_range.end), "&.fetch(#{key})")
|
|
99
|
+
else
|
|
100
|
+
corrector.replace(node.loc.selector.join(node.source_range.end), ".fetch(#{key})")
|
|
101
|
+
end
|
|
90
102
|
end
|
|
91
103
|
end
|
|
92
104
|
end
|
|
@@ -11,9 +11,11 @@ module RuboCop
|
|
|
11
11
|
# (`transform_keys` was added in Ruby 2.5.)
|
|
12
12
|
#
|
|
13
13
|
# @safety
|
|
14
|
-
# This cop
|
|
15
|
-
#
|
|
16
|
-
#
|
|
14
|
+
# This cop identifies the receiver as a hash by checking for literal hash
|
|
15
|
+
# syntax and common methods that are known to return hashes (e.g. `to_h`,
|
|
16
|
+
# `merge`, `invert`, `group_by`, etc.). However, it is unsafe because it
|
|
17
|
+
# is possible for a custom class to define one of these methods and return
|
|
18
|
+
# something other than a hash.
|
|
17
19
|
#
|
|
18
20
|
# @example
|
|
19
21
|
# # bad
|
|
@@ -21,10 +23,18 @@ module RuboCop
|
|
|
21
23
|
# Hash[{a: 1, b: 2}.collect { |k, v| [foo(k), v] }]
|
|
22
24
|
# {a: 1, b: 2}.map { |k, v| [k.to_s, v] }.to_h
|
|
23
25
|
# {a: 1, b: 2}.to_h { |k, v| [k.to_s, v] }
|
|
26
|
+
# foo.to_h.each_with_object({}) { |(k, v), h| h[k.to_sym] = v }
|
|
27
|
+
# foo.merge(bar).map { |k, v| [k.to_s, v] }.to_h
|
|
24
28
|
#
|
|
25
29
|
# # good
|
|
26
30
|
# {a: 1, b: 2}.transform_keys { |k| foo(k) }
|
|
27
31
|
# {a: 1, b: 2}.transform_keys { |k| k.to_s }
|
|
32
|
+
# foo.to_h.transform_keys { |k| k.to_sym }
|
|
33
|
+
# foo.merge(bar).transform_keys { |k| k.to_s }
|
|
34
|
+
#
|
|
35
|
+
# # Won't register an offense - receiver is not known to be a hash
|
|
36
|
+
# foo.bar.each_with_object({}) { |(k, v), h| h[k.to_s] = v }
|
|
37
|
+
# baz.map { |k, v| [k.to_s, v] }.to_h
|
|
28
38
|
class HashTransformKeys < Base
|
|
29
39
|
include HashTransformMethod
|
|
30
40
|
extend AutoCorrector
|
|
@@ -35,7 +45,7 @@ module RuboCop
|
|
|
35
45
|
# @!method on_bad_each_with_object(node)
|
|
36
46
|
def_node_matcher :on_bad_each_with_object, <<~PATTERN
|
|
37
47
|
(block
|
|
38
|
-
(call
|
|
48
|
+
(call #hash_receiver? :each_with_object (hash))
|
|
39
49
|
(args
|
|
40
50
|
(mlhs
|
|
41
51
|
(arg $_)
|
|
@@ -50,7 +60,7 @@ module RuboCop
|
|
|
50
60
|
(const _ :Hash)
|
|
51
61
|
:[]
|
|
52
62
|
(block
|
|
53
|
-
(call
|
|
63
|
+
(call #hash_receiver? {:map :collect})
|
|
54
64
|
(args
|
|
55
65
|
(arg $_)
|
|
56
66
|
(arg _val))
|
|
@@ -61,7 +71,7 @@ module RuboCop
|
|
|
61
71
|
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
|
62
72
|
(call
|
|
63
73
|
(block
|
|
64
|
-
(call
|
|
74
|
+
(call #hash_receiver? {:map :collect})
|
|
65
75
|
(args
|
|
66
76
|
(arg $_)
|
|
67
77
|
(arg _val))
|
|
@@ -72,7 +82,7 @@ module RuboCop
|
|
|
72
82
|
# @!method on_bad_to_h(node)
|
|
73
83
|
def_node_matcher :on_bad_to_h, <<~PATTERN
|
|
74
84
|
(block
|
|
75
|
-
(call
|
|
85
|
+
(call #hash_receiver? :to_h)
|
|
76
86
|
(args
|
|
77
87
|
(arg $_)
|
|
78
88
|
(arg _val))
|
|
@@ -9,9 +9,11 @@ module RuboCop
|
|
|
9
9
|
# call to `transform_values` instead.
|
|
10
10
|
#
|
|
11
11
|
# @safety
|
|
12
|
-
# This cop
|
|
13
|
-
#
|
|
14
|
-
#
|
|
12
|
+
# This cop identifies the receiver as a hash by checking for literal hash
|
|
13
|
+
# syntax and common methods that are known to return hashes (e.g. `to_h`,
|
|
14
|
+
# `merge`, `invert`, `group_by`, etc.). However, it is unsafe because it
|
|
15
|
+
# is possible for a custom class to define one of these methods and return
|
|
16
|
+
# something other than a hash.
|
|
15
17
|
#
|
|
16
18
|
# @example
|
|
17
19
|
# # bad
|
|
@@ -19,10 +21,18 @@ module RuboCop
|
|
|
19
21
|
# Hash[{a: 1, b: 2}.collect { |k, v| [k, foo(v)] }]
|
|
20
22
|
# {a: 1, b: 2}.map { |k, v| [k, v * v] }.to_h
|
|
21
23
|
# {a: 1, b: 2}.to_h { |k, v| [k, v * v] }
|
|
24
|
+
# foo.to_h.each_with_object({}) { |(k, v), h| h[k] = foo(v) }
|
|
25
|
+
# foo.merge(bar).map { |k, v| [k, v.to_s] }.to_h
|
|
22
26
|
#
|
|
23
27
|
# # good
|
|
24
28
|
# {a: 1, b: 2}.transform_values { |v| foo(v) }
|
|
25
29
|
# {a: 1, b: 2}.transform_values { |v| v * v }
|
|
30
|
+
# foo.to_h.transform_values { |v| foo(v) }
|
|
31
|
+
# foo.merge(bar).transform_values { |v| v.to_s }
|
|
32
|
+
#
|
|
33
|
+
# # Won't register an offense - receiver is not known to be a hash
|
|
34
|
+
# foo.bar.each_with_object({}) { |(k, v), h| h[k] = v.to_s }
|
|
35
|
+
# baz.map { |k, v| [k, v.to_s] }.to_h
|
|
26
36
|
class HashTransformValues < Base
|
|
27
37
|
include HashTransformMethod
|
|
28
38
|
extend AutoCorrector
|
|
@@ -33,7 +43,7 @@ module RuboCop
|
|
|
33
43
|
# @!method on_bad_each_with_object(node)
|
|
34
44
|
def_node_matcher :on_bad_each_with_object, <<~PATTERN
|
|
35
45
|
(block
|
|
36
|
-
(call
|
|
46
|
+
(call #hash_receiver? :each_with_object (hash))
|
|
37
47
|
(args
|
|
38
48
|
(mlhs
|
|
39
49
|
(arg _key)
|
|
@@ -48,7 +58,7 @@ module RuboCop
|
|
|
48
58
|
(const _ :Hash)
|
|
49
59
|
:[]
|
|
50
60
|
(block
|
|
51
|
-
(call
|
|
61
|
+
(call #hash_receiver? {:map :collect})
|
|
52
62
|
(args
|
|
53
63
|
(arg _key)
|
|
54
64
|
(arg $_))
|
|
@@ -59,7 +69,7 @@ module RuboCop
|
|
|
59
69
|
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
|
60
70
|
(call
|
|
61
71
|
(block
|
|
62
|
-
(call
|
|
72
|
+
(call #hash_receiver? {:map :collect})
|
|
63
73
|
(args
|
|
64
74
|
(arg _key)
|
|
65
75
|
(arg $_))
|
|
@@ -70,7 +80,7 @@ module RuboCop
|
|
|
70
80
|
# @!method on_bad_to_h(node)
|
|
71
81
|
def_node_matcher :on_bad_to_h, <<~PATTERN
|
|
72
82
|
(block
|
|
73
|
-
(call
|
|
83
|
+
(call #hash_receiver? :to_h)
|
|
74
84
|
(args
|
|
75
85
|
(arg _key)
|
|
76
86
|
(arg $_))
|
|
@@ -64,7 +64,7 @@ module RuboCop
|
|
|
64
64
|
|
|
65
65
|
MSG = 'Convert `if` nested inside `else` to `elsif`.'
|
|
66
66
|
|
|
67
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
|
67
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
68
68
|
def on_if(node)
|
|
69
69
|
return if node.ternary? || node.unless?
|
|
70
70
|
|
|
@@ -72,6 +72,7 @@ module RuboCop
|
|
|
72
72
|
|
|
73
73
|
return unless else_branch&.if_type? && else_branch.if?
|
|
74
74
|
return if allow_if_modifier_in_else_branch?(else_branch)
|
|
75
|
+
return if comments_between_else_and_if?(node, else_branch)
|
|
75
76
|
|
|
76
77
|
add_offense(else_branch.loc.keyword) do |corrector|
|
|
77
78
|
next if part_of_ignored_node?(node)
|
|
@@ -80,12 +81,12 @@ module RuboCop
|
|
|
80
81
|
ignore_node(node)
|
|
81
82
|
end
|
|
82
83
|
end
|
|
83
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
|
84
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
84
85
|
|
|
85
86
|
private
|
|
86
87
|
|
|
87
88
|
def autocorrect(corrector, node)
|
|
88
|
-
if then?
|
|
89
|
+
if node.then?
|
|
89
90
|
# If the nested `if` is a then node, correct it first,
|
|
90
91
|
# then the next pass will use `correct_to_elsif_from_if_inside_else_form`
|
|
91
92
|
IfThenCorrector.new(node, indentation: 0).call(corrector)
|
|
@@ -124,10 +125,6 @@ module RuboCop
|
|
|
124
125
|
corrector.remove(range_by_whole_lines(find_end_range(node), include_final_newline: true))
|
|
125
126
|
end
|
|
126
127
|
|
|
127
|
-
def then?(node)
|
|
128
|
-
node.loc.begin&.source == 'then'
|
|
129
|
-
end
|
|
130
|
-
|
|
131
128
|
def find_end_range(node)
|
|
132
129
|
end_range = node.loc.end
|
|
133
130
|
return end_range if end_range
|
|
@@ -139,6 +136,18 @@ module RuboCop
|
|
|
139
136
|
range_between(node.loc.keyword.begin_pos, condition.source_range.end_pos)
|
|
140
137
|
end
|
|
141
138
|
|
|
139
|
+
def comments_between_else_and_if?(node, else_branch)
|
|
140
|
+
return false if else_branch.modifier_form?
|
|
141
|
+
|
|
142
|
+
else_end = node.loc.else.end_pos
|
|
143
|
+
if_begin = else_branch.loc.keyword.begin_pos
|
|
144
|
+
|
|
145
|
+
processed_source.comments.any? do |comment|
|
|
146
|
+
comment_pos = comment.source_range.begin_pos
|
|
147
|
+
comment_pos > else_end && comment_pos < if_begin
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
142
151
|
def allow_if_modifier_in_else_branch?(else_branch)
|
|
143
152
|
allow_if_modifier? && else_branch&.modifier_form?
|
|
144
153
|
end
|
|
@@ -89,9 +89,9 @@ module RuboCop
|
|
|
89
89
|
[Style::SoleNestedConditional]
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
# rubocop:disable Metrics/AbcSize
|
|
92
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
93
93
|
def on_if(node)
|
|
94
|
-
return if endless_method?(node.body)
|
|
94
|
+
return if endless_method?(node.body) || node.ancestors.any?(&:dstr_type?)
|
|
95
95
|
|
|
96
96
|
condition = node.condition
|
|
97
97
|
return if defined_nodes(condition).any? { |n| defined_argument_is_undefined?(node, n) } ||
|
|
@@ -101,12 +101,13 @@ module RuboCop
|
|
|
101
101
|
|
|
102
102
|
add_offense(node.loc.keyword, message: format(msg, keyword: node.keyword)) do |corrector|
|
|
103
103
|
next if part_of_ignored_node?(node)
|
|
104
|
+
next if another_modifier_if_on_same_line?(node)
|
|
104
105
|
|
|
105
106
|
autocorrect(corrector, node)
|
|
106
107
|
ignore_node(node)
|
|
107
108
|
end
|
|
108
109
|
end
|
|
109
|
-
# rubocop:enable Metrics/AbcSize
|
|
110
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
110
111
|
|
|
111
112
|
private
|
|
112
113
|
|
|
@@ -280,6 +281,16 @@ module RuboCop
|
|
|
280
281
|
node.parent if node&.type?(:pair)
|
|
281
282
|
end
|
|
282
283
|
|
|
284
|
+
def another_modifier_if_on_same_line?(node)
|
|
285
|
+
collection = find_containing_collection(node)
|
|
286
|
+
return false unless collection
|
|
287
|
+
|
|
288
|
+
line = node.source_range.line
|
|
289
|
+
collection.each_descendant(:if).any? do |sibling|
|
|
290
|
+
sibling != node && sibling.modifier_form? && sibling.source_range.line == line
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
283
294
|
def non_simple_if_unless?(node)
|
|
284
295
|
node.ternary? || node.elsif? || node.else?
|
|
285
296
|
end
|
|
@@ -17,9 +17,9 @@ module RuboCop
|
|
|
17
17
|
include OnNormalIfUnless
|
|
18
18
|
extend AutoCorrector
|
|
19
19
|
|
|
20
|
-
MSG_IF_ELSE = 'Do not use
|
|
21
|
-
MSG_NEWLINE = 'Do not use
|
|
22
|
-
MSG_TERNARY = 'Do not use
|
|
20
|
+
MSG_IF_ELSE = 'Do not use `%<keyword>s %<expr>s;` - use `if/else` instead.'
|
|
21
|
+
MSG_NEWLINE = 'Do not use `%<keyword>s %<expr>s;` - use a newline instead.'
|
|
22
|
+
MSG_TERNARY = 'Do not use `%<keyword>s %<expr>s;` - use a ternary operator instead.'
|
|
23
23
|
|
|
24
24
|
def on_normal_if_unless(node)
|
|
25
25
|
return if node.parent&.if_type?
|
|
@@ -49,7 +49,7 @@ module RuboCop
|
|
|
49
49
|
MSG_TERNARY
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
format(template, expr: node.condition.source)
|
|
52
|
+
format(template, keyword: node.keyword, expr: node.condition.source)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def autocorrect(corrector, node)
|
|
@@ -71,7 +71,7 @@ module RuboCop
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def use_return_with_argument?(node)
|
|
74
|
-
node.
|
|
74
|
+
node.branches.compact.any? { |branch| branch.return_type? && branch.arguments.any? }
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def replacement(node)
|
|
@@ -80,6 +80,8 @@ module RuboCop
|
|
|
80
80
|
then_code = node.if_branch ? build_expression(node.if_branch) : 'nil'
|
|
81
81
|
else_code = node.else_branch ? build_expression(node.else_branch) : 'nil'
|
|
82
82
|
|
|
83
|
+
then_code, else_code = else_code, then_code if node.unless?
|
|
84
|
+
|
|
83
85
|
"#{node.condition.source} ? #{then_code} : #{else_code}"
|
|
84
86
|
end
|
|
85
87
|
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for trailing inline comments.
|
|
6
|
+
# Checks for trailing inline comments. Inline comments can
|
|
7
|
+
# make lines harder to read, especially when they are long.
|
|
8
|
+
# Placing comments on their own line above the code they
|
|
9
|
+
# describe is often clearer.
|
|
7
10
|
#
|
|
8
11
|
# @example
|
|
9
12
|
#
|
|
@@ -48,8 +48,7 @@ module RuboCop
|
|
|
48
48
|
private
|
|
49
49
|
|
|
50
50
|
def allowed_addresses
|
|
51
|
-
allowed_addresses
|
|
52
|
-
Array(allowed_addresses).map(&:downcase)
|
|
51
|
+
@allowed_addresses ||= Array(cop_config['AllowedAddresses']).map(&:downcase).freeze
|
|
53
52
|
end
|
|
54
53
|
|
|
55
54
|
def potential_ip?(str)
|
|
@@ -176,7 +176,7 @@ module RuboCop
|
|
|
176
176
|
if first_non_comment_token
|
|
177
177
|
0...first_non_comment_token.line
|
|
178
178
|
else
|
|
179
|
-
|
|
179
|
+
0..
|
|
180
180
|
end
|
|
181
181
|
end
|
|
182
182
|
|
|
@@ -299,7 +299,7 @@ module RuboCop
|
|
|
299
299
|
end
|
|
300
300
|
|
|
301
301
|
def supported_capitalizations
|
|
302
|
-
cop_config['SupportedCapitalizations'].map(&:to_sym)
|
|
302
|
+
@supported_capitalizations ||= cop_config['SupportedCapitalizations'].map(&:to_sym).freeze
|
|
303
303
|
end
|
|
304
304
|
end
|
|
305
305
|
end
|