|
NAMEClass::MethodMaker - Create generic methods for OO PerlSYNOPSISuse Class::MethodMaker [ scalar => [qw/ foo bar baz /], new => [qw/ new /] , ]; DESCRIPTIONThis module solves the problem of having to continually write accessor methods for your objects that perform standard tasks.The argument to 'use' is an arrayref, as pairs whose "keys" are the names of types of generic methods generated by MethodMaker and whose "values" tell method maker what methods to make. To override any generated methods, it is sufficient to ensure that the overriding method is defined when Class::MethodMaker is called. Note that the "use" keyword introduces a "BEGIN" block, so you may need to define (or at least declare) your overriding method in a "BEGIN" block. Simple UseA simple class made with "Class::MethodMaker" looks like this:package MyClass; use Class::MethodMaker [ scalar => [qw/ name /], new => [qw/ new /], ]; This creates a class, of which new instances may be created using "new", each with a single scalar component called "name". Name may be queried and (re)set using the methods "name", "name_reset" and "name_isset": package main; my $m = MyClass->new; my $n; $\ = "\n"; print $m->name_isset ? "true" : "false"; # false $m->name("foo"); $n = $m->name; print defined $n ? "->$n<-" : "*undef*"; # ->foo<- print $m->name_isset ? "true" : "false"; # true $m->name(undef); $n = $m->name; print defined $n ? "->$n<-" : "*undef*"; # *undef* print $m->name_isset ? "true" : "false"; # true $m->name_reset; $n = $m->name; print defined $n ? "->$n<-" : "*undef*"; # *undef* print $m->name_isset ? "true" : "false"; # false The available component types are scalar, array, hash. Certain non-data-type utilities are also provided: new, for constructors, deep_copy and copy for object copies, and abstract for creating abstract methods. Each of the components take common options. These include -static, for per-class rather than per-instance data, -type, to restrict the data stored to certain types (e.g., objects of a certain class), -forward to forward (proxy) given methods onto components, -default/-default_ctor to set default values for components, -tie_class to tie the storage of a data type to a given class, -read_cb/-store_cb to call user-defined functions on read/store (without the overhead/complexity of ties; and allowing callbacks on existing tie classes). Detailed Use"Class::MethodMaker" installs components into a class, by means of methods that interrogate and amend those components. A component, sometimes referred in other documentation as a slot is a group of one or more attributes (variables) that are associated with an instance of a class (sometimes called an object), or occasionally a class itself (often referred to as a static component). A component is intended as a cohesive unit of data that should only normally be interrogated or set through the methods provided.Given an instance of a class where each instance represents a car, examples of components are the "make" and "model" (each of which would be a simple scalar, a string), the engine (a simple scalar, an instance of Engine::Combustion), and the wheels (an array of instances of Wheel). Note that the wheels form one component, an array. Of course, the implementor might instead choose to use four components, each being a scalar wheel. To have the components created, the principle use of Class::MethodMaker is to specify the type (data-structure) and name of each component to the import method of Class::MethodMaker package MyClass; use Class::MethodMaker [ scalar => 'name', new => [qw/ new /], ]; In this example, the import is called implicitly via the "use" statement. The components are installed in the package in effect where the import is called. The argument to import is arranged as pairs, where the first of each pair is the type of the data-structure, the second is the arguments for that data-structure; in the most simple case, the name of a component to install using that data-structure. The second of the pair should be an arrayref if not a simple name. Data-structures may be repeated in the call: use Class::MethodMaker [ scalar => 'name1', new => [qw/ new /], scalar => 'name2', ]; It is an error to attempt to install a two or more components with the same name twice. Options may be given to data structures to amend the nature and behaviour of the components created. Some options are common across all data structure (e.g., "static") whilst some are specific to their respective data structures. Option syntax is laid out in detail below. In simple, options are provided by way of hashrefs from option name to option value. Options and component names are order-sensitive; options appearing after a component do not affect that component. Options only apply to the data-structure to which they are specified. Boolean options (e.g., static) may be abbreviated to -option to set, !option to unset, without a hashref. use Class::MethodMaker [ scalar => [+{ -type => 'File::stat' }, qw/ -static name /], new => 'new', ]; There are also non-data-structure methods that may be created by Class::MethodMaker. "new" is an example of one such value; it instead causes a standard "new" method to be created for the calling class. The arguments and options syntax remains the same, but many options clearly do not apply (e.g., "type" for "new"). Interaction with SuperclassesBasically, "Class::MethodMaker" takes no notice of class hierarchies. If you choose to install a component x in a class B that is a subclass of class A that already has a component x, then the methods addressing x in B will simply override those in class A in the usual fashion. "Class::MethodMaker" takes no special action for this situation. This is a feature.Option SyntaxThe arguments to Class::MethodMaker are passed in a single arrayref, as pairs, with the first of each pair being the name of the data-structure, and the second being the arguments to that structure.use Class::MethodMaker [ scalar => 'name', new => [qw/ new /], ]; The second of the pair may in the most simple case be a single scalar that is the name of a component to use. use Class::MethodMaker [ scalar => 'bob', ]; For anything more complex, the second argument must itself be an arrayreference. Simple names within this arrayreference are again taken as component names to use; in the following example, both "foo" and "bar" scalar components are created: use Class::MethodMaker [ scalar => [qw/ foo bar /], ]; Options to the data-structure, to change the behaviour of the component, or methods available, etc., are specified by the presence of a hash reference in line with the component names. Each key of the hashref is the name of an option; the corresponding value is the option value. Option names are easily recognized by a leading hyphen ("-") (or leading exclamation mark, "!"). The options affect only the components named after the option itself. In the following example, "foo" is non-static (the default), whilst bar is a static: use Class::MethodMaker [ scalar => ['foo', { -static => 1 }, 'bar'], ]; Naturally, options may be altered by later settings overriding earlier ones. The example below has exactly the same effect as the one above: use Class::MethodMaker [ scalar => [{ -static => 1 }, 'bar', { -static => 0 }, 'foo'], ]; Options that are boolean (on/off) valued, such as "-static", may be specified external to any hashref as "-optionname" to set them on and "!optionname" to set them off. The example below has exactly the same effect as the one above: use Class::MethodMaker [ scalar => [ qw/ -static bar !static foo /], ]; Options that take a value, e.g., "-type", must be specified within a hashref: use Class::MethodMaker [ scalar => [ +{ type => 'File::stat' }, 'bob' ], ]; Options affect is limited by the scope of the nearest enclosing arrayref. This particularly means that for multiple invocations of a data structure type, options on earlier invocations do not affect later ones. In the following example, "foo" is non-static (the default), whilst bar is a static: use Class::MethodMaker [ scalar => [ qw/ -static bar /], scalar => [ 'foo' ], ]; This is true even if later invocations do not use an arrayref. The example below has exactly the same effect as the one above: use Class::MethodMaker [ scalar => [ qw/ -static bar /], scalar => 'foo', ]; Arrayrefs may be employed within a set of arguments for a single data-structure to likewise limit scope. The example below has exactly the same effect as the one above: use Class::MethodMaker [ scalar => [ [ qw/ -static bar / ], 'foo' ], ]; Method RenamingMethods may be renamed, by providing options that map from one generic name to another. These are identified by the presence of a '*' in the option name.The example below installs component "a" as a scalar, but the method that would normally be installed as "a_get" is instead installed as "get_a", and likewise "set_a" is installed in place of "a_set". use Class::MethodMaker [ scalar => [ { '*_get' => 'get_*', '*_set' => 'set_*', }, 'a' ], ]; Default & Optional MethodsClass::MethodMaker installs a number of methods by default. Some methods, considered to be useful only to a subset of developers are installed only on request. Each method is marked in the text to state whether it is installed by default or only upon request.To request that a non-default method is installed, one needs to rename it (even possibly to its normal name). So, to install the *_get method for a scalar attribute (as *_get), the syntax is: package MyClass; use Class::MethodMaker [ scalar => [{'*_get' => '*_get'}, 'a'] ]; The method may be installed using a non-default name using similar syntax: package MyClass; use Class::MethodMaker [ scalar => [{'*_get' => 'get_*'}, 'a'] ]; The client may choose to not install a default method by renaming it to undef: use Class::MethodMaker [ scalar => [{'*' => undef }, 'a'] ]; Note Class::MethodMaker will not install a method in place of an existing method, so if the intent is to not install a default method because the client has their own version, an alternative to the above is to define the client version before calling Class::MethodMaker. Naming & Method-Design ConventionsThe standard method names are designed with predictability and class extendibility in mind.Naming For any component x that Class::MethodMaker creates, the method names are always "x" or "x_*". This enables predictability, for you do not need to remember which methods are named "x_*" and which *_x, and also you can name methods that you create by avoiding prefixing them with "x", and so avoid any clash with Class::MethodMaker-generated methods (even if Class::MethodMaker is upgraded with shiny new extra methods). Class::MethodMaker users may rename methods (see "Method Renaming"). For any data-structure component (scalar, array, hash, etc.) x that Class::MethodMaker creates, the method "x" sets the value of that component: i.e., overriding any existing value, not amending or modifying. E.g., for array components, "x" does not push or pull values but all old values are removed, and new ones placed in their stead: package MyClass; use Class::MethodMaker [ array => 'a', new => 'new', ]; package main; my $m = MyClass->new; $m->a(4,5); print join(' ', $m->a), "\n"; # 4 5 $m->a(6,7); print join(' ', $m->a), "\n"; # 6 7 The method returns the new value of the component: print join(' ', $m->a(8,9)), "\n"; # 8 9 Note that calling the method with an empty list does not reset the value to empty; this is so that normal lookups work on the method (i.e., if $m->a emptied the component, then @a = $m->a would always give an empty list: not that useful. Set/Unset Each data-structure component has the concept of being set/unset as a whole, independent of individual members being set. Each component starts life unset (unless a default or default option or tie class has been supplied), and is becomes set by any assignment. The component is then reset with the *_reset method. Thus it is possible to distinguish between a component that has been set to an explicitly empty value, and one that has not been set (or been reset). This distinction is analogous to the distinction in hashes between a missing key and a key whose value is undef. package MyClass; use Class::MethodMaker [ new => 'new', scalar => 'x', ]; package main; my $m = MyClass->new; $\ = "\n"; print $m->x_isset ? "true" : "false"; # false; components start this way my $x = $m->x; print defined $n ? "->$n<-" : '*undef*'; # *undef* print $m->x_isset ? "true" : "false"; # false; reading doesn't set $m->x(undef); $x = $m->x; print $m->x_isset ? "true" : "false"; # true; print defined $n ? "->$n<-" : '*undef*'; # ->foo<- $m->x("foo"); $x = $m->x; print $m->x_isset ? "true" : "false"; # true; undef is valid value print defined $n ? "->$n<-" : '*undef*'; # *undef* $m->x_reset; $x = $m->x; print defined $n ? "->$n<-" : '*undef*'; # *undef* print $m->x_isset ? "true" : "false"; # false It is not an error to query the value of an unset component: the value is undef. Querying (any passive command, or pure function) an unset component does not cause it to become set; only assigning (any active command, or procedure) changes the set status of a component. NOTE THAT lvalues are still experimental (as of perl 5.8.0), and so their implementation may change r disappear in the future. Note that lvalue use defeats type-checking. This may be considered a bug, and so may be fixed if possible at some point in the future. Other Design Considerations Further design goals for Class::MethodMaker version 2:
Options to "use"/"import"
Standard Options for Data-Structure Components.The following options are observed by all data structure components (scalar, array, hash).
EXPERIMENTAL & COMPATIBILITY notesSome new facilities may be marked as EXPERIMENTAL in the documentation. These facilities are being trialled, and whilst it is hoped that they will become mainstream code, no promises are made. They may change or disappear at any time. Caveat Emptor. The maintainer would be delighted to hear any feedback particularly regarding such facilities, be it good or bad, so long as it is constructive.Some old facilities may be marked as COMPATIBILITY in the documentation. These facilities are being maintained purely for compatibility with old versions of this module, but will ultimately disappear. They are normally replaced by alternatives that are considered preferable. Please avoid using them, and consider amending any existing code that does use them not to. If you believe that their removal will cast an unacceptable pall over your life, please contact the maintainer. SEE ALSOClass::MethodMaker::Engine, Class::MethodMaker::scalar, Class::MethodMaker::array, Class::MethodMaker::hash, Class::MethodMaker::V1Compat
Visit the GSP FreeBSD Man Page Interface. |