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