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

each_with_object style must respect immutable method_args #2321

Closed
abriel opened this issue Oct 14, 2015 · 5 comments
Closed

each_with_object style must respect immutable method_args #2321

abriel opened this issue Oct 14, 2015 · 5 comments

Comments

@abriel
Copy link

abriel commented Oct 14, 2015

each_with_object does not work on immutable objects like integer.
http://stackoverflow.com/questions/19064209/how-is-each-with-object-supposed-to-work

In case of
[1, 2, 3].reduce(0) { |a, e| a += e }
rubocop must leave it as is.

rubocop -V
0.34.2 (using Parser 2.2.2.5, running on ruby 2.2.2 x86_64-linux)

Thanks.

@minustehbare
Copy link
Contributor

Can you provide the message you are receiving? I reproduced the environment you listed and used a test file (shown below) and got a warning which does not relate to each_with_object:

W: Useless assignment to variable - a. Use just operator +.

puts [1, 2, 3].reduce(0) { |a, e| a += e }

@abriel
Copy link
Author

abriel commented Oct 28, 2015

r = [1, 2, 3].reduce(0) do |memo, item|
  memo += item > 2 ? item : 0
  memo
end

puts r
Offenses:

t.rb:1:15: C: Use each_with_object instead of reduce.
r = [1, 2, 3].reduce(0) do |memo, item|
              ^^^^^^

1 file inspected, 1 offense detected

If I just replace like it suggested, I got:

t.rb:1:5: W: The argument to each_with_object can not be immutable.
r = [1, 2, 3].each_with_object(0) do |item, memo|
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1 file inspected, 1 offense detected

Which is right.

@abriel
Copy link
Author

abriel commented Oct 28, 2015

There is the simple condition inside the closure, but in real it could be complex and cannot be modified into a simple one.

@minustehbare
Copy link
Contributor

Ok, with that example I am getting the same output; thank you. I toyed around with different syntax and it seems that RuboCop::Cop::Style::EachWithObject class specifically checks if your inject or reduce block ends with the accumulator value you pass in (e.g. memo).

# this does not generate an offense
r = [1, 2, 3].reduce(0) do |memo, item|
  memo + item > 2 ? memo + item : memo
end

I was also able to reproduce this error against the latest master changes using Ruby 2.2.3 and Parser 2.2.3.0

rubocop -V
0.34.2 (using Parser 2.2.3.0, running on ruby 2.2.3 x86_64-linux)

I will look into providing a fix in a pull request.

@alexdowad
Copy link
Contributor

The point isn't whether the initial value for reduce is immutable or not. Replacing reduce with each_with_object is not valid if the accumulator variable is assigned to within the block.

I'm just opening a PR which fixes this in EachWithObject.

bbatsov added a commit that referenced this issue Oct 29, 2015
[Fix #2321] Don't replace reduce with each_with_object if accumulator var is assigned to
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

No branches or pull requests

3 participants