whoops
[gitmo/Class-MOP.git] / examples / InsideOutClass.pod
CommitLineData
9ec169fe 1
2package # hide the package from PAUSE
3 InsideOutClass;
4
5use strict;
6use warnings;
7
a977cf65 8our $VERSION = '0.04';
9ec169fe 9
10use Scalar::Util 'refaddr';
11
12use base 'Class::MOP::Class';
13
14sub construct_instance {
15 my ($class, %params) = @_;
16 # create a scalar ref to use as
17 # the inside-out instance
18 my $instance = \(my $var);
c9e77dbb 19 foreach my $attr ($class->compute_all_applicable_attributes()) {
9ec169fe 20 # if the attr has an init_arg, use that, otherwise,
21 # use the attributes name itself as the init_arg
651955fb 22 my $init_arg = $attr->init_arg();
9ec169fe 23 # try to fetch the init arg from the %params ...
24 my $val;
25 $val = $params{$init_arg} if exists $params{$init_arg};
26 # if nothing was in the %params, we can use the
27 # attribute's default value (if it has one)
a977cf65 28 if (!defined $val && $attr->has_default) {
29 $val = $attr->default($instance);
30 }
9ec169fe 31 # now add this to the instance structure
32 $class->get_package_variable('%' . $attr->name)->{ refaddr($instance) } = $val;
33 }
34 return $instance;
35}
36
37package # hide the package from PAUSE
38 InsideOutClass::Attribute;
39
40use strict;
41use warnings;
42
99e5b7e8 43our $VERSION = '0.04';
9ec169fe 44
45use Scalar::Util 'refaddr';
46
47use base 'Class::MOP::Attribute';
48
49sub generate_accessor_method {
50 my ($self, $attr_name) = @_;
51 $attr_name = ($self->associated_class->name . '::' . $attr_name);
52 eval 'sub {
53 $' . $attr_name . '{ refaddr($_[0]) } = $_[1] if scalar(@_) == 2;
54 $' . $attr_name . '{ refaddr($_[0]) };
55 }';
56}
57
58sub generate_reader_method {
59 my ($self, $attr_name) = @_;
60 eval 'sub {
61 $' . ($self->associated_class->name . '::' . $attr_name) . '{ refaddr($_[0]) };
62 }';
63}
64
65sub generate_writer_method {
66 my ($self, $attr_name) = @_;
67 eval 'sub {
68 $' . ($self->associated_class->name . '::' . $attr_name) . '{ refaddr($_[0]) } = $_[1];
69 }';
70}
71
72sub generate_predicate_method {
73 my ($self, $attr_name) = @_;
74 eval 'sub {
75 defined($' . ($self->associated_class->name . '::' . $attr_name) . '{ refaddr($_[0]) }) ? 1 : 0;
76 }';
77}
78
79## &remove_attribute is left as an exercise for the reader :)
80
811;
82
83__END__
84
85=pod
86
87=head1 NAME
88
89InsideOutClass - A set of example metaclasses which implement the Inside-Out technique
90
91=head1 SYNOPSIS
92
93 package Foo;
94
677eb158 95 use metaclass 'InsideOutClass' => (
96 # tell our metaclass to use the
97 # InsideOut attribute metclass
98 # to construct all it's attributes
99 ':attribute_metaclass' => 'InsideOutClass::Attribute'
100 );
9ec169fe 101
2e41896e 102 __PACKAGE__->meta->add_attribute('foo' => (
103 reader => 'get_foo',
104 writer => 'set_foo'
105 ));
9ec169fe 106
107 sub new {
108 my $class = shift;
5659d76e 109 $class->meta->new_object(@_);
110 }
9ec169fe 111
112 # now you can just use the class as normal
113
114=head1 DESCRIPTION
115
116This is a set of example metaclasses which implement the Inside-Out
117class technique. What follows is a brief explaination of the code
118found in this module.
119
120First step is to subclass B<Class::MOP::Class> and override the
121C<construct_instance> method. The default C<construct_instance>
122will create a HASH reference using the parameters and attribute
123default values. Since inside-out objects don't use HASH refs, and
124use package variables instead, we need to write code to handle
125this difference.
126
127The next step is to create the subclass of B<Class::MOP::Attribute>
128and override the method generation code. This requires overloading
129C<generate_accessor_method>, C<generate_reader_method>,
130C<generate_writer_method> and C<generate_predicate_method>. All
131other aspects are taken care of with the existing B<Class::MOP::Attribute>
132infastructure.
133
134And that is pretty much all. Of course I am ignoring need for
135inside-out objects to be C<DESTROY>-ed, and some other details as
136well, but this is an example. A real implementation is left as an
137exercise to the reader.
138
139=head1 AUTHOR
140
141Stevan Little E<lt>stevan@iinteractive.comE<gt>
142
143=head1 COPYRIGHT AND LICENSE
144
145Copyright 2006 by Infinity Interactive, Inc.
146
147L<http://www.iinteractive.com>
148
149This library is free software; you can redistribute it and/or modify
150it under the same terms as Perl itself.
151
152=cut