http://www.perlmonks.org?node_id=1003105


in reply to Re^3: Moo and Spreadsheet::ParseExcel
in thread Moo and Spreadsheet::ParseExcel

The whole stuff:

ETL.pm

package Karl::ETL; use Moo; use MooX::Types::MooseLike::Base qw( Str ); has user => ( is => 'rw', isa => Str ); has passwd => ( is => 'rw', isa => Str ); has dsn => ( is => 'rw', isa => Str ); with qw( Karl::DBIxODBC Karl::MyParseExcel ); 1;

DBIxODBC.pm

package Karl::DBIxODBC; use Moo::Role; use MooX::Types::MooseLike::Base qw(InstanceOf HashRef ArrayRef); use DBIx::Simple; requires qw( user passwd dsn ); has 'loader' => ( is => 'rw', isa => HashRef[ ArrayRef ], trigger => \&_load, ); has '_dbix' => ( is => 'ro', isa => InstanceOf('DBIx::Simple'), handles => [qw( insert )], builder => '_build_dbix', lazy => 1, ); sub _build_dbix() { my $self = shift; my $connect_string; $connect_string = "dbi:ODBC:" . $self->dsn; DBIx::Simple->new( $connect_string, $self->user, $self->passwd ); } sub _load() { my ( $self, $input ) = @_; my $table = ( keys %$input )[0]; foreach my $row ( @{ $input->{$table} } ) { $self->insert( $table, $row ); } } 1;

MyParseExcel.pm

package Karl::MyParseExcel; use Moo::Role; use Spreadsheet::ParseExcel; use MooX::Types::MooseLike::Base qw(InstanceOf Str); 1;

etl.pl (was run.pl)

#!C:/perl/bin/perl.exe use strict; use warnings; use lib q(C:/local/lib/perl); use Karl::ETL; my $etl = Karl::ETL->new( dsn => 'dsn_name', user => 'name', passwd => 'secret', ); my $data->{test} = [ [qw(foo bar)] ]; $etl->loader($data);
Regards, Karl
«The Crux of the Biscuit is the Apostrophe» Karl Goethebier

Replies are listed 'Best First'.
Re^5: Moo and Spreadsheet::ParseExcel
by tobyink (Canon) on Nov 09, 2012 at 12:21 UTC

    Error reproduced! :-)

    Here's a one line patch for Moo::Role that fixes your issue. I'll report it to the Moo bug tracker when I've figured out why this patch makes any difference to anything!

    # Replace this sub... sub apply_roles_to_package { my ($me, $to, @roles) = @_; $me->_inhale_if_moose($_) for @roles; $me->SUPER::apply_roles_to_package($to, @roles); } # With this instead... sub apply_roles_to_package { my ($me, $to, @roles) = @_; for my $r (@roles) { $me->_inhale_if_moose($r) }; $me->SUPER::apply_roles_to_package($to, @roles); }

    Update: OK, it happens because something inadvertently causes the global $_ to become undefined.

    Update 2: Bug report submitted.

    Update 3: patched on git.

    Update 4 (about a week later): Moo 1.000006 released.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      Great! But how strange. local $_ also fails. It would be very interesting to hear why this fails.

      Update: Ergo better omit $_ in general?

      Thank you very much for your help and best regards,

      Karl

      «The Crux of the Biscuit is the Apostrophe»

        my $_ should work, but local $_ would fail.

        It's because the loop variable in a for loop is an alias to each element of the array. So the global $_ is an alias into @roles in this case. Assigning to global $_ assigns into the @roles array. local (despite the name) operates on global variables, providing a local value for them, but not really creating a new local variable. So even in the scope of local $_ assigning to $_ will assign into @roles.

        It's a particular combination of Perl features which is normally fairly safe to use, but because apply_roles_to_package also happens to load modules (and thus run third-party code - i.e. code which is not part of Moo) it causes problems.

        perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      Thanks again for fixing this. Regards, Karl

      «The Crux of the Biscuit is the Apostrophe»