Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metrics/AbcSize needs love #8037

Merged
merged 1 commit into from Jul 29, 2020
Merged

Metrics/AbcSize needs love #8037

merged 1 commit into from Jul 29, 2020

Conversation

marcandre
Copy link
Contributor

@marcandre marcandre commented May 26, 2020

It made no sense to me that this commit would actually increase the Abc complexity.

So I looked a bit into it, and the current Cop underestimates the complexity of a lot of things. This PR fixes many of them. It also tweaks Metrics/CyclomaticComplexity.

I personally dislike this metric.
  • Creating intermediate variables is typically a good thing, but it increases the metric
  • No distinction between calling obj.attribute and obj.my_method(arg, opt: 42, other_opt: 42); both are considered a branch. 2 + 2 is also a branch.
  • Same weight assigned to A, B and C. A method with n conditions and n branches and 0 assignment is considered as complex as 0 conditions, n branches and n assignments...

But for those that actually like it, it should at least try to be relevant; failure in the calculation might lead someone to rewrite the method some strange to game the cop instead of actually addressing the issue.

Now the specs pass, but with the adjusted calculations there are 64 offenses where the code is now over the limit of 15. I think the max for these is 19.47

lib/rubocop/cached_data.rb:45:5: C: Metrics/AbcSize: Assignment Branch Condition size for deserialize_offenses is too high. [<4, 16, 0> 16.49/15]
    def deserialize_offenses(offenses) ...
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cli/command/execute_runner.rb:45:9: C: Metrics/AbcSize: Assignment Branch Condition size for display_error_summary is too high. [<1, 15, 1> 15.07/15]
        def display_error_summary(errors) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/comment_config.rb:58:5: C: Metrics/AbcSize: Assignment Branch Condition size for analyze is too high. [<14, 13, 0> 19.1/15]
    def analyze ...
    ^^^^^^^^^^^
lib/rubocop/config.rb:68:5: C: Metrics/AbcSize: Assignment Branch Condition size for make_excludes_absolute is too high. [<2, 15, 4> 15.65/15]
    def make_excludes_absolute ...
    ^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/config.rb:84:5: C: Metrics/AbcSize: Assignment Branch Condition size for add_excludes_from_higher_level is too high. [<3, 15, 5> 16.09/15]
    def add_excludes_from_higher_level(highest_config) ...
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/config_loader.rb:126:7: C: Metrics/AbcSize: Assignment Branch Condition size for warn_on_pending_cops is too high. [<2, 15, 2> 15.26/15]
      def warn_on_pending_cops(pending_cops) ...
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/config_loader_resolver.rb:21:5: C: Metrics/AbcSize: Assignment Branch Condition size for resolve_inheritance is too high. [<7, 16, 2> 17.58/15]
    def resolve_inheritance(path, hash, file, debug) ...
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/config_loader_resolver.rb:62:5: C: Metrics/AbcSize: Assignment Branch Condition size for merge_with_default is too high. [<7, 13, 4> 15.3/15]
    def merge_with_default(config, config_file, unset_nil:) ...
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/config_loader_resolver.rb:198:5: C: Metrics/AbcSize: Assignment Branch Condition size for handle_disabled_by_default is too high. [<8, 18, 2> 19.8/15]
    def handle_disabled_by_default(config, new_default_configuration) ...
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/config_validator.rb:153:5: C: Metrics/AbcSize: Assignment Branch Condition size for validate_enforced_styles is too high. [<9, 17, 3> 19.47/15]
    def validate_enforced_styles(valid_cop_names) ...
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/correctors/unused_arg_corrector.rb:12:9: C: Metrics/AbcSize: Assignment Branch Condition size for correct is too high. [<3, 14, 5> 15.17/15]
        def correct(processed_source, node) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/generator/require_file_injector.rb:42:9: C: Metrics/AbcSize: Assignment Branch Condition size for target_line is too high. [<7, 13, 7> 16.34/15]
        def target_line ...
        ^^^^^^^^^^^^^^^
lib/rubocop/cop/ignored_node.rb:11:7: C: Metrics/AbcSize: Assignment Branch Condition size for part_of_ignored_node? is too high. [<2, 15, 5> 15.94/15]
      def part_of_ignored_node?(node) ...
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/layout/class_structure.rb:165:9: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<7, 14, 2> 15.78/15]
        def autocorrect(node) ...
        ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/layout/empty_comment.rb:68:9: C: Metrics/AbcSize: Assignment Branch Condition size for investigate is too high. [<4, 17, 4> 17.92/15]
        def investigate(processed_source) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/layout/empty_line_between_defs.rb:88:9: C: Metrics/AbcSize: Assignment Branch Condition size for multiple_blank_lines_groups? is too high. [<5, 15, 3> 16.09/15]
        def multiple_blank_lines_groups?(first_def_node, second_def_node) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/layout/extra_spacing.rb:153:9: C: Metrics/AbcSize: Assignment Branch Condition size for align_equal_signs is too high. [<7, 14, 0> 15.65/15]
        def align_equal_signs(range, corrector) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/layout/hash_alignment.rb:236:9: C: Metrics/AbcSize: Assignment Branch Condition size for check_pairs is too high. [<6, 17, 0> 18.03/15]
        def check_pairs(node) ...
        ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/layout/multiline_assignment_layout.rb:75:9: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<3, 16, 2> 16.4/15]
        def autocorrect(node) ...
        ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/layout/multiline_block_layout.rb:73:9: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<3, 15, 5> 16.09/15]
        def autocorrect(node) ...
        ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb:89:9: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<3, 14, 6> 15.52/15]
        def autocorrect(node) ...
        ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/layout/trailing_whitespace.rb:36:9: C: Metrics/AbcSize: Assignment Branch Condition size for investigate is too high. [<5, 15, 3> 16.09/15]
        def investigate(processed_source) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb:59:9: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<2, 15, 0> 15.13/15]
        def autocorrect(node) ...
        ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/lint/erb_new_arguments.rb:85:9: C: Metrics/AbcSize: Assignment Branch Condition size for on_send is too high. [<4, 14, 4> 15.1/15]
        def on_send(node) ...
        ^^^^^^^^^^^^^^^^^
lib/rubocop/cop/lint/erb_new_arguments.rb:123:9: C: Metrics/AbcSize: Assignment Branch Condition size for build_kwargs is too high. [<5, 14, 3> 15.17/15]
        def build_kwargs(node) ...
        ^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/lint/implicit_string_concatenation.rb:33:9: C: Metrics/AbcSize: Assignment Branch Condition size for on_dstr is too high. [<4, 15, 4> 16.03/15]
        def on_dstr(node) ...
        ^^^^^^^^^^^^^^^^^
lib/rubocop/cop/lint/missing_cop_enable_directive.rb:53:9: C: Metrics/AbcSize: Assignment Branch Condition size for investigate is too high. [<5, 16, 2> 16.88/15]
        def investigate(processed_source) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/lint/ordered_magic_comments.rb:49:9: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<5, 15, 0> 15.81/15]
        def autocorrect(_node) ...
        ^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/lint/redundant_cop_disable_directive.rb:138:9: C: Metrics/AbcSize: Assignment Branch Condition size for find_redundant is too high. [<4, 15, 8> 17.46/15]
        def find_redundant(comment, offenses, cop, line_range, next_line_range) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/lint/safe_navigation_consistency.rb:42:9: C: Metrics/AbcSize: Assignment Branch Condition size for check is too high. [<7, 14, 0> 15.65/15]
        def check(node) ...
        ^^^^^^^^^^^^^^^
lib/rubocop/cop/lint/shadowed_argument.rb:97:9: C: Metrics/AbcSize: Assignment Branch Condition size for shadowing_assignment is too high. [<5, 14, 6> 16.03/15]
        def shadowing_assignment(argument) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/lint/struct_new_override.rb:36:9: C: Metrics/AbcSize: Assignment Branch Condition size for on_send is too high. [<4, 16, 5> 17.23/15]
        def on_send(node) ...
        ^^^^^^^^^^^^^^^^^
lib/rubocop/cop/lint/useless_assignment.rb:46:9: C: Metrics/AbcSize: Assignment Branch Condition size for check_for_unused_assignments is too high. [<3, 15, 4> 15.81/15]
        def check_for_unused_assignments(variable) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/migration/department_name.rb:21:9: C: Metrics/AbcSize: Assignment Branch Condition size for investigate is too high. [<6, 14, 3> 15.52/15]
        def investigate(processed_source) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/mixin/alignment.rb:27:7: C: Metrics/AbcSize: Assignment Branch Condition size for check_alignment is too high. [<4, 14, 4> 15.1/15]
      def check_alignment(items, base_column = nil) ...
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/mixin/array_min_size.rb:19:7: C: Metrics/AbcSize: Assignment Branch Condition size for array_style_detected is too high. [<7, 14, 8> 17.58/15]
      def array_style_detected(style, ary_size) ...
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/mixin/method_preference.rb:13:7: C: Metrics/AbcSize: Assignment Branch Condition size for preferred_methods is too high. [<8, 14, 1> 16.16/15]
      def preferred_methods ...
      ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/mixin/uncommunicative_name.rb:14:7: C: Metrics/AbcSize: Assignment Branch Condition size for check is too high. [<4, 14, 6> 15.75/15]
      def check(node, args) ...
      ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/naming/file_name.rb:176:9: C: Metrics/AbcSize: Assignment Branch Condition size for to_namespace is too high. [<7, 16, 3> 17.72/15]
        def to_namespace(path) ...
        ^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/style/attr.rb:32:9: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<6, 14, 3> 15.52/15]
        def autocorrect(node) ...
        ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/style/command_literal.rb:94:9: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<2, 15, 3> 15.43/15]
        def autocorrect(node) ...
        ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/style/comment_annotation.rb:43:9: C: Metrics/AbcSize: Assignment Branch Condition size for investigate is too high. [<7, 13, 5> 15.59/15]
        def investigate(processed_source) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/style/conditional_assignment.rb:429:9: C: Metrics/AbcSize: Assignment Branch Condition size for remove_whitespace_in_branches is too high. [<3, 16, 1> 16.31/15]
        def remove_whitespace_in_branches(corrector, branch, condition, column) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/style/empty_case_condition.rb:69:9: C: Metrics/AbcSize: Assignment Branch Condition size for correct_case_when is too high. [<2, 15, 0> 15.13/15]
        def correct_case_when(corrector, case_node, when_nodes) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/style/empty_else.rb:107:9: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<2, 15, 2> 15.26/15]
        def autocorrect(node) ...
        ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/style/nested_modifier.rb:45:9: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<2, 15, 2> 15.26/15]
        def autocorrect(node) ...
        ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/style/next.rb:197:9: C: Metrics/AbcSize: Assignment Branch Condition size for reindentable_lines is too high. [<4, 15, 0> 15.52/15]
        def reindentable_lines(node) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/style/redundant_exception.rb:31:9: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<6, 15, 2> 16.28/15]
        def autocorrect(node) # rubocop:disable Metrics/MethodLength ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/style/rescue_standard_error.rb:108:9: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<3, 15, 2> 15.43/15]
        def autocorrect(node) ...
        ^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/style/semicolon.rb:42:9: C: Metrics/AbcSize: Assignment Branch Condition size for on_begin is too high. [<6, 13, 6> 15.52/15]
        def on_begin(node) ...
        ^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/style/symbol_array.rb:72:9: C: Metrics/AbcSize: Assignment Branch Condition size for correct_bracketed is too high. [<4, 15, 2> 15.65/15]
        def correct_bracketed(node) ...
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/team.rb:77:7: C: Metrics/AbcSize: Assignment Branch Condition size for autocorrect is too high. [<7, 13, 6> 15.94/15]
      def autocorrect(buffer, cops) ...
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/cop/util.rb:130:7: C: Metrics/AbcSize: Assignment Branch Condition size for tokens is too high. [<6, 15, 5> 16.91/15]
      def tokens(node) ...
      ^^^^^^^^^^^^^^^^
lib/rubocop/formatter/junit_formatter.rb:31:7: C: Metrics/AbcSize: Assignment Branch Condition size for file_finished is too high. [<6, 18, 1> 19/15]
      def file_finished(file, offenses) ...
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/options.rb:58:5: C: Metrics/AbcSize: Assignment Branch Condition size for define_options is too high. [<3, 15, 0> 15.3/15]
    def define_options ...
    ^^^^^^^^^^^^^^^^^^
lib/rubocop/rake_task.rb:20:5: C: Metrics/AbcSize: Assignment Branch Condition size for initialize is too high. [<2, 16, 2> 16.25/15]
    def initialize(name = :rubocop, *args, &task_block) ...
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/rake_task.rb:65:5: C: Metrics/AbcSize: Assignment Branch Condition size for setup_subtasks is too high. [<3, 16, 1> 16.31/15]
    def setup_subtasks(name, *args, &task_block) ...
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/result_cache.rb:161:5: C: Metrics/AbcSize: Assignment Branch Condition size for rubocop_checksum is too high. [<6, 16, 1> 17.12/15]
    def rubocop_checksum ...
    ^^^^^^^^^^^^^^^^^^^^
lib/rubocop/rspec/host_environment_simulation_helper.rb:8:3: C: Metrics/AbcSize: Assignment Branch Condition size for in_its_own_process_with is too high. [<3, 15, 3> 15.59/15]
  def in_its_own_process_with(*files) ...
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/runner.rb:305:5: C: Metrics/AbcSize: Assignment Branch Condition size for mobilized_cop_classes is too high. [<4, 16, 4> 16.97/15]
    def mobilized_cop_classes(config) ...
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
lib/rubocop/yaml_duplication_checker.rb:20:5: C: Metrics/AbcSize: Assignment Branch Condition size for traverse is too high. [<7, 15, 4> 17.03/15]
    def self.traverse(tree, &on_duplicated) ...
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
spec/support/statement_modifier_helper.rb:11:3: C: Metrics/AbcSize: Assignment Branch Condition size for check_really_short is too high. [<1, 15, 0> 15.03/15]
  def check_really_short(keyword) ...
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tasks/cops_documentation.rake:99:3: C: Metrics/AbcSize: Assignment Branch Condition size for configurations is too high. [<8, 16, 1> 17.92/15]
  def configurations(pars) ...
  ^^^^^^^^^^^^^^^^^^^^^^^^
tasks/cops_documentation.rake:219:3: C: Metrics/AbcSize: Assignment Branch Condition size for table_of_content_for_department is too high. [<5, 15, 0> 15.81/15]
  def table_of_content_for_department(cops, department) ...
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Possible solutions:

  1. Bump the default to 20 (my preference)
  2. Modify our todo (I'm not sure how, sorry)
  3. Find a volunteer to fix the 64 offences

@marcandre
Copy link
Contributor Author

marcandre commented May 27, 2020

For the record, the commit that "increased" the ABC complexity reduces it with these calculations (one less assignment, block call switched to a method call so same number of branches). Moreover, the origin of the 'offenses' being yielded instead of relying on the return_of_the_method.offenses was a commit whose only goal was to "reduce complexity". That's the problem with metrics as a goal, they are often getting gamed 🤷‍♂️

Copy link
Collaborator

@jonas054 jonas054 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job on fixing bugs and clarifying things in the tests! I did have some comments about how some nodes should count, which I would like you to address.

spec/rubocop/cop/metrics/abc_size_spec.rb Show resolved Hide resolved
let(:source) { <<~RUBY }
def method_name
x = foo # <1, 1, 0>
bar do # <1, 3, 0> (+1 for bar, +1 for non-empty block)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not so sure that a block in itself should count as a branch. It says in abc_size_calculator.rb that a branch is "an explicit forward program branch out of scope". So a code block that can be called from outside the scope of the current method is not a branch IMO.

Copy link
Contributor Author

@marcandre marcandre Jun 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm not too sure. I read "For example, the B (branch) count is virtually identical to "cyclomatic complexity" here, so that's where I got my +1. But I'm not sure I can really make sense of that quote actually and I didn't understand that ABC is meant as a metric for size more than complexity. So yeah, maybe you're right and blocks shouldn't be counted.
I still need to make a PR for cyclomatic complexity that doesn't count blocks. Do you agree it's a +1 for all non-empty blocks as a block constitutes an additional disconnected node?
Also, yield should be counted as branches and I don't think they are.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, maybe the quote meant to say "For example, the C (condition) count is virtually identical to "cyclomatic complexity". Maybe we should consider counting blocks as a "condition", in the sense that control flow is not linear at a block and entering it or not will be decided at runtime; exactly like and ifs or for. What do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree on yield. About cyclomatic complexity and blocks, I believe that's one of those things we can't know for sure with static analysis. The block could be another possible path through the method, but then again it might not be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I said "additional disconnected node" I was wrong. Could be disconnected, if the block is captured and executed later, but typically it will behave like a loop/condition and be connected to the graph and add +1. In all cases it adds +1 to the cyclomatic complexity though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Cyclomatic complexity, https://github.com/metricfu/Saikuro also counts +1 for blocks. I just can't find an example of Abc calculator though

Copy link
Contributor Author

@marcandre marcandre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking at this! I've replied to your comments; I'll amend the PR not to count blocks, check for yield and also for (not that we use them)

@jonas054
Copy link
Collaborator

jonas054 commented Jun 8, 2020

Bump the default to 20 (my preference)

Mine too. Ideally we want to find a value that makes the cop behave like the current version, which has Max: 15. It not possible to find such a value, but try to get as close as you can.

@marcandre
Copy link
Contributor Author

Bump the default to 20 (my preference)

Mine too. Ideally we want to find a value that makes the cop behave like the current version, which has Max: 15. It not possible to find such a value, but try to get as close as you can.

With the last few tweaks, autogen says that 18 is sufficient (see last temporary commit)

@marcandre marcandre marked this pull request as draft June 8, 2020 18:34
@marcandre
Copy link
Contributor Author

Bumping both by 1 creates only 9 more todos and removes one, doesn't seem so bad

@marcandre marcandre marked this pull request as ready for review June 11, 2020 21:27
@marcandre
Copy link
Contributor Author

I'm moving the Cyclomatic issues to a different PR so this can be merged.

Summary of PR as it stands:
ABC Size now counts correctly: multiple assignments, block variables, foo.bar=, foo[42]=, ||=, &&=, for and yield

If default for AbcSize remains at 15, there are 24 new todos in the main gem...
If the default is bumped to 16, there are 5 new todos and 2 no longer needed
If bumped to 17, then there's +2 new todo and 7 no longer needed.
I'm proposing 16. How does that sound? cc/ @jonas054 @bbatsov

@marcandre
Copy link
Contributor Author

I'd like to add Condition: +1 for the same known iterating methods than in #8149: questions/objections?

@marcandre marcandre marked this pull request as draft June 12, 2020 21:27
@marcandre
Copy link
Contributor Author

I updated the PR to count +1 condition for methods like each, map, etc., in a similar fashion as CyclomaticComplexity.

If default for AbcSize remains at 15, there are 30 new todos in the main gem...
If the default is bumped to 16, there are 11 new todos and 2 no longer needed
If bumped to 17, then there's 2 new todo and 7 no longer needed.

I hesitate between 16 and 17, so I tried 16.5 which gives +4 and -5, so that's what I'm proposing.

@marcandre
Copy link
Contributor Author

I made a (hopefully 😅) final tweak to exclude some "non-assignments", either to _unused_variables or to no variable (e.g. _, _ignored, *, count_me_in = ary should count as 1 assignment, not 4. This brings one more method under the proposed 16.5 threshold.

@marcandre marcandre marked this pull request as ready for review June 19, 2020 22:28
CHANGELOG.md Outdated Show resolved Hide resolved
CHANGELOG.md Outdated Show resolved Hide resolved
@@ -1884,7 +1884,7 @@ Metrics/AbcSize:
# The ABC size is a calculated magnitude, so this number can be an Integer or
# a Float.
IgnoredMethods: []
Max: 15
Max: 16.5
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking that since the max is pretty arbitrary anyway, you could choose a number that will cause very few new offenses for users, i.e. a hight number. But I guess you gave it a lot of thought.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tried a few settings. 17 might be better and trigger less new failures (which could be frustrating) for people using our default.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First of all, thank you for the research and discussion to difficult default value.

17 might be better and trigger less new failures (which could be frustrating) for people using our default.

IMHO, I often hear talk about disabling Metrics/AbcSize cop or increasing the maximum value. I think it is better to have Metrics/AbcSize cop work with increasing the default maximum value, rather than disabling the cop due to strict default.
So, if possible default value 17 seems to be a good value to me. (Of course, well thought out current value 16.5 is fine :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, bumped to 17

Now counts correctly ||=, &&=, multiple assignments, for, yield, iterating blocks.
All &. count as a condition, unless it's on a repeated and unchanged lvar [see rubocop#8276]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants