CDBI + :lvalue

cwest on 2003-10-10T15:42:43

I thought it would be neat to make Class::DBI support lvalued accessors. For example.

my $film = File->retrieve(1);
$film->rating = 'PG-13';
$film->update;

So I decided to take a shot. The first step, and so I thought, only step was to make Class::Accessor create lvalue subroutines. I used Want.pm to make this happen. So here is what I did to the make_accessor() method. I did something similar to make_wo_accessor().

sub make_accessor {
my($class, $field) = @_;
# Build a closure around $field.
return sub :lvalue {
my($self) = shift;
require Want;
        if ( Want::want('LVALUE ASSIGN') ) {
$self->set($field, Want::want('ASSIGN'));
Want::lnoreturn();
} elsif (@_) {
if ( Want::want( 'RVALUE' ) ) {
Want::rreturn($self->set($field, @_));
} else {
return($self->set($field, @_));
}
} else {
if ( Want::want( 'RVALUE' ) ) {
Want::rreturn($self->get($field));
} else {
return($self->get($field));
}
}
return;
};
}

Ok, so all tests pass? Yes. New tests added? Yes. So all I have to do is install Class::Accessor and Class::DBI will Just Work? No.

I'm not sure what I did wrong, but here is how it broke down. There were situations that Want.pm apparently thought were lvalue context. Or maybe it was just Perl. Either way, it was confusing. Here are a couple examples.

show_film_name( $film->name );

Right there, I was getting errors about trying to modify a non-lvalue subroutine call. What? I'm not trying to modify anything of the sort, am I? Another example came right from the tests, 02-Film.t test number 10.

is($btaste->Title, 'Bad Taste', 'Title() get');

Produced the fatal error.

Can't modify non-lvalue subroutine call at ../Class-Accessor-0.18/lib/Class/Accessor.pm line 396.

I could stop the error by doing this.

my $title = $btaste->Title;
is($title, 'Bad Taste', 'Title() get');

At this point I decided to give up.

Posted from caseywest.com, comment here.