Ensure that the local class wins over a role, and that the role over a parent class
[gitmo/Mouse.git] / lib / Mouse / Object.pm
CommitLineData
c3398f5b 1#!/usr/bin/env perl
2package Mouse::Object;
3use strict;
4use warnings;
5use MRO::Compat;
6
b17094ce 7use Scalar::Util qw/blessed weaken/;
c3398f5b 8use Carp 'confess';
9
10sub new {
11 my $class = shift;
da4cb913 12 my %args;
13 if (scalar @_ == 1) {
14 if (defined $_[0]) {
15 (ref($_[0]) eq 'HASH')
16 || confess "Single parameters to new() must be a HASH ref";
17 %args = %{$_[0]};
18 }
19 }
20 else {
21 %args = @_;
22 }
23
c3398f5b 24 my $instance = bless {}, $class;
25
28d26949 26 for my $attribute ($class->meta->compute_all_applicable_attributes) {
384072a3 27 my $from = $attribute->init_arg;
28 my $key = $attribute->name;
c3398f5b 29 my $default;
30
491e5923 31 if (defined($from) && exists($args{$from})) {
32 $attribute->verify_type_constraint($args{$from})
33 if $attribute->has_type_constraint;
34
35 $instance->{$key} = $args{$from};
36
37 weaken($instance->{$key})
38 if ref($instance->{$key}) && $attribute->is_weak_ref;
39
40 if ($attribute->has_trigger) {
41 $attribute->trigger->($instance, $args{$from}, $attribute);
42 }
43 }
44 else {
de9a434a 45 if ($attribute->has_default || $attribute->has_builder) {
2434d21b 46 unless ($attribute->is_lazy) {
fb706f5c 47 my $default = $attribute->default;
de9a434a 48 my $builder = $attribute->builder;
49 my $value = $attribute->has_builder
50 ? $instance->$builder
51 : ref($default) eq 'CODE'
52 ? $default->()
53 : $default;
54
55 $attribute->verify_type_constraint($value)
5aa30ced 56 if $attribute->has_type_constraint;
57
de9a434a 58 $instance->{$key} = $value;
5aa30ced 59
b17094ce 60 weaken($instance->{$key})
3645b316 61 if ref($instance->{$key}) && $attribute->is_weak_ref;
c3398f5b 62 }
63 }
64 else {
2434d21b 65 if ($attribute->is_required) {
398327c3 66 confess "Attribute (".$attribute->name.") is required";
c3398f5b 67 }
68 }
69 }
c3398f5b 70 }
71
72 $instance->BUILDALL(\%args);
73
74 return $instance;
75}
76
77sub DESTROY { shift->DEMOLISHALL }
78
79sub BUILDALL {
80 my $self = shift;
81
82 # short circuit
83 return unless $self->can('BUILD');
84
85 no strict 'refs';
86
2230a6a3 87 for my $class (reverse $self->meta->linearized_isa) {
c3398f5b 88 my $code = *{ $class . '::BUILD' }{CODE}
89 or next;
90 $code->($self, @_);
91 }
92}
93
94sub DEMOLISHALL {
95 my $self = shift;
96
97 # short circuit
98 return unless $self->can('DEMOLISH');
99
100 no strict 'refs';
101
102 for my $class ($self->meta->linearized_isa) {
103 my $code = *{ $class . '::DEMOLISH' }{CODE}
104 or next;
105 $code->($self, @_);
106 }
107}
108
1091;
110
111__END__
112
113=head1 NAME
114
115Mouse::Object - we don't need to steenkin' constructor
116
117=head1 METHODS
118
119=head2 new arguments -> object
120
121Instantiates a new Mouse::Object. This is obviously intended for subclasses.
122
123=head2 BUILDALL \%args
124
125Calls L</BUILD> on each class in the class hierarchy. This is called at the
126end of L</new>.
127
128=head2 BUILD \%args
129
130You may put any business logic initialization in BUILD methods. You don't
131need to redispatch or return any specific value.
132
133=head2 DEMOLISHALL
134
135Calls L</DEMOLISH> on each class in the class hierarchy. This is called at
136L</DESTROY> time.
137
138=head2 DEMOLISH
139
140You may put any business logic deinitialization in DEMOLISH methods. You don't
141need to redispatch or return any specific value.
142
143=cut
144