summaryrefslogtreecommitdiff
path: root/lib/Class/MakeMethods/Emulator/MethodMaker.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Class/MakeMethods/Emulator/MethodMaker.pm')
-rw-r--r--lib/Class/MakeMethods/Emulator/MethodMaker.pm676
1 files changed, 676 insertions, 0 deletions
diff --git a/lib/Class/MakeMethods/Emulator/MethodMaker.pm b/lib/Class/MakeMethods/Emulator/MethodMaker.pm
new file mode 100644
index 0000000..4956ba3
--- /dev/null
+++ b/lib/Class/MakeMethods/Emulator/MethodMaker.pm
@@ -0,0 +1,676 @@
+package Class::MakeMethods::Emulator::MethodMaker;
+
+use Class::MakeMethods '-isasubclass';
+require Class::MakeMethods::Emulator;
+
+$VERSION = 1.03;
+
+use strict;
+
+=head1 NAME
+
+Class::MakeMethods::Emulator::MethodMaker - Emulate Class::MethodMaker
+
+
+=head1 SYNOPSIS
+
+ package MyObject;
+ use Class::MakeMethods::Emulator::MethodMaker(
+ new_with_init => 'new',
+ get_set => [ qw / foo bar baz / ];
+ );
+
+ ... OR ...
+
+ package MyObject;
+ use Class::MakeMethods::Emulator::MethodMaker '-take_namespace';
+ use Class::MethodMaker (
+ new_with_init => 'new',
+ get_set => [ qw / foo bar baz / ];
+ );
+
+
+=head1 DESCRIPTION
+
+This module provides emulation of Class::MethodMaker, using the Class::MakeMethods framework.
+
+Although originally based on Class::MethodMaker, the calling convention
+for Class::MakeMethods differs in a variety of ways; most notably, the names
+given to various types of methods have been changed, and the format for
+specifying method attributes has been standardized. This package uses
+the aliasing capability provided by Class::MakeMethods, defining methods
+that modify the declaration arguments as necessary and pass them off to
+various subclasses of Class::MakeMethods.
+
+
+=head1 COMPATIBILITY
+
+Full compatibility is maintained with version 1.03; some of the
+changes in versions 1.04 through 1.10 are not yet included.
+
+The test suite from Class::MethodMaker version 1.10 is included
+with this package, in the t/emulator_class_methodmaker/ directory.
+The unsupported tests have names ending in ".todo".
+
+The tests are unchanged from those in the Class::MethodMaker
+distribution, except for the substitution of
+C<Class::MakeMethods::Emulator::MethodMaker> in the place of
+C<Class::MethodMaker>.
+
+In cases where earlier distributions of Class::MethodMaker contained
+a different version of a test, it is also included. (Note that
+version 0.92's get_concat returned '' for empty values, but in
+version 0.96 this was changed to undef; this emulator follows the
+later behavior. To avoid "use of undefined value" warnings from
+the 0.92 version of get_concat.t, that test has been modified by
+appending a new flag after the name, C<'get_concat --noundef'>,
+which restores the earlier behavior.)
+
+
+=head1 USAGE
+
+There are several ways to call this emulation module:
+
+=over 4
+
+=item *
+
+Direct Access
+
+Replace occurances in your code of C<Class::MethodMaker> with C<Class::MakeMethods::Emulator::MethodMaker>.
+
+=item *
+
+Install Emulation
+
+If you C<use Class::MakeMethods::Emulator::MethodMaker '-take_namespace'>, the Class::MethodMaker namespace will be aliased to this package, and calls to the original package will be transparently handled by this emulator.
+
+To remove the emulation aliasing, call C<use Class::MakeMethods::Emulator::MethodMaker '-release_namespace'>.
+
+B<Note:> This affects B<all> subsequent uses of Class::MethodMaker in your program, including those in other modules, and might cause unexpected effects.
+
+=item *
+
+The -sugar Option
+
+Passing '-sugar' as the first argument in a use or import call will cause the 'methods' package to be declared as an alias to this one.
+
+This allows you to write declarations in the following manner.
+
+ use Class::MakeMethods::Emulator::MethodMaker '-sugar';
+
+ make methods
+ get_set => [ qw / foo bar baz / ],
+ list => [ qw / a b c / ];
+
+B<Note:> This feature is deprecated in Class::MethodMaker version 0.96 and later.
+
+=back
+
+=cut
+
+my $emulation_target = 'Class::MethodMaker';
+
+sub import {
+ my $mm_class = shift;
+
+ if ( scalar @_ and $_[0] =~ /^-take_namespace/ and shift ) {
+ Class::MakeMethods::Emulator::namespace_capture(__PACKAGE__, $emulation_target);
+ } elsif ( scalar @_ and $_[0] =~ /^-release_namespace/ and shift ) {
+ Class::MakeMethods::Emulator::namespace_release(__PACKAGE__, $emulation_target);
+ }
+
+ if ( scalar @_ and $_[0] eq '-sugar' and shift ) {
+ Class::MakeMethods::Emulator::namespace_capture(__PACKAGE__, "methods");
+ }
+
+ $mm_class->make( @_ ) if ( scalar @_ );
+}
+
+
+=head1 METHOD CATALOG
+
+B<NOTE:> The documentation below is derived from version 1.02 of
+Class::MethodMaker. Class::MakeMethods::Emulator::MethodMaker
+provides support for all of the features and examples shown below,
+with no changes required.
+
+
+=head1 CONSTRUCTOR METHODS
+
+=head2 new
+
+Equivalent to Class::MakeMethods 'Template::Hash:new --with_values'.
+
+=cut
+
+sub new { return 'Template::Hash:new --with_values' }
+
+
+=head2 new_with_init
+
+Equivalent to Class::MakeMethods 'Template::Hash:new --with_init'.
+
+=cut
+
+sub new_with_init { return 'Template::Hash:new --with_init' }
+
+
+=head2 new_hash_init
+
+Equivalent to Class::MakeMethods 'Template::Hash:new --instance_with_methods'.
+
+=cut
+
+sub new_hash_init { return 'Template::Hash:new --instance_with_methods' }
+
+
+=head2 new_with_args
+
+Equivalent to Class::MakeMethods 'Template::Hash:new --with_values'.
+
+=cut
+
+sub new_with_args { return 'Template::Hash:new --with_values' }
+
+
+=head2 copy
+
+Equivalent to Class::MakeMethods 'Template::Hash:new --copy_with_values'.
+
+=cut
+
+sub copy { return 'Template::Hash:new --copy_with_values' }
+
+
+=head1 SCALAR ACCESSORS
+
+=head2 get_set
+
+Basically equivalent to Class::MakeMethods 'Template::Hash:scalar', except that various arguments are intercepted and converted into the parallel Class::MakeMethods::Template interface declarations.
+
+=cut
+
+my $scalar_interface = { '*'=>'get_set', 'clear_*'=>'clear' };
+
+sub get_set {
+ shift and return [
+ ( ( $_[0] and $_[0] eq '-static' and shift ) ? 'Template::Static:scalar'
+ : 'Template::Hash:scalar' ),
+ '-interface' => $scalar_interface,
+ map {
+ ( ref($_) eq 'ARRAY' )
+ ? ( '-interface'=>{
+ ( $_->[0] ? ( $_->[0] => 'get_set' ) : () ),
+ ( $_->[1] ? ( $_->[1] => 'clear' ) : () ),
+ ( $_->[2] ? ( $_->[2] => 'get' ) : () ),
+ ( $_->[3] ? ( $_->[3] => 'set_return' ) : () ),
+ } )
+ : ($_ eq '-compatibility')
+ ? ( '-interface', $scalar_interface )
+ : ($_ eq '-noclear')
+ ? ( '-interface', 'default' )
+ : ( /^-/ ? "-$_" : $_ )
+ } @_
+ ]
+}
+
+
+=head2 get_concat
+
+Equivalent to Class::MakeMethods 'Template::Hash:string' with a special interface declaration that provides the get_concat and clear behaviors.
+
+=cut
+
+my $get_concat_interface = {
+ '*'=>'get_concat', 'clear_*'=>'clear',
+ '-params'=>{ 'join' => '', 'return_value_undefined' => undef() }
+};
+
+my $old_get_concat_interface = {
+ '*'=>'get_concat', 'clear_*'=>'clear',
+ '-params'=>{ 'join' => '', 'return_value_undefined' => '' }
+};
+
+sub get_concat {
+ shift and return [ 'Template::Hash:string', '-interface',
+ ( $_[0] eq '--noundef' ? ( shift and $old_get_concat_interface )
+ : $get_concat_interface ), @_ ]
+}
+
+=head2 counter
+
+Equivalent to Class::MakeMethods 'Template::Hash:number --counter'.
+
+=cut
+
+sub counter { return 'Template::Hash:number --counter' }
+
+
+=head1 OBJECT ACCESSORS
+
+Basically equivalent to Class::MakeMethods 'Template::Hash:object' with an declaration that provides the "delete_x" interface. Due to a difference in expected argument syntax, the incoming arguments are revised before being delegated to Template::Hash:object.
+
+=cut
+
+my $object_interface = { '*'=>'get_set_init', 'delete_*'=>'clear' };
+
+sub object {
+ shift and return [
+ 'Template::Hash:object',
+ '-interface' => $object_interface,
+ _object_args(@_)
+ ]
+}
+
+sub _object_args {
+ my @meta_methods;
+ ! (@_ % 2) or Carp::croak("Odd number of arguments for object declaration");
+ while ( scalar @_ ) {
+ my ($class, $list) = (shift(), shift());
+ push @meta_methods, map {
+ (! ref $_) ? { name=> $_, class=>$class }
+ : { name=> $_->{'slot'}, class=>$class,
+ delegate=>( $_->{'forward'} || $_->{'comp_mthds'} ) }
+ } ( ( ref($list) eq 'ARRAY' ) ? @$list : ($list) );
+ }
+ return @meta_methods;
+}
+
+
+=head2 object_list
+
+Basically equivalent to Class::MakeMethods 'Template::Hash:object_list' with an declaration that provides the relevant helper methods. Due to a difference in expected argument syntax, the incoming arguments are revised before being delegated to Template::Hash:object_list.
+
+=cut
+
+my $array_interface = {
+ '*'=>'get_push',
+ '*_set'=>'set_items', 'set_*'=>'set_items',
+ map( ('*_'.$_ => $_, $_.'_*' => $_ ),
+ qw( pop push unshift shift splice clear count ref index )),
+};
+
+sub object_list {
+ shift and return [
+ 'Template::Hash:array_of_objects',
+ '-interface' => $array_interface,
+ _object_args(@_)
+ ];
+}
+
+=head2 forward
+
+Basically equivalent to Class::MakeMethods 'Template::Universal:forward_methods'. Due to a difference in expected argument syntax, the incoming arguments are revised before being delegated to Template::Universal:forward_methods.
+
+ forward => [ comp => 'method1', comp2 => 'method2' ]
+
+Define pass-through methods for certain fields. The above defines that
+method C<method1> will be handled by component C<comp>, whilst method
+C<method2> will be handled by component C<comp2>.
+
+=cut
+
+sub forward {
+ my $class = shift;
+ my @results;
+ while ( scalar @_ ) {
+ my ($comp, $method) = ( shift, shift );
+ push @results, { name=> $method, target=> $comp };
+ }
+ [ 'forward_methods', @results ]
+}
+
+
+
+=head1 REFERENCE ACCESSORS
+
+=head2 list
+
+Equivalent to Class::MakeMethods 'Template::Hash:array' with a custom method naming interface.
+
+=cut
+
+sub list {
+ shift and return [ 'Template::Hash:array', '-interface' => $array_interface, @_ ];
+}
+
+
+=head2 hash
+
+Equivalent to Class::MakeMethods 'Template::Hash:hash' with a custom method naming interface.
+
+=cut
+
+my $hash_interface = {
+ '*'=>'get_push',
+ '*s'=>'get_push',
+ 'add_*'=>'get_set_items',
+ 'add_*s'=>'get_set_items',
+ 'clear_*'=>'delete',
+ 'clear_*s'=>'delete',
+ map {'*_'.$_ => $_} qw(push set keys values exists delete tally clear),
+};
+
+sub hash {
+ shift and return [ 'Template::Hash:hash', '-interface' => $hash_interface, @_ ];
+}
+
+
+=head2 tie_hash
+
+Equivalent to Class::MakeMethods 'Template::Hash:tiedhash' with a custom method naming interface.
+
+=cut
+
+sub tie_hash {
+ shift and return [ 'Template::Hash:tiedhash', '-interface' => $hash_interface, @_ ];
+}
+
+=head2 hash_of_lists
+
+Equivalent to Class::MakeMethods 'Template::Hash:hash_of_arrays', or if the -static flag is present, to 'Template::Static:hash_of_arrays'.
+
+=cut
+
+sub hash_of_lists {
+ shift and return ( $_[0] and $_[0] eq '-static' and shift )
+ ? [ 'Template::Static:hash_of_arrays', @_ ]
+ : [ 'Template::Hash:hash_of_arrays', @_ ]
+}
+
+
+=head1 STATIC ACCESSORS
+
+=head2 static_get_set
+
+Equivalent to Class::MakeMethods 'Template::Static:scalar' with a custom method naming interface.
+
+=cut
+
+sub static_get_set {
+ shift and return [ 'Template::Static:scalar', '-interface', $scalar_interface, @_ ]
+}
+
+=head2 static_list
+
+Equivalent to Class::MakeMethods 'Template::Static:array' with a custom method naming interface.
+
+=cut
+
+sub static_list {
+ shift and return [ 'Template::Static:array', '-interface' => $array_interface, @_ ];
+}
+
+=head2 static_hash
+
+Equivalent to Class::MakeMethods 'Template::Static:hash' with a custom method naming interface.
+
+=cut
+
+sub static_hash {
+ shift and return [ 'Template::Static:hash', '-interface' => $hash_interface, @_ ];
+}
+
+
+=head1 GROUPED ACCESSORS
+
+=head2 boolean
+
+Equivalent to Class::MakeMethods 'Template::Static:bits' with a custom method naming interface.
+
+=cut
+
+my $bits_interface = {
+ '*'=>'get_set', 'set_*'=>'set_true', 'clear_*'=>'set_false',
+ 'bit_fields'=>'bit_names', 'bits'=>'bit_string', 'bit_dump'=>'bit_hash'
+};
+
+sub boolean {
+ shift and return [ 'Template::Hash:bits', '-interface' => $bits_interface, @_ ];
+}
+
+
+=head2 grouped_fields
+
+Creates get/set methods like get_set but also defines a method which
+returns a list of the slots in the group.
+
+ use Class::MakeMethods::Emulator::MethodMaker
+ grouped_fields => [
+ some_group => [ qw / field1 field2 field3 / ],
+ ];
+
+Its argument list is parsed as a hash of group-name => field-list
+pairs. Get-set methods are defined for all the fields and a method with
+the name of the group is defined which returns the list of fields in the
+group.
+
+=cut
+
+sub grouped_fields {
+ my ($class, %args) = @_;
+ my @methods;
+ foreach (keys %args) {
+ my @slots = @{ $args{$_} };
+ push @methods,
+ $_, sub { @slots },
+ $class->make( 'get_set', \@slots );
+ }
+ return @methods;
+}
+
+=head2 struct
+
+Equivalent to Class::MakeMethods 'Template::Hash::struct'.
+
+B<Note:> This feature is included but not documented in Class::MethodMaker version 1.
+
+
+=cut
+
+sub struct { return 'Template::Hash:struct' }
+
+
+=head1 INDEXED ACCESSORS
+
+=head2 listed_attrib
+
+Equivalent to Class::MakeMethods 'Template::Flyweight:boolean_index' with a custom method naming interface.
+
+=cut
+
+sub listed_attrib {
+ shift and return [ 'Template::Flyweight:boolean_index', '-interface' => {
+ '*'=>'get_set', 'set_*'=>'set_true', 'clear_*'=>'set_false',
+ '*_objects'=>'find_true', }, @_ ]
+}
+
+
+=head2 key_attrib
+
+Equivalent to Class::MakeMethods 'Template::Hash:string_index'.
+
+=cut
+
+sub key_attrib { return 'Template::Hash:string_index' }
+
+=head2 key_with_create
+
+Equivalent to Class::MakeMethods 'Template::Hash:string_index --find_or_new'.
+
+=cut
+
+sub key_with_create { return 'Template::Hash:string_index --find_or_new'}
+
+
+=head1 CODE ACCESSORS
+
+=head2 code
+
+Equivalent to Class::MakeMethods 'Template::Hash:code'.
+
+=cut
+
+sub code { return 'Template::Hash:code' }
+
+
+=head2 method
+
+Equivalent to Class::MakeMethods 'Template::Hash:code --method'.
+
+=cut
+
+sub method { return 'Template::Hash:code --method' }
+
+
+=head2 abstract
+
+Equivalent to Class::MakeMethods 'Template::Universal:croak --abstract'.
+
+=cut
+
+sub abstract { return 'Template::Universal:croak --abstract' }
+
+
+=head1 ARRAY CONSTRUCTOR AND ACCESSORS
+
+=head2 builtin_class (EXPERIMENTAL)
+
+Equivalent to Class::MakeMethods 'Template::StructBuiltin:builtin_isa' with a modified argument order.
+
+=cut
+
+sub builtin_class {
+ shift and return [ 'Template::StructBuiltin:builtin_isa',
+ '-new_function'=>(shift), @{(shift)} ]
+}
+
+=head1 CONVERSION
+
+If you wish to convert your code from use of the Class::MethodMaker emulator to direct use of Class::MakeMethods, you will need to adjust the arguments specified in your C<use> or C<make> calls.
+
+Often this is simply a matter of replacing the names of aliased method-types listed below with the new equivalents.
+
+For example, suppose that you code contained the following declaration:
+
+ use Class::MethodMaker (
+ counter => [ 'foo' ]
+ );
+
+Consulting the listings below you can find that C<counter> is an alias for C<Hash:number --counter> and you could thus revise your declaration to read:
+
+ use Class::MakeMethods (
+ 'Hash:number --counter' => [ 'foo' ]
+ );
+
+However, note that those methods marked "(with custom interface)" below have a different default naming convention for helper methods in Class::MakeMethods, and you will need to either supply a similar interface or alter your module's calling interface.
+
+Also note that the C<forward>, C<object>, and C<object_list> method types, marked "(with modified arguments)" below, require their arguments to be specified differently.
+
+See L<Class::MakeMethods::Template::Generic> for more information about the default interfaces of these method types.
+
+
+=head2 Hash methods
+
+The following equivalencies are declared for old meta-method names that are now handled by the Hash implementation:
+
+ new 'Template::Hash:new --with_values'
+ new_with_init 'Template::Hash:new --with_init'
+ new_hash_init 'Template::Hash:new --instance_with_methods'
+ copy 'Template::Hash:copy'
+ get_set 'Template::Hash:scalar' (with custom interfaces)
+ counter 'Template::Hash:number --counter'
+ get_concat 'Template::Hash:string --get_concat' (with custom interface)
+ boolean 'Template::Hash:bits' (with custom interface)
+ list 'Template::Hash:array' (with custom interface)
+ struct 'Template::Hash:struct'
+ hash 'Template::Hash:hash' (with custom interface)
+ tie_hash 'Template::Hash:tiedhash' (with custom interface)
+ hash_of_lists 'Template::Hash:hash_of_arrays'
+ code 'Template::Hash:code'
+ method 'Template::Hash:code --method'
+ object 'Template::Hash:object' (with custom interface and modified arguments)
+ object_list 'Template::Hash:array_of_objects' (with custom interface and modified arguments)
+ key_attrib 'Template::Hash:string_index'
+ key_with_create 'Template::Hash:string_index --find_or_new'
+
+=head2 Static methods
+
+The following equivalencies are declared for old meta-method names
+that are now handled by the Static implementation:
+
+ static_get_set 'Template::Static:scalar' (with custom interface)
+ static_hash 'Template::Static:hash' (with custom interface)
+
+=head2 Flyweight method
+
+The following equivalency is declared for the one old meta-method name
+that us now handled by the Flyweight implementation:
+
+ listed_attrib 'Template::Flyweight:boolean_index'
+
+=head2 Struct methods
+
+The following equivalencies are declared for old meta-method names
+that are now handled by the Struct implementation:
+
+ builtin_class 'Template::Struct:builtin_isa'
+
+=head2 Universal methods
+
+The following equivalencies are declared for old meta-method names
+that are now handled by the Universal implementation:
+
+ abstract 'Template::Universal:croak --abstract'
+ forward 'Template::Universal:forward_methods' (with modified arguments)
+
+
+=head1 EXTENDING
+
+In order to enable third-party subclasses of MethodMaker to run under this emulator, several aliases or stub replacements are provided for internal Class::MethodMaker methods which have been eliminated or renamed.
+
+=over 4
+
+=item *
+
+install_methods - now simply return the desired methods
+
+=item *
+
+find_target_class - now passed in as the target_class attribute
+
+=item *
+
+ima_method_maker - no longer supported; use target_class instead
+
+=back
+
+=cut
+
+sub find_target_class { (shift)->_context('TargetClass') }
+sub get_target_class { (shift)->_context('TargetClass') }
+sub install_methods { (shift)->_install_methods(@_) }
+sub ima_method_maker { 1 }
+
+
+=head1 BUGS
+
+This module aims to provide a 100% compatible drop-in replacement for Class::MethodMaker; if you detect a difference when using this emulation, please inform the author.
+
+
+=head1 SEE ALSO
+
+See L<Class::MakeMethods> for general information about this distribution.
+
+See L<Class::MakeMethods::Emulator> for more about this family of subclasses.
+
+See L<Class::MethodMaker> for more information about the original module.
+
+A good introduction to Class::MethodMaker is provided by pages 222-234 of I<Object Oriented Perl>, by Damian Conway (Manning, 1999).
+
+ http://www.browsebooks.com/Conway/
+
+=cut
+
+1;