})->generate_method($target, $name, \%spec);
($MAKERS{$target}{constructor} ||= do {
require Method::Generate::Constructor;
- Method::Generate::Constructor->new(package => $target)->install_delayed
- })->register_attribute_spec($name, \%spec);
+ Method::Generate::Constructor
+ ->new(package => $target)
+ ->install_delayed
+ ->register_attribute_specs(do {
+ my @spec;
+ if (my $super = do { no strict 'refs'; ${"${target}::ISA"}[0] }) {
+ if (my $con = $MAKERS{$super}{constructor}) {
+ @spec = %{$con->all_attribute_specs};
+ }
+ }
+ @spec;
+ });
+ })->register_attribute_specs($name, \%spec);
};
foreach my $type (qw(before after around)) {
*{_getglob "${target}::${type}"} = sub {
use base qw(Class::Tiny::Object);
use Sub::Defer;
-sub register_attribute_spec {
- my ($self, $name, $spec) = @_;
- $self->{attribute_specs}{$name} = $spec;
+sub register_attribute_specs {
+ my ($self, %spec) = @_;
+ @{$self->{attribute_specs}||={}}{keys %spec} = values %spec;
+ $self;
+}
+
+sub all_attribute_specs {
+ $_[0]->{attribute_specs}
}
sub install_delayed {
die "Only one role supported at a time by with" if @_ > 1;
Role::Tiny->apply_role_to_package($_[0], $target);
};
+ *{_getglob "${target}::has"} = sub {
+ my ($name, %spec) = @_;
+ ($INFO{$target}{accessor_maker} ||= do {
+ require Method::Generate::Accessor;
+ Method::Generate::Accessor->new
+ })->generate_method($target, $name, \%spec);
+ $INFO{$target}{attributes}{$name} = \%spec;
+ };
# grab all *non-constant* (ref eq 'SCALAR') subs present
# in the symbol table and store their refaddrs (no need to forcibly
# inflate constant subs into real subs) - also add '' to here (this
if (not $INFO{$to} and not $to->can('does')) {
${_getglob "${to}::does"} = \&does_role;
}
-
+
+ if (my $attr_info = $info->{attributes}) {
+ if ($INFO{$to}) {
+ @{$INFO{$to}{attributes}||={}}{keys %$attr_info} = values %$attr_info;
+ } else {
+ my $con = $Class::Tiny::MAKERS{$to}{constructor} ||= do {
+ require Method::Generate::Constructor;
+ Method::Generate::Constructor
+ ->new(package => $to)
+ ->install_delayed
+ ->register_attribute_specs(do {
+ my @spec;
+ if (my $super = do { no strict 'refs'; ${"${to}::ISA"}[0] }) {
+ if (my $con = $Class::Tiny::MAKERS{$super}{constructor}) {
+ @spec = %{$con->all_attribute_specs};
+ }
+ }
+ @spec;
+ });
+ };
+ $con->register_attribute_specs(%$attr_info);
+ }
+ }
# copy our role list into the target's
@{$APPLIED_TO{$to}||={}}{keys %{$APPLIED_TO{$role}}} = ();
has one => (is => 'ro');
has two => (is => 'rw', init_arg => undef);
has three => (is => 'ro', init_arg => 'THREE', required => 1);
+
+ package Bar;
+
+ use Role::Tiny;
+
+ has four => (is => 'ro');
+
+ package Baz;
+
+ use Class::Tiny;
+
+ extends 'Foo';
+
+ with 'Bar';
+
+ has five => (is => 'rw');
}
my $foo = Foo->new(
);
is_deeply(
- { %$foo }, { one => 1, three => 3 }, 'internals ok'
+ { %$foo }, { one => 1, three => 3 }, 'simple class ok'
+);
+
+my $baz = Baz->new(
+ one => 1,
+ THREE => 3,
+ four => 4,
+ five => 5,
+);
+
+is_deeply(
+ { %$baz }, { one => 1, three => 3, four => 4, five => 5 },
+ 'subclass with role ok'
);
done_testing;