Moose::Cookbook::Recipe9 - builder -
拡張可能な default と同等の機能である builder です。
ソースコード
package BinaryTree; use Moose; has 'node' => ( is => 'rw', isa => 'Any' ); has 'parent' => ( is => 'rw', isa => 'BinaryTree', predicate => 'has_parent', weak_ref => 1, ); has 'left' => ( is => 'rw', isa => 'BinaryTree', predicate => 'has_left', lazy => 1, builder => '_build_child_tree', ); has 'right' => ( is => 'rw', isa => 'BinaryTree', predicate => 'has_right', lazy => 1, builder => '_build_child_tree', ); before 'right', 'left' => sub { my ( $self, $tree ) = @_; $tree->parent($self) if defined $tree; }; sub _build_child_tree { my $self = shift; return BinaryTree->new( parent => $self ); } package main; use Perl6::Say; use Data::Dump qw(dump); my $tree = BinaryTree->new; say dump $tree; my $left = $tree->left; say dump $tree;
解説
default を sub {} にしておき、lazy 付けたりって話は Moose::Cookbook::Recipe3 - predicate, weak_ref, lazy - - Yet Another Hackadelic で既にやりました。ソースもほとんど似たような構成です。
先にソースの実行結果を貼っておきます。
bless({}, "BinaryTree") do { my $a = bless({ left => bless({ parent => 'fix' }, "BinaryTree") }, "BinaryTree"); $a->{left}{parent} = $a; $a; }
まず単純に new した段階では left, right, parent などには何も入ってません。しかし left を getter として利用した後に見てみると left に新しく BinaryTree オブジェクトが生成されているのが分かります。
default + lazy と同じ効果ですね。
default + lazy vs builder
builder は
has 'left' => ( is => 'rw', isa => 'BinaryTree', predicate => 'has_left', lazy => 1, builder => '_build_child_tree', );
とあるように、メソッド名を指定するだけです。で実際にメソッドが存在しますね。
sub _build_child_tree { my $self = shift; return BinaryTree->new( parent => $self ); }
実際に存在するメソッドなんだから、このメソッド上書きするなり、before, after, augment など Moose の機能をふんだんに使った拡張するなり自由に出来ますが、default の場合は直接 CODEREF を指定するので拡張性がありません。
この点が違いですね。