package MooseX::Bread::Board::Meta::Role::Attribute; use Moose::Role; Moose::Util::meta_attribute_alias('Service'); use Bread::Board::Types; use List::MoreUtils qw(any); use MooseX::Bread::Board::BlockInjection; use MooseX::Bread::Board::ConstructorInjection; use MooseX::Bread::Board::Literal; has service => ( is => 'ro', isa => 'Bool', default => 1, ); has block => ( is => 'ro', isa => 'CodeRef', predicate => 'has_block', ); # has_value is already a method has literal_value => ( is => 'ro', isa => 'Str|CodeRef', init_arg => 'value', predicate => 'has_literal_value', ); has lifecycle => ( is => 'ro', isa => 'Str', predicate => 'has_lifecycle', ); has dependencies => ( is => 'ro', isa => 'Bread::Board::Service::Dependencies', coerce => 1, predicate => 'has_dependencies', ); has constructor_name => ( is => 'ro', isa => 'Str', predicate => 'has_constructor_name', ); has associated_service => ( is => 'rw', isa => 'Bread::Board::Service', predicate => 'has_associated_service', ); after attach_to_class => sub { my $self = shift; return unless $self->service; my %params = ( associated_attribute => $self, name => $self->name, ($self->has_lifecycle ? (lifecycle => $self->lifecycle) : ()), ($self->has_dependencies ? (dependencies => $self->dependencies) : ()), ($self->has_constructor_name ? (constructor_name => $self->constructor_name) : ()), ); my $service; if ($self->has_block) { $service = MooseX::Bread::Board::BlockInjection->new( %params, block => $self->block, ); } elsif ($self->has_literal_value) { $service = MooseX::Bread::Board::Literal->new( %params, value => $self->literal_value, ); } elsif ($self->has_type_constraint) { my $tc = $self->type_constraint; if ($tc->isa('Moose::Meta::TypeConstraint::Class')) { $service = MooseX::Bread::Board::ConstructorInjection->new( %params, class => $tc->class, ); } } $self->associated_service($service) if $service; }; after _process_options => sub { my $class = shift; my ($name, $opts) = @_; return unless exists $opts->{default} || exists $opts->{builder}; return unless exists $opts->{class} || exists $opts->{block} || exists $opts->{value}; # XXX: uggggh return if any { $_ eq 'Moose::Meta::Attribute::Native::Trait::String' || $_ eq 'Moose::Meta::Attribute::Native::Trait::Counter' } @{ $opts->{traits} }; my $exists = exists($opts->{default}) ? 'default' : 'builder'; die "$exists is not valid when Bread::Board service options are set"; }; around get_value => sub { my $orig = shift; my $self = shift; my ($instance) = @_; return $self->$orig($instance) if $self->has_value($instance); my $val = $instance->get_service($self->name)->get; $self->verify_against_type_constraint($val, instance => $instance) if $self->has_type_constraint; if ($self->should_auto_deref) { if (ref($val) eq 'ARRAY') { return wantarray ? @$val : $val; } elsif (ref($val) eq 'HASH') { return wantarray ? %$val : $val; } else { die 'XXX'; } } else { return $val; } }; if (Moose->VERSION > 1.9900) { around _inline_instance_get => sub { my $orig = shift; my $self = shift; my ($instance) = @_; return 'do {' . "\n" . 'my $val;' . "\n" . 'if (' . $self->_inline_instance_has($instance) . ') {' . "\n" . '$val = ' . $self->$orig($instance) . ';' . "\n" . '}' . "\n" . 'else {' . "\n" . '$val = ' . $instance . '->get_service(\'' . $self->name . '\')->get;' . "\n" . $self->_inline_check_constraint( '$val', '$type_constraint', '$type_constraint_obj' ) . '}' . "\n" . '$val' . "\n" . '}'; }; } else { around accessor_metaclass => sub { my $orig = shift; my $self = shift; return Moose::Meta::Class->create_anon_class( superclasses => [ $self->$orig(@_) ], roles => [ 'MooseX::Bread::Board::Meta::Role::Accessor' ], cache => 1 )->name; }; } no Moose::Role; 1;