Область применения методов Mason — переопределение

Используя Mason2. Иметь 3 компонента.

/Base.mc
/tmp/Base.mc
/tmp/index.mc

/tmp/index.mc с содержимым:

hello from <% $m->request_path %></br>
<% $.Some %>

$.Some — это метод, определенный в /Base.mc:

<%augment wrap><% inner() %></%augment>

<%method Some>
The default "Some" method defined in the <% __PACKAGE__ %>
</%method>

/tmp/Base.mc содержит только

<%augment wrap><% inner() %></%augment>

Запрос /tmp/index распечаток:

hello from /tmp/index
The default "Some" method defined in the MC0::Base_mc

Теперь добавил метод Some в /tmp/Base.mc

<%method Some>
Redefined "Some" method in <% __PACKAGE__ %>
</%method>

Снова запросив /tmp/index, он печатает:

hello from /tmp/index
Redefined "Some" method in MC0::tmp_Base_mc

Он соблюдал переопределенный метод Some в обернутом /tmp/Base.mc

Вопрос в том:

Если Мейсон позволяет переопределять методы, как указано выше, какова цель <%override method>? Отличается ли <%override Some> чем-то другим? (когда я тестировал, он печатает то же самое).

EDIT Возможно, вопрос можно свести к следующему коду perl.

use 5.014;
use warnings;

package My;
use Moose;
sub some { say "some from " . __PACKAGE__ }

package My2;
use Moose;
extends 'My';
sub some { say "another some from " . __PACKAGE__ }
#the above line is an correct way to refefine a sub "some"?
#so don;t need to use the
#override 'some' => sub { say "another some from " . __PACKAGE__ };

package main;
use My2;
my $m = My2->new();
$m->some();

в обоих случаях (например, «простое» переопределение и переопределение с «переопределением») печатает:

another some from My2

Таким образом, единственная разница заключается в возможности вызова super() в some с помощью override? и извините, если я пропустил некоторые базовые знания... ;(


person cajwine    schedule 20.09.2014    source источник


Ответы (1)


override в Mason реализует модификатор метода override в Moose; override в Moose — это синтаксический сахар для стандартного объектно-ориентированного метода для переопределения родительского метода, но с некоторыми ограничениями, если метод принимает аргументы. Из документов Moose для override:

override 'display_name' => sub {
    my $self = shift;
    return super() . q{, } . $self->title(); };

Вызов super() почти такой же, как вызов $self->SUPER::display_name. Разница в том, что аргументы, передаваемые методу суперкласса, всегда будут такими же, как аргументы, переданные модификатору метода, и не могут быть изменены. Все аргументы, переданные в super(), игнорируются, как и любые изменения, внесенные в @_ до вызова super().

Чтобы привести пример из ваших классов Moose выше, давайте some приведем несколько аргументов:

package My;
use Moose;
sub some {
    my $self = shift;
    say "   " . __PACKAGE__ . " method 'some' args: " . join " ", @_;
}

Вывод после создания объекта My и вызова $obj->some('pip', 'pop'):

My method 'some' args: pip pop

Теперь давайте посмотрим на My2. Определите some как обычный метод пакета:

package My2;
use Moose;
extends 'My';
sub some {
    my $self = shift;
    say "   # running 'some'";
    say "   " . __PACKAGE__ . " method 'some' args: " . join " ", @_;
    @_ = reverse @_;
    say "   # running \$self->SUPER::some with no args";
    $self->SUPER::some();
    say "   # running \$self->SUPER::some with reversed args";
    $self->SUPER::some( @_ );
    say "   # running super() with no args";
    super();
    say "   # running super() with reversed args";
    super( @_ );
};

Создайте объект My2 и вызовите $obj->some('pip','pop'). Вывод:

# running 'some'
My2 method 'some' args: pip pop
# running $self->SUPER::some with no args
My method 'some' args: 
# running $self->SUPER::some with reversed args
My method 'some' args: pop pip
# running super() with no args
# running super() with reversed args
Arguments passed to super() are ignored at test.pl line 29.

Что следует отметить:

  • super() ничего не делает в переопределенном методе;
  • super() не может принимать аргументы;
  • $self->SUPER::some не получает никаких аргументов автоматически;
  • аргументы $self->SUPER::some могут быть изменены.

Теперь переопределите метод some, используя override:

override 'some' => sub {
    my $self = shift;
    say "   # running 'some'";
    say "   " . __PACKAGE__ . " method 'some' args: " . join " ", @_;
    @_ = reverse @_;
    say "   # running \$self->SUPER::some with no args";
    $self->SUPER::some();
    say "   # running \$self->SUPER::some with reversed args";
    $self->SUPER::some( @_ );
    say "   # running super() with no args";
    super();
    say "   # running super() with reversed args";
    super( @_ );
};

Вывод:

# running 'some'
My2 method 'some' args: pip pop
# running $self->SUPER::some with no args
My method 'some' args: 
# running $self->SUPER::some with reversed args
My method 'some' args: pop pip
# running super() with no args
My method 'some' args: pip pop
# running super() with reversed args
Arguments passed to super() are ignored at test.pl line 29.
My method 'some' args: pip pop

Что следует отметить:

  • метод super() теперь корректно вызывает метод суперкласса some;
  • super() не может принимать аргументы; он автоматически использует тот же @_, который вы передаете методу подкласса;
  • аргументы $self->SUPER::some могут быть изменены.

В основном вам решать, как вы реализуете методы в своих подклассах, но это должно было проиллюстрировать различия между override и стандартным переопределением методов.

person i alarmed alien    schedule 21.09.2014
comment
Итак, единственная разница: при использовании <%override...> я могу вызвать <% super() %>, но при простом переопределении метода я не могу вызвать <% super() %>? - person cajwine; 21.09.2014
comment
Отредактировал вопрос - может понятнее как Mason. - person cajwine; 21.09.2014
comment
Очень хороший ответ. (в My2 отсутствует extend My;) Прочитав ответ, я только что понял, что вы сказали: super() does nothing in a redefined method - и это меня смутило - с помощью простого переопределения я должен вызвать shift->SUPER::some. Спасибо - очень полезно. - person cajwine; 21.09.2014