File Coverage

blib/lib/Class/MakeMethods/Template/InsideOut.pm
Criterion Covered Total %
statement 16 21 76.1
branch 1 4 25.0
condition 2 2 100.0
subroutine 7 9 77.7
pod 2 3 66.6
total 28 39 71.7


line stmt bran cond sub pod time code
1             package Class::MakeMethods::Template::InsideOut;
2              
3 4     4   6380 use Class::MakeMethods::Template::Generic '-isasubclass';
  4         14  
  4         55  
4              
5             $VERSION = 1.008;
6 4     4   34 use strict;
  4         7  
  4         2016  
7             require 5.0;
8              
9             my %ClassInfo;
10             my %Data;
11              
12             sub generic {
13             {
14             '-import' => {
15             'Template::Generic:generic' => '*'
16             },
17             'code_expr' => {
18             '_VALUE_' => '_ATTR_{data}->{_SELF_}',
19             },
20             'behavior' => {
21             -register => [ sub {
22 13     13   19 my $m_info = shift;
23 13   100     63 my $class_info = ( $ClassInfo{$m_info->{target_class}} ||= [] );
24             return (
25             'DESTROY' => sub {
26 7     7   812 my $self = shift;
27 7         344 foreach ( @$class_info ) { delete $self->{data}->{$self} }
  0         0  
28             # $self->SUPER::DESTROY( @_ )
29             },
30 13         116 );
31 4     4 0 49 } ],
32             }
33             }
34             }
35              
36             ########################################################################
37              
38             =head1 NAME
39              
40             Class::MakeMethods::Template::InsideOut - External data
41              
42             =head1 SYNOPSIS
43              
44             package MyObject;
45             use Class::MakeMethods::Template::InsideOut (
46             scalar => [ 'foo', 'bar' ]
47             );
48             sub new { ... }
49            
50             package main;
51              
52             my $obj = MyObject->new( foo => "Foozle", bar => "Bozzle" );
53             print $obj->foo(); # Prints Foozle
54             $obj->bar("Bamboozle"); # Sets $obj's bar value
55              
56             =head1 DESCRIPTION
57              
58             Supports the Generic object constructor and accessors meta-method
59             types, but accepts any object as the underlying implementation type,
60             with member data stored in external indices.
61              
62             Each method stores the values associated with various objects in
63             an hash keyed by the object's stringified identity. Since that hash
64             is accessible only from the generated closures, it is impossible
65             for foreign code to manipulate those values except through the
66             method interface.
67              
68             A DESTROY method is installed to remove data for expired objects
69             from the various hashes. (If the DESTROY method is not called, your
70             program will not release this data and memory will be wasted.)
71              
72             B: The following parameters are defined for
73             InsideOut meta-methods.
74              
75             =over 4
76              
77             =item data
78              
79             An auto-vivified reference to a hash to be used to store the values
80             for each object.
81              
82             =back
83              
84             Note that using InsideOut meta-methods causes the installation of
85             a DESTROY method in the calling class, which deallocates data for
86             each instance when it is discarded.
87              
88             NOTE: This needs some more work to properly handle inheritance.
89              
90             =head2 Standard Methods
91              
92             The following methods from Generic are all supported:
93              
94             scalar
95             string
96             string_index *
97             number
98             boolean
99             bits
100             array
101             hash
102             tiedhash
103             hash_of_arrays
104             object
105             instance
106             array_of_objects
107             code
108             code_or_scalar
109              
110             See L for the interfaces and behaviors of these method types.
111              
112             The items marked with a * above are specifically defined in this package, whereas the others are formed automatically by the interaction of this package's generic settings with the code templates provided by the Generic superclass.
113              
114             =cut
115              
116             ########################################################################
117              
118             =head2 boolean_index
119              
120             boolean_index => [ qw / foo bar baz / ]
121              
122             Like InsideOut:boolean, boolean_index creates x, set_x, and clear_x
123             methods. However, it also defines a class method find_x which returns
124             a list of the objects which presently have the x-flag set to
125             true.
126              
127             Note that to free items from memory, you must clear these bits!
128              
129             =cut
130              
131             sub boolean_index {
132             {
133             '-import' => {
134             'Template::Generic:boolean' => '*',
135             },
136             'interface' => {
137             default => {
138             '*'=>'get_set', 'set_*'=>'set_true', 'clear_*'=>'set_false',
139             'find_*'=>'find_true',
140             },
141             },
142             'behavior' => {
143             '-init' => [ sub {
144 6     6   31 my $m_info = $_[0];
145 6 50       29 defined $m_info->{data} or $m_info->{data} = {};
146 6         17 return;
147 2     2 1 41 } ],
148             'set_true' => q{ _SET_VALUE_{ _SELF_ } },
149             'set_false' => q{ delete _VALUE_; 0 },
150             'find_true' => q{
151             values %{ _ATTR_{data} };
152             },
153             },
154             }
155             }
156              
157             sub string_index {
158             {
159             '-import' => {
160             'Template::Generic:string_index' => '*',
161             },
162             'interface' => {
163             default => {
164             '*'=>'get_set', 'set_*'=>'set_true', 'clear_*'=>'set_false',
165             'find_*'=>'find_true',
166             },
167             },
168             'code_expr' => {
169             _INDEX_HASH_ => '_ATTR_{data}',
170             _GET_FROM_INDEX_ => q{
171             if (defined ( my $old_v = _GET_VALUE_ ) ) {
172             delete _ATTR_{'data'}{ $old_v };
173             }
174             },
175             _REMOVE_FROM_INDEX_ => q{
176             if (defined ( my $old_v = _GET_FROM_INDEX_ ) ) {
177             delete _ATTR_{'data'}{ $old_v };
178             }
179             },
180             _ADD_TO_INDEX_{} => q{
181             if (defined ( my $new_value = _GET_VALUE_ ) ) {
182             if ( my $old_item = _ATTR_{'data'}{$new_value} ) {
183             # There's already an object stored under that value so we
184             # need to unset it's value.
185             # And maybe issue a warning? Or croak?
186             my $m_name = _ATTR_{'name'};
187             $old_item->$m_name( undef );
188             }
189            
190             # Put ourself in the index under that value
191             _ATTR_{'data'}{ * } = _SELF_;
192             }
193             },
194             },
195             'behavior' => {
196             '-init' => [ sub {
197 0     0     my $m_info = $_[0];
198 0 0         defined $m_info->{data} or $m_info->{data} = {};
199 0           return;
200 0     0 1   } ],
201             'get' => q{
202             return _GET_FROM_INDEX_;
203             },
204             'set' => q{
205             my $new_value = shift;
206             _REMOVE_FROM_INDEX_
207             _ADD_TO_INDEX_{ $new_value }
208             },
209             'clear' => q{
210             _REMOVE_FROM_INDEX_
211             },
212             },
213             }
214             }
215              
216             ########################################################################
217              
218             1;