->install_delayed
->register_attribute_specs(do {
my @spec;
- if (my $super = do { no strict 'refs'; ${"${target}::ISA"}[0] }) {
+ # using the -last- entry in @ISA means that classes created by
+ # Role::Tiny as N roles + superclass will still get the attributes
+ # from the superclass
+ if (my $super = do { no strict 'refs'; ${"${target}::ISA"}[-1] }) {
if (my $con = $MAKERS{$super}{constructor}) {
@spec = %{$con->all_attribute_specs};
}
use strictures 1;
+our %NO_BUILD;
+our $BUILD_MAKER;
+
sub new {
my $class = shift;
- bless({ @_ }, $class);
+ $NO_BUILD{$class} and
+ return bless({ ref($_[0]) eq 'HASH' ? %{$_[0]} : @_ }, $class);
+ $NO_BUILD{$class} = !$class->can('BUILD') unless exists $NO_BUILD{$class};
+ $NO_BUILD{$class}
+ ? bless({ ref($_[0]) eq 'HASH' ? %{$_[0]} : @_ }, $class)
+ : bless({ ref($_[0]) eq 'HASH' ? %{$_[0]} : @_ }, $class)->BUILDALL;
+}
+
+sub BUILDALL {
+ my $self = shift;
+ $self->${\(($BUILD_MAKER ||= do {
+ require Method::Generate::BuildAll;
+ Method::Generate::BuildAll->new
+ })->generate_method(ref($self)))}(@_);
}
sub does {
--- /dev/null
+package Class::Tiny::_mro;
+
+if ($] > 5.010) {
+ require mro;
+} else {
+ require MRO::Compat;
+}
+
+1;
--- /dev/null
+package Method::Generate::BuildAll;
+
+use strictures 1;
+use base qw(Class::Tiny::Object);
+use Sub::Quote;
+use Class::Tiny::_mro;
+use Class::Tiny::_Utils;
+
+sub generate_method {
+ my ($self, $into) = @_;
+ my @builds =
+ grep *{_getglob($_)}{CODE},
+ map "${_}::BUILD",
+ reverse @{mro::get_linear_isa($into)};
+ quote_sub "${into}::BUILDALL", join '',
+ qq{ my \$self = shift;\n},
+ (map qq{ \$self->${_}(\@_);\n}, @builds),
+ qq{ return \$self\n};
+}
+
+1;
die "${role} is not a Role::Tiny" unless my $info = $INFO{$role};
}
- if ($] > 5.010) {
- require mro;
- } else {
- require MRO::Compat;
- }
-
+ require Class::Tiny::_mro;
require Sub::Quote;
my @composable = map $me->_composable_package_for($_), reverse @roles;
--- /dev/null
+use strictures 1;
+use Test::More;
+
+my @ran;
+
+{
+ package Foo; use Class::Tiny; sub BUILD { push @ran, 'Foo' }
+ package Bar; use Class::Tiny; extends 'Foo'; sub BUILD { push @ran, 'Bar' }
+ package Baz; use Class::Tiny; extends 'Bar';
+ package Quux; use Class::Tiny; extends 'Baz'; sub BUILD { push @ran, 'Quux' }
+}
+
+my $o = Quux->new;
+
+is(ref($o), 'Quux', 'object returned');
+is_deeply(\@ran, [ qw(Foo Bar Quux) ], 'BUILDs ran in order');
+
+done_testing;