|
Class::Prototype, for fast OOP development
|
Social links
Class::Prototype
WWW::Spyder Javascript tricks serial() join function Smart quotes Text to Excel Developing Featherweight Web Services with JavaScript
Miscellaneous
|
|
| Class::Prototype, for fast OOP... |
Class::Prototype Perldoc This module makes setting up an object oriented package (your own module) simple and fast. I use it for when I’m writing test code, code I’m not sure I’ll keep, or just trying to get something done in a hurry. I wrote Class::Prototype before I was acquainted with some of the Class namespace. I’m actually glad because I might not have written it if I’d seen some of the similar modules like Class::Base from Andy Wardley, and Class::Accessor from Michael G Schwern. Class::Prototype is for generally different purposes, is more simple to just drop in and use, and I like it better for those cases. I have not released it to CPAN because I’m not sure I will have time to ever maintain it and it could be deeper (more auto-methods available per data type) and it could stand a code review. Here is the POD for the module. You can view the source of Class::Prototype too. NAMEClass::Prototype VERSION0.03 ABSTRACTClass::Prototype is an object oriented prototyping base class. It is designed to throw together a module or family of modules quickly by giving self-installed methods defined via the child class’s attributes() method. The types of methods which can be self-installed cover 80-90% of what a typical OOP module does. Ie: making a hash based object, installing attributes, and then getting, setting, resetting, stacking, shifting those attributes. Class::Prototype is not really intended for building production code. The use of the code it generates is terse (set/get methods are one in the same) and DWIM (do what I mean — context determines behavior). As such it will for some users “not do what I expected” and “not work the way I prefer.” Class::Prototype code is also generally slower than what you might code up by hand b/c it’s installing its own methods as it goes. Class::Prototype is for putting up a scaffolding of prototype code that will work immediately and will be phased completely out as development progresses. Class::Prototype is for jumping in and writing code that works. SYNOPSISDefine your new class—must contain attributes()#------------------------------------------------------------ package Fish; use base 'Class::Prototype'; #------------------------------------------------------------ # set some lexical class data my @family = qw( Loricariidae Balistidae Gobiidae Syngnathidae Megachasmidae ); my %sizes; @sizes{@family} = qw( medium small small tiny huge ); #------------------------------------------------------------ # set up the only method required to start coding, # attributes(), which must be defined in this general format sub attributes { {# DEFAULT ACCESS _favorite => [ undef, 'writeonce' ], _current_fish => [ undef, 'write' ], _family => [ \@family, 'readonly' ], _size => [ \%sizes, 'readonly' ], } } #------------------------------------------------------------ 1; # save it in the @INC path as Fish.pm and we're ready! Now use it in a scriptuse Fish; # <<-- your new class/module #--------------------------------------------- my $fish_obj = Fish->new(); # set your favorite fish $fish_obj->favorite("Kuhli Loach"); print "Fish Chart:\n"; for my $fish ( sort $fish_obj->family ) { printf "%15s --> %s\n", $fish, $fish_obj->size($fish); # keep track of last fish seen here $fish_obj->current_fish($fish); } print "The last fish family I saw was ", $fish_obj->current_fish, ".\n"; # try to reset the "writeonce" favorite $fish_obj->favorite("7 Gill Shark"); print "My favorite fish is still the ", $fish_obj->favorite, ".\n"; And you should get: Fish Chart:
Balistidae --> small
Gobiidae --> small
Loricariidae --> medium
Megachasmidae --> huge
Syngnathidae --> tiny
The last fish family I saw was Syngnathidae.
You cannot reset favorite() (to 7 Gill Shark),
skipping! at fish line 22
My favorite fish is still the Kuhli Loach.
You give, you getattributes() is just a wrapper for a hash reference which describes your object’s automated behavior. You can use scalars, arrays and hashes in your object. In your hash ref, you have keys (attributes) which point to 2 element array ref of initialization information. Like so: attribute => [ 'default value', 'access' ], Access can be set to one of the following:
Default values can be scalars (undef is acceptable default for a scalar, especially a “writeonce” scalar), array refs, hash refs. So, another sample attributes() method with examples: sub attributes { return { # DEFAULT ACCESS scalar_attr => [ 'default value', 'write' ], scalar_attr2 => [ undef, 'writeonce' ], array_attr => [ [], 'write' ], array_attr2 => [ [ 1 .. 99 ], 'readonly' ], hash_attr => [ { perl => 'rocks', ruby => 'rolls', java => 'hmm...' }, 'readonly' ], hash_attr2 => [ {}, 'write' ] }; } What happens now? Methods are installedAssuming the attribute name is “my_attr,” regardless of the default data type or access, the method my_attr() is installed for your object and behaves in the following ways.
my $obj = Subclass->new( my_attr => 'my only value' ); # or the equivalent my $obj = Subclass->new(); $obj->my_attr('my only value'); my @array = $obj->my_attr(); # list context, gets the list my $element = $obj->my_attr(); # scalar, shifts off an element for my $element ( $obj->my_attr ) { print $element, "\n"; } while ( my $element = $obj->my_attr() ) { print $element, "\n"; } $obj->my_attr(@elements_to_append); for my $key ( sort $obj->keys_my_attr ) { print "$key -->> ", $obj->my_attr($key), "\n"; } METHODSCorrection, no methodsClass::Prototype is a parent class. You cannot create objects in it and you should never directly use its methods. This means you will never do this: use Class::Prototype; You’ll always use a subclass of it. Because if you try to do something like my $obj = Class::Prototype->new(); You will get a croak along the lines of “Class::Prototype is a parent class only. You cannot create Class::Prototypes in it!” Subclass methods you start with
sub method1 { my ( $self, @args ) = @_; warn "method1() got ", join(', ', @args), ".\n" if $self->verbosity >= 2; #... do the rest of what you came to do } Initializing the object specially with new_hook()new_hook() is run on the object immediately after it is bless’d and before any methods are installed or default values are set. This means you can define anything into your object you like before the automatic installation runs. Also note that if you have an attribute named xyz in your attributes() but you also create an xyz() method in your subclass, the automatic installation of xyz(), or its related methods, like keys_xyz() and delete_xyz() for hash refs attributes, does not occur. Class::Prototype::new() contains this: # auto-install method unless the package already defines it $ego->_install_method($method, $access, $type, $value) unless $ego->can($method); which does what you’d expect — skips the method installation if you already defined a method by the same name. This is so that you can drop in methods as you go which will replace the automated ones. You can also take them back out to restore the automatic behavior as long as the attribute remains in your attributes() method. Setting and getting all in oneAny attribute which is defined as “write” is set/get and any attribute defined as “writeonce” is set-once/get. Subclass POD writerIT SHOULD WRITE ITS OWN POD WITH A COMPANION SCRIPT, to show the methods the child will have. And either put it to STDOUT or append it to the .pm in question. THANKSAnyone who owns “Object Oriented Perl,” Damian Conway, 1884777791, already knows this module is heavily based on techniques therein. Anyone who hasn’t dropped Mr. Conway a line just to say, “Thank you for your Perl work and advocacy,” should. COPYRIGHT©2002-2003 Ashley Pond V, ashley@cpan.org, all rights reserved; modify and redistribute under the same terms as Perl. | |