LINUX.ORG.RU

Динамическое добавление полей при создании объекта

 ,


0

1

Как можно динамически создать свойства объекта класса, если я узнаю их характеристики только в момент создания объекта (в sub BUILD - читаю из БД)?

т.е. Хочется примерно такой код:


package MyClass; {

   use strict;
   use Moose;

   sub BUILD {
      my $self = shift;
      my $attrs = GET_FROM_DB();
      for my $attr (@$attrs) {
         has $attr => (
            is => 'rw',
            isa => 'Any'
         };
      }
   }
}

1;

В таком варианте ошибок нет, но и свойства не создаются...

★★★★★

Последнее исправление: cetjs2 (всего исправлений: 1)
Ответ на: комментарий от bvn13
package A;
use Moose;
sub make {
    has $_, is => "rw" for "a" .. "z";
}

package main;
my $a = new A;
$a->make;
print $a->b("s");



Пиши, где хочешь. После исполнения кода, который описывает поля, появятся поля.

helios ★★★★★
()
Последнее исправление: helios (всего исправлений: 1)
Ответ на: комментарий от bvn13
package MyClass; {

   use strict;
   use Moose;

   sub BUILD {
      my $self = shift;
      my $attrs = [qw/some attrs are here/];
      for my $attr (@$attrs) {
         has $attr, is => 'rw', isa => 'Any';
      }
   }
}

package main;
my $a = new MyClass;
print $a->here('there');

УМВР

helios ★★★★★
()
Ответ на: комментарий от helios

а вот содержимое объекта после создания:

$VAR1 = bless( {
                 'attrs' => {
                              'id' => {
                                        'value' => 12
                                      }
                            },
                 'tables' => {},
                 '_type' => 'Nomenclatures'
               }, 'ASObjects::CatalogTest' );
bvn13 ★★★★★
() автор топика
Ответ на: комментарий от helios

У меня они создаются! но их не видно в структуре, если я через Data::Dumper смотрю! о_О как быть? Забиыть? Мне бы поглядеть иной раз... :)

bvn13 ★★★★★
() автор топика
Ответ на: комментарий от bvn13

А это уже вопрос реализации: никто не обещал, что будет сразу создан элемент хеша.

helios ★★★★★
()
Ответ на: комментарий от helios

а кто знает? может, кого-то скастовать можно?

по сабжу.

в качестве типов для динамических атрибутов ставлю объекты самописного класса

has $aname => ( is => 'rw', isa => 'ASObjects::MValue', required => '1', default => sub { ASObjects::MValue->new } );

но потом почему-то не могу установить value у созданных атрибутов:

my $c = ASObjects::Catalog->new(_type=>'Nomenclatures');
print $c->name;
$c->name->value('test');
print $c->name;

при первом обращении к $c->name уже ругается, что undef... хотя в списке добавленных он есть.

Как быть? Где правда?

bvn13 ★★★★★
() автор топика
Ответ на: комментарий от bvn13
package My1;
use Moose;

has value => (
    is => 'rw',
    isa => 'Str',
    default => sub { 'hello'; }
);


package My2;
use Moose;

has name => (
    is => 'rw',
    isa => 'My1',
    default => sub { My1->new(); }
);


package main;
print My2->new->name->value('Buy');

Работает.

ps Надо было создавать тред с тегом «perl» а не «perl5» :)

а кто знает? может, кого-то скастовать можно?

На память приходят следующие ники:

[user]AITap[/user], [user]outtaspace[/user], [user]buddhist[/user], [user]Hoodoo[/user]
helios ★★★★★
()

Если я правильно понял, то можно делать так. Объект создаётся на основе того, что есть в базе.

sub construct_object {
        my $class = shift;
        my $table = $_[0];
        my @columns = SomePackage::Model::Base::struct_query($table);
        my $self = {};
        bless($self, $class);
        for $column (@columns) {
                $self->{$column} = '';
        }
        return $self;
}
А запрос к базе простейший:
sub struct_query {
        my $table = $_[0];
        my $query_result = $db_handle->selectall_arrayref("SHOW COLUMNS FROM $table");
        my @result;
        for my $name (@$query_result) {
                push(@result, $$name[0]);
        }
        return @result;
}

shell-script ★★★★★
()
Ответ на: комментарий от shell-script

немного неправильно понял :) вопрос не в том, как создать атрибуты на основе колонок в БД в ОБЫЧНОМ классе Перл, а как динамически создать атрибуты в классе, унаследованном от Moose.

bvn13 ★★★★★
() автор топика
Ответ на: комментарий от helios

а тег поменять можно? :)

bvn13 ★★★★★
() автор топика
Ответ на: комментарий от helios

кстати! подогнал этот рабочий код под свою реализацию с учетом условия динамического создания атрибутов:

#!/usr/bin/perl
package My1;
use Moose;

has value => (
    is => 'rw',
    isa => 'Str',
    default => sub { 'hello'; }
);


package My2;
use Moose;

sub BUILD {
    for my $aname ([qw/a b c/]) {
        has $aname => (
            is => 'rw',
            isa => 'My1',
            default => sub { My1->new(); }
        );
    }
}

has name => (
    is => 'rw',
    isa => 'My1',
    default => sub { My1->new(); }
);


package main;
print My2->new->a->value('Buy');

таки не работает!

> ./test1
Can't call method "value" on an undefined value at ./test1 line 33.

вопрос: почему?

bvn13 ★★★★★
() автор топика
Ответ на: комментарий от bvn13
#!/usr/bin/perl

package My1;

use Moose;

has value => (
    is      => 'rw',
    isa     => 'Str',
    default => 'hello from M1',
);

package My2;

use Moose;

sub BUILD {
    map {
        has $_ => (
            is => 'rw',
            isa => 'My1',
            default => sub { My1->new },
            lazy => 1,
        );
    } qw( test_field );
}

package main;

print My1->new->value(); # >hello from M1
print My2->new->test_field->value; # >hello from M1

Обратите внимание на lazy-buid. Посмотрите Moose::Meta::Attribute (The Moose attribute metaclass).

outtaspace ★★★
()
Ответ на: комментарий от outtaspace

Вы - мой спаситель! Все получилось! Не подумал, что нужно отложенно инициализировать. Кстати, а чем объясняется сие поведение?

bvn13 ★★★★★
() автор топика
Ответ на: комментарий от outtaspace

А можно попутный вопрос, вытекющий из данной проблемы? А в момент динамического создания можно ли как-нибудь изменить тип M1::value-атрибута? Хм... Думается, что можно как-то замутить через обработку переданных параметров в BUILDARGS-методе класса My1.

bvn13 ★★★★★
() автор топика
Ответ на: комментарий от bvn13

Не могу сказать. Очень давно не пишу Moose-код и многие концепции забыты. Смотрите в сторону иммутабельности: «Some of these practices are designed to help Moose do the right thing, especially when it comes to immutabilization. This means your code will be faster when immutabilized».

Посмотрите Moose::Manual::BestPractices если еще не видели, обязательно пригодится.

outtaspace ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.