Commit | Line | Data |
d6fbcd05 |
1 | |
2 | package # hide the package from PAUSE |
3 | ClassEncapsulatedAttributes; |
4 | |
5 | use strict; |
6 | use warnings; |
7 | |
2bab2be6 |
8 | our $VERSION = '0.06'; |
d6fbcd05 |
9 | |
10 | use base 'Class::MOP::Class'; |
11 | |
351bd7d4 |
12 | sub initialize { |
13 | (shift)->SUPER::initialize(@_, |
14 | # use the custom attribute metaclass here |
c23184fc |
15 | 'attribute_metaclass' => 'ClassEncapsulatedAttributes::Attribute', |
351bd7d4 |
16 | ); |
17 | } |
18 | |
d6fbcd05 |
19 | sub construct_instance { |
20 | my ($class, %params) = @_; |
2d711cc8 |
21 | |
f892c0f0 |
22 | my $meta_instance = $class->get_meta_instance; |
23 | my $instance = $meta_instance->create_instance(); |
2d711cc8 |
24 | |
25 | # initialize *ALL* attributes, including masked ones (as opposed to applicable) |
d6fbcd05 |
26 | foreach my $current_class ($class->class_precedence_list()) { |
aa448b16 |
27 | my $meta = $current_class->meta; |
d6fbcd05 |
28 | foreach my $attr_name ($meta->get_attribute_list()) { |
29 | my $attr = $meta->get_attribute($attr_name); |
f892c0f0 |
30 | $attr->initialize_instance_slot($meta_instance, $instance, \%params); |
d6fbcd05 |
31 | } |
32 | } |
2d711cc8 |
33 | |
34 | return $instance; |
d6fbcd05 |
35 | } |
36 | |
37 | package # hide the package from PAUSE |
38 | ClassEncapsulatedAttributes::Attribute; |
39 | |
40 | use strict; |
41 | use warnings; |
42 | |
2bab2be6 |
43 | our $VERSION = '0.04'; |
d6fbcd05 |
44 | |
45 | use base 'Class::MOP::Attribute'; |
46 | |
2d711cc8 |
47 | # alter the way parameters are specified |
fed4cee7 |
48 | sub initialize_instance_slot { |
f892c0f0 |
49 | my ($self, $meta_instance, $instance, $params) = @_; |
fed4cee7 |
50 | # if the attr has an init_arg, use that, otherwise, |
51 | # use the attributes name itself as the init_arg |
52 | my $init_arg = $self->init_arg(); |
53 | # try to fetch the init arg from the %params ... |
2d711cc8 |
54 | my $class = $self->associated_class; |
55 | my $val; |
fed4cee7 |
56 | $val = $params->{$class->name}->{$init_arg} |
57 | if exists $params->{$class->name} && |
58 | exists ${$params->{$class->name}}{$init_arg}; |
59 | # if nothing was in the %params, we can use the |
60 | # attribute's default value (if it has one) |
61 | if (!defined $val && $self->has_default) { |
2d711cc8 |
62 | $val = $self->default($instance); |
fed4cee7 |
63 | } |
fed4cee7 |
64 | |
2d711cc8 |
65 | # now add this to the instance structure |
f892c0f0 |
66 | $meta_instance->set_slot_value($instance, $self->name, $val); |
d6fbcd05 |
67 | } |
68 | |
49c93440 |
69 | sub name { |
70 | my $self = shift; |
71 | return ($self->associated_class->name . '::' . $self->SUPER::name) |
d6fbcd05 |
72 | } |
73 | |
d6fbcd05 |
74 | 1; |
75 | |
76 | __END__ |
77 | |
78 | =pod |
79 | |
80 | =head1 NAME |
81 | |
82 | ClassEncapsulatedAttributes - A set of example metaclasses with class encapsulated attributes |
83 | |
84 | =head1 SYNOPSIS |
85 | |
86 | package Foo; |
87 | |
677eb158 |
88 | use metaclass 'ClassEncapsulatedAttributes'; |
d6fbcd05 |
89 | |
2e41896e |
90 | Foo->meta->add_attribute('foo' => ( |
91 | accessor => 'Foo_foo', |
92 | default => 'init in FOO' |
93 | )); |
d6fbcd05 |
94 | |
95 | sub new { |
96 | my $class = shift; |
5659d76e |
97 | $class->meta->new_object(@_); |
d6fbcd05 |
98 | } |
99 | |
100 | package Bar; |
101 | our @ISA = ('Foo'); |
102 | |
103 | # duplicate the attribute name here |
2e41896e |
104 | Bar->meta->add_attribute('foo' => ( |
105 | accessor => 'Bar_foo', |
106 | default => 'init in BAR' |
107 | )); |
d6fbcd05 |
108 | |
109 | # ... later in other code ... |
110 | |
111 | my $bar = Bar->new(); |
112 | prints $bar->Bar_foo(); # init in BAR |
113 | prints $bar->Foo_foo(); # init in FOO |
114 | |
115 | # and ... |
116 | |
117 | my $bar = Bar->new( |
118 | 'Foo' => { 'foo' => 'Foo::foo' }, |
119 | 'Bar' => { 'foo' => 'Bar::foo' } |
120 | ); |
121 | |
122 | prints $bar->Bar_foo(); # Foo::foo |
123 | prints $bar->Foo_foo(); # Bar::foo |
124 | |
125 | =head1 DESCRIPTION |
126 | |
d7c2cbe3 |
127 | This is an example metaclass which encapsulates a class's |
128 | attributes on a per-class basis. This means that there is no |
129 | possibility of name clashes with inherited attributes. This |
130 | is similar to how C++ handles its data members. |
131 | |
132 | =head1 ACKNOWLEDGEMENTS |
133 | |
134 | Thanks to Yuval "nothingmuch" Kogman for the idea for this example. |
135 | |
1a09d9cc |
136 | =head1 AUTHORS |
d6fbcd05 |
137 | |
138 | Stevan Little E<lt>stevan@iinteractive.comE<gt> |
139 | |
1a09d9cc |
140 | Yuval Kogman E<lt>nothingmuch@woobling.comE<gt> |
141 | |
d6fbcd05 |
142 | =head1 COPYRIGHT AND LICENSE |
143 | |
2367814a |
144 | Copyright 2006, 2007 by Infinity Interactive, Inc. |
d6fbcd05 |
145 | |
146 | L<http://www.iinteractive.com> |
147 | |
148 | This library is free software; you can redistribute it and/or modify |
149 | it under the same terms as Perl itself. |
150 | |
151 | =cut |