Import Mouse
[gitmo/Mouse.git] / lib / Mouse / Object.pm
1 #!/usr/bin/env perl
2 package Mouse::Object;
3 use strict;
4 use warnings;
5 use MRO::Compat;
6
7 use Scalar::Util 'blessed';
8 use Carp 'confess';
9
10 sub new {
11     my $class = shift;
12     my %args  = @_;
13     my $instance = bless {}, $class;
14
15     for my $attribute ($class->meta->attributes) {
16         my $key = $attribute->init_arg;
17         my $default;
18
19         if (!exists($args{$key})) {
20             if (exists($attribute->{default})) {
21                 unless ($attribute->{lazy}) {
22                     if (ref($attribute->{default}) eq 'CODE') {
23                         $instance->{$key} = $attribute->{default}->();
24                         Scalar::Util::weaken($instance->{$key})
25                             if $attribute->{weak_ref};
26                     }
27                     else {
28                         $instance->{$key} = $attribute->{default};
29                         Scalar::Util::weaken($instance->{$key})
30                             if $attribute->{weak_ref};
31                     }
32                 }
33             }
34             else {
35                 if ($attribute->{required}) {
36                     confess "Attribute '$attribute->{name}' is required";
37                 }
38             }
39         }
40
41         if (exists($args{$key})) {
42             $instance->{$key} = $args{$key};
43             Scalar::Util::weaken($instance->{$key})
44                 if $attribute->{weak_ref};
45
46             if ($attribute->{trigger}) {
47                 $attribute->{trigger}->($instance, $args{$key}, $attribute);
48             }
49         }
50     }
51
52     $instance->BUILDALL(\%args);
53
54     return $instance;
55 }
56
57 sub DESTROY { shift->DEMOLISHALL }
58
59 sub BUILDALL {
60     my $self = shift;
61
62     # short circuit
63     return unless $self->can('BUILD');
64
65     no strict 'refs';
66
67     for my $class ($self->meta->linearized_isa) {
68         my $code = *{ $class . '::BUILD' }{CODE}
69             or next;
70         $code->($self, @_);
71     }
72 }
73
74 sub DEMOLISHALL {
75     my $self = shift;
76
77     # short circuit
78     return unless $self->can('DEMOLISH');
79
80     no strict 'refs';
81
82     for my $class ($self->meta->linearized_isa) {
83         my $code = *{ $class . '::DEMOLISH' }{CODE}
84             or next;
85         $code->($self, @_);
86     }
87 }
88
89 1;
90
91 __END__
92
93 =head1 NAME
94
95 Mouse::Object - we don't need to steenkin' constructor
96
97 =head1 METHODS
98
99 =head2 new arguments -> object
100
101 Instantiates a new Mouse::Object. This is obviously intended for subclasses.
102
103 =head2 BUILDALL \%args
104
105 Calls L</BUILD> on each class in the class hierarchy. This is called at the
106 end of L</new>.
107
108 =head2 BUILD \%args
109
110 You may put any business logic initialization in BUILD methods. You don't
111 need to redispatch or return any specific value.
112
113 =head2 DEMOLISHALL
114
115 Calls L</DEMOLISH> on each class in the class hierarchy. This is called at
116 L</DESTROY> time.
117
118 =head2 DEMOLISH
119
120 You may put any business logic deinitialization in DEMOLISH methods. You don't
121 need to redispatch or return any specific value.
122
123 =cut
124