I think I would use a coercion to simplify that, and, yes, shed the unwanted attributes (accessors). Note I dropped the signatures as I don;t have the Filter module installed, but also no longer needed.
package Moo::Role::DBIConnection {
use Moo::Role;
use DBI;
has 'dbh' => (
is => 'ro',
required => 1,
coerce => sub {
my $args = shift;
return $args if ref($args) eq 'DBI::db';
ref($args) eq 'HASH' or die 'Not a DB handle nor a hashref
+';
return DBI->connect( @{$args}{qw/dsn user password options
+/} );
},
);
};
##
# testing
package MyClass {
use Moo;
with 'Moo::Role::DBIConnection';
};
use Test::Most 'die';
my %args = (
dsn => 'dbi:mysql:database=mysql',
user => 'ntonkin',
password => undef,
options => { RaiseError => 1 },
);
subtest 'With no args' => sub {
dies_ok sub { my $o = MyClass->new }, 'exception on no args';
};
subtest 'With bad type' => sub {
throws_ok { my $o = MyClass->new(dbh => [\%args]) } qr/Not a DB ha
+ndle nor a hashref/;
};
subtest 'With existing handle' => sub {
my $dbh = DBI->connect( @args{qw/dsn user password options/} );
cmp_ok( $dbh->do('select count(*) from db'), '>', 0, 'Found a DB'
+);
my $o = new_ok('MyClass', [dbh => $dbh], 'No exception with handle
+ passed in');
cmp_ok( $o->dbh->do('select count(*) from db'), '>', 0, 'Found a D
+B via obj');
};
subtest 'With bad params' => sub {
local $args{user} = 'frobnicator';
throws_ok { my $o = MyClass->new(dbh => \%args) } qr/coercion for
+"dbh" failed/;
throws_ok { my $o = MyClass->new(dbh => \%args) } qr/Access denied
+ for user/;
};
subtest 'With params' => sub {
my $o = new_ok('MyClass', [dbh => \%args], 'No exception with args
+ hash passed in');
cmp_ok( $o->dbh->do('select count(*) from db'), '>', 0, 'Found a D
+B via obj');
dies_ok sub { print $o->dsn }, 'No DSN accessor!';
};
done_testing;
Output:
$ prove -lrv 11107494.pl
11107494.pl ..
# Subtest: With no args
ok 1 - exception on no args
1..1
ok 1 - With no args
# Subtest: With bad type
ok 1 - threw Regexp ((?^:Not a DB handle nor a hashref))
1..1
ok 2 - With bad type
# Subtest: With existing handle
ok 1 - Found a DB
ok 2 - 'No exception with handle passed in' isa 'MyClass'
ok 3 - Found a DB via obj
1..3
ok 3 - With existing handle
# Subtest: With bad params
ok 1 - threw Regexp ((?^:coercion for "dbh" failed))
ok 2 - threw Regexp ((?^:Access denied for user))
1..2
ok 4 - With bad params
# Subtest: With params
ok 1 - 'No exception with args hash passed in' isa 'MyClass'
ok 2 - Found a DB via obj
ok 3 - No DSN accessor!
1..3
ok 5 - With params
1..5
ok
All tests successful.
Files=1, Tests=5, 0 wallclock secs ( 0.01 usr 0.00 sys + 0.09 cusr
+ 0.01 csys = 0.11 CPU)
Result: PASS
Hope this helps!
update: added test for bad type and moved isa check to coercion
The way forward always starts with a minimal test.
|