rubocop / ruby-style-guide

A community-driven Ruby coding style guide
https://rubystyle.guide
16.45k stars 3.4k forks source link

Style/BlockDelimiters breaks natural language of rspec matchers #522

Open aspiers opened 8 years ago

aspiers commented 8 years ago

RSpec Expectations allow syntax like:

expect { ... some code ... }.to raise_error(MyErrorClass, my_error_message)

However if the code under test is not trivially short, it will need to be split onto multiple lines, e.g. here's some real-world code:

it "should barf if the definition's type is not right" do
  expect {
    fixture.definition = "sometype #{fixture.name} blah blah"
  }.to \
    raise_error(
      Pacemaker::CIBObject::TypeMismatch,
      "Expected #{object_type} type but loaded definition was type sometype"
    )
end

but this causes

Style/BlockDelimiters: Avoid using {...} for multi-line blocks.
https://github.com/bbatsov/ruby-style-guide#single-line-blocks

complaints from rubocop.

The problem is that changing it to

expect do
  ... some code ...
end.to raise_error(MyErrorClass, my_error_message)

completely ruins the previously natural language flow of the "expect ... to" statement. So what's the solution?

A related problem is that I'm also struggling to find a combination of line breaks/continuations and indentation which looks good here. Suggestions very welcome.

onebree commented 8 years ago

This is not just a problem for rspec, but any time you want to chain off a method block -- such as mapping out a new array and calling #uniq on it

fuadsaud commented 8 years ago

Possibly related: #162

JelF commented 8 years ago

what about

expect { fixture.definition = "sometype #{fixture.name} blah blah" }
  .to ...

???

ghost commented 8 years ago

It's easy to suppress the complaints through .rubocop.yml

Style/BlockDelimiters:
  Exclude:
    - 'spec/**/*'
aspiers commented 8 years ago

@monkseal Thanks, I'll give that a try when I get a chance! Does it make sense to change the rubocop defaults based on this new information?

zzeni commented 6 years ago

There's a built-in configuration that allows usage of the curly braces when chaining methods:

Style/BlockDelimiters:
  EnforcedStyle: braces_for_chaining

https://github.com/bbatsov/rubocop/pull/2329

monkseal commented 6 years ago

@zzeni Thanks! Removed my comment incase anybody is doing it the wrong way.

aspiers commented 4 years ago

Great to see some progress here, but I think this is still an issue until the default behaviour of this cop doesn't complain about the natural language of rspec matchers.

aspiers commented 4 years ago

Turns out that @zzeni's approach doesn't just allow usage of curly braces, it insists on them. I'm looking for a solution which normally insists on do ... end but makes an exception when it's an expect block. In the mean time it seems @ghost's solution is the best workaround.

pirj commented 3 years ago

RuboCop discussions aside, I believe the Guide can be improved:

  1. ~multi-line chaining is always ugly~
    
    # not so ugly
    expect {
    filter_applies?(:foo, lambda { |a,b,c| true }, example_metadata)
    }.to raise_error(ArgumentError)

a little uglier

expect { filter_applies?(:foo, lambda { |a,b,c| true }, example_metadata) } .to raise_error(ArgumentError)


2.
```ruby
# bad
names.each do |name|
  puts name
end

# not so bad already?
names.each do |name|
  SomeExtravagantServiceName.process_incoming_names_and_welcome_new_user(full_name: name)
end

# this is arguably uglier than the one above
names.each { |name| SomeExtravagantServiceName.process_incoming_names_and_welcome_new_user(full_name: name) }

3.

Some will argue that multi-line chaining would look OK with the use of {…​}, but they should ask themselves - is this code really readable and can the blocks' contents be extracted into nifty methods?

I ask this myself quite often, but most of my colleagues get surprised that expect(...) can be extracted to expect_filter_for(:foo) and contain_exactly(...) to return_a_full_list. So, in general, the answer is "yes, it's readable" and "no, extracting to methods gives my colleagues a hard time".