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