File Coverage

blib/lib/reform.pm
Criterion Covered Total %
statement 14 55 25.4
branch 0 14 0.0
condition n/a
subroutine 4 12 33.3
pod 0 4 0.0
total 18 85 21.1


line stmt bran cond sub pod time code
1             # reform.pm
2             #
3             # Third millenium syntax for Perl 5 OOP.
4             # Written by Henning Koch .
5            
6 1     1   36128 use strict;
  1         2  
  1         103  
7             package reform;
8            
9             our $VERSION = 0.3;
10            
11 1     1   4414 use Filter::Simple;
  1         46171  
  1         10  
12            
13             # Filters the code of a package.
14             # This is going to be even more ugly than usual as we
15             # want to preserve whitespace so line numbers won't change.
16             sub process
17             {
18            
19 1     1 0 5 my ($code) = @_;
20            
21 1         4 $code =~ s/ \b fields (\s+) ([\w\s\,]+) (\s*) \;
22 0         0 /$1 . process_fields($2) . $3
23             /xse;
24            
25 1         4 $code =~ s/ \b sub (\s+) (\w+) (\s*) # 1:space 2:subname 3:space
26             (\( (.*?) \))? (\s*) # 4:paramsbracket 5:params 6:space
27             (: \s* \w+ (\(\w+\))? )? (\s*) \{ # 7:fullattr 8:attrparam 9:space
28 0 0       0 / "sub" . $1 . $2 . $3 .
29             $7 . $9 . $6 .
30             "{ my(\$self" . ($5? ", $5" : "") . ") = \@_; "
31             /xseg;
32            
33 1         3 $code =~ s/ \b package (\s+) ([\w\:]+)
34             ((\s*) \< (\s*) ([\w\:\,\s]+))? (\s*) \;
35             /
36 0         0 "package" . $1 . $2 . "; " .
37             "use strict; no strict 'subs'; " .
38             $4 . $5 .
39             process_bases($6) .
40             "use base 'Class'; " .
41             "use reform::implicit; " .
42             $7
43             /xse;
44            
45             # print "-----------------\n$code\n-----------\n";
46            
47 1         9 $code . "\n1;";
48            
49             }
50            
51             # Processes a "fields" directive.
52             sub process_fields
53             {
54 0     0 0   my($list) = @_;
55            
56 0           $list =~ s/(\w+) ([\s,]*)
57 0           /"class->add_field('$1'); " . remove_commas($2)
58             /gesx;
59            
60 0           $list;
61             }
62            
63             # Processes inheritance directives.
64             sub process_bases
65             {
66 0     0 0   my($list) = @_;
67            
68 0           $list =~ s/([\w\:]+) ([\s,]*)
69 0           /"use base '$1'; " . remove_commas($2)
70             /gesx;
71            
72 0           $list;
73             }
74            
75            
76             # Removes commas from a string.
77             sub remove_commas
78             {
79 0     0 0   my($str) = @_;
80 0           $str =~ s/,//g;
81 0           $str;
82             }
83            
84            
85             # Called upon use.
86             FILTER
87             {
88             s/^(.*)$/process($1)/es;
89             }
90            
91             "";
92            
93            
94             # Every reformed package inherits from Class.
95             package Class;
96            
97 1     1   4007 use reform::Property;
  1         23  
  1         3042  
98            
99             # Saves fields by class
100             my %fields;
101            
102             # Basic constructor. When you need custom contructors,
103             # don't overwrite this - overwrite "initialize".
104             sub new
105             {
106 0     0     my $class = shift;
107 0           my $self = {};
108 0           bless($self, $class);
109 0           $self->_tie_field($_) for $self->fields;
110 0           $self->initialize(@_);
111 0           $self;
112             }
113            
114            
115             # Called by constructor. When you need custom contructors,
116             # overwrite this method rather than "new".
117             sub initialize
118 0     0     {
119             }
120            
121             # Create accessors for a field.
122             # The accessors actually work on self->{_field}, which is "tied"
123             # to self->{field} through the methods get_field and set_field.
124             sub add_field
125             {
126 0     0     my($self, $field) = @_;
127 0           my $class = $self;
128 0 0         ref $class and $class = ref $class;
129 0           eval "sub $class\:\:$field : lvalue { \$_[0]->{_$field} }";
130 0 0         eval "sub $class\:\:get_$field { \$_[0]->{_$field} }"
131             unless $class->can("get_$field");
132 0 0         eval "sub $class\:\:set_$field { \$_[0]->{_$field} = \$_[1] }"
133             unless $class->can("set_$field");
134 0 0         $@ and die "Could not add field $field for class $class: $@";
135 0           push @{$fields{$class}}, $field;
  0            
136 0 0         ref $self and $self->_tie_field($field);
137             }
138            
139             # Goes through all classes in %fields and returns fields
140             # of any class that is a parent of self (or is self's class).
141             sub fields
142             {
143 0     0     my($self) = @_;
144 0           my %re; # Hash to weed out duplicates
145 0           foreach my $class (keys %fields) {
146 0 0         if($self->isa($class)) {
147 0           map { $re{$_} = 1 } @{$fields{$class}};
  0            
  0            
148             }
149             }
150 0           keys %re;
151             }
152            
153             # Ties getter/setter methods to a field accessor.
154             sub _tie_field
155             {
156 0     0     my($self, $field) = @_;
157 0           tie $self->{"_$field"}, 'reform::Property', $self, $field;
158             }
159            
160             #sub _call_base_method
161             #{
162             # my($self, $method) = (shift, shift);
163             # my $class = $self;
164             # ref $class and $class = ref $class;
165             # print "$self\n";
166             # my @re = eval "package $class; \$self->SUPER::$method(\@_)";
167             # $@ and die "Error calling base method: $@";
168             # @re;
169             #}
170            
171            
172             =head1 NAME
173            
174             reform - Third millenium syntax for Perl 5 OOP
175            
176             =head1 SYNOPSIS
177            
178             use reform;
179            
180             package Class < Base;
181            
182             fields foo,
183             bar,
184             baz;
185            
186             sub initialize($foo, $bar, $baz)
187             {
188             base->initialize($foo);
189             self->foo = $foo;
190             self->bar = $bar;
191             self->baz = $baz;
192             }
193            
194             sub method
195             {
196             print "Hi there";
197             class->static_method();
198             }
199            
200             sub get_foo
201             {
202             print "Getting self->foo!";
203             return self->{foo};
204             }
205            
206             sub set_foo($value)
207             {
208             print "Setting self->foo!";
209             self->{foo} = $value;
210             }
211            
212             =head1 DESCRIPTION
213            
214             This module provides a less awkward syntax for Perl 5 OOP.
215             C must be the B thing to be used in your code,
216             even above your package declaration.
217            
218             =head2 Shorthand inheritance
219            
220             Rather than using the cumbersome C you may write:
221            
222             package Child < Parent;
223            
224             =head2 Shorthand parameters
225            
226             It is no longer necessary to fish method parameters out of C<@_>:
227            
228             sub method($foo, $bar)
229             {
230             print "First param: $foo";
231             print "Second param: $bar";
232             }
233            
234             =head2 Implicit self, class and base
235            
236             References to the instance, the class (package) and the base class
237             are implicitely provided as C, C and C:
238            
239             sub method
240             {
241             self->instance_method();
242             class->static_method();
243             base->super_class_method();
244             }
245            
246             =head2 Pretty field accessors
247            
248             You may omit the curly brackets in C{foo}> if you declare
249             your field names using C:
250            
251             fields foo, bar;
252            
253             sub method {
254             self->foo = "some value";
255             print self->foo;
256             }
257            
258             You may intercept read and write access to instance fields by overwriting
259             getter and setter methods:
260            
261             fields foo;
262            
263             sub get_foo
264             {
265             print "Getting foo!";
266             return self->{foo};
267             }
268            
269             sub set_foo($value)
270             {
271             print "Setting foo!";
272             self->{foo} = $value;
273             }
274            
275             Note that you must wrap the field names in curly brackets
276             to access the actual C{foo}> inside of getter and
277             setter methods.
278            
279             =head2 Clean constructors
280            
281             All reformed packages inherit a basic constructor C from the C package.
282             When you need custom contructors, don't overwrite C - overwrite C:
283            
284             use reform;
285             package Amy;
286            
287             fields foo,
288             bar;
289            
290             sub initialize($foo)
291             {
292             self->foo = $foo;
293             }
294            
295             You may call the constructor of a base class by calling Cinitialize()>.
296            
297             =head2 Dynamically adding field accessors
298            
299             When you need to dynamically add field accessors, use Cadd_field($field)>:
300            
301             sub method
302             {
303             self->add_field('boo');
304             self->boo = 55;
305             }
306            
307             Note that all objects constructed after a use of C will also
308             bear the new accessors.
309            
310             You may request a list of all fields currently assigned to a class by
311             calling Cfields> or Cfields>;
312            
313             =head1 INSTALLING
314            
315             This package should have come with three files:
316             C, C and C.
317            
318             The only somewhat exotic CPAN package you will need to run this
319             is C >.
320             This package comes included with Perl 5.8, so you only need to act when you're running Perl 5.6.
321            
322             =head2 Installing Filter::Simple on Windows
323            
324             Open a command prompt and type:
325            
326             ppm install Filter
327             ppm install Text-Balanced
328            
329             Now copy the document at L
330             to C or wherever you store your packages.
331            
332             =head2 Installing Filter::Simple anywhere else
333            
334             I guess copying C, C, C and all their prerequisites
335             from CPAN should work.
336            
337             =head1 EXPORTS
338            
339             C, C, C.
340            
341             =head1 BUGS
342            
343             Plenty I'm sure.
344            
345             =head1 UPDATES
346            
347             Will be posted to CPAN.
348            
349             =head1 COPYRIGHT
350            
351             Copyright (C) 2004 Henning Koch. All rights reserved.
352            
353             This library is free software; you can redistribute it and/or modify
354             it under the same terms as Perl itself.
355            
356             =head1 AUTHOR
357            
358             Henning Koch
359            
360             =cut
361            
362             1;