On 4/2/07, [EMAIL PROTECTED] wrote:
>   sub setup {
>       my ( $self, %arg_for ) = @_;
>       $self->SUPER::setup(%arg_for);
>       foreach my $column ( $self->columns ) {
>           my $name = $column->name;
>
>           # here's the problem
>           $self->alias_column( $name => "_$name" )
>             unless $self->class->is_public($column);

At this point (after calling SUPER::setup()), the column methods have
already been created, so aliasing a columns will not do what you want
unless you then re-initialize() or otherwise re-make the column
methods, overriding the existing methods.

But there's a better time to do this kind of thing.  When mucking with
Metadata subclasses, the rule of thumb is to override the most
specific method possible.  setup() is the least specific method (i.e.,
it's the highest level).  If you want to twiddle columns, I suggest
overriding add_columns() and getting them as soon as they come into
being:

    sub add_columns
    {
      my($self) = shift;

      my @added_columns = $self->SUPER::add_columns(@_);

      foreach my $column (@added_columns )
      {
        $self->alias_column($column->name => '_' . $column->name)
           unless($self->class->is_public($column));
      }

      return @added_columns ;
    }

(The return value for add_columns() wasn't documented, but has always
been the list of columns just added.  It's documented in SVN.)

> So somehow, when aliasing a column, column_mutator_method_names_hash()
> appears to return incorrect values or, perhaps, @$column_names is
> getting incorrect values.  I'll dig into this more later, but if anyone
> can offer insight, I'd appreciate it.

I suspect this is a side-effect of aliasing columns after the column
methods have already been created.  The cache of mutator method names
is wiped, but then never repopulated (as it would be if the column
methods were explicitly re-created after aliasing-too-late).  Anyway,
all this is side-stepped by aliasing the columns as soon as possible,
rather than after the entire setup process has finished.

>  # XXX There should be a simpler way to push this into the base class.
>  # I have an idea of how to do it, but for now, I'll table it.
>  __PACKAGE__->meta->make_manager_class('os');

This is actually one thing you can and should do after the entire
Rose::DB::Object-derived class is entirely set up.  So here you could
override setup() and add the appropriate make_manager_class() call at
the end.

> Note: the 'Readonly' class merely makes the mutators throw exceptions
> if called.

If I understand your intent correctly, and you really never want to be
able to set certain columns at all from Perl-land, another possible
technique is to simply create accessor-only methods for them.  That
is, just "get" methods instead of the usual "get_set" methods.

Each column (and fk and relationship) can have zero or more methods
created on behalf of it.  By default, each column has one method, a
"get_set" method created for it.  Read more here:

http://search.cpan.org/dist/Rose-DB-Object/lib/Rose/DB/Object/Metadata/Column.pm#MAKING_METHODS

So, here's an alternate implementation off the top of my head:

    sub add_columns
    {
      my($self) = shift;

      my @columns = $self->SUPER::add_columns(@_);

      foreach my $column (@columns)
      {
        unless($self->class->is_public($column))
        {
          $column->auto_method_types('get'); # only create accessor
        }
      }

      return @columns;
    }

Unfortunately, most 'get' methods will not throw an exception if you
pass an arg; they'll just ignore any args.  Of course, you can always
alias the column and only create a get method and then *also* create
an exception-thrower under the usual name:

    sub add_columns
    {
      my($self) = shift;

      my @columns = $self->SUPER::add_columns(@_);

      foreach my $column (@columns)
      {
        unless($self->class->is_public($column))
        {
          my $name    = $column->name;
          my $mangled = "_$name";

          # alias column
          $self->alias_column($name => $mangled);

          # only create accessor
          $column->auto_method_types('get');

          unless($self->class->can($name))
          {
            # Create exception-thrower under unmangled name
            no strict 'refs';
            *{"${class}::$name"} = sub
            {
              my($self) = shift;
              croak "No args, please..."  if(@_);
              $self->$mangled();
            };
          }
        }
      }

      return @columns;
    }

Hm, that's kind of ugly.  Anyway, TMTOWTDI :)

-John

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Rose-db-object mailing list
Rose-db-object@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/rose-db-object

Reply via email to