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