<div dir="ltr"><div><br></div><div class="gmail_extra"><div class="gmail_quote">17 октября 2013 г., 2:25 пользователь Ivan Petrov <span dir="ltr"><<a href="mailto:i.petro.77.00@gmail.com" target="_blank">i.petro.77.00@gmail.com</a>></span> написал:<br>

<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">есть допустим объект<br>
<br>
<br>
package User;<br>
use Mouse;<br>
has name => is => 'ro', isa => 'Str';<br>
<br>
далее роль у него составляющая некие списки юзеров<br>
<br>
with 'User::List';<br>
<br>
...<br>
<br>
package User::List;<br>
use Mouse::Role;<br>
<br>
sub list {<br>
    ... возвратит список пользователей<br>
}<br>
<br>
sub list_by_some {<br>
    ... возвратит еще какой-то список<br>
}<br>
<br>
ну понятно<br>
<br>
далее у юзеров могут быть допустим  заказы. всю работу с заказами<br>
выносим в отдельную роль (тут в примере работа со списками заказов)<br>
<br>
<br>
package User::Order::List;<br>
use Mouse::Role;<br>
<br>
sub list_orders {<br>
    ... возвратит список заказов пользователя<br>
}<br>
<br>
или игрушки<br>
<br>
package User::Toy::List;<br>
use Mouse::Role;<br>
<br>
sub list_toys {<br>
    ... возвратит игрушки пользователя<br>
}<br>
<br>
Ну вот, в большом проекте накапливается у некоторых сущностей много<br>
разных ролей (или иерархия наследования, тут по разному можно<br>
смотреть, это непринципиально).<br>
<br>
и хочется писать далее не<br>
<br>
$user->list_orders;<br>
$user->list_toys;<br>
<br>
а организовать нечто вроде неймспейсов ролевых.<br>
<br>
то есть я хочу чтобы можно было написать<br>
<br>
ns 'User::Order::List' => as => 'orders';<br>
ns 'User::Toy::List' => as => 'toys';<br>
<br>
в основном классе и далее чтобы можно было обращаться к его методам<br>
так:<br>
<br>
$user->orders->list;<br>
$user->toys->list;<br>
<br>
то есть очень похоже на контейнер, но это не контейнер.<br>
это неймспейс.<br>
функция $user->orders->list в качестве self должна получать объект $user.<br>
<br>
то есть<br>
<br>
has things => is => 'ro', isa => 'User::Thing::List';<br>
<br>
тут не подходит. можно прослойку сделать на базе has конечно, но я<br>
боюсь сильно просесть на бенчмарках.<br>
<br>
что еще хочется:<br>
- has внутри namespace<br>
- в идеале наследования какого-то всей этой "хрени с которой<br>
  взлетать", но в целом наследование мы почти не применяем в Mouse,<br>
  поэтому не сильно актуально<br>
<br>
<br>
я примерно представляю как такое написать, но<br>
<br>
1. может быть кто-то писал уже подобное? дайте ссылку<br>
2. сейчас сильно занят другими проектами, но если бы кто взялся мог бы<br>
профинансировать появление подобного модуля на cpan :) с<br>
документацией, тестами и сравнительными бенчмарками<br>
(сравниваем с Mouse::Role). Пусть бенчмаркает вдвое хуже метода<br>
Mouse::Role, но не хуже чем вдвое. Я думаю можно сделать чтобы<br>
бенчмаркало соизмеримо.<br>
<br>
кто что думает?<br>
<span><font color="#888888"><br></font></span></blockquote><div><br></div><div>Действительно странного хотите.</div><div><br></div><div>По-моему более очевидно для каждой сущности (игрушка, заказ, пользователь) сделать отдельный класс (не роль), в котором прописать, в какой таблице хранятся записи для этого класса, а в роль вынести как раз работу с БД. Примерно так мы делаем в нашем проекте на работе. При этом никто не мешает добавить в класс User метод orders(), который будет возвращать список заказов данного пользователя. И, что важно, сможет сделать обратное - например, добавить в класс Toy метод users(), который выдаст юзеров, пользующихся данной игрушкой (а как вы это будете делать с неймспейсами - непонятно).</div>
<div><br></div><div>Из $self, который вы хотите получать в качестве параметра, вам нужно только значение первичного ключа, который вы добавите в поисковый запрос.</div><div><br></div><div>Кусок кода, который иллюстрирует вышесказанное, приведен ниже (я в нём использую более привычный мне Moose, но код на Mouse должен выглядеть похоже, если не идентично).</div>
<div><br></div><div><div>package Role::DatabaseObject;</div><div><br></div><div>use Moose::Role;</div><div>requires 'table';</div><div><br></div><div>sub list {</div><div>    my $self = shift;</div><div>    return $self->_list_table($self->table, @_);</div>
<div>}</div><div><br></div><div>sub _list_table {</div><div>    my ($self, $table, @args) = @_;</div><div><br></div><div>    # свой код для выборки из $table с поиском по параметрам @args</div><div>}</div><div><br></div><div>
sub list_related {</div><div>    my ($self, $related_table, @args) = @_;</div><div><br></div><div>    # Это если внешний ключ связанной таблицы имеет вид $foreign_table . '_id',</div><div>    # иначе делайте свой маппинг.</div>
<div>    my $key_name  = $self->table . '_id';</div><div>    my $key_value = $self->get_column_value($foreign_key_name);</div><div><br></div><div>    return $self->_list_table(</div><div>        $related_table,</div>
<div>        @args,</div><div>        $foreign_key_name => $foreign_key_value</div><div>    );</div><div>}</div></div><div><br></div><div><div># Это можно добавить в BUILD, а можно добавлять в каждый класс вручную - в зависимости</div>
<div># от того, как будет удобнее и что фантазия позволит</div><div>sub add_relations {</div><div>    my ($class, %class_mapping) = @_;</div><div>    while (my ($relation, $related_class) = each %class_mapping) {</div><div>
        $class->meta->add_method(</div><div>            $relation => sub {</div><div>                my ($self) = @_;</div><div><br></div><div>                require $related_class;</div><div>                return $self->list_related($related_class->table),;</div>
<div>            }</div><div>        );</div><div>    }</div><div>}</div><div><br></div><div>package User;</div><div>use Moose;</div><div>with 'Role::DatabaseObject';</div><div>sub table { 'user' }</div><div>
<br></div><div>__PACKAGE__->add_relations(</div><div>    orders => 'Order',</div><div>    toys   => 'Toy',</div><div>);</div><div><br></div><div>package Order;</div><div>use Moose;</div><div>with 'Role::DatabaseObject';</div>
<div>sub table { 'order' }</div><div><br></div><div># здесь логика работы с заказами</div><div><br></div><div>1;</div></div><div><br></div><div><div>package Toy;</div><div>use Moose;</div><div>with 'Role::DatabaseObject';</div>
<div>sub table { 'toy' }</div><div><br></div><div>__PACKAGE__->add_relations(users => 'User');</div><div><br></div><div># здесь логика работы с игрушками</div><div><br></div><div>1;</div></div><div><br>
</div></div>-- <br>Best regards,<br>Ilya Chesnokov
</div><div class="gmail_extra"><br></div></div>