Rubocop: Align the operands of an expression in an assignment spanning multiple lines bug (or me not understanding the config)

Created on 4 Feb 2015  路  26Comments  路  Source: rubocop-hq/rubocop

I'm running: 0.28.0 (using Parser 2.2.0.2, running on ruby 2.0.0 x86_64-darwin14.0.0)

With the code:

users = User.where(email: '[email protected]').
             update_all(user_parameters)

I get the rubocop warning:

Align the operands of an expression in an assignment spanning multiple lines

It passes with this which I feel isn't correct indentation:

users = User.where(email: '[email protected]').
        update(user_parameters)

I'm not sure if this is a bug or my error.

Most helpful comment

Style/MultilineOperationIndentation can be configured with the aligned style (default), which enforces

users = User.where(email: '[email protected]').
        update(user_parameters)

and indented, which enforces

users = User.where(email: '[email protected]').
  update(user_parameters)

The aligned style is supported by ruby-mode 1.1 in Emacs and indented is another common style.

So I wouldn't say that there's a bug in RuboCop here. The behavior is intended. To support your style, which I wouldn't rule out at this point, we'd have to add a third alternative. Maybe call is semantic since it tries to convey a meaning relating to a call chain? I have a suspicion there might be a few corner cases with this new style that I can't describe in detail right now, but I don't know.

All 26 comments

Style/MultilineOperationIndentation can be configured with the aligned style (default), which enforces

users = User.where(email: '[email protected]').
        update(user_parameters)

and indented, which enforces

users = User.where(email: '[email protected]').
  update(user_parameters)

The aligned style is supported by ruby-mode 1.1 in Emacs and indented is another common style.

So I wouldn't say that there's a bug in RuboCop here. The behavior is intended. To support your style, which I wouldn't rule out at this point, we'd have to add a third alternative. Maybe call is semantic since it tries to convey a meaning relating to a call chain? I have a suspicion there might be a few corner cases with this new style that I can't describe in detail right now, but I don't know.

I see. Thanks for the explanation. I could have sworn this wasn't the case in previous versions? Anyway, I understand it's a weird problem. I think I was looking at it like "aligning method calls", as you said, as opposed to multiline operations in general.

Just sort of thinking out loud. Feel free to close if you don't think it's a good idea to add.

Being able to verticaly align method calls when they are related can ease the understanding, in my opinion.

For instance with this dummy exemple:

a = [1, 3, 5].map { |i| i + 1 }
             .map { |i| i + 2 }

It seems to me more self explanatory than the rubocop compliant:

a = [1, 3, 5].map { |i| i + 1 }
    .map { |i| i + 2 }

In rails, this situation happen when you have severals query/scope:

@users = User.active
             .visible
             .where(is_admin: true)    

I agree with raphaelpra on this one, it's quite common to align them that way in rails

@rafalchmiel Why not simply use one method call per line?

a = [1, 3, 5]
    .map { |i| i + 1 }
    .map { |i| i + 2 }

You should keep in mind this is expression continuation and the expression starts with the first receiver. I understand your reasoning, but it seems flawed to me. There's also the fact few editors support the indentation you suggest.

Would that translate to this?

@users = User
         .active
         .visible
         .where(is_admin: true)    

I'm not sure that's easier to read than the version above.

@bbatsov, I think you mean @raphaelpra :smile:.

@rafalchmiel Sorry about this.

There's also the fact few editors support the indentation you suggest.

This is actually what brought me to this issue. For me, Sublime doesn't correctly use syntax highlighting on the object when I align the code like @matthewford's example.

@raphaelpra's example seems to be common in Rails, I see it a lot, but it's failing in Rubocop.

:+1:

I'm completely OCD about code style, but I can't reconcile this rule with my OCD. :( Sorry, but I disagree with this cop. I'll disable it completely for now but I hope you'll re-evaluate based on all this feedback.

Looks like were in the same boat. We're going to disable the rule for now, which I would rather not do, but it seems that neither indented or aligned will work with chaining like this

results = scope.where(facebook_accounts_connections: { account_id: params[:account_id] })
               .order("facebook_connections.created_at desc")
               .page(page)
               .per(page_size)

It reads a lot easier when all of the methods that are chained are lined up so you can easily see what is connected to what. I'll discuss with the team on the alternative mentioned here as well. It's definitely not what we're used too.

Count me as one looking for support for the style @nathanpalmer and @raphaelpra pointed out. :+1:

Another vote to support the style proposed by @nathanpalmer and @raphaelpra. We use this style a lot, in a variety of languages. It is concise, vertical-space efficient, and makes abundantly clear even with a quick glance how the call chain is structured. As an example a definition of strong parameters in Rails:

params.require(:objective)
      .permit(:due_date, :title, :key_results)

:+1: for @nathanpalmer, @raphaelpra and @kevgo 's style

:+1: for @nathanpalmer and @raphaelpra style

:+1: the dot-aligned style @nathanpalmer and @raphaelpra pointed out. We use it heavily in Rails projects, also this similar syntax when dealing with long lists of symbol parameters.

delegate :name,
         :count,
         :budget,
         to: :project_plan

:+1:

:+1:

:+1: for @nathanpalmer and @raphaelpra style. We use it alot in our code as well.

:+1: Thanks for adding this style:

  .exchange_draw_shares
  .includes(includes_query)
  .joins(:share)
  .where.not(share_id: previous_ids)

IMHO This enables the source of the pipeline to be easily recognised.

Yes, noticed that this is working and it's great! Allows for comments as well.

  .exchange_draw_shares                          # complicated scope logic
  .includes(includes_query)                      # this eager loads associations that we need
  .joins(:share)                                 # the shares join table
  .where.not(share_id: previous_ids)             # where no previous shares exist

big :+1:

@globalkeith @saneshark You're welcome, but this style has been accepted since the introduction of Style/MultilineOperationIndentation in v0.27.0. :smile: What we're discussion now is the addition of

model.exchange_draw_shares
     .includes(includes_query)
     .joins(:share)
     .where.not(share_id: previous_ids)

as an accepted alignment. It's added in the pull request you see mentioned above, but hasn't been merged yet.

Both indented and aligned use a different style than Rubymine (version 8.x, but I think it hasn't changed compared to previous versions) does when copy-pasting. Rubymine will use:

array = Model
            .includes(something)
            .joins(:blah)
            .where.not(some_id: ids)

Is this a style that should be considered as bug of Rubymine, or should it be supported by Rubocop as additional style? I find it nicer than both the rubocop aligned style:

array = Model
        .includes(includes_query)
        .joins(:share)
        .where.not(share_id: previous_ids)

and the rubocop indented style:

array = Model
  .includes(includes_query)
  .joins(:share)
  .where.not(share_id: previous_ids)

Does the Rubymine style align the dot with the last character of the first line? We need more examples if we are to support it. I suggest adding a separate issue, but we have to wait and see what happens with #2493 first.

Rubymine does not align with the last character of the first line, but instead uses an indentation of 4 spaces:

test = Abc
           .hello
           .world

test = Abcd
           .hello
           .world

test = Abcde
           .hello
           .world

test = Abcdef
           .hello
           .world

test = Abcdefg
           .hello
           .world

and:

    .hello
    .world

Abcd
    .hello
    .world

Abcde
    .hello
    .world

Abcdef
    .hello
    .world

Abcdefg
    .hello
    .world

(let me add that in all other cases Rubymine uses the standard 2 spaces as indentation, there must be a reason why they double that in multilines)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

deivid-rodriguez picture deivid-rodriguez  路  3Comments

bbugh picture bbugh  路  3Comments

benoittgt picture benoittgt  路  3Comments

kirrmann picture kirrmann  路  3Comments

lepieru picture lepieru  路  3Comments