Forum: RSpec Can I do foo.should (be_nil || be_empty) in rspec

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Andrew P. (Guest)
on 2008-11-04 13:12
(Received via mailing list)
Is there any way to do

  foo.should (be_nil || be_empty)

in rspec.

Thanks in advance
Tom S. (Guest)
on 2008-11-04 13:23
(Received via mailing list)
On 4 Nov 2008, at 11:10, Andrew P. wrote:
> Is there any way to do
>   foo.should (be_nil || be_empty)
> in rspec.

"foo.should be_blank" would work if you're using Rails (i.e.
ActiveSupport is loaded).

Cheers,
-Tom
Ashley M. (Guest)
on 2008-11-04 13:25
(Received via mailing list)
On 4 Nov 2008, at 11:10, Andrew P. wrote:

> Is there any way to do
>
>   foo.should (be_nil || be_empty)
>
> in rspec.

That won't do what you want it to, at first glance it will always
match with be_nil.  You could write a custom matcher
(be_nil_or_empty), but I suspect that's not the real answer here.

Why do you want to do this?  What is the distinction between nil and
empty in your app?  I suspect this is a data modelling issue rather
than a spec issue.  (Be very wary as soon as you see conditionals in
your code.)

Ashley


--
http://www.patchspace.co.uk/
http://aviewfromafar.net/
Andrew P. (Guest)
on 2008-11-04 13:28
(Received via mailing list)
Sweet I'm using rails so will give it a go. Any ideas about the general
case, is making a custom matcher the (only) way to go?
All best

Andrew

2008/11/4 Tom S. <removed_email_address@domain.invalid>
Ashley M. (Guest)
on 2008-11-04 13:57
(Received via mailing list)
On 4 Nov 2008, at 11:26, Andrew P. wrote:

> Any ideas about the general case, is making a custom matcher the
> (only) way to go?

Can you give an example of what you're doing, or think you might do?
Until I saw Tom's reply it never occurred to me that you might be
dealing with strings (I thought you were doing something with an array
or other collection.)

Ashley

--
http://www.patchspace.co.uk/
http://aviewfromafar.net/
Andrew P. (Guest)
on 2008-11-04 14:47
(Received via mailing list)
General case I'm thinking about is just testing that something should be
one
thing or another
   e.g x.should be(foo || bar)

Haven't got a specific example at the moment apart from the blank one.
What
I'm thinking about is the syntax to say this in a spec, as I think there
must be lots of times when having this sort of syntax would be useful.

All best

Andrew



2008/11/4 Ashley M. <removed_email_address@domain.invalid>
Ashley M. (Guest)
on 2008-11-04 15:59
(Received via mailing list)
On 4 Nov 2008, at 12:45, Andrew P. wrote:

> General case I'm thinking about is just testing that something
> should be one thing or another
>
>    e.g x.should be(foo || bar)
>
> Haven't got a specific example at the moment apart from the blank
> one.  What I'm thinking about is the syntax to say this in a spec,
> as I think there must be lots of times when having this sort of
> syntax would be useful.

Hi Andrew

I suspect that in general the concept of an object O being (foo ||
bar) actually means there's a rule that makes your object baz
instead.  The reason is that if you spec foo and bar independently,
you double the number of contexts for objects that depend on O.

So this might not look to bad:

   describe MyObject do
     before(:each) do
       @o = MyObject.new
     end

     it "should be foo or bar" do
       @o.should be_foo_or_bar
     end
   end

but it means everywhere else you're forced to duplicate that logic, eg:

   describe MyOtherObject do
     describe "when its MyObject is foo" do
       before(:each) do
         o = mock(MyObject, :foo => true, :bar => false)
         @oo = MyOtherObject.new(o)
       end
       it "should be faz" do
         @oo.should be_faz
       end
     end

     describe "when its MyObject is bar" do
       before(:each) do
         o = mock(MyObject, :foo => false, :bar => true)
         @oo = MyOtherObject.new(o)
       end
       it "should be faz" do
         @oo.should be_faz
       end
     end

     describe "when its MyObject is neither foo nor bar" do
       before(:each) do
         o = mock(MyObject, :foo => false, :bar => false)
         @oo = MyOtherObject.new(o)
       end
       it "should not be faz" do
         @oo.should_not be_faz
       end
     end
   end

instead of just:

   describe MyOtherObject do
     describe "when its MyObject is baz" do
       before(:each) do
         o = mock(MyObject, :baz => true)
         @oo = MyOtherObject.new(o)
       end
       it "should be faz" do
         @oo.should be_faz
       end
     end

     describe "when its MyObject is not baz" do
       before(:each) do
         o = mock(MyObject, :baz => false)
         @oo = MyOtherObject.new(o)
       end
       it "should not be faz" do
         @oo.should_not be_faz
       end
     end
   end

s/foo/nil/
s/bar/empty/
s/baz/blank/

This make sense?  Sorry if it's a bit abstract, or has typos.  I
didn't actually run that code, of course...

I think in summary, two branches in your specs => you are violating
Tell Don't Ask (somewhere else) in your code.

Ashley

--
http://www.patchspace.co.uk/
http://aviewfromafar.net/
Pat M. (Guest)
on 2008-11-04 17:32
(Received via mailing list)
"Andrew P." <removed_email_address@domain.invalid> writes:

> General case I'm thinking about is just testing that something should be one thing or 
another
>
>    e.g x.should be(foo || bar)
>
> Haven't got a specific example at the moment apart from the blank one.  What I'm 
thinking about is the syntax to say this in a spec, as I
> think there must be lots of times when having this sort of syntax would be useful.

Hi,

This is a case where a custom matcher would be hiding a concept that
belongs directly in your code.  If you really don't care about the
difference between empty and nil, you should create a method - such as
#blank? - that handles that for you.

Pat
Andrew P. (Guest)
on 2008-11-04 18:23
(Received via mailing list)
Ashley,
Thanks for your time on this, the reply does make sense, and I can see
from
an OO point of view that any particular object being (foo||bar) is
equivalent to that object being baz. However with the dynamic nature of
ruby
we often don't know what object we are going to be dealing with in our
tests/specs. Whilst a unit test will generally (always?) be aimed at a
particular type, when implementing a plain text feature/story we are
often
working at a much higher level. In these cases the (foo || bar)
construct
could mean different types and a baz might not exist or be particularly
easy
to represent or formulate.

I can see that wanting this construct, could indicate a smell maybe a
badly
worded story - i.e. a conjunction step.

All best

Andrew

2008/11/4 Ashley M. <removed_email_address@domain.invalid>
Andrew P. (Guest)
on 2008-11-04 18:42
(Received via mailing list)
Ok I see. I was approaching this more from the syntax that my stories
can
express rather than what my code does. However from these replies and a
re-read of the cucumber wiki I can see that any step that requires the
(foo||bar) construct is by definition a conjunction and can be broken
into
smaller steps.
However we only have 'And' available in stories, do we need 'Or'?

All best

Andrew

2008/11/4 Pat M. <removed_email_address@domain.invalid>
Zach D. (Guest)
on 2008-11-04 18:46
(Received via mailing list)
On Tue, Nov 4, 2008 at 11:36 AM, Andrew P. 
<removed_email_address@domain.invalid>
wrote:
> Ok I see. I was approaching this more from the syntax that my stories can
> express rather than what my code does. However from these replies and a
> re-read of the cucumber wiki I can see that any step that requires the
> (foo||bar) construct is by definition a conjunction and can be broken into
> smaller steps.
> However we only have 'And' available in stories, do we need 'Or'?

What is your scenario that you are thinking of using an "or" ? This
may be helpful, otherwise we're going to speculating about the
theoretical use cases. I'd rather focus on your specific use case. :)

--
Zach D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com
Andrew P. (Guest)
on 2008-11-04 18:59
(Received via mailing list)
Oh I was definitely into theoretical speculation here :) - haven't got a
particular case at the moment

2008/11/4 Zach D. <removed_email_address@domain.invalid>
David C. (Guest)
on 2008-11-04 19:16
(Received via mailing list)
On Tue, Nov 4, 2008 at 9:29 AM, Pat M. <removed_email_address@domain.invalid> 
wrote:
>
> This is a case where a custom matcher would be hiding a concept that
> belongs directly in your code.  If you really don't care about the
> difference between empty and nil, you should create a method - such as
> #blank? - that handles that for you.

In which case you would get be_blank for free, in case you weren't
aware.

FYI - if you REALLY want to match against either, it's pretty easy to
do w/ simple matcher:

def be_nil_or_empty
  simple_matcher "nil? or empty? to return true" do |actual|
    actual.nil? || actual.empty?
  end
end

Cheers,
David
Ashley M. (Guest)
on 2008-11-04 21:17
(Received via mailing list)
On Nov 04, 2008, at 5:07 pm, David C. wrote:

> FYI - if you REALLY want to match against either, it's pretty easy to
> do w/ simple matcher:
>
> def be_nil_or_empty
>  simple_matcher "nil? or empty? to return true" do |actual|
>    actual.nil? || actual.empty?
>  end
> end


Wow, I completely forgot about simple_matcher.  That REALLY deserves a
more prominent place in the docs!  It's a great feature.

Would be really cool if you could do it like this though:

  simple_matcher :be_nil_or_empty, "nil? or empty? to return true" do |
actual|
    actual.nil? || actual.empty?
  end

and have it call define_method for you.

That's one I could hopefully do myself in time, after I've got a few
Merb/DataMapper jobs out of the way.

WYDAT?  Worth filing a ticket for?

Ashley

--
http://www.patchspace.co.uk/
http://aviewfromafar.net/
David C. (Guest)
on 2008-11-04 21:28
(Received via mailing list)
On Tue, Nov 4, 2008 at 1:14 PM, Ashley M.
<removed_email_address@domain.invalid> wrote:
>> end
>  end
>
> and have it call define_method for you.
>
> That's one I could hopefully do myself in time, after I've got a few
> Merb/DataMapper jobs out of the way.
>
> WYDAT?  Worth filing a ticket for?

If you can do it w/o breaking existing behaviour, sure.

Alternatively, you could add a new method:

def_matcher

or something like that.

Either way, it would be totally worth it.
Zach D. (Guest)
on 2008-11-04 21:33
(Received via mailing list)
On Tue, Nov 4, 2008 at 2:14 PM, Ashley M.
<removed_email_address@domain.invalid> wrote:
>> end
>  end
>
> and have it call define_method for you.
>
> That's one I could hopefully do myself in time, after I've got a few
> Merb/DataMapper jobs out of the way.
>
> WYDAT?  Worth filing a ticket for?

There are a few obstacles that it would have to overcome. As-is I
don't think that will work. If you file a ticket I'll comment there as
to why I think that. :)


--
Zach D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com
Pat M. (Guest)
on 2008-11-04 21:49
(Received via mailing list)
"David C." <removed_email_address@domain.invalid> writes:

> Alternatively, you could add a new method:
>
> def_matcher

I dig this.

Pat
David C. (Guest)
on 2008-11-04 21:56
(Received via mailing list)
On Tue, Nov 4, 2008 at 1:47 PM, Pat M. <removed_email_address@domain.invalid> 
wrote:
> "David C." <removed_email_address@domain.invalid> writes:
>
>> Alternatively, you could add a new method:
>>
>> def_matcher
>
> I dig this.

FYI - I was talking off-line (on line, really, but outside this list)
to wycats and he's got some matcher stuff in merb that I, shamefully,
have yet to check out in detail. It'd be good to peak at that and see
if it makes sense to bring it into rspec, or maybe release it as a
plugin/extension.
Ashley M. (Guest)
on 2008-11-04 22:43
(Received via mailing list)
On Nov 04, 2008, at 7:24 pm, Zach D. wrote:

> There are a few obstacles that it would have to overcome. As-is I
> don't think that will work. If you file a ticket I'll comment there as
> to why I think that. :)


I've filed a ticket[1].  Unleash your scepticism, Zach! :)

Ashley


[1]
http://rspec.lighthouseapp.com/projects/5645-rspec...

--
http://www.patchspace.co.uk/
http://aviewfromafar.net/
This topic is locked and can not be replied to.