in reply to Re^5: If Perl 5 were to become Perl 7, what (backward-compatible) features would you want to see?
in thread If Perl 5 were to become Perl 7, what (backward-compatible) features would you want to see?

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.
  • Comment on Re^6: If Perl 5 were to become Perl 7, what (backward-compatible) features would you want to see?
  • Select or Download Code

Replies are listed 'Best First'.
Re^7: If Perl 5 were to become Perl 7, what (backward-compatible) features would you want to see?
by tobyink (Canon) on Oct 16, 2019 at 07:29 UTC

    If you're happy to coerce from an arrayref ([$dsn,$u,$p,\%opts]) instead of a hashref, then:

    package Moo::Role::DBIConnection { use Moo::Role; use DBI; use Types::DBI; has dbh => (is => 'ro', isa => Dbh, required => 1, coerce => 1); };

    Coercion from HashRef isn't provided in Types::DBI (because that would require choosing hash key names, something probably application-specific) but it's pretty easy to add in if you need it:

    package Moo::Role::DBIConnection { use Moo::Role; use DBI; use Types::DBI; use Types::Standard qw(HashRef); has dbh => ( is => 'ro', isa => Dbh->plus_coercions(HashRef, sub { DBI->connect( +@{$_}{qw/dsn user password options/}) }), required => 1, coerce => 1, ); };
      Neat. Neater, see below. ;-)

      *** Trigger Warning *** Raku content *** Trigger Warning ***


      holli

      You can lead your users to water, but alas, you cannot drown them.