+ - handle "has '+foo'" for attrs from superclass or consumed role
- document override -> around translation
- use D::GD if installed rather than re-adding it as a requirement
sub generate_method {
my ($self, $into, $name, $spec, $quote_opts) = @_;
+ $name =~ s/^\+//;
die "Must have an is" unless my $is = $spec->{is};
if ($is eq 'ro') {
$spec->{reader} = $name unless exists $spec->{reader};
my ($self, $type, $into, $name, $slot) = @_;
Class::XSAccessor->import(
class => $into,
- $type => { $name => $slot }
+ $type => { $name => $slot },
+ replace => 1,
);
$into->can($name);
}
my ($self, @new_specs) = @_;
my $specs = $self->{attribute_specs}||={};
while (my ($name, $new_spec) = splice @new_specs, 0, 2) {
+ if ($name =~ s/^\+//) {
+ die "has '+${name}' given but no ${name} attribute already exists"
+ unless my $old_spec = $specs->{$name};
+ foreach my $key (keys %$old_spec) {
+ $new_spec->{$key} = $old_spec->{$key}
+ unless exists $new_spec->{$key};
+ }
+ }
$new_spec->{index} = scalar keys %$specs
unless defined $new_spec->{index};
$specs->{$name} = $new_spec;
--- /dev/null
+use strictures 1;
+use Test::More;
+use Test::Fatal;
+
+{
+ package RollyRole;
+
+ use Moo::Role;
+
+ has f => (is => 'ro', default => sub { 0 });
+}
+
+{
+ package ClassyClass;
+
+ use Moo;
+
+ has f => (is => 'ro', default => sub { 1 });
+}
+
+{
+ package UsesTheRole;
+
+ use Moo;
+
+ with 'RollyRole';
+}
+
+{
+ package UsesTheRole2;
+
+ use Moo;
+
+ with 'RollyRole';
+
+ has '+f' => (default => sub { 2 });
+}
+
+{
+
+ package ExtendsTheClass;
+
+ use Moo;
+
+ extends 'ClassyClass';
+
+ has '+f' => (default => sub { 3 });
+}
+
+{
+ package BlowsUp;
+
+ use Moo;
+
+ ::like(::exception { has '+f' => () }, qr/\Qhas '+f'/, 'Kaboom');
+}
+
+is(UsesTheRole->new->f, 0, 'role attr');
+is(ClassyClass->new->f, 1, 'class attr');
+is(UsesTheRole2->new->f, 2, 'role attr with +');
+is(ExtendsTheClass->new->f, 3, 'class attr with +');
+
+done_testing;