sonicop 26.8.103 → 26.8.104
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/CONFORMANCE.md +138 -49
- data/Cargo.lock +1 -1
- data/Cargo.toml +1 -1
- data/README.ja.md +23 -18
- data/README.md +24 -20
- data/lib/sonicop/version.rb +1 -1
- data/src/config/loader.rs +76 -1
- data/src/config/mod.rs +24 -25
- data/src/directives.rs +177 -39
- data/src/engine.rs +23 -3
- data/src/rules/bundler/gem_comment.rs +242 -0
- data/src/rules/bundler/gem_filename.rs +1 -20
- data/src/rules/bundler/gem_version.rs +35 -0
- data/src/rules/bundler/mod.rs +2 -0
- data/src/rules/gemspec/add_runtime_dependency.rs +40 -0
- data/src/rules/gemspec/attribute_assignment.rs +104 -0
- data/src/rules/gemspec/dependency_version.rs +67 -0
- data/src/rules/gemspec/deprecated_attribute_assignment.rs +173 -0
- data/src/rules/gemspec/development_dependencies.rs +44 -0
- data/src/rules/gemspec/duplicated_assignment.rs +7 -49
- data/src/rules/gemspec/mod.rs +10 -3
- data/src/rules/gemspec/require_mfa.rs +292 -0
- data/src/rules/gemspec/support.rs +50 -1
- data/src/rules/layout/class_structure.rs +439 -0
- data/src/rules/layout/element_line_breaks.rs +319 -0
- data/src/rules/layout/empty_line_after_multiline_condition.rs +201 -0
- data/src/rules/layout/empty_lines_after_module_inclusion.rs +197 -0
- data/src/rules/layout/first_array_element_line_break.rs +41 -0
- data/src/rules/layout/first_hash_element_line_break.rs +21 -0
- data/src/rules/layout/first_method_argument_line_break.rs +38 -0
- data/src/rules/layout/first_method_parameter_line_break.rs +24 -0
- data/src/rules/layout/heredoc_argument_closing_parenthesis.rs +386 -0
- data/src/rules/layout/indentation_width.rs +11 -1
- data/src/rules/layout/line_continuation_leading_space.rs +151 -0
- data/src/rules/layout/line_continuation_spacing.rs +135 -0
- data/src/rules/layout/line_end_string_concatenation_indentation.rs +163 -0
- data/src/rules/layout/mod.rs +20 -0
- data/src/rules/layout/multiline_array_line_breaks.rs +13 -0
- data/src/rules/layout/multiline_assignment_layout.rs +154 -0
- data/src/rules/layout/multiline_hash_key_line_breaks.rs +15 -0
- data/src/rules/layout/multiline_method_argument_line_breaks.rs +30 -0
- data/src/rules/layout/multiline_method_parameter_line_breaks.rs +17 -0
- data/src/rules/layout/redundant_line_break.rs +398 -0
- data/src/rules/layout/single_line_block_chain.rs +74 -0
- data/src/rules/layout/space_before_brackets.rs +73 -0
- data/src/rules/layout/space_inside_block_braces.rs +17 -2
- data/src/rules/lint/ambiguous_assignment.rs +69 -0
- data/src/rules/lint/ambiguous_operator_precedence.rs +81 -0
- data/src/rules/lint/ambiguous_range.rs +115 -0
- data/src/rules/lint/array_literal_in_regexp.rs +108 -0
- data/src/rules/lint/blocks.rs +5 -5
- data/src/rules/lint/constant_overwritten_in_rescue.rs +41 -0
- data/src/rules/lint/constant_reassignment.rs +293 -0
- data/src/rules/lint/constant_resolution.rs +132 -0
- data/src/rules/lint/cop_directive_syntax.rs +15 -0
- data/src/rules/lint/data_define_override.rs +98 -0
- data/src/rules/lint/deprecated_constants.rs +85 -0
- data/src/rules/lint/deprecated_reference.rs +17 -0
- data/src/rules/lint/duplicate_branch.rs +292 -0
- data/src/rules/lint/duplicate_magic_comment.rs +58 -0
- data/src/rules/lint/duplicate_match_pattern.rs +80 -0
- data/src/rules/lint/duplicate_regexp_character_class_element.rs +46 -0
- data/src/rules/lint/duplicate_set_element.rs +127 -0
- data/src/rules/lint/empty_block.rs +73 -0
- data/src/rules/lint/empty_class.rs +31 -0
- data/src/rules/lint/empty_in_pattern.rs +101 -0
- data/src/rules/lint/hash_new_with_keyword_arguments_as_default.rs +60 -0
- data/src/rules/lint/heredoc_method_call_position.rs +134 -0
- data/src/rules/lint/incompatible_io_select_with_fiber_scheduler.rs +117 -0
- data/src/rules/lint/it_without_arguments_in_block.rs +75 -0
- data/src/rules/lint/lambda_without_literal_block.rs +57 -0
- data/src/rules/lint/literal_as_condition.rs +2 -1
- data/src/rules/lint/literal_assignment_in_condition.rs +148 -0
- data/src/rules/lint/literal_in_interpolation.rs +1 -124
- data/src/rules/lint/mixed_case_range.rs +119 -0
- data/src/rules/lint/mod.rs +64 -1
- data/src/rules/lint/name_typo.rs +14 -0
- data/src/rules/lint/no_return_in_begin_end_blocks.rs +94 -0
- data/src/rules/lint/node_equality.rs +52 -0
- data/src/rules/lint/non_atomic_file_operation.rs +336 -0
- data/src/rules/lint/number_conversion.rs +264 -0
- data/src/rules/lint/numbered_parameter_assignment.rs +44 -0
- data/src/rules/lint/numeric_operation_with_constant_result.rs +149 -0
- data/src/rules/lint/or_assignment_to_constant.rs +54 -0
- data/src/rules/lint/ranges.rs +1 -8
- data/src/rules/lint/redundant_dir_glob_sort.rs +117 -0
- data/src/rules/lint/redundant_regexp_quantifiers.rs +137 -0
- data/src/rules/lint/redundant_type_conversion.rs +203 -0
- data/src/rules/lint/refinement_import_methods.rs +72 -0
- data/src/rules/lint/regexp_source.rs +113 -0
- data/src/rules/lint/regexp_tree.rs +985 -0
- data/src/rules/lint/require_range_parentheses.rs +153 -0
- data/src/rules/lint/require_relative_self_path.rs +64 -0
- data/src/rules/lint/shadowing_outer_local_variable.rs +290 -0
- data/src/rules/lint/shared_mutable_default.rs +75 -0
- data/src/rules/lint/statements.rs +5 -0
- data/src/rules/lint/suppressed_exception_in_number_conversion.rs +142 -0
- data/src/rules/lint/symbol_conversion.rs +251 -0
- data/src/rules/lint/to_enum_arguments.rs +241 -0
- data/src/rules/lint/triple_quotes.rs +50 -0
- data/src/rules/lint/unescaped_bracket_in_regexp.rs +140 -0
- data/src/rules/lint/unexpected_block_arity.rs +56 -0
- data/src/rules/lint/unmodified_reduce_accumulator.rs +361 -0
- data/src/rules/lint/unreachable_pattern_branch.rs +66 -0
- data/src/rules/lint/unused_block_argument.rs +13 -6
- data/src/rules/lint/unused_private_method.rs +14 -0
- data/src/rules/lint/useless_constant_scoping.rs +70 -0
- data/src/rules/lint/useless_default_value_argument.rs +96 -0
- data/src/rules/lint/useless_defined.rs +59 -0
- data/src/rules/lint/useless_numeric_operation.rs +139 -0
- data/src/rules/lint/useless_or.rs +105 -0
- data/src/rules/lint/useless_rescue.rs +111 -0
- data/src/rules/lint/useless_ruby2_keywords.rs +123 -0
- data/src/rules/metrics/collection_literal_length.rs +134 -0
- data/src/rules/metrics/mod.rs +1 -0
- data/src/rules/mod.rs +34 -1
- data/src/rules/naming/block_forwarding.rs +341 -0
- data/src/rules/naming/inclusive_language.rs +414 -0
- data/src/rules/naming/memoized_instance_variable_name.rs +28 -21
- data/src/rules/naming/mod.rs +3 -0
- data/src/rules/naming/predicate_method.rs +520 -0
- data/src/rules/naming/support.rs +21 -3
- data/src/rules/ruby_literal.rs +177 -0
- data/src/rules/security/compound_hash.rs +205 -0
- data/src/rules/security/io_methods.rs +55 -0
- data/src/rules/security/mod.rs +2 -0
- data/src/rules/single_line.rs +238 -0
- data/src/rules/style/ambiguous_endless_method_definition.rs +73 -0
- data/src/rules/style/arguments_forwarding.rs +889 -0
- data/src/rules/style/array_coercion.rs +127 -0
- data/src/rules/style/array_first_last.rs +107 -0
- data/src/rules/style/array_intersect.rs +228 -0
- data/src/rules/style/array_intersect_with_single_element.rs +90 -0
- data/src/rules/style/ascii_comments.rs +45 -0
- data/src/rules/style/auto_resource_cleanup.rs +77 -0
- data/src/rules/style/bitwise_predicate.rs +146 -0
- data/src/rules/style/class_methods_definitions.rs +202 -0
- data/src/rules/style/collection_compact.rs +219 -0
- data/src/rules/style/collection_methods.rs +75 -0
- data/src/rules/style/collection_querying.rs +144 -0
- data/src/rules/style/combinable_defined.rs +167 -0
- data/src/rules/style/comments.rs +25 -1
- data/src/rules/style/comparable_between.rs +90 -0
- data/src/rules/style/comparable_clamp.rs +209 -0
- data/src/rules/style/concat_array_literals.rs +152 -0
- data/src/rules/style/constant_visibility.rs +137 -0
- data/src/rules/style/copyright.rs +81 -0
- data/src/rules/style/data_inheritance.rs +119 -0
- data/src/rules/style/date_time.rs +94 -0
- data/src/rules/style/dig_chain.rs +113 -0
- data/src/rules/style/dir_empty.rs +118 -0
- data/src/rules/style/disable_cops_within_source_code_directive.rs +130 -0
- data/src/rules/style/document_dynamic_eval_definition.rs +233 -0
- data/src/rules/style/documentation.rs +1 -1
- data/src/rules/style/documentation_method.rs +84 -0
- data/src/rules/style/empty_class_definition.rs +125 -0
- data/src/rules/style/empty_heredoc.rs +75 -0
- data/src/rules/style/empty_string_inside_interpolation.rs +141 -0
- data/src/rules/style/endless.rs +53 -0
- data/src/rules/style/endless_method.rs +168 -0
- data/src/rules/style/env_home.rs +100 -0
- data/src/rules/style/exact_regexp_match.rs +102 -0
- data/src/rules/style/exponential_notation.rs +45 -3
- data/src/rules/style/fetch_env_var.rs +280 -0
- data/src/rules/style/file_empty.rs +168 -0
- data/src/rules/style/file_null.rs +66 -0
- data/src/rules/style/file_open.rs +63 -0
- data/src/rules/style/file_open_call.rs +105 -0
- data/src/rules/style/file_read.rs +70 -0
- data/src/rules/style/file_touch.rs +63 -0
- data/src/rules/style/file_write.rs +134 -0
- data/src/rules/style/hash_conversion.rs +303 -0
- data/src/rules/style/hash_except.rs +15 -0
- data/src/rules/style/hash_fetch_chain.rs +125 -0
- data/src/rules/style/hash_lookup_method.rs +144 -0
- data/src/rules/style/hash_slice.rs +16 -0
- data/src/rules/style/hash_subset.rs +282 -0
- data/src/rules/style/if_with_boolean_literal_branches.rs +202 -0
- data/src/rules/style/implicit_runtime_error.rs +45 -0
- data/src/rules/style/in_pattern_then.rs +68 -0
- data/src/rules/style/inline_comment.rs +34 -0
- data/src/rules/style/invertible_unless_condition.rs +346 -0
- data/src/rules/style/ip_addresses.rs +108 -0
- data/src/rules/style/it_assignment.rs +56 -0
- data/src/rules/style/it_block_parameter.rs +260 -0
- data/src/rules/style/keyword_arguments_merging.rs +100 -0
- data/src/rules/style/literal.rs +14 -1
- data/src/rules/style/magic_comment_format.rs +229 -0
- data/src/rules/style/map_chain.rs +47 -0
- data/src/rules/style/map_compact_with_conditional_block.rs +284 -0
- data/src/rules/style/map_into_array.rs +407 -0
- data/src/rules/style/map_join.rs +132 -0
- data/src/rules/style/map_to_hash.rs +91 -0
- data/src/rules/style/map_to_set.rs +63 -0
- data/src/rules/style/method_call_with_args_parentheses.rs +831 -0
- data/src/rules/style/method_called_on_do_end_block.rs +71 -0
- data/src/rules/style/method_preference.rs +30 -0
- data/src/rules/style/min_max_comparison.rs +117 -0
- data/src/rules/style/missing_else.rs +114 -0
- data/src/rules/style/mod.rs +131 -0
- data/src/rules/style/module_member_existence_check.rs +140 -0
- data/src/rules/style/multiline_in_pattern_then.rs +56 -0
- data/src/rules/style/multiline_method_signature.rs +151 -0
- data/src/rules/style/negated_if_else_condition.rs +176 -0
- data/src/rules/style/negative_array_index.rs +257 -0
- data/src/rules/style/nested_file_dirname.rs +101 -0
- data/src/rules/style/nil_lambda.rs +135 -0
- data/src/rules/style/nodes.rs +19 -0
- data/src/rules/style/numbered_parameters.rs +42 -0
- data/src/rules/style/numbered_parameters_limit.rs +89 -0
- data/src/rules/style/object_then.rs +59 -0
- data/src/rules/style/one_class_per_file.rs +44 -0
- data/src/rules/style/open_struct_use.rs +78 -0
- data/src/rules/style/operator_method_call.rs +185 -0
- data/src/rules/style/option_hash.rs +95 -0
- data/src/rules/style/partition_instead_of_double_select.rs +401 -0
- data/src/rules/style/predicate_with_kind.rs +118 -0
- data/src/rules/style/quoted_symbols.rs +218 -0
- data/src/rules/style/reduce_to_hash.rs +236 -0
- data/src/rules/style/redundant_argument.rs +133 -0
- data/src/rules/style/redundant_array_constructor.rs +80 -0
- data/src/rules/style/redundant_array_flatten.rs +81 -0
- data/src/rules/style/redundant_constant_base.rs +56 -0
- data/src/rules/style/redundant_current_directory_in_path.rs +75 -0
- data/src/rules/style/redundant_double_splat_hash_braces.rs +196 -0
- data/src/rules/style/redundant_each.rs +150 -0
- data/src/rules/style/redundant_filter_chain.rs +106 -0
- data/src/rules/style/redundant_format.rs +859 -0
- data/src/rules/style/redundant_heredoc_delimiter_quotes.rs +119 -0
- data/src/rules/style/redundant_initialize.rs +161 -0
- data/src/rules/style/redundant_interpolation_unfreeze.rs +121 -0
- data/src/rules/style/redundant_line_continuation.rs +327 -0
- data/src/rules/style/redundant_min_max_by.rs +88 -0
- data/src/rules/style/redundant_parentheses.rs +1 -0
- data/src/rules/style/redundant_regexp_argument.rs +192 -0
- data/src/rules/style/redundant_regexp_constructor.rs +75 -0
- data/src/rules/style/redundant_self_assignment_branch.rs +109 -0
- data/src/rules/style/redundant_string_escape.rs +245 -0
- data/src/rules/style/redundant_struct_keyword_init.rs +132 -0
- data/src/rules/style/require_order.rs +182 -0
- data/src/rules/style/return_nil.rs +100 -0
- data/src/rules/style/return_nil_in_predicate_method_definition.rs +127 -0
- data/src/rules/style/reverse_find.rs +90 -0
- data/src/rules/style/safe_navigation_chain_length.rs +78 -0
- data/src/rules/style/select_by.rs +269 -0
- data/src/rules/style/select_by_kind.rs +78 -0
- data/src/rules/style/select_by_range.rs +147 -0
- data/src/rules/style/select_by_regexp.rs +152 -0
- data/src/rules/style/send.rs +26 -0
- data/src/rules/style/send_with_literal_method_name.rs +101 -0
- data/src/rules/style/single_line_block_params.rs +137 -0
- data/src/rules/style/single_line_do_end_block.rs +226 -0
- data/src/rules/style/single_line_methods.rs +6 -0
- data/src/rules/style/static_class.rs +172 -0
- data/src/rules/style/string_chars.rs +49 -0
- data/src/rules/style/string_hash_keys.rs +158 -0
- data/src/rules/style/string_methods.rs +36 -0
- data/src/rules/style/super_arguments.rs +278 -0
- data/src/rules/style/super_with_args_parentheses.rs +51 -0
- data/src/rules/style/swap_values.rs +103 -0
- data/src/rules/style/tally_method.rs +289 -0
- data/src/rules/style/top_level_method_definition.rs +44 -0
- data/src/rules/style/trailing_comma_in_block_args.rs +66 -0
- data/src/rules/style/unless_logical_operators.rs +102 -0
- data/src/rules/style/yaml_file_read.rs +88 -0
- data/src/rules/style/yoda_expression.rs +110 -0
- data/src/rules/support.rs +435 -8
- data/src/rules/visibility.rs +119 -0
- data/src/source.rs +14 -0
- metadata +228 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 267d186a55418ccb97a890bcea5da9eda428dd6567ae4282b61755779783d6e2
|
|
4
|
+
data.tar.gz: baa0dfdcff20c0a1888222298deab0fd2af37fd9fcd25ef8beb2871bb89083fc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1f983d82729522d8a18d1155a4d9b1b6d020b837e987abc2d5bbf14558587997f1abf8808e69ae1e36132b6d15f8cac0d0cf440f116cb9280b98397d7b8f3c03
|
|
7
|
+
data.tar.gz: 2ffd0dd8db704b600fda62f08c1f61455fc36310f1adc33d4ae6f1bc1b2a53998c8034103a871e4e9e2b239f798a181a66982dafbda3d9b6ae0f5b74845d0887
|
data/CONFORMANCE.md
CHANGED
|
@@ -9,34 +9,39 @@ Re-fetch it with `scripts/sync_default_yml.sh <rubocop-version>`.
|
|
|
9
9
|
|
|
10
10
|
## What is measured
|
|
11
11
|
|
|
12
|
-
Five Ruby projects, 18,
|
|
12
|
+
Five Ruby projects, 18,251 target files between them, are linted by both tools and compared offense
|
|
13
13
|
by offense. An offense is keyed by cop name, path, line and column; at each shared key the last
|
|
14
14
|
line, last column, length, message, severity and correctability are compared as well.
|
|
15
15
|
|
|
16
16
|
| Corpus | Commit | Target files | Reference offenses |
|
|
17
17
|
|---|---|---:|---:|
|
|
18
18
|
| rubocop/rubocop | `f009b33` | 1,765 | 5,766 |
|
|
19
|
-
| rails/rails | `
|
|
20
|
-
| ruby/ruby | `
|
|
21
|
-
| Homebrew/brew | `
|
|
22
|
-
| mastodon/mastodon | `
|
|
19
|
+
| rails/rails | `62b5458` | 3,551 | 167,760 |
|
|
20
|
+
| ruby/ruby | `3349f41` | 7,466 | 761,578 |
|
|
21
|
+
| Homebrew/brew | `38ee325` | 2,179 | 49,920 |
|
|
22
|
+
| mastodon/mastodon | `fad3685` | 3,290 | 15,286 |
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
The commits are pinned because the numbers move with them: check the corpora out at these before
|
|
25
|
+
comparing, or a difference in the corpus will read as a difference in the port.
|
|
26
|
+
|
|
27
|
+
ruby/ruby's reference had to be assembled from chunked runs, and two files are excluded from it.
|
|
28
|
+
`test/ruby/test_regexp.rb` cannot be inspected at all — RuboCop's lexer raises `invalid byte
|
|
29
|
+
sequence in UTF-8` on it — and `test/ruby/test_file_exhaustive.rb` holds an offense whose text is
|
|
30
|
+
not valid UTF-8, which stops the JSON formatter from emitting a document. The comparison for that
|
|
31
|
+
corpus therefore covers 7,464 of its 7,466 files.
|
|
28
32
|
|
|
29
33
|
The **target file lists match exactly** on all five — not just the counts but the paths. That is
|
|
30
34
|
worth stating separately because file discovery is where a port silently diverges first: RuboCop
|
|
31
35
|
never reads `.gitignore`, applies a shebang test only to extensionless files, descends through
|
|
32
36
|
directory symlinks, and treats a hidden path by its *first* component rather than by any dot in it.
|
|
33
37
|
|
|
34
|
-
Sonicop implements **
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
Sonicop implements **all 609 of RuboCop's cops**, matched name for name, with nothing extra on either
|
|
39
|
+
side. That includes the 159 RuboCop ships as `Enabled: pending` and the 56 it ships as
|
|
40
|
+
`Enabled: false`, neither of which a default run reaches — checking those means naming them with
|
|
41
|
+
`--only` or switching them on in a configuration, exactly as with RuboCop.
|
|
37
42
|
|
|
38
|
-
Because the two
|
|
39
|
-
|
|
43
|
+
Because the two cop sets are identical, neither side is restricted with `--only`; the plain run is
|
|
44
|
+
already like for like. RuboCop's extension plugins are not installed, so this measures the range
|
|
40
45
|
that can be checked without them.
|
|
41
46
|
|
|
42
47
|
```bash
|
|
@@ -51,18 +56,20 @@ sonicop --force-default-config --format json
|
|
|
51
56
|
| rubocop/rubocop | 0 | 0 | none |
|
|
52
57
|
| rails/rails | 0 | 0 | none |
|
|
53
58
|
| mastodon/mastodon | 0 | 0 | none |
|
|
54
|
-
| Homebrew/brew |
|
|
55
|
-
| ruby/ruby |
|
|
59
|
+
| Homebrew/brew | 263 | 997 | none |
|
|
60
|
+
| ruby/ruby | 142 | 585 | 5 |
|
|
56
61
|
|
|
57
62
|
Three of the five agree offense for offense — RuboCop's own tree, Rails and Mastodon — with no
|
|
58
63
|
excess, no shortfall and no metadata differences anywhere.
|
|
59
64
|
|
|
60
65
|
Homebrew's remaining difference is entirely `Lint/Syntax`; every other cop matches exactly. Much of
|
|
61
|
-
ruby/ruby's is too, with
|
|
66
|
+
ruby/ruby's is too, with 117 of the 585 missing and 44 of the 142 excess being `Lint/Syntax` itself,
|
|
62
67
|
and the rest follows from it: a file the two disagree about is inspected by one tool and skipped by
|
|
63
|
-
the other, so every offense in it lands on one side of the ledger.
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
the other, so every offense in it lands on one side of the ledger. Counting that through, 635 of the
|
|
69
|
+
727 differences sit in files one tool or the other calls a syntax error, and they are spread thinly
|
|
70
|
+
across the Layout department rather than sitting in one cop. Of the 92 that do not, 77 are the
|
|
71
|
+
`Style/RedundantParentheses` case under *Differences that should not be closed*, which leaves 15 —
|
|
72
|
+
ten of them in TRICK entries or encoding fixtures. Both are explained under *Known divergences*.
|
|
66
73
|
|
|
67
74
|
ruby/ruby also carries five differences at positions both tools reported: two `correctable` flags and
|
|
68
75
|
one `last_column`/`length` pair, all on indentation cops inside files the two parse differently, plus
|
|
@@ -103,22 +110,36 @@ Two traps make a run look better or worse than it is, and both have produced wro
|
|
|
103
110
|
**Counts cancel out.** Comparing offense totals hides an excess and a shortfall of the same size.
|
|
104
111
|
Compare the *set* of locations, then compare fields at the locations both tools produced.
|
|
105
112
|
|
|
106
|
-
**RuboCop can stop early
|
|
107
|
-
`
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
every
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
113
|
+
**RuboCop can stop early.** On ruby/ruby its lexer raises `invalid byte sequence in UTF-8` on
|
|
114
|
+
`test/ruby/test_regexp.rb` and the whole run unwinds. A single-invocation run reports 6,909 of 7,466
|
|
115
|
+
files inspected, and the 557 files after that one in sort order were never looked at — so every
|
|
116
|
+
offense Sonicop found in them counts as "excess". Check `summary.inspected_file_count` against
|
|
117
|
+
`summary.target_file_count` on every run. To get a complete reference for that corpus, split the file
|
|
118
|
+
list into chunks and re-run each chunk past the file that killed it.
|
|
119
|
+
|
|
120
|
+
Read those two counts with `-f offenses`, not `-f json`: with the full cop set the JSON formatter
|
|
121
|
+
never gets to write them (see below), and the run looks like a crash rather than a truncation.
|
|
122
|
+
|
|
123
|
+
**And sometimes it emits nothing at all.** `test/ruby/test_file_exhaustive.rb` holds an offense whose
|
|
124
|
+
text is not valid UTF-8, and `JSONFormatter#finished` raises `source sequence is illegal/malformed
|
|
125
|
+
utf-8` while serializing — before a single byte reaches stdout. The failure is not per-file but
|
|
126
|
+
per-document: one such file discards the JSON for the entire run, summary included, which is why the
|
|
127
|
+
counts above have to come from another formatter.
|
|
128
|
+
|
|
129
|
+
Two things about this are easy to get backwards. **What matters is the encoding of the offense text,
|
|
130
|
+
not of the source.** `test/ruby/enc/test_euc_jp.rb` and `test/ruby/enc/test_shift_jis.rb` do hold
|
|
131
|
+
bytes that are not valid UTF-8, yet both serialize fine on their own — their magic comments make
|
|
132
|
+
RuboCop read them in their declared encoding — while `test_file_exhaustive.rb` is valid UTF-8 as a
|
|
133
|
+
file. **And which files are affected depends on the cop set, not on the corpus.** Running the full
|
|
134
|
+
609 excludes two files from ruby/ruby; running `--only Lint/LiteralAsCondition,Layout/IndentationWidth`
|
|
135
|
+
excludes one, because neither of those two cops produces an offense whose text is ill-formed. A
|
|
136
|
+
recorded exclusion count is part of a measurement's conditions, not a property of the corpus.
|
|
137
|
+
|
|
138
|
+
A chunked reference run has to tell this apart from the case above: retrying one file at a time is
|
|
139
|
+
right when a file killed the parser, and useless when the run never had a chance to start. Two other
|
|
140
|
+
stdout notices break JSON the same way — `--parallel` being ignored under `--cache false`, and the
|
|
141
|
+
plugin suggestions RuboCop prints after a run — so a reference reader should skip to the first `{`
|
|
142
|
+
rather than trust byte zero.
|
|
122
143
|
|
|
123
144
|
## Known divergences
|
|
124
145
|
|
|
@@ -130,23 +151,51 @@ but no longer reproduces fails the test, and so does one that appears without be
|
|
|
130
151
|
RuboCop parses with `parser`, an LALR parser that recovers from an error and keeps going, emitting
|
|
131
152
|
further diagnostics from the recovered state. Sonicop parses with tree-sitter, which does not model
|
|
132
153
|
that recovery, so the follow-on diagnostics cannot be reproduced. On Homebrew this accounts for the
|
|
133
|
-
|
|
154
|
+
997 missing `Lint/Syntax` offenses: `class definition in method body`, `dynamic constant assignment`,
|
|
134
155
|
`cannot assign to a keyword`, and repeated `unexpected token` inside one multi-line hash.
|
|
135
156
|
|
|
136
157
|
What the divergence does not change is **which** files are held to be unparseable, and that is what
|
|
137
158
|
decides whether a file is inspected at all: RuboCop runs no cop other than `Lint/Syntax` on a file
|
|
138
|
-
that does not parse, and Sonicop does the same. On Homebrew
|
|
139
|
-
|
|
140
|
-
despite the 1,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
159
|
+
that does not parse, and Sonicop does the same. On Homebrew the two agree on the *set*, not merely on
|
|
160
|
+
its size: 569 files, with the difference in either direction empty. This is why every cop other than
|
|
161
|
+
`Lint/Syntax` matches exactly there despite the 1,260 offenses of difference.
|
|
162
|
+
|
|
163
|
+
The agreement is not universal. On ruby/ruby the sets differ by six files: 56 agree, five are flagged
|
|
164
|
+
only by Sonicop and one only by RuboCop. The five are TRICK contest entries — deliberately obfuscated
|
|
165
|
+
programs, one of which is English prose that happens to parse as Ruby — where tree-sitter reports an
|
|
166
|
+
error and `parser` does not. Those five hold 465 of that corpus's 773 differences.
|
|
167
|
+
|
|
168
|
+
Within Homebrew's 569 files the agreement is partial, as recovery cannot be reproduced: 499 report the
|
|
169
|
+
same first diagnostic (position and message), and 222 report an identical list end to end. The 277
|
|
170
|
+
files in between are the divergence in its purest form — the two agree on where the file first goes
|
|
171
|
+
wrong and part company on what follows. The 70
|
|
144
172
|
files whose first diagnostic differs follow one shape — an endless method definition (`def to_s =
|
|
145
173
|
to_str`, valid from Ruby 3.0, rejected by the default `TargetRubyVersion: 2.7`) leaves `parser`'s
|
|
146
174
|
method context open, so the enclosing `class` emits `class definition in method body` when it is
|
|
147
175
|
finally reduced. The diagnostic is reported at the `class` keyword, far above the line that actually
|
|
148
176
|
failed, which puts it first in source order.
|
|
149
177
|
|
|
178
|
+
### What is left on ruby/ruby
|
|
179
|
+
|
|
180
|
+
ruby/ruby is the only corpus with a residue that is not one shape, so it is worth taking apart. Of
|
|
181
|
+
its 727 differences:
|
|
182
|
+
|
|
183
|
+
| | Count | |
|
|
184
|
+
|---|---:|---|
|
|
185
|
+
| in files one tool calls a syntax error | 635 | the recovery difference above |
|
|
186
|
+
| `Style/RedundantParentheses` in one file | 77 | RuboCop's defect, see below |
|
|
187
|
+
| everything else | 15 | |
|
|
188
|
+
|
|
189
|
+
The last 15 are the honest remainder. Ten of them sit in TRICK entries or encoding fixtures —
|
|
190
|
+
`Layout/SpaceInsideParens` five times in one obfuscated program, `Layout/TrailingWhitespace` and
|
|
191
|
+
`Layout/LeadingCommentSpace` on a UTF-16 fixture that holds no BOM. Three are the `"…"%[…]` lexing
|
|
192
|
+
gap described under *Grammar gaps*. That leaves two — `Lint/NestedMethodDefinition` on
|
|
193
|
+
`def (obj.bar = Object.new).baz` and `Style/MixinUsage` on a top-level `include RbConfig` — which
|
|
194
|
+
have not been investigated.
|
|
195
|
+
|
|
196
|
+
Naming that number is the point. It was 138 before the cop fixes that landed with the 609th cop, and
|
|
197
|
+
every step down came from taking one shape at a time rather than from a general improvement.
|
|
198
|
+
|
|
150
199
|
### Grammar gaps
|
|
151
200
|
|
|
152
201
|
Where tree-sitter rejects code that Ruby accepts, Sonicop reports a syntax error and — following the
|
|
@@ -161,6 +210,13 @@ What remains are constructs whose ambiguity Ruby resolves with information a gra
|
|
|
161
210
|
whether the token before it completed an expression, which in turn depends on knowing that `a` is a
|
|
162
211
|
local variable rather than a method call.
|
|
163
212
|
|
|
213
|
+
A gap does not have to reject the file to cost offenses. `"%3d %s"%[l+1, line]` parses, but not as
|
|
214
|
+
Ruby reads it: a `%` written against a string literal can only be the operator, while tree-sitter
|
|
215
|
+
takes `%[…]` for a percent-literal string and yields two adjacent strings instead of a binary
|
|
216
|
+
operation. Nothing downstream can recover it — the operator node the cop would report on is not in
|
|
217
|
+
the tree — so `Layout/SpaceAroundOperators` misses both the `%` and the `+` nested inside the
|
|
218
|
+
brackets. Three offenses on ruby/ruby come from this, all on one line of `libexec/erb`.
|
|
219
|
+
|
|
164
220
|
### Encoding — the one deliberate difference
|
|
165
221
|
|
|
166
222
|
RuboCop's autocorrect ends in a plain `File.write`, so a corrected Shift_JIS file is written back as
|
|
@@ -171,11 +227,43 @@ cp932 and you get mojibake, not the source you had.
|
|
|
171
227
|
when the correction holds a character that encoding cannot represent, leaving the file untouched
|
|
172
228
|
rather than substituting something else. Drop-in compatibility reaches a long way, but not as far as
|
|
173
229
|
reproducing data loss on purpose. This is the only place Sonicop knowingly differs, and it only
|
|
174
|
-
shows up on files that declare a non-UTF-8 encoding — 8 of the 18,
|
|
230
|
+
shows up on files that declare a non-UTF-8 encoding — 8 of the 18,251 files measured here.
|
|
175
231
|
|
|
176
232
|
A source declaring `ASCII-8BIT` or `binary` needs no such treatment: Ruby measures it one byte at a
|
|
177
233
|
time, so Sonicop reads it that way too and the bytes go back out unchanged.
|
|
178
234
|
|
|
235
|
+
## Differences that should not be closed
|
|
236
|
+
|
|
237
|
+
Everything above records a place Sonicop has not reached. This section records the opposite: a
|
|
238
|
+
difference where RuboCop is the one that is wrong, and matching it would mean discarding a correct
|
|
239
|
+
report. The two are worth separating, because a table that mixes them reads as though every
|
|
240
|
+
difference counts against the port.
|
|
241
|
+
|
|
242
|
+
On ruby/ruby's `test/-ext-/bignum/test_pack.rb`, `Style/RedundantParentheses` finds 3 offenses in
|
|
243
|
+
RuboCop and 79 in Sonicop. The 76 are real: they are `(-n)`, `(-n+1)` and `(+n-1)` written as method
|
|
244
|
+
arguments, the same shape RuboCop reports elsewhere in the same file and in a file of its own.
|
|
245
|
+
|
|
246
|
+
RuboCop drops them because of an unrelated line further down. Truncating the file shows it exactly:
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
first 82 lines + a closing end → RuboCop reports 8
|
|
250
|
+
first 83 lines + a closing end → RuboCop reports 0 ← the 8 already reported are withdrawn
|
|
251
|
+
line 83 with \xFF changed to \x00 → RuboCop reports 9
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
Line 83 is `assert_equal([-1, "\xFF"], Bug::Bignum.test_pack((-0x0FF), 1, 1, 0, BIG_ENDIAN))`, in a
|
|
255
|
+
file whose first line is `# coding: ASCII-8BIT`. Reading that far makes RuboCop abandon
|
|
256
|
+
`Style/RedundantParentheses` for the whole file, silently:
|
|
257
|
+
|
|
258
|
+
- it is specific to that cop — `Style/StringLiterals` still reports its 10 offenses in the same file
|
|
259
|
+
- it is not the cop-error path — `--raise-cop-error` says nothing
|
|
260
|
+
- the file is inspected — the run reports `inspected: 1` and simply finds no offense of that cop
|
|
261
|
+
- it is not a parse failure — neither tool emits `Lint/Syntax`, and `ruby -c` accepts the file
|
|
262
|
+
- a synthesised minimum does not reproduce it; the surrounding file is part of the trigger
|
|
263
|
+
|
|
264
|
+
Sonicop reports all 79. Bringing that down to 3 would mean suppressing correct output to match a
|
|
265
|
+
defect, so the difference stands as it is.
|
|
266
|
+
|
|
179
267
|
## Limits
|
|
180
268
|
|
|
181
269
|
A clean run is a property of the corpora, not a general claim. `known_divergences.yml` carries the
|
|
@@ -183,11 +271,12 @@ current list of what these corpora never exercise; the main ones are non-default
|
|
|
183
271
|
values, extension plugins, and Windows line endings. Cops that never fire contribute nothing to a
|
|
184
272
|
match count, and their silence is indistinguishable from agreement.
|
|
185
273
|
|
|
186
|
-
The 215 cops RuboCop ships switched off are a limit of a different kind.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
274
|
+
The 215 cops RuboCop ships switched off are a limit of a different kind. They are implemented, but a
|
|
275
|
+
default run never reaches them, so the corpus numbers above say nothing about them. What stands
|
|
276
|
+
behind those is a separate measurement: the same corpora linted with all 609 cops switched on, on
|
|
277
|
+
both sides, and the residue classified. That is weaker evidence than it sounds — a cop that never
|
|
278
|
+
fires on these corpora contributes nothing either way — and the residue is not yet zero. The figures
|
|
279
|
+
for that run are tracked in `known_divergences.yml` rather than here, because they are still moving.
|
|
191
280
|
|
|
192
281
|
Closing that gap properly means porting RuboCop's own spec suite, which exercises each cop against
|
|
193
282
|
inputs written to break it. Until that lands, this document records what was measured.
|
data/Cargo.lock
CHANGED
data/Cargo.toml
CHANGED
data/README.ja.md
CHANGED
|
@@ -33,16 +33,17 @@ CI へ最小限の変更で導入できます。
|
|
|
33
33
|
## 主な機能
|
|
34
34
|
|
|
35
35
|
Bundler、Gemspec、Layout、Lint、Metrics、Migration、Naming、Security、Style の各部門の Cop を実装しています。
|
|
36
|
-
|
|
36
|
+
一覧はバイナリ自身が正本です。
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
39
|
# 認識済み Cop と実装状況の一覧
|
|
40
40
|
sonicop --show-cops
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
RuboCop 1.89 の全 609 Cop
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
**RuboCop 1.89 の全 609 Cop を実装しています。** 本家のレジストリと名前まで一致しており、
|
|
44
|
+
`Enabled: pending` の 159 個と `Enabled: false` の 56 個も含みます。この 215 個は本家でも
|
|
45
|
+
既定の実行では走らないので、`--only` で名指しするか設定で有効にしてください。本家にも
|
|
46
|
+
存在しない Cop 名だけをエラーにし、必要なら `--ignore-unrecognized-cops` で続行できます。
|
|
46
47
|
|
|
47
48
|
## インストール
|
|
48
49
|
|
|
@@ -108,10 +109,10 @@ Ruby プラグイン実行、キャッシュ再利用、カスタム Cop、実
|
|
|
108
109
|
### 適合性
|
|
109
110
|
|
|
110
111
|
実装済み Cop は、RuboCop 自身・Rails・Ruby・Homebrew・Mastodon の 5 プロジェクト
|
|
111
|
-
計 18,
|
|
112
|
+
計 18,251 ファイルに対して、両者とも本家既定設定で検証しています。offense は Cop 名・パス・
|
|
112
113
|
行・桁・終端行・終端桁・長さ・メッセージ・重大度・修正可否のすべてで突き合わせます。
|
|
113
114
|
|
|
114
|
-
5 つのうち 3 つが**完全一致**です。RuboCop 自身のツリー(5,766 件)、Rails(167,
|
|
115
|
+
5 つのうち 3 つが**完全一致**です。RuboCop 自身のツリー(5,766 件)、Rails(167,760 件)、
|
|
115
116
|
Mastodon(15,286 件)で、過剰も不足もメタデータ差もありません。対象ファイル一覧は 5 つすべてで
|
|
116
117
|
一致します。残る差分は `Lint/Syntax` に集中しており、本家の LALR パーサが構文エラーから回復して
|
|
117
118
|
出す追加診断を tree-sitter では再現できないことによるものです。autocorrect は RuboCop 自身のツリーと
|
|
@@ -133,15 +134,18 @@ Mastodon でバイト単位に一致します。この 2 つは死守ライン
|
|
|
133
134
|
|
|
134
135
|
| コーパス | ファイル | RuboCop 並列 | Sonicop 並列 | RuboCop 単一 | Sonicop 単一 |
|
|
135
136
|
|---|---:|---:|---:|---:|---:|
|
|
136
|
-
| rubocop/rubocop | 1,765 |
|
|
137
|
-
| mastodon/mastodon | 3,290 |
|
|
138
|
-
| Homebrew/brew | 2,
|
|
139
|
-
| rails/rails | 3,
|
|
140
|
-
| ruby/ruby | 7,
|
|
141
|
-
|
|
142
|
-
差は並列で 2.4
|
|
143
|
-
|
|
144
|
-
|
|
137
|
+
| rubocop/rubocop | 1,765 | 11.49 秒 | **3.45 秒** | 42.49 秒 | **16.39 秒** |
|
|
138
|
+
| mastodon/mastodon | 3,290 | 27.26 秒 | **6.03 秒** | 42.07 秒 | **19.53 秒** |
|
|
139
|
+
| Homebrew/brew | 2,179 | 20.37 秒 | **5.36 秒** | 45.08 秒 | **16.03 秒** |
|
|
140
|
+
| rails/rails | 3,551 | 45.89 秒 | **18.96 秒** | 99.56 秒 | **44.61 秒** |
|
|
141
|
+
| ruby/ruby | 7,466 | 117.79 秒 | **54.97 秒** | 215.87 秒 | **100.62 秒** |
|
|
142
|
+
|
|
143
|
+
差は並列で 2.1〜4.5 倍、単一プロセスで 2.1〜2.8 倍と幅があり、1 コーパスでは代表できません。
|
|
144
|
+
**単一プロセスの列を読み、並列は目安として扱ってください。** 同じ 2 つのバイナリを 1 日に
|
|
145
|
+
3 回測ったところ、単一プロセスの値は毎回 16% 以内に収まったのに対し、RuboCop 自身のツリーでの
|
|
146
|
+
並列の倍率は、マシンが他に何をしていたかだけで 3.3 倍から 9.2 倍まで動きました。単一プロセスは
|
|
147
|
+
エンジンを測っていますが、並列はエンジンに加えて「その実行でスケジューリングがそのツリーに
|
|
148
|
+
どれだけ噛み合ったか」を測っています。
|
|
145
149
|
|
|
146
150
|
仕事を省いて速いわけではありません。この同じ 394 Cop について、RuboCop 自身のツリーと
|
|
147
151
|
Mastodon では**すべての offense が一致**し、autocorrect もバイト単位で一致します。
|
|
@@ -162,10 +166,11 @@ sonicop --force-default-config --format quiet
|
|
|
162
166
|
```
|
|
163
167
|
|
|
164
168
|
測定機は Apple M2(8 コア)、Ruby 4.0.6(YJIT 利用可)、RubyGems 導入の RuboCop 1.89.0。
|
|
165
|
-
|
|
169
|
+
1 分平均のロードアベレージは、計測開始時が 3.6、終了時が 9.6 でした。**アイドル状態ではありません**。
|
|
166
170
|
両者を同じ条件で測っているため倍率は保たれますが、秒数そのものは下限ではなく、静かなマシンなら
|
|
167
|
-
|
|
168
|
-
|
|
171
|
+
より速く出ます。コアを奪い合うものが動いていると両者とも膨らみ、その度合いは一致しません。それが
|
|
172
|
+
並列の列があれだけ動く理由です。秒数そのものが重要なときは、他に負荷のない状態で測り、**実行の
|
|
173
|
+
前後でロードアベレージを記録してください** — その情報が無い数値は、別の数値と比べられません。
|
|
169
174
|
|
|
170
175
|
## 開発
|
|
171
176
|
|
data/README.md
CHANGED
|
@@ -33,17 +33,17 @@ existing editor and CI integrations with minimal changes.
|
|
|
33
33
|
## Features
|
|
34
34
|
|
|
35
35
|
Sonicop implements cops in the Bundler, Gemspec, Layout, Lint, Metrics, Migration, Naming,
|
|
36
|
-
Security, and Style departments.
|
|
37
|
-
The implemented set grows with each release, so the binary itself is the authoritative list:
|
|
36
|
+
Security, and Style departments. The binary itself is the authoritative list:
|
|
38
37
|
|
|
39
38
|
```bash
|
|
40
39
|
# Every recognized cop and its implementation status
|
|
41
40
|
sonicop --show-cops
|
|
42
41
|
```
|
|
43
42
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
**All 609 RuboCop 1.89 cops are implemented**, matched name for name against the upstream registry.
|
|
44
|
+
That includes the 159 shipped as `Enabled: pending` and the 56 shipped as `Enabled: false`, which a
|
|
45
|
+
default run does not reach on either side — name them with `--only` or switch them on in a
|
|
46
|
+
configuration, exactly as with RuboCop. Unknown cop names still fail validation unless
|
|
47
47
|
`--ignore-unrecognized-cops` is supplied.
|
|
48
48
|
|
|
49
49
|
## Installation
|
|
@@ -118,11 +118,11 @@ reuse, custom Ruby cops, or cops outside the implemented set.
|
|
|
118
118
|
### Conformance
|
|
119
119
|
|
|
120
120
|
The implemented cops are verified against RuboCop 1.89.0 over five Ruby projects — RuboCop itself,
|
|
121
|
-
Rails, Ruby, Homebrew and Mastodon — totalling 18,
|
|
121
|
+
Rails, Ruby, Homebrew and Mastodon — totalling 18,251 files, with the upstream default
|
|
122
122
|
configuration on both sides. Every offense is compared by cop, path, line, column, last line, last
|
|
123
123
|
column, length, message, severity and correctability.
|
|
124
124
|
|
|
125
|
-
Three of the five match **exactly**: RuboCop's own tree (5,766 offenses), Rails (167,
|
|
125
|
+
Three of the five match **exactly**: RuboCop's own tree (5,766 offenses), Rails (167,760) and
|
|
126
126
|
Mastodon (15,286), with no excess, no shortfall and no metadata differences. The target file lists
|
|
127
127
|
match exactly on all five. What remains is concentrated in `Lint/Syntax`, where RuboCop's LALR
|
|
128
128
|
parser recovers from an error and emits diagnostics a tree-sitter parse cannot reconstruct.
|
|
@@ -144,15 +144,18 @@ warmed runs.
|
|
|
144
144
|
|
|
145
145
|
| Corpus | Files | RuboCop parallel | Sonicop parallel | RuboCop single | Sonicop single |
|
|
146
146
|
|---|---:|---:|---:|---:|---:|
|
|
147
|
-
| rubocop/rubocop | 1,765 |
|
|
148
|
-
| mastodon/mastodon | 3,290 |
|
|
149
|
-
| Homebrew/brew | 2,
|
|
150
|
-
| rails/rails | 3,
|
|
151
|
-
| ruby/ruby | 7,
|
|
152
|
-
|
|
153
|
-
The gap is 2.
|
|
154
|
-
it.
|
|
155
|
-
|
|
147
|
+
| rubocop/rubocop | 1,765 | 11.49 s | **3.45 s** | 42.49 s | **16.39 s** |
|
|
148
|
+
| mastodon/mastodon | 3,290 | 27.26 s | **6.03 s** | 42.07 s | **19.53 s** |
|
|
149
|
+
| Homebrew/brew | 2,179 | 20.37 s | **5.36 s** | 45.08 s | **16.03 s** |
|
|
150
|
+
| rails/rails | 3,551 | 45.89 s | **18.96 s** | 99.56 s | **44.61 s** |
|
|
151
|
+
| ruby/ruby | 7,466 | 117.79 s | **54.97 s** | 215.87 s | **100.62 s** |
|
|
152
|
+
|
|
153
|
+
The gap is 2.1x to 4.5x in parallel and 2.1x to 2.8x single-process, so no single corpus summarizes
|
|
154
|
+
it. **Read the single-process column and treat the parallel one as indicative.** Measuring the same
|
|
155
|
+
two binaries three times over a day put the single-process figures within 16% of each other every
|
|
156
|
+
time, while the parallel ratio on RuboCop's own tree moved between 3.3x and 9.2x purely with what
|
|
157
|
+
else the machine was doing. Single-process measures the engines; parallel measures the engines plus
|
|
158
|
+
how well each one's scheduling happens to fit that tree on that run.
|
|
156
159
|
|
|
157
160
|
The speed is not bought by skipping work: over those same 394 cops the two agree on **every offense**
|
|
158
161
|
on RuboCop's own tree and on Mastodon, and autocorrect there is byte-identical.
|
|
@@ -173,11 +176,12 @@ sonicop --force-default-config --format quiet
|
|
|
173
176
|
```
|
|
174
177
|
|
|
175
178
|
Machine: Apple M2 (8 cores), Ruby 4.0.6 with YJIT available, RubyGems-installed RuboCop 1.89.0.
|
|
176
|
-
The
|
|
177
|
-
use, not idle. Both tools ran under the same conditions, so the ratios hold, but the absolute
|
|
179
|
+
The one-minute load average was 3.6 when the run started and 9.6 when it finished — the machine was
|
|
180
|
+
in use, not idle. Both tools ran under the same conditions, so the ratios hold, but the absolute
|
|
178
181
|
seconds are not a floor: expect better on a quiet machine. Anything competing for cores inflates
|
|
179
|
-
both sides, and not by the same factor on each,
|
|
180
|
-
absolute numbers matter to you
|
|
182
|
+
both sides, and not by the same factor on each, which is what makes the parallel column move as much
|
|
183
|
+
as it does. If the absolute numbers matter to you, measure on an idle machine and record the load
|
|
184
|
+
either side of the run — a figure without that context cannot be compared with another one.
|
|
181
185
|
|
|
182
186
|
## Development
|
|
183
187
|
|
data/lib/sonicop/version.rb
CHANGED
data/src/config/loader.rs
CHANGED
|
@@ -48,6 +48,48 @@ fn home_directory() -> Option<PathBuf> {
|
|
|
48
48
|
resolve_home_directory(|key| std::env::var_os(key))
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/// `base_dir_for_path_parameters`: where the paths a configuration file mentions are taken from.
|
|
52
|
+
///
|
|
53
|
+
/// A file whose name starts with `.rubocop` speaks about the directory holding it; any other file
|
|
54
|
+
/// speaks about the directory the command ran in. The gem's own `default.yml` is the reason for the
|
|
55
|
+
/// split -- its paths must not be read as relative to the gem. The dotfile in the home directory
|
|
56
|
+
/// describes whatever is being inspected rather than the home directory, so it counts as an other.
|
|
57
|
+
pub(super) fn path_parameter_base_directory<'a>(
|
|
58
|
+
config_path: Option<&'a Path>,
|
|
59
|
+
cwd: &'a Path,
|
|
60
|
+
) -> &'a Path {
|
|
61
|
+
let home = home_directory();
|
|
62
|
+
base_directory_for(config_path, cwd, home.as_deref())
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
fn base_directory_for<'a>(
|
|
66
|
+
config_path: Option<&'a Path>,
|
|
67
|
+
cwd: &'a Path,
|
|
68
|
+
home: Option<&Path>,
|
|
69
|
+
) -> &'a Path {
|
|
70
|
+
let Some(path) = config_path else {
|
|
71
|
+
return cwd;
|
|
72
|
+
};
|
|
73
|
+
let named_for_rubocop = path
|
|
74
|
+
.file_name()
|
|
75
|
+
.and_then(|name| name.to_str())
|
|
76
|
+
.is_some_and(|name| name.starts_with(".rubocop"));
|
|
77
|
+
if !named_for_rubocop || is_home_dotfile(path, home) {
|
|
78
|
+
return cwd;
|
|
79
|
+
}
|
|
80
|
+
path.parent().unwrap_or(cwd)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/// The configuration path is stored canonicalized, so the dotfile is compared both as written and
|
|
84
|
+
/// as the file system resolves it.
|
|
85
|
+
fn is_home_dotfile(path: &Path, home: Option<&Path>) -> bool {
|
|
86
|
+
home.is_some_and(|home| {
|
|
87
|
+
let dotfile = home.join(".rubocop.yml");
|
|
88
|
+
path == dotfile
|
|
89
|
+
|| fs::canonicalize(&dotfile).is_ok_and(|canonical| path == canonical.as_path())
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
51
93
|
/// RuboCop expands `~` through `Dir.home`, which on Windows falls back to
|
|
52
94
|
/// `USERPROFILE` and then `HOMEDRIVE`+`HOMEPATH` because `HOME` is normally unset
|
|
53
95
|
/// there. Reading `HOME` alone hides the user-global configuration on Windows.
|
|
@@ -74,8 +116,9 @@ pub(super) fn find_project_root(start: &Path) -> Option<PathBuf> {
|
|
|
74
116
|
#[cfg(test)]
|
|
75
117
|
mod tests {
|
|
76
118
|
use std::ffi::OsString;
|
|
119
|
+
use std::path::Path;
|
|
77
120
|
|
|
78
|
-
use super::resolve_home_directory;
|
|
121
|
+
use super::{base_directory_for, resolve_home_directory};
|
|
79
122
|
|
|
80
123
|
fn environment<'a>(pairs: &'a [(&str, &str)]) -> impl Fn(&str) -> Option<OsString> + 'a {
|
|
81
124
|
move |key| {
|
|
@@ -114,4 +157,36 @@ mod tests {
|
|
|
114
157
|
);
|
|
115
158
|
assert_eq!(resolve_home_directory(environment(&[])), None);
|
|
116
159
|
}
|
|
160
|
+
|
|
161
|
+
#[test]
|
|
162
|
+
fn takes_path_parameters_from_the_directory_only_for_a_rubocop_dotfile() {
|
|
163
|
+
let cwd = Path::new("/work/project");
|
|
164
|
+
let home = Some(Path::new("/home/dev"));
|
|
165
|
+
// Nothing loaded: the command's own directory is all there is.
|
|
166
|
+
assert_eq!(base_directory_for(None, cwd, home), cwd);
|
|
167
|
+
// `.rubocop.yml` and its siblings speak about where they sit.
|
|
168
|
+
assert_eq!(
|
|
169
|
+
base_directory_for(Some(Path::new("/work/project/ci/.rubocop.yml")), cwd, home),
|
|
170
|
+
Path::new("/work/project/ci")
|
|
171
|
+
);
|
|
172
|
+
assert_eq!(
|
|
173
|
+
base_directory_for(
|
|
174
|
+
Some(Path::new("/work/project/.rubocop_todo.yml")),
|
|
175
|
+
cwd,
|
|
176
|
+
home
|
|
177
|
+
),
|
|
178
|
+
Path::new("/work/project")
|
|
179
|
+
);
|
|
180
|
+
// Any other name is read against the directory the command ran in, so a configuration kept
|
|
181
|
+
// outside the project does not drag the target Ruby version out of its own neighbourhood.
|
|
182
|
+
assert_eq!(
|
|
183
|
+
base_directory_for(Some(Path::new("/tmp/checks/all609.yml")), cwd, home),
|
|
184
|
+
cwd
|
|
185
|
+
);
|
|
186
|
+
// The dotfile in the home directory describes the project, not the home directory.
|
|
187
|
+
assert_eq!(
|
|
188
|
+
base_directory_for(Some(Path::new("/home/dev/.rubocop.yml")), cwd, home),
|
|
189
|
+
cwd
|
|
190
|
+
);
|
|
191
|
+
}
|
|
117
192
|
}
|