Skip to content

Instantly share code, notes, and snippets.

@clscott
Created May 10, 2010 14:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save clscott/396125 to your computer and use it in GitHub Desktop.
Save clscott/396125 to your computer and use it in GitHub Desktop.
package XX::Foobar;
use lib './lib';
use Moose;
use MooseX::DependsOnA;
has foo => (
traits => [qw/DependsOnA/],
is => 'rw',
isa => 'Num',
);
has bar => (
traits => [qw/DependsOnA/],
is => 'rw',
isa => 'Num',
clearer => 'clear_bar'
);
has calc => (
traits => [qw/DependsOnA/],
depends_on => [qw/foo bar/],
is => 'rw',
isa => 'Num',
lazy => 1,
builder => 'do_calc'
);
sub do_calc {
my ($self) = @_;
return $self->foo * $self->bar;
}
package main;
use strict;
use warnings;
my $f = XX::Foobar->new( foo => '10', bar => '10' );
print $f->calc(), "\n"; # Calc slot now populated with value of do_calc
print "Bar should clear 1\n";
$f->clear_bar();
print $f->calc(), "\n"; # Calc slot now populated with value of do_calc
print "Bar should clear 2\n";
$f->bar(2); # Calc cleared
print $f->calc(), "\n"; # Calc slot now populated with value of do_calc
package MooseX::DependsOnA;
use strict;
use warnings;
sub init_meta {
shift;
my %options = @_;
my $for_class = $options{for_class};
### in init_meta: $options{for_class}
Moose->init_meta(%options);
Moose::Util::MetaRole::apply_metaclass_roles(
for_class => $options{for_class},
attribute_metaclass_traits =>
['MooseX::DependsOnA::Attribute'],
);
return $for_class->meta;
}
package MooseX::DependsOnA::Attribute;
use Moose::Role;
has depends_on => (
is => 'rw',
isa => 'ArrayRef[Str]',
);
after set_value => sub { $_[0]->_clear_depends($_[1]) };
after clear_value => sub { $_[0]->_clear_depends($_[1]) };
sub _clear_depends {
my ($self, $instance) = @_;
print "Clearing for ", $self->name,"\n";
print "\tcalled by: ", (caller(2))[3], "\n";
my @with_deps = grep { $_->can('depends_on') } $instance->meta->get_all_attributes();
use Data::Dumper;
print join "\n", map { $_->name } @with_deps;
print "\n";
my @dep_on_me;# = grep { grep { $_ eq $self->name } @{$_->depends_on} } @with_deps;
for my $attr_with_dep (@with_deps){
next unless $attr_with_dep->depends_on;
for my $dep_name ( @{$attr_with_dep->depends_on}){
push @dep_on_me, $attr_with_dep if $dep_name eq $self->name;
}
}
print $self->name, " is depended on: \n" if @dep_on_me;
for ( @dep_on_me ){
print "\t", $_->name, "\n";
$_->clear_value($instance);
}
}
around accessor_metaclass => sub {
my ($orig, $self, @rest) = @_;
return Moose::Meta::Class->create_anon_class(
superclasses => [ $self->$orig(@_) ],
roles => [ 'MooseX::DependsOnA::Accessor' ],
cache => 1
)->name
};
package MooseX::DependsOnA::Accessor;
use Moose::Role;
around _inline_store => sub {
my ($orig, $self, $instance, $value) = @_;
print "around _inline_store\n";
my $code = $self->$orig($instance, $value);
$code = sprintf qq[%s->meta->get_attribute("%s")->_clear_depends(%s);\n%s],
$instance,
quotemeta($self->associated_attribute->name),
$instance,
$code;
return $code;
};
package Moose::Meta::Attribute::Custom::Trait::DependsOnA;
sub register_implementation { 'MooseX::DependsOnA::Attribute' }
1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment