Selectively ignoring exceptions in examples

Hi all

Long time since I’ve posted to rspec-users. Glad to see the place is
still here and hope you’re all well :slight_smile:

I have a question about ignoring exceptions when they’re not
interesting. For example, I have a few cases in my code along these
lines

it “prints an error” do
expect {
run_command(%w[ missing_wallet.dat ])
}.to raise_error

 stream_bundle.captured_error.should eq "Couldn't find wallet file: 

missing_wallet.dat\n"
end

it “raises a CLI::CommandError” do
expect {
run_command(%w[ missing_wallet.dat ])
}.to raise_error(CLI::CommandError)
end

But in the first example, I’m only bothered about the output, not the
error. So I was thinking of writing something along the lines of:

it “prints an error” do
ignoring_errors {
run_command(%w[ missing_wallet.dat ])
}
stream_bundle.captured_error.should eq “Couldn’t find wallet file:
missing_wallet.dat\n”
end

Now obviously that wouldn’t be hard to add as a helper method. But it
got me thinking

  • Do any of you do this?
  • Does RSpec already let you somehow?
  • Is it a useful convention?
  • Is it hiding anything else? (I don’t use exceptions much, so I may be
    abusing them.)

Cheers
Ash


http://www.patchspace.co.uk/
http://www.linkedin.com/in/ashmoran

Hey there, Ash. Why not put your call to #run_command inside a
begin-rescue
statement?

On 29 Aug 2011, at 20:09, Nick wrote:

Hey there, Ash. Why not put your call to #run_command inside a begin-rescue
statement?

Hi Nick

Yes I’m missing the obvious as usual* :slight_smile:

Well I guess I could, but the syntax then is even more intrusive. I
guess I just want the lightest way possible to say “Yes, I know this
code fails, but I still want to know what’s going on inside it!” That’s
why I wondered maybe I should give more thought to how I’m using
exceptions. (I’m raising a CLI::CommandError anywhere in a Command class
where I know I don’t want the CLI to proceed any further.)

Cheers
Ash

  • I’m sorry, I wrote the code on my own, my pair was actually taking his
    bank holiday off :slight_smile:


http://www.patchspace.co.uk/
http://www.linkedin.com/in/ashmoran

On Mon, Aug 29, 2011 at 9:24 AM, Ash M. [email protected]
wrote:

it “prints an error” do
ignoring_errors {
run_command(%w[ missing_wallet.dat ])
}
stream_bundle.captured_error.should eq “Couldn’t find wallet file:
missing_wallet.dat\n”
end

Now obviously that wouldn’t be hard to add as a helper method. But it got me
thinking

  • Do any of you do this?

I do. So often that I wrote a helper and put it in Wrong.

I don’t quite get what “stream_bundle.captured_error” is in your
example, but I think the above example would become

rescuing {
run_command(%w[ missing_wallet.dat ])
}.message.should == “Couldn’t find whatever”

We’ve also got “capturing” for grabbing console output, e.g.

capturing { puts “hi” }.should == “hi”

or

out, err = capturing(:stdout, :stderr) { … }

See GitHub - sconover/wrong: Wrong provides a general assert method that takes a predicate block. Assertion failure messages are rich in detail.


Alex C. - [email protected]
http://alexch.github.com
http://twitter.com/alexch

I’ve found this pattern useful as now that only files in my bin/ folder ever
access ARGV, STDOUT etc, the code is more loosely coupled, but also I can see
exactly where I’m talking to the outside world. Every time I want to send some
output, I think- “Should I really be giving this object a StreamBundle? Is it
really appropriate for it to be talking to the user directly?”

I hear you. When I first started coding in Ruby I was injecting all
over the place. But nowadays I’m much more comfortable with the
flexibility of things like reopening classes during tests, or mocking
methods, or resetting globals…

…or grabbing and reassigning $stdout and $stderr, which is what
“capturing” does.

The basic idea is that Ruby is already decoupled from stdin/out/err
via its dynamic nature and $globals. I get that by naming the inputs
explicitly you’re ensuring 100% compliance but you should consider
whether it’s worth it. Passing around DI clumps (aka “value objects”
or “parameter objects” in some circles) can make your code a lot less
concise, and concision is one of the great joys of Ruby.

btw apologies if you already know this, but inside a normal Ruby
program you should always use $stderr/$stdout/$stdin, not
STDERR/STDOUT/STDIN since the former are settable and the latter are
hardcoded to the “real” streams and, as true CONSTANTS, not easy to
change. For whatever reason I see the caps versions used a lot more
than the dollar versions, which is a shame.


Alex C. - [email protected]
http://alexch.github.com
http://twitter.com/alexch

On 30 Aug 2011, at 00:09, Alex C. wrote:

I do. So often that I wrote a helper and put it in Wrong.

Cool, and also I really should try Wrong! I’ve just put it on my project
TODO list as something to investigate

I don’t quite get what “stream_bundle.captured_error” is in your
example, but I think the above example would become

rescuing {
run_command(%w[ missing_wallet.dat ])
}.message.should == “Couldn’t find whatever”

We’ve also got “capturing” for grabbing console output, e.g.

capturing { puts “hi” }.should == “hi”

Sorry, I didn’t realise how opaque that is if you don’t know what one
is.

Basically, I wanted to decouple the app from STDIN/STDOUT/STDERR so I
started injecting StringIO objects around for testing. After a while I
had a data clump of @input/@output/@error in classes everywhere, so I
made a StreamBundle[1] to encapsulate them. (Apologies for lack of
syntax highlighting on patch-tag.com)

But then I realised my tests were making a
StreamBundle.new(StringIO.new, StringIO.new, StringIO.new) everywhere,
so I factored out the duplication into a CapturingStreamBundle[2]
decorator that records all output to secondary StringIO objects. Now I
just call CapturingStreamBundle.test_bundle to get one.

I’ve found this pattern useful as now that only files in my bin/ folder
ever access ARGV, STDOUT etc, the code is more loosely coupled, but also
I can see exactly where I’m talking to the outside world. Every time I
want to send some output, I think- “Should I really be giving this
object a StreamBundle? Is it really appropriate for it to be talking to
the user directly?”

That’s the backstory anyway!

Ash

[1]
https://patch-tag.com/r/ashmoran/rbcoin/snapshot/current/content/pretty/lib/bitcoin/console/stream_bundle.rb
[2]
https://patch-tag.com/r/ashmoran/rbcoin/snapshot/current/content/pretty/lib/bitcoin/console/capturing_stream_bundle.rb


http://www.patchspace.co.uk/
http://www.linkedin.com/in/ashmoran

On 30 Aug 2011, at 19:24, Alex C. wrote:

…or grabbing and reassigning $stdout and $stderr, which is what
“capturing” does.

The basic idea is that Ruby is already decoupled from stdin/out/err
via its dynamic nature and $globals. I get that by naming the inputs
explicitly you’re ensuring 100% compliance but you should consider
whether it’s worth it. Passing around DI clumps (aka “value objects”
or “parameter objects” in some circles) can make your code a lot less
concise, and concision is one of the great joys of Ruby.

Yes, I’ve done constant reassigning in the past, with before/after
blocks to control the environment. I wasn’t specifically avoiding that
here, it’s just what fell out my my initial design to pass the standard
streams in as variables from the bin/ command. I’m going to see how it
pans out, as I’ve never been so strict about IO before.

btw apologies if you already know this, but inside a normal Ruby
program you should always use $stderr/$stdout/$stdin, not
STDERR/STDOUT/STDIN since the former are settable and the latter are
hardcoded to the “real” streams and, as true CONSTANTS, not easy to
change. For whatever reason I see the caps versions used a lot more
than the dollar versions, which is a shame.

Actually I didn’t know that, so thanks for pointing it out :slight_smile: Although
I have often been puzzled by the presence of both forms

Cheers
Ash


http://www.patchspace.co.uk/
http://www.linkedin.com/in/ashmoran