rubocop 0.76.0 → 0.83.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.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +6 -6
- data/config/default.yml +466 -306
- data/lib/rubocop/ast/builder.rb +45 -42
- data/lib/rubocop/ast/node/array_node.rb +13 -0
- data/lib/rubocop/ast/node/block_node.rb +7 -1
- data/lib/rubocop/ast/node/case_match_node.rb +56 -0
- data/lib/rubocop/ast/node/def_node.rb +11 -0
- data/lib/rubocop/ast/node/forward_args_node.rb +18 -0
- data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +8 -0
- data/lib/rubocop/ast/node/regexp_node.rb +2 -4
- data/lib/rubocop/ast/node/send_node.rb +4 -0
- data/lib/rubocop/ast/node.rb +13 -20
- data/lib/rubocop/ast/traversal.rb +29 -10
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +105 -0
- data/lib/rubocop/cli/command/base.rb +33 -0
- data/lib/rubocop/cli/command/execute_runner.rb +76 -0
- data/lib/rubocop/cli/command/init_dotfile.rb +45 -0
- data/lib/rubocop/cli/command/show_cops.rb +80 -0
- data/lib/rubocop/cli/command/version.rb +17 -0
- data/lib/rubocop/cli/command.rb +21 -0
- data/lib/rubocop/cli/environment.rb +21 -0
- data/lib/rubocop/cli.rb +20 -233
- data/lib/rubocop/comment_config.rb +6 -1
- data/lib/rubocop/config.rb +41 -11
- data/lib/rubocop/config_loader.rb +54 -44
- data/lib/rubocop/config_loader_resolver.rb +28 -1
- data/lib/rubocop/config_obsoletion.rb +67 -11
- data/lib/rubocop/config_validator.rb +74 -99
- data/lib/rubocop/cop/autocorrect_logic.rb +7 -4
- data/lib/rubocop/cop/badge.rb +5 -5
- data/lib/rubocop/cop/bundler/gem_comment.rb +4 -4
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +3 -3
- data/lib/rubocop/cop/cop.rb +21 -0
- data/lib/rubocop/cop/corrector.rb +48 -24
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -2
- data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +3 -3
- data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/space_corrector.rb +1 -2
- data/lib/rubocop/cop/correctors/string_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/generator/configuration_injector.rb +1 -1
- data/lib/rubocop/cop/generator.rb +6 -6
- data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +59 -0
- data/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb +1 -1
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/{align_arguments.rb → argument_alignment.rb} +1 -1
- data/lib/rubocop/cop/layout/array_alignment.rb +82 -0
- data/lib/rubocop/cop/layout/{indent_assignment.rb → assignment_indentation.rb} +1 -1
- data/lib/rubocop/cop/layout/block_end_newline.rb +5 -3
- data/lib/rubocop/cop/layout/condition_position.rb +12 -2
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/else_alignment.rb +8 -0
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +68 -0
- data/lib/rubocop/cop/layout/end_of_line.rb +2 -2
- data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/{indent_first_argument.rb → first_argument_indentation.rb} +5 -5
- data/lib/rubocop/cop/layout/{indent_first_array_element.rb → first_array_element_indentation.rb} +20 -14
- data/lib/rubocop/cop/layout/{indent_first_hash_element.rb → first_hash_element_indentation.rb} +4 -4
- data/lib/rubocop/cop/layout/{indent_first_parameter.rb → first_parameter_indentation.rb} +3 -3
- data/lib/rubocop/cop/layout/{align_hash.rb → hash_alignment.rb} +10 -6
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/{indent_heredoc.rb → heredoc_indentation.rb} +7 -7
- data/lib/rubocop/cop/layout/{tab.rb → indentation_style.rb} +48 -6
- data/lib/rubocop/cop/layout/leading_comment_space.rb +34 -3
- data/lib/rubocop/cop/layout/{leading_blank_lines.rb → leading_empty_lines.rb} +1 -1
- data/lib/rubocop/cop/{metrics → layout}/line_length.rb +72 -110
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +15 -6
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +0 -4
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +13 -4
- data/lib/rubocop/cop/layout/{align_parameters.rb → parameter_alignment.rb} +1 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +3 -3
- data/lib/rubocop/cop/layout/space_around_keyword.rb +12 -0
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +133 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +69 -9
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +17 -0
- data/lib/rubocop/cop/layout/space_before_first_arg.rb +8 -0
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -2
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -9
- data/lib/rubocop/cop/layout/space_inside_range_literal.rb +2 -2
- data/lib/rubocop/cop/layout/{trailing_blank_lines.rb → trailing_empty_lines.rb} +1 -1
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +2 -2
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +38 -0
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +14 -0
- data/lib/rubocop/cop/lint/boolean_symbol.rb +12 -0
- data/lib/rubocop/cop/lint/debugger.rb +2 -2
- data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +1 -1
- data/lib/rubocop/cop/lint/{duplicated_key.rb → duplicate_hash_key.rb} +1 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -5
- data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -1
- data/lib/rubocop/cop/lint/empty_when.rb +29 -6
- data/lib/rubocop/cop/lint/ensure_return.rb +18 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -1
- data/lib/rubocop/cop/lint/inherit_exception.rb +1 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +1 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +10 -13
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/loop.rb +6 -4
- data/lib/rubocop/cop/lint/{multiple_compare.rb → multiple_comparison.rb} +2 -2
- data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +89 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +21 -9
- data/lib/rubocop/cop/lint/percent_string_array.rb +2 -2
- data/lib/rubocop/cop/lint/raise_exception.rb +75 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +4 -9
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +13 -8
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -1
- data/lib/rubocop/cop/lint/{string_conversion_in_interpolation.rb → redundant_string_coercion.rb} +2 -2
- data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +58 -0
- data/lib/rubocop/cop/lint/{handle_exceptions.rb → suppressed_exception.rb} +13 -29
- data/lib/rubocop/cop/lint/unified_integer.rb +0 -2
- data/lib/rubocop/cop/lint/unused_method_argument.rb +32 -6
- data/lib/rubocop/cop/lint/uri_regexp.rb +4 -4
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +69 -23
- data/lib/rubocop/cop/lint/useless_assignment.rb +3 -2
- data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +5 -0
- data/lib/rubocop/cop/lint/useless_setter_call.rb +5 -1
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/migration/department_name.rb +47 -6
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +4 -0
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +6 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +14 -5
- data/lib/rubocop/cop/mixin/{hash_alignment.rb → hash_alignment_styles.rb} +1 -1
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +178 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +89 -0
- data/lib/rubocop/cop/mixin/method_complexity.rb +5 -0
- data/lib/rubocop/cop/mixin/nil_methods.rb +4 -4
- data/lib/rubocop/cop/mixin/parser_diagnostic.rb +1 -1
- data/lib/rubocop/cop/mixin/rational_literal.rb +18 -0
- data/lib/rubocop/cop/mixin/statement_modifier.rb +9 -24
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +5 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +9 -13
- data/lib/rubocop/cop/naming/{uncommunicative_block_param_name.rb → block_parameter_name.rb} +3 -3
- data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +1 -1
- data/lib/rubocop/cop/naming/constant_name.rb +2 -1
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +6 -6
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/method_name.rb +26 -0
- data/lib/rubocop/cop/naming/{uncommunicative_method_param_name.rb → method_parameter_name.rb} +4 -4
- data/lib/rubocop/cop/naming/predicate_name.rb +6 -6
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +11 -0
- data/lib/rubocop/cop/registry.rb +15 -3
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -6
- data/lib/rubocop/cop/style/alias.rb +5 -5
- data/lib/rubocop/cop/style/and_or.rb +5 -6
- data/lib/rubocop/cop/style/array_join.rb +2 -2
- data/lib/rubocop/cop/style/attr.rb +8 -0
- data/lib/rubocop/cop/style/block_delimiters.rb +60 -1
- data/lib/rubocop/cop/style/case_equality.rb +24 -1
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/collection_methods.rb +2 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +10 -10
- data/lib/rubocop/cop/style/copyright.rb +1 -1
- data/lib/rubocop/cop/style/dir.rb +1 -1
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -0
- data/lib/rubocop/cop/style/documentation.rb +43 -5
- data/lib/rubocop/cop/style/double_cop_disable_directive.rb +1 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +3 -3
- data/lib/rubocop/cop/style/empty_method.rb +1 -5
- data/lib/rubocop/cop/style/end_block.rb +6 -0
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/even_odd.rb +2 -2
- data/lib/rubocop/cop/style/expand_path_arguments.rb +3 -3
- data/lib/rubocop/cop/style/exponential_notation.rb +119 -0
- data/lib/rubocop/cop/style/format_string.rb +2 -2
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +89 -11
- data/lib/rubocop/cop/style/guard_clause.rb +28 -4
- data/lib/rubocop/cop/style/hash_each_methods.rb +89 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +3 -5
- data/lib/rubocop/cop/style/hash_transform_keys.rb +83 -0
- data/lib/rubocop/cop/style/hash_transform_values.rb +80 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +61 -6
- data/lib/rubocop/cop/style/if_with_semicolon.rb +16 -0
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +9 -5
- data/lib/rubocop/cop/style/ip_addresses.rb +4 -4
- data/lib/rubocop/cop/style/lambda.rb +3 -2
- data/lib/rubocop/cop/style/lambda_call.rb +1 -21
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +169 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +54 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -205
- data/lib/rubocop/cop/style/mixin_grouping.rb +2 -2
- data/lib/rubocop/cop/style/module_function.rb +58 -12
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +1 -1
- data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -1
- data/lib/rubocop/cop/style/multiline_when_then.rb +21 -2
- data/lib/rubocop/cop/style/mutable_constant.rb +2 -4
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +9 -9
- data/lib/rubocop/cop/style/next.rb +7 -7
- data/lib/rubocop/cop/style/nil_comparison.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +4 -4
- data/lib/rubocop/cop/style/not.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literals.rb +8 -4
- data/lib/rubocop/cop/style/numeric_predicate.rb +5 -4
- data/lib/rubocop/cop/style/one_line_conditional.rb +4 -3
- data/lib/rubocop/cop/style/option_hash.rb +3 -3
- data/lib/rubocop/cop/style/optional_arguments.rb +1 -1
- data/lib/rubocop/cop/style/or_assignment.rb +4 -3
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +7 -7
- data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
- data/lib/rubocop/cop/style/perl_backrefs.rb +2 -2
- data/lib/rubocop/cop/style/proc.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
- data/lib/rubocop/cop/style/redundant_condition.rb +18 -6
- data/lib/rubocop/cop/style/redundant_conditional.rb +1 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +3 -3
- data/lib/rubocop/cop/style/redundant_interpolation.rb +2 -2
- data/lib/rubocop/cop/style/redundant_parentheses.rb +3 -3
- data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -2
- data/lib/rubocop/cop/style/redundant_return.rb +7 -15
- data/lib/rubocop/cop/style/redundant_self.rb +1 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +3 -3
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
- data/lib/rubocop/cop/style/return_nil.rb +1 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/slicing_with_range.rb +39 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -4
- data/lib/rubocop/cop/style/string_hash_keys.rb +1 -1
- data/lib/rubocop/cop/style/symbol_array.rb +3 -3
- data/lib/rubocop/cop/style/symbol_literal.rb +2 -2
- data/lib/rubocop/cop/style/ternary_parentheses.rb +2 -3
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +35 -22
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +41 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +88 -0
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +44 -0
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +7 -1
- data/lib/rubocop/cop/style/trivial_accessors.rb +6 -6
- data/lib/rubocop/cop/style/unpack_first.rb +0 -4
- data/lib/rubocop/cop/style/variable_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/while_until_modifier.rb +2 -2
- data/lib/rubocop/cop/style/word_array.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +16 -1
- data/lib/rubocop/cop/style/zero_length_predicate.rb +1 -1
- data/lib/rubocop/cop/team.rb +5 -0
- data/lib/rubocop/cop/util.rb +24 -0
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -0
- data/lib/rubocop/cop/variable_force/scope.rb +1 -0
- data/lib/rubocop/cop/variable_force/variable.rb +1 -0
- data/lib/rubocop/cop/variable_force.rb +4 -1
- data/lib/rubocop/formatter/base_formatter.rb +2 -2
- data/lib/rubocop/formatter/clang_style_formatter.rb +0 -2
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/formatter/json_formatter.rb +6 -5
- data/lib/rubocop/formatter/junit_formatter.rb +74 -0
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
- data/lib/rubocop/formatter/tap_formatter.rb +0 -2
- data/lib/rubocop/name_similarity.rb +12 -9
- data/lib/rubocop/node_pattern.rb +97 -11
- data/lib/rubocop/options.rb +26 -13
- data/lib/rubocop/processed_source.rb +1 -4
- data/lib/rubocop/rake_task.rb +1 -0
- data/lib/rubocop/result_cache.rb +23 -7
- data/lib/rubocop/rspec/cop_helper.rb +1 -1
- data/lib/rubocop/rspec/expect_offense.rb +1 -1
- data/lib/rubocop/rspec/shared_contexts.rb +5 -4
- data/lib/rubocop/runner.rb +25 -4
- data/lib/rubocop/target_finder.rb +6 -4
- data/lib/rubocop/target_ruby.rb +151 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +53 -27
- metadata +73 -48
- data/lib/rubocop/cop/layout/align_array.rb +0 -39
- data/lib/rubocop/cop/lint/end_in_method.rb +0 -40
- data/lib/rubocop/cop/mixin/safe_mode.rb +0 -24
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +0 -209
- data/lib/rubocop/formatter/disabled_lines_formatter.rb +0 -57
- data/lib/rubocop/string_util.rb +0 -14
data/lib/rubocop/node_pattern.rb
CHANGED
@@ -78,6 +78,8 @@ module RuboCop
|
|
78
78
|
# # matching process starts
|
79
79
|
# '^^send' # each ^ ascends one level in the AST
|
80
80
|
# # so this matches against the grandparent node
|
81
|
+
# '`send' # descends any number of level in the AST
|
82
|
+
# # so this matches against any descendant node
|
81
83
|
# '#method' # we call this a 'funcall'; it calls a method in the
|
82
84
|
# # context where a pattern-matching method is defined
|
83
85
|
# # if that returns a truthy value, the match succeeds
|
@@ -112,7 +114,7 @@ module RuboCop
|
|
112
114
|
SYMBOL = %r{:(?:[\w+@*/?!<>=~|%^-]+|\[\]=?)}.freeze
|
113
115
|
IDENTIFIER = /[a-zA-Z_][a-zA-Z0-9_-]*/.freeze
|
114
116
|
META = Regexp.union(
|
115
|
-
%w"( ) { } [ ] $< < > $... $ ! ^ ... + * ?"
|
117
|
+
%w"( ) { } [ ] $< < > $... $ ! ^ ` ... + * ?"
|
116
118
|
).freeze
|
117
119
|
NUMBER = /-?\d+(?:\.\d+)?/.freeze
|
118
120
|
STRING = /".+?"/.freeze
|
@@ -188,7 +190,7 @@ module RuboCop
|
|
188
190
|
|
189
191
|
@temps = 0 # avoid name clashes between temp variables
|
190
192
|
@captures = 0 # number of captures seen
|
191
|
-
@unify = {} # named wildcard -> temp variable
|
193
|
+
@unify = {} # named wildcard -> temp variable
|
192
194
|
@params = 0 # highest % (param) number seen
|
193
195
|
run(node_var)
|
194
196
|
end
|
@@ -223,6 +225,7 @@ module RuboCop
|
|
223
225
|
when '!' then compile_negation
|
224
226
|
when '$' then compile_capture
|
225
227
|
when '^' then compile_ascend
|
228
|
+
when '`' then compile_descend
|
226
229
|
when WILDCARD then compile_wildcard(token[1..-1])
|
227
230
|
when FUNCALL then compile_funcall(token)
|
228
231
|
when LITERAL then compile_literal(token)
|
@@ -380,7 +383,7 @@ module RuboCop
|
|
380
383
|
def compile_seq_head
|
381
384
|
return unless seq_head?
|
382
385
|
|
383
|
-
fail_due_to 'sequences
|
386
|
+
fail_due_to 'sequences cannot start with <' \
|
384
387
|
if @terms[0].respond_to? :call
|
385
388
|
|
386
389
|
with_seq_head_context(@terms[0])
|
@@ -466,12 +469,67 @@ module RuboCop
|
|
466
469
|
end
|
467
470
|
end
|
468
471
|
|
472
|
+
def access_unify(name)
|
473
|
+
var = @unify[name]
|
474
|
+
|
475
|
+
if var == :forbidden_unification
|
476
|
+
fail_due_to "Wildcard #{name} was first seen in a subset of a" \
|
477
|
+
" union and can't be used outside that union"
|
478
|
+
end
|
479
|
+
var
|
480
|
+
end
|
481
|
+
|
482
|
+
def forbid_unification(*names)
|
483
|
+
names.each do |name|
|
484
|
+
@unify[name] = :forbidden_unification
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
489
|
+
def unify_in_union(enum)
|
490
|
+
# We need to reset @unify before each branch is processed.
|
491
|
+
# Moreover we need to keep track of newly encountered wildcards.
|
492
|
+
# Var `new_unify_intersection` will hold those that are encountered
|
493
|
+
# in all branches; these are not a problem.
|
494
|
+
# Var `partial_unify` will hold those encountered in only a subset
|
495
|
+
# of the branches; these can't be used outside of the union.
|
496
|
+
|
497
|
+
return to_enum __method__, enum unless block_given?
|
498
|
+
|
499
|
+
new_unify_intersection = nil
|
500
|
+
partial_unify = []
|
501
|
+
unify_before = @unify.dup
|
502
|
+
|
503
|
+
result = enum.each do |e|
|
504
|
+
@unify = unify_before.dup if new_unify_intersection
|
505
|
+
yield e
|
506
|
+
new_unify = @unify.keys - unify_before.keys
|
507
|
+
if new_unify_intersection.nil?
|
508
|
+
# First iteration
|
509
|
+
new_unify_intersection = new_unify
|
510
|
+
else
|
511
|
+
union = new_unify_intersection | new_unify
|
512
|
+
new_unify_intersection &= new_unify
|
513
|
+
partial_unify |= union - new_unify_intersection
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
# At this point, all members of `new_unify_intersection` can be used
|
518
|
+
# for unification outside of the union, but partial_unify may not
|
519
|
+
|
520
|
+
forbid_unification(*partial_unify)
|
521
|
+
|
522
|
+
result
|
523
|
+
end
|
524
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
525
|
+
|
469
526
|
def compile_union
|
470
527
|
# we need to ensure that each branch of the {} contains the same
|
471
528
|
# number of captures (since only one branch of the {} can actually
|
472
529
|
# match, the same variables are used to hold the captures for each
|
473
530
|
# branch)
|
474
531
|
enum = tokens_until('}', 'union')
|
532
|
+
enum = unify_in_union(enum)
|
475
533
|
terms = insure_same_captures(enum, 'branch of {}')
|
476
534
|
.map { compile_expr }
|
477
535
|
|
@@ -496,6 +554,19 @@ module RuboCop
|
|
496
554
|
with_context("#{CUR_NODE} && #{compile_expr}", "#{CUR_NODE}.parent")
|
497
555
|
end
|
498
556
|
|
557
|
+
def compile_descend
|
558
|
+
with_temp_variables do |descendant|
|
559
|
+
pattern = with_context(compile_expr, descendant,
|
560
|
+
use_temp_node: false)
|
561
|
+
[
|
562
|
+
"RuboCop::NodePattern.descend(#{CUR_ELEMENT}).",
|
563
|
+
"any? do |#{descendant}|",
|
564
|
+
" #{pattern}",
|
565
|
+
'end'
|
566
|
+
].join("\n")
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
499
570
|
def compile_wildcard(name)
|
500
571
|
if name.empty?
|
501
572
|
'true'
|
@@ -503,12 +574,12 @@ module RuboCop
|
|
503
574
|
# we have already seen a wildcard with this name before
|
504
575
|
# so the value it matched the first time will already be stored
|
505
576
|
# in a temp. check if this value matches the one stored in the temp
|
506
|
-
"#{CUR_ELEMENT} ==
|
577
|
+
"#{CUR_ELEMENT} == #{access_unify(name)}"
|
507
578
|
else
|
508
|
-
n = @unify[name] =
|
509
|
-
# double assign to
|
510
|
-
"(
|
511
|
-
"
|
579
|
+
n = @unify[name] = "unify_#{name.gsub('-', '__')}"
|
580
|
+
# double assign to avoid "assigned but unused variable"
|
581
|
+
"(#{n} = #{CUR_ELEMENT}; " \
|
582
|
+
"#{n} = #{n}; true)"
|
512
583
|
end
|
513
584
|
end
|
514
585
|
|
@@ -560,9 +631,8 @@ module RuboCop
|
|
560
631
|
def compile_arg(token)
|
561
632
|
case token
|
562
633
|
when WILDCARD then
|
563
|
-
name
|
564
|
-
|
565
|
-
"temp#{number}"
|
634
|
+
name = token[1..-1]
|
635
|
+
access_unify(name) || fail_due_to('invalid in arglist: ' + token)
|
566
636
|
when LITERAL then token
|
567
637
|
when PARAM then get_param(token[1..-1])
|
568
638
|
when CLOSING then fail_due_to("#{token} in invalid position")
|
@@ -796,6 +866,22 @@ module RuboCop
|
|
796
866
|
def to_s
|
797
867
|
"#<#{self.class} #{pattern}>"
|
798
868
|
end
|
869
|
+
|
870
|
+
# Yields its argument and any descendants, depth-first.
|
871
|
+
#
|
872
|
+
def self.descend(element, &block)
|
873
|
+
return to_enum(__method__, element) unless block_given?
|
874
|
+
|
875
|
+
yield element
|
876
|
+
|
877
|
+
if element.is_a?(::RuboCop::AST::Node)
|
878
|
+
element.children.each do |child|
|
879
|
+
descend(child, &block)
|
880
|
+
end
|
881
|
+
end
|
882
|
+
|
883
|
+
nil
|
884
|
+
end
|
799
885
|
end
|
800
886
|
end
|
801
887
|
# rubocop:enable Metrics/ClassLength, Metrics/CyclomaticComplexity
|
data/lib/rubocop/options.rb
CHANGED
@@ -83,6 +83,12 @@ module RuboCop
|
|
83
83
|
|
84
84
|
def add_cop_selection_csv_option(option, opts)
|
85
85
|
option(opts, "--#{option} [COP1,COP2,...]") do |list|
|
86
|
+
unless list
|
87
|
+
message = "--#{option} argument should be [COP1,COP2,...]."
|
88
|
+
|
89
|
+
raise OptionArgumentError, message
|
90
|
+
end
|
91
|
+
|
86
92
|
@options[:"#{option}"] =
|
87
93
|
if list.empty?
|
88
94
|
['']
|
@@ -97,6 +103,7 @@ module RuboCop
|
|
97
103
|
def add_configuration_options(opts)
|
98
104
|
option(opts, '-c', '--config FILE')
|
99
105
|
option(opts, '--force-exclusion')
|
106
|
+
option(opts, '--only-recognized-file-types')
|
100
107
|
option(opts, '--ignore-parent-exclusion')
|
101
108
|
option(opts, '--force-default-config')
|
102
109
|
add_auto_gen_options(opts)
|
@@ -154,6 +161,7 @@ module RuboCop
|
|
154
161
|
end
|
155
162
|
end
|
156
163
|
|
164
|
+
# rubocop:disable Metrics/MethodLength
|
157
165
|
def add_boolean_flags(opts)
|
158
166
|
option(opts, '-F', '--fail-fast')
|
159
167
|
option(opts, '-C', '--cache FLAG')
|
@@ -162,6 +170,8 @@ module RuboCop
|
|
162
170
|
option(opts, '-E', '--extra-details')
|
163
171
|
option(opts, '-S', '--display-style-guide')
|
164
172
|
option(opts, '-a', '--auto-correct')
|
173
|
+
option(opts, '--disable-pending-cops')
|
174
|
+
option(opts, '--enable-pending-cops')
|
165
175
|
option(opts, '--ignore-disable-comments')
|
166
176
|
|
167
177
|
option(opts, '--safe')
|
@@ -172,6 +182,7 @@ module RuboCop
|
|
172
182
|
option(opts, '-V', '--verbose-version')
|
173
183
|
option(opts, '-P', '--parallel')
|
174
184
|
end
|
185
|
+
# rubocop:enable Metrics/MethodLength
|
175
186
|
|
176
187
|
def add_aliases(opts)
|
177
188
|
option(opts, '-l', '--lint') do
|
@@ -237,10 +248,7 @@ module RuboCop
|
|
237
248
|
def format_message_from(name, cop_names)
|
238
249
|
message = 'Unrecognized cop or department: %<name>s.'
|
239
250
|
message_with_candidate = "%<message>s\nDid you mean? %<candidate>s"
|
240
|
-
corrections =
|
241
|
-
score = StringUtil.similarity(cn, name)
|
242
|
-
score >= NameSimilarity::MINIMUM_SIMILARITY_TO_SUGGEST
|
243
|
-
end.sort
|
251
|
+
corrections = NameSimilarity.find_similar_names(name, cop_names)
|
244
252
|
|
245
253
|
if corrections.empty?
|
246
254
|
format(message, name: name)
|
@@ -264,18 +272,18 @@ module RuboCop
|
|
264
272
|
# rubocop:disable Metrics/AbcSize
|
265
273
|
def validate_compatibility # rubocop:disable Metrics/MethodLength
|
266
274
|
if only_includes_redundant_disable?
|
267
|
-
raise OptionArgumentError, 'Lint/RedundantCopDisableDirective
|
268
|
-
'
|
275
|
+
raise OptionArgumentError, 'Lint/RedundantCopDisableDirective cannot ' \
|
276
|
+
'be used with --only.'
|
269
277
|
end
|
270
278
|
if except_syntax?
|
271
|
-
raise OptionArgumentError, 'Syntax checking
|
279
|
+
raise OptionArgumentError, 'Syntax checking cannot be turned off.'
|
272
280
|
end
|
273
281
|
unless boolean_or_empty_cache?
|
274
282
|
raise OptionArgumentError, '-C/--cache argument must be true or false'
|
275
283
|
end
|
276
284
|
|
277
285
|
if display_only_fail_level_offenses_with_autocorrect?
|
278
|
-
raise OptionArgumentError, '--autocorrect
|
286
|
+
raise OptionArgumentError, '--autocorrect cannot be used with ' \
|
279
287
|
'--display-only-fail-level-offenses'
|
280
288
|
end
|
281
289
|
validate_auto_gen_config
|
@@ -329,8 +337,8 @@ module RuboCop
|
|
329
337
|
auto_gen_config: '-P/--parallel uses caching to speed up execution, ' \
|
330
338
|
'while --auto-gen-config needs a non-cached run, ' \
|
331
339
|
'so they cannot be combined.',
|
332
|
-
fail_fast: '-P/--parallel
|
333
|
-
auto_correct: '-P/--parallel
|
340
|
+
fail_fast: '-P/--parallel cannot be combined with -F/--fail-fast.',
|
341
|
+
auto_correct: '-P/--parallel cannot be combined with --auto-correct.'
|
334
342
|
}
|
335
343
|
|
336
344
|
combos.each do |key, msg|
|
@@ -362,7 +370,7 @@ module RuboCop
|
|
362
370
|
end
|
363
371
|
|
364
372
|
def validate_exclude_limit_option
|
365
|
-
return if @options[:exclude_limit]
|
373
|
+
return if /^\d+$/.match?(@options[:exclude_limit])
|
366
374
|
|
367
375
|
# Emulate OptionParser's behavior to make failures consistent regardless
|
368
376
|
# of option order.
|
@@ -373,7 +381,7 @@ module RuboCop
|
|
373
381
|
# This module contains help texts for command line options.
|
374
382
|
module OptionsHelp
|
375
383
|
MAX_EXCL = RuboCop::Options::DEFAULT_MAXIMUM_EXCLUSION_ITEMS.to_s
|
376
|
-
# rubocop:disable
|
384
|
+
# rubocop:disable Layout/LineLength
|
377
385
|
FORMATTER_OPTION_LIST = RuboCop::Formatter::FormatterSet::BUILTIN_FORMATTERS_FOR_KEYS.keys
|
378
386
|
|
379
387
|
TEXT = {
|
@@ -405,6 +413,9 @@ module RuboCop
|
|
405
413
|
force_exclusion: ['Force excluding files specified in the',
|
406
414
|
'configuration `Exclude` even if they are',
|
407
415
|
'explicitly passed as arguments.'],
|
416
|
+
only_recognized_file_types: ['Inspect files given on the command line only if',
|
417
|
+
'they are listed in AllCops/Include parameters',
|
418
|
+
'of user configuration or default configuration.'],
|
408
419
|
ignore_disable_comments: ['Run cops even when they are disabled locally',
|
409
420
|
'with a comment.'],
|
410
421
|
ignore_parent_exclusion: ['Prevent from inheriting AllCops/Exclude from',
|
@@ -438,7 +449,9 @@ module RuboCop
|
|
438
449
|
debug: 'Display debug info.',
|
439
450
|
display_cop_names: ['Display cop names in offense messages.',
|
440
451
|
'Default is true.'],
|
452
|
+
disable_pending_cops: 'Run without pending cops.',
|
441
453
|
display_style_guide: 'Display style guide URLs in offense messages.',
|
454
|
+
enable_pending_cops: 'Run with pending cops.',
|
442
455
|
extra_details: 'Display extra details in offense messages.',
|
443
456
|
lint: 'Run only lint cops.',
|
444
457
|
safe: 'Run only safe cops.',
|
@@ -455,6 +468,6 @@ module RuboCop
|
|
455
468
|
'reports. This is useful for editor integration.'],
|
456
469
|
init: 'Generate a .rubocop.yml file in the current directory.'
|
457
470
|
}.freeze
|
458
|
-
# rubocop:enable
|
471
|
+
# rubocop:enable Layout/LineLength
|
459
472
|
end
|
460
473
|
end
|
@@ -163,7 +163,7 @@ module RuboCop
|
|
163
163
|
ast, comments, tokens = parser.tokenize(@buffer)
|
164
164
|
|
165
165
|
ast.respond_to?(:complete!) && ast.complete!
|
166
|
-
rescue Parser::SyntaxError
|
166
|
+
rescue Parser::SyntaxError
|
167
167
|
# All errors are in diagnostics. No need to handle exception.
|
168
168
|
end
|
169
169
|
|
@@ -175,9 +175,6 @@ module RuboCop
|
|
175
175
|
# rubocop:disable Metrics/MethodLength
|
176
176
|
def parser_class(ruby_version)
|
177
177
|
case ruby_version
|
178
|
-
when 2.3
|
179
|
-
require 'parser/ruby23'
|
180
|
-
Parser::Ruby23
|
181
178
|
when 2.4
|
182
179
|
require 'parser/ruby24'
|
183
180
|
Parser::Ruby24
|
data/lib/rubocop/rake_task.rb
CHANGED
data/lib/rubocop/result_cache.rb
CHANGED
@@ -77,12 +77,13 @@ module RuboCop
|
|
77
77
|
config_store.for('.').for_all_cops['AllowSymlinksInCacheRootDirectory']
|
78
78
|
end
|
79
79
|
|
80
|
-
def initialize(file, options, config_store, cache_root = nil)
|
80
|
+
def initialize(file, team, options, config_store, cache_root = nil)
|
81
81
|
cache_root ||= ResultCache.cache_root(config_store)
|
82
82
|
@allow_symlinks_in_cache_location =
|
83
83
|
ResultCache.allow_symlinks_in_cache_location?(config_store)
|
84
|
-
@path = File.join(cache_root,
|
85
|
-
|
84
|
+
@path = File.join(cache_root,
|
85
|
+
rubocop_checksum,
|
86
|
+
context_checksum(team, options),
|
86
87
|
file_checksum(file, config_store))
|
87
88
|
@cached_data = CachedData.new(file)
|
88
89
|
end
|
@@ -182,10 +183,25 @@ module RuboCop
|
|
182
183
|
# don't affect caching.
|
183
184
|
def relevant_options_digest(options)
|
184
185
|
options = options.reject { |key, _| NON_CHANGING.include?(key) }
|
185
|
-
options
|
186
|
-
|
187
|
-
|
188
|
-
|
186
|
+
options.to_s.gsub(/[^a-z]+/i, '_')
|
187
|
+
end
|
188
|
+
|
189
|
+
# The external dependency checksums are cached per RuboCop team so that
|
190
|
+
# the checksums don't need to be recomputed for each file.
|
191
|
+
def team_checksum(team)
|
192
|
+
@checksum_by_team ||= {}
|
193
|
+
@checksum_by_team[team.object_id] ||= team.external_dependency_checksum
|
194
|
+
end
|
195
|
+
|
196
|
+
# We combine team and options into a single "context" checksum to avoid
|
197
|
+
# making file names that are too long for some filesystems to handle.
|
198
|
+
# This context is for anything that's not (1) the RuboCop executable
|
199
|
+
# checksum or (2) the inspected file checksum.
|
200
|
+
def context_checksum(team, options)
|
201
|
+
Digest::SHA1.hexdigest([
|
202
|
+
team_checksum(team),
|
203
|
+
relevant_options_digest(options)
|
204
|
+
].join)
|
189
205
|
end
|
190
206
|
end
|
191
207
|
end
|
@@ -153,7 +153,7 @@ module RuboCop
|
|
153
153
|
annotations = []
|
154
154
|
|
155
155
|
annotated_source.each_line do |source_line|
|
156
|
-
if source_line
|
156
|
+
if ANNOTATION_PATTERN.match?(source_line)
|
157
157
|
annotations << [source.size, source_line]
|
158
158
|
else
|
159
159
|
source << source_line
|
@@ -52,6 +52,7 @@ RSpec.shared_context 'config', :config do
|
|
52
52
|
cop_name = described_class.cop_name
|
53
53
|
hash[cop_name] = RuboCop::ConfigLoader
|
54
54
|
.default_configuration[cop_name]
|
55
|
+
.merge('Enabled' => true) # in case it is 'pending'
|
55
56
|
.merge(cop_config)
|
56
57
|
end
|
57
58
|
|
@@ -73,10 +74,6 @@ RSpec.shared_context 'mock console output' do
|
|
73
74
|
end
|
74
75
|
end
|
75
76
|
|
76
|
-
RSpec.shared_context 'ruby 2.3', :ruby23 do
|
77
|
-
let(:ruby_version) { 2.3 }
|
78
|
-
end
|
79
|
-
|
80
77
|
RSpec.shared_context 'ruby 2.4', :ruby24 do
|
81
78
|
let(:ruby_version) { 2.4 }
|
82
79
|
end
|
@@ -88,3 +85,7 @@ end
|
|
88
85
|
RSpec.shared_context 'ruby 2.6', :ruby26 do
|
89
86
|
let(:ruby_version) { 2.6 }
|
90
87
|
end
|
88
|
+
|
89
|
+
RSpec.shared_context 'ruby 2.7', :ruby27 do
|
90
|
+
let(:ruby_version) { 2.7 }
|
91
|
+
end
|
data/lib/rubocop/runner.rb
CHANGED
@@ -61,7 +61,12 @@ module RuboCop
|
|
61
61
|
|
62
62
|
def find_target_files(paths)
|
63
63
|
target_finder = TargetFinder.new(@config_store, @options)
|
64
|
-
|
64
|
+
mode = if @options[:only_recognized_file_types]
|
65
|
+
:only_recognized_file_types
|
66
|
+
else
|
67
|
+
:all_file_types
|
68
|
+
end
|
69
|
+
target_files = target_finder.find(paths, mode)
|
65
70
|
target_files.each(&:freeze).freeze
|
66
71
|
end
|
67
72
|
|
@@ -121,8 +126,14 @@ module RuboCop
|
|
121
126
|
end
|
122
127
|
end
|
123
128
|
|
129
|
+
def cached_result(file, team)
|
130
|
+
ResultCache.new(file, team, @options, @config_store)
|
131
|
+
end
|
132
|
+
|
124
133
|
def file_offense_cache(file)
|
125
|
-
|
134
|
+
config = @config_store.for(file)
|
135
|
+
cache = cached_result(file, standby_team(config)) if cached_run?
|
136
|
+
|
126
137
|
if cache&.valid?
|
127
138
|
offenses = cache.load
|
128
139
|
# If we're running --auto-correct and the cache says there are
|
@@ -208,7 +219,7 @@ module RuboCop
|
|
208
219
|
@config_store.for(Dir.pwd).for_all_cops['UseCache']) &&
|
209
220
|
# When running --auto-gen-config, there's some processing done in the
|
210
221
|
# cops related to calculating the Max parameters for Metrics cops. We
|
211
|
-
# need to do that processing and
|
222
|
+
# need to do that processing and cannot use caching.
|
212
223
|
!@options[:auto_gen_config] &&
|
213
224
|
# We can't cache results from code which is piped in to stdin
|
214
225
|
!@options[:stdin]
|
@@ -308,7 +319,7 @@ module RuboCop
|
|
308
319
|
|
309
320
|
cop_classes.reject! { |c| c.match?(@options[:except]) }
|
310
321
|
|
311
|
-
Cop::Registry.new(cop_classes)
|
322
|
+
Cop::Registry.new(cop_classes, @options)
|
312
323
|
end
|
313
324
|
end
|
314
325
|
|
@@ -359,5 +370,15 @@ module RuboCop
|
|
359
370
|
ProcessedSource.from_file(file, ruby_version)
|
360
371
|
end
|
361
372
|
end
|
373
|
+
|
374
|
+
# A Cop::Team instance is stateful and may change when inspecting.
|
375
|
+
# The "standby" team for a given config is an initialized but
|
376
|
+
# otherwise dormant team that can be used for config- and option-
|
377
|
+
# level caching in ResultCache.
|
378
|
+
def standby_team(config)
|
379
|
+
@team_by_config ||= {}
|
380
|
+
@team_by_config[config.object_id] ||=
|
381
|
+
Cop::Team.new(mobilized_cop_classes(config), config, @options)
|
382
|
+
end
|
362
383
|
end
|
363
384
|
end
|
@@ -27,7 +27,7 @@ module RuboCop
|
|
27
27
|
# (if any). If args is empty, recursively find all Ruby source
|
28
28
|
# files under the current directory
|
29
29
|
# @return [Array] array of file paths
|
30
|
-
def find(args)
|
30
|
+
def find(args, mode)
|
31
31
|
return target_files_in_dir if args.empty?
|
32
32
|
|
33
33
|
files = []
|
@@ -36,7 +36,7 @@ module RuboCop
|
|
36
36
|
files += if File.directory?(arg)
|
37
37
|
target_files_in_dir(arg.chomp(File::SEPARATOR))
|
38
38
|
else
|
39
|
-
process_explicit_path(arg)
|
39
|
+
process_explicit_path(arg, mode)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
@@ -169,10 +169,12 @@ module RuboCop
|
|
169
169
|
ruby_file?(file) || configured_include?(file)
|
170
170
|
end
|
171
171
|
|
172
|
-
def process_explicit_path(path)
|
172
|
+
def process_explicit_path(path, mode)
|
173
173
|
files = path.include?('*') ? Dir[path] : [path]
|
174
174
|
|
175
|
-
|
175
|
+
if mode == :only_recognized_file_types || force_exclusion?
|
176
|
+
files.select! { |file| included_file?(file) }
|
177
|
+
end
|
176
178
|
|
177
179
|
return files unless force_exclusion?
|
178
180
|
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
# The kind of Ruby that code inspected by RuboCop is written in.
|
5
|
+
class TargetRuby
|
6
|
+
KNOWN_RUBIES = [2.4, 2.5, 2.6, 2.7].freeze
|
7
|
+
DEFAULT_VERSION = KNOWN_RUBIES.first
|
8
|
+
|
9
|
+
OBSOLETE_RUBIES = {
|
10
|
+
1.9 => '0.50', 2.0 => '0.50', 2.1 => '0.58', 2.2 => '0.69', 2.3 => '0.82'
|
11
|
+
}.freeze
|
12
|
+
private_constant :KNOWN_RUBIES, :OBSOLETE_RUBIES
|
13
|
+
|
14
|
+
# A place where information about a target ruby version is found.
|
15
|
+
class Source
|
16
|
+
attr_reader :version, :name
|
17
|
+
|
18
|
+
def initialize(config)
|
19
|
+
@config = config
|
20
|
+
@version = find_version
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# The target ruby version may be configured in RuboCop's config.
|
29
|
+
class RuboCopConfig < Source
|
30
|
+
def name
|
31
|
+
"`TargetRubyVersion` parameter (in #{@config.smart_loaded_path})"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def find_version
|
37
|
+
@config.for_all_cops['TargetRubyVersion']&.to_f
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# The target ruby version may be found in a .ruby-version file.
|
42
|
+
class RubyVersionFile < Source
|
43
|
+
FILENAME = '.ruby-version'
|
44
|
+
|
45
|
+
def name
|
46
|
+
"`#{FILENAME}`"
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def find_version
|
52
|
+
file = ruby_version_file
|
53
|
+
return unless file && File.file?(file)
|
54
|
+
|
55
|
+
File.read(file).match(/\A(ruby-)?(?<version>\d+\.\d+)/) do |md|
|
56
|
+
md[:version].to_f
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def ruby_version_file
|
61
|
+
@ruby_version_file ||=
|
62
|
+
@config.find_file_upwards(FILENAME,
|
63
|
+
@config.base_dir_for_path_parameters)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# The lock file of Bundler may identify the target ruby version.
|
68
|
+
class BundlerLockFile < Source
|
69
|
+
def name
|
70
|
+
"`#{bundler_lock_file_path}`"
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def find_version
|
76
|
+
lock_file_path = bundler_lock_file_path
|
77
|
+
return nil unless lock_file_path
|
78
|
+
|
79
|
+
in_ruby_section = false
|
80
|
+
File.foreach(lock_file_path) do |line|
|
81
|
+
# If ruby is in Gemfile.lock or gems.lock, there should be two lines
|
82
|
+
# towards the bottom of the file that look like:
|
83
|
+
# RUBY VERSION
|
84
|
+
# ruby W.X.YpZ
|
85
|
+
# We ultimately want to match the "ruby W.X.Y.pZ" line, but there's
|
86
|
+
# extra logic to make sure we only start looking once we've seen the
|
87
|
+
# "RUBY VERSION" line.
|
88
|
+
in_ruby_section ||= line.match(/^\s*RUBY\s*VERSION\s*$/)
|
89
|
+
next unless in_ruby_section
|
90
|
+
|
91
|
+
# We currently only allow this feature to work with MRI ruby. If
|
92
|
+
# jruby (or something else) is used by the project, it's lock file
|
93
|
+
# will have a line that looks like:
|
94
|
+
# RUBY VERSION
|
95
|
+
# ruby W.X.YpZ (jruby x.x.x.x)
|
96
|
+
# The regex won't match in this situation.
|
97
|
+
result = line.match(/^\s*ruby\s+(\d+\.\d+)[p.\d]*\s*$/)
|
98
|
+
return result.captures.first.to_f if result
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def bundler_lock_file_path
|
103
|
+
@config.bundler_lock_file_path
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# If all else fails, a default version will be picked.
|
108
|
+
class Default < Source
|
109
|
+
def name
|
110
|
+
'default'
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def find_version
|
116
|
+
DEFAULT_VERSION
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.supported_versions
|
121
|
+
KNOWN_RUBIES
|
122
|
+
end
|
123
|
+
|
124
|
+
SOURCES = [RuboCopConfig, RubyVersionFile, BundlerLockFile, Default].freeze
|
125
|
+
private_constant :SOURCES
|
126
|
+
|
127
|
+
def initialize(config)
|
128
|
+
@config = config
|
129
|
+
end
|
130
|
+
|
131
|
+
def source
|
132
|
+
@source ||= SOURCES.each.lazy.map { |c| c.new(@config) }.detect(&:version)
|
133
|
+
end
|
134
|
+
|
135
|
+
def version
|
136
|
+
source.version
|
137
|
+
end
|
138
|
+
|
139
|
+
def supported?
|
140
|
+
KNOWN_RUBIES.include?(version)
|
141
|
+
end
|
142
|
+
|
143
|
+
def rubocop_version_with_support
|
144
|
+
if supported?
|
145
|
+
RuboCop::Version.version
|
146
|
+
else
|
147
|
+
OBSOLETE_RUBIES[version]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|