Mooseでデザパタ - Compositeパターン

#!/usr/bin/env perl
use strict;
use warnings;

{

    package Entry;
    use Moose::Role 'requires';

    requires 'get_name';
    requires 'get_size';
}

{

    package File;
    use Moose;
    use Perl6::Say;
    with 'Entry';

    has name => ( is => 'rw', isa => 'Str', required => 1 );
    has size => ( is => 'rw', isa => 'Int', required => 1 );

    sub get_name {
        my $self = shift;
        $self->name;
    }

    sub get_size {
        my $self = shift;
        $self->size;
    }

    sub print_list {
        my ( $self, $prefix ) = @_;
        say $prefix . '/' . $self->name . '(' . $self->size . ')';
    }
}

{

    package Directory;
    use Moose;
    use Moose::Autobox;
    use Perl6::Say;
    with 'Entry';

    has name => ( is => 'rw', isa => 'Str', required => 1 );
    has directory => ( is => 'rw', isa => 'ArrayRef', default => sub { [] } );

    sub get_name {
        my $self = shift;
        $self->name;
    }

    sub get_size {
        my $self = shift;
        my $size = 0;
        foreach my $entry ( @{ $self->directory } ) {
            $size += $entry->get_size;
        }
        return $size;
    }

    sub add {
        my ( $self, $entry ) = @_;
        $self->directory->push($entry);
    }

    sub print_list {
        my ( $self, $prefix ) = @_;
        say $prefix . '/' . $self->get_name . '(' . $self->get_size . ')';
        foreach my $entry ( @{ $self->directory } ) {
            $entry->print_list( $prefix . "/" . $self->get_name );
        }
    }
}

use Perl6::Say;
say "Making root entries...";
my $root_dir = Directory->new( name => "root" );
my $bin_dir  = Directory->new( name => "bin" );
my $tmp_dir  = Directory->new( name => "tmp" );
my $usr_dir  = Directory->new( name => "usr" );
$root_dir->add($bin_dir);
$root_dir->add($tmp_dir);
$root_dir->add($usr_dir);
$bin_dir->add( File->new( name => "vi",    size => 10000 ) );
$bin_dir->add( File->new( name => "latex", size => 20000 ) );
$root_dir->print_list(" ");

Moose的なポイントは、

  • Mooseのインターフェースとしての機能としてRoleを使って、Entryの実装を強制する点

でしょうか

See also:
http://www.ceres.dti.ne.jp/~kaga/composite.txt

# Moose::Autoboxを少し拡張すれば、ほとんどRubyのコードと等価なコードにできそうですね
# 暇なときにパッチ作るかなぁ