ムース(X)。 継続

トピック「Mooseを使用する」の続き Perlの最新のOOPでは 、Mooseとその拡張機能が提供する興味深い機能について説明します。
上記のトピックから、Mooseを使用してオブジェクトモデルの実装に時間を浪費する必要がないことを理解できます。 しかし、アクセサー/ミューテーターとコンストラクターの自動作成に加えて、あらゆる種類の有用性と興味深いものがまだたくさんあります。 そして、拡張機能の助けを借りて、一般に、Perlを認識以上に変換することができます(もちろん、良い方法で)。

moduleからのコードの例を示します 。これは現代のperlのスタイルで書き直そうとしています。

パート1.ムース



1.1継承された属性の変更

簡単なものから始めましょう。 上記のトピックから学んだように、Mooseベースのクラスはメソッドに加えて属性を継承できます。 また、[継承された属性]を部分的に変更できます。 とても快適です。 これが必要になる可能性のある状況:基本クラスとそれから継承するいくつかがあります。 基本クラスの属性には、すべての子が必要とするものがありますが、それらのデフォルト値のみがすべての子に必要です。 すべての子のすべてのプロパティ(データ型、アクセス権など)で属性を宣言する必要はありません。

コード:
基本クラス:
has request_type => ( is => 'ro', isa => 'Int', lazy => 1, default => undef, init_arg => undef, );

子:
has '+request_type' => ( default => 32, ); # default


1.2メソッド修飾子

ある意味では、デコレータのように見えますが、そうではありません。 3つの修飾子があります:before、after、およびaround。 最初の2つは適用されるメソッドの前後に実行されます。 3番目については、もう少し説明する価値があります。 around修飾子は、それが適用されたメソッドの名前を引数として取り、既に修飾子の内側で、あなた自身が明示的にそれを呼び出さなければなりません[method]。 修飾子の内部と、必要な場所で何が起こるかがわかります。 したがって、呼び出しのAFTERの両方を実行できます。

適用例:(対応するオプションが指定されている場合、修飾子は作成後に特定のリクエストを暗号化します)
after create_request => sub {
my $self = shift;

return unless $self->cipher;

require Crypt::TripleDES;

my $ciphered_text = sprintf "Phone%s\n%s",
$self->trm_id,
unpack('H*', Crypt::TripleDES->new->encrypt3($self->request, $self->ciphering_key));

$self->request($ciphered_text)
};


1.3拡張+インナー

この機能は特に気に入っています。
同じ抽象サービスへのある種の抽象リクエストのテンプレートである基本クラスがあると想像してください。 各リクエストに追加する必要のあるパラメーターのセットがあります(たとえば、ログイン、パスワード、番号など)。 各クラスでこの追加を複製しないようにするために、基本クラスに追加し、すべての子クラスはリクエストの特定の部分でのみ機能します。

すぐにコード:
基本クラス:
method create_request() { #
my $req_node = inner() ;
$req_node->appendChild( $self->_create_extra_node($_, $self->$_) ) foreach qw(password serial);
$req_node->appendChild( $self->_create_simple_node('protocol-version', $self->protocol_version) );
$req_node->appendChild( $self->_create_simple_node('terminal-id', $self->trm_id) );
$req_node->appendChild( $self->_create_simple_node('request-type', $self->request_type) );

my $xml = XML::LibXML::Document->new('1.0', 'utf-8');
$xml->setDocumentElement($req_node);

$self->request($xml->toString)
}

子:
augment create_request => sub { #
my $self = shift;

my $xml = $self->_create_simple_node('request');
$xml->appendChild( $self->_create_extra_node('phone', $self->phone) );

$xml
};

仕組み:create_requestメソッド(ところで、その宣言に注意してください。これについては第2部)では、「magic」関数inner()の呼び出しがあります。 これは変更可能な部分です。 子クラスでは、augment修飾子に匿名のsubを渡します。 そのため、子クラスのインスタンスでcreate_requestを呼び出すときに、inner()の代わりに実行されます。
一見、トリッキーで役に立たないようです。 トリッキー-はい、役に立たない-いいえ。 理解を容易にするために、継承された属性を変更することから類推する価値があります。子はメソッドを継承しますが、親の機能を部分的に保持します。
この機会を悪用しないでください。なぜなら コードの「透明性」が低下します。

パート2. MooseX


これが本当の楽しみの始まりです)ところで、念のために、MooseXはMoose拡張機能のモジュール名前空間であると言います。

2.1 MooseX ::宣言

このモジュールは、Mooseベースのクラスに優れた構文糖衣を提供します。 それにより、メソッドはメソッドになり、クラスはクラスになります。
use MooseX::Declare;

class Business::Qiwi {
has trm_id => ( is => 'rw', isa => 'Str', required => 1, );
has password => ( is => 'rw', isa => 'Str', required => 1, );
has serial => ( is => 'rw', isa => 'Str', required => 1, );
#...
method get_balance() {
# ...
}
};

そして、これは次のように可能です:
class Business::Qiwi::Balance extends Business::Qiwi::Request {
# ...
};

さらにいくつかの重要な有用性:
  1. my $self = shift;する必要がなくなりましたmy $self = shift; 。 インボカントは、メソッド内で自動的に使用できます($ selfという名前で)。
  2. MooseXで宣言されたクラス::宣言は自動的に不変になります。 つまり __PACKAGE__->meta->make_immutableを行う必要が__PACKAGE__->meta->make_immutable


2.2 MooseX ::タイプ

新しいデータ型の作成(既存のものに基づくものを含む)。 例:
use MooseX::Types -declare => [qw(Date EntriesList IdsList TxnsList BillsList)]; #
use MooseX::Types::Moose qw(Int Str ArrayRef HashRef); # Moose

subtype Date => as Str => where { /^\d{2}\.\d{2}\.\d{4}$/ } => message { 'Date must be provided in DD.MM.YYYY format' }; # Str

MooseX :: Typesを使用すると、データ型の名前を引用符で囲むことを回避できます。
subtype IdsList => as ArrayRef[Int] ; # has


2.3 MooseX ::宣言+ MooseX ::タイプ

上記の2つのモジュールを使用する場合、次のように実行できます。
method create_bill( Num $amount, Str $to, Str $txn, Str $comment, Bool $sms_notify?, Bool $call_notify?, Int $confirm_time? ) { # //
# ...
}

method get_bill_status( BillsList $bill ) { # !
# ...
}


2.4 MooseX ::マルチメソッド

multiキーワードを使用してメソッドをオーバーロードする機能を追加します。 このモジュールのテストからの次のコードは、私にとって完璧に言うでしょう(こんにちは、「ビッグバン理論」)。

use strict;
use warnings;
use Test::More tests => 3;

{
package Paper; use Moose;
package Scissors; use Moose;
package Rock; use Moose;
package Lizard; use Moose;
package Spock; use Moose;

package Game;
use Moose;
use MooseX::MultiMethod;

multi method play (Paper $x, Rock $y) { 1 }
multi method play (Paper $x, Spock $y) { 1 }
multi method play (Scissors $x, Paper $y) { 1 }
multi method play (Scissors $x, Lizard $y) { 1 }
multi method play (Rock $x, Scissors $y) { 1 }
multi method play (Rock $x, Lizard $y) { 1 }
multi method play (Lizard $x, Paper $y) { 1 }
multi method play (Lizard $x, Spock $y) { 1 }
multi method play (Spock $x, Rock $y) { 1 }
multi method play (Spock $x, Scissors $y) { 1 }
multi method play (Any $x, Any $y) { 0 }
}

my $game = Game->new;
ok($game->play(Spock->new, Scissors->new), 'Spock smashes Scissors');
ok(!$game->play(Lizard->new, Rock->new), 'Rock crushes Lizard');
ok(!$game->play(Spock->new, Paper->new), 'Paper disproves Spock');

1;


これは、Mooseの機能(およびその拡張機能)-新しいPerl5オブジェクトモデルの簡単な概要でした。
明るい未来では、おそらく私は、継承の代わりとしての役割について話そうとします。 シムのために私は私の休暇を取ることができます。

Source: https://habr.com/ru/post/J59542/


All Articles