I wanted to build an awesome place for people to discuss module specific issues, but I don't have any more time for this, and there are much better places to discuss Perl-related issues. I'd recommend asking your question on Stack Overflow or on Perl Monks.
If you are looking for a Perl tutorial or Perl-related news, I hope these links will serve you well.
Posted on 2007-04-05 03:29:36-07 by geraud
Object::InsideOut and Test::Deep, the worst ennemies?
Heya all, I was writing some tests on a project at work using OIO when I stumbled upon a little annoyance. I'm not really sure to know which of the two modules should be considered the 'guilty' one (if any), but since this forum is more active than Test::Deep's one and the problem is user-visible via OIO, I come here first in search of wisdom.

So here's a reproducible case (my_test.t):
#!/usr/bin/perl -w use strict; package MyObj; { use Object::InsideOut; my @data :Field :Std(data) :Arg(Name => 'data', Mandatory => 1); sub push_data { my ($self, $str); my $new_data = $self->get_data() . $str; $self->set_data( $new_data ); return $new_data; } } package main; use Test::More 'no_plan'; use Test::Deep; can_ok('MyObj', 'push_data'); eval { my $obj = MyObj->new(); }; if ($@) { print $@->full_message(); }
If you run my_test.t, you'll get several warnings about "Use of uninitialized value in concatenation (.) or string at .../Object/InsideOut/Exception.pm line 124.". Now if you remove the 'use Test::Deep;' line, the warnings are gone. Note also that this is triggered only when doing something with the OIO::Args object, i.e. if you remove the print line but still use T::D, no warnings.

With a 'print Dumper $@;' it shows that if T::D is used, the $@->{file|package|line} are gone as well as the frames array in $@->{trace}. After that, I'm lost. Does anyone have an idea about how I could still use T::D while silencing those warnings?

Thanks Jerry and other contributors for the work on OIO, totally amazing module I must say.

G.
Direct Responses: 4769 | 4773 | Write a response
Posted on 2007-04-05 13:26:19-07 by jdhedden in response to 4765
Re: Object::InsideOut and Test::Deep, the worst ennemies?
Wow. This took me a bit, but I tracked it down to a problem with Test::Deep - it screws up the ->isa() method:
#!/usr/bin/perl use strict; use warnings; use Test::More tests => 2; BEGIN { ok(! main->isa('Foo'), q/'main' is not a 'Foo' before using Test::Deep/); } use Test::Deep; ok(! main->isa('Foo'), q/'main' should not be a 'Foo' after using Test::Deep/); diag("'main->isa('Foo')' yields: " . main->isa('Foo'));
This produces:
1..2 ok 1 - 'main' is not a 'Foo' before using Test::Deep not ok 2 - 'main' should not be a 'Foo' after using Test::Deep # Failed test ''main' should not be a 'Foo' after using Test::Deep' # at ./bug.pl line 14. # 'main->isa('Foo')' yields: Test::Deep::Isa=HASH(0x10194378) # Looks like you failed 1 test of 2.
I will file this information as a bug report against Test::Deep. Until it gets fixed, it appears that Test::Deep is incompatible with OIO (and anything else that makes use of ->isa()).
Direct Responses: 4772 | Write a response
Posted on 2007-04-05 15:02:06-07 by jdhedden in response to 4769
Re: Object::InsideOut and Test::Deep, the worst ennemies?
The author for Test::Deep has suggested a work-around:
use Test::Deep ();
Direct Responses: Write a response
Posted on 2007-04-05 15:14:25-07 by fergal in response to 4765
Re: Object::InsideOut and Test::Deep, the worst ennemies?
I don't consider this a bug, creating a main::isa subroutine should be harmless, &isa is only supposed to have a special meaning in OO packages. The fact that something else has decided to start calling isa() on non-OO packages is unfortunate. If you don't want Test::Deep to export &isa you can do

use Test::Deep qw(just the functions I want);

just like any other module that exports functions.
Direct Responses: 4777 | Write a response
Posted on 2007-04-06 04:09:36-07 by jdhedden in response to 4773
Re: Object::InsideOut and Test::Deep, the worst ennemies?
The issue isn't the existence of main::isa: You can do '$main::isa = \&UNIVERSAL::isa;' to create main::isa, and then call main->isa('Foo') and you get false as you should.

The problem is that the 'isa' installed by Test::Deep is 'broken' with respect to 'main': It causes main->isa('Foo') to return true when it shouldn't.
Direct Responses: 4781 | Write a response
Posted on 2007-04-06 08:31:53-07 by fergal in response to 4777
Re: Object::InsideOut and Test::Deep, the worst ennemies?
For the benefit of those not following along on the CPAN bug, here's a copy of my response.

---
My code doesn't "break" isa. When you define an isa subroutine in a class, it has a special meaning but I'm not defining it in a class, I'm just defining it in a normal package where it should be called as a function, not as a method, this is perfectly valid perl. The same goes for can() and does() subroutines. They only have a special with relation to classes.

The problem is that Devel::StackTrace calls ->isa() on _all_ of the packages it sees in the stack, whether they're classes or not (a more fundamental problem with Perl is that there's no way to tell).

The reason I won't change Test::Deep is because the existing users of Test::Deep have written their tests expecting it to export isa. If it stopped, these test scripts would break and modules authors would receive bug reports and have to make new releases etc etc.

I will however file a bug against Devel::StackTrace and see if we can work out something better than calling ->isa on everything it sees.

---

I would add that unless somewhere in your code you do

$o = bless {}, "main";

or

main->some_method()

then nothing should ever call main::isa as a method.
Direct Responses: Write a response