.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.43) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "OOorNO 3pm" .TH OOorNO 3pm "2022-12-04" "perl v5.36.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Class::OOorNO \- Give your module classic AND OO interfaces .SH "STATUS!" .IX Header "STATUS!" This is a developer's release, and is not intended for use in the public sector. This code is made available for developers who wish to aid in the furthering of the code. .PP This is \fInot\fR a registered module in the \s-1CPAN\s0 module list. It is not part of the \s-1CPAN\s0 yet. .SH "SYNOPSIS" .IX Header "SYNOPSIS" .IP "\fBFunctional\fR programming interface" 4 .IX Item "Functional programming interface" .Vb 2 \& package Your::Class; \& use Class::OOorNO qw( coerce_array ); .Ve .IP "\fBObject-Oriented\fR programming interface" 4 .IX Item "Object-Oriented programming interface" .Vb 3 \& package Your::Class; \& use Class::OOorNO; \& my($obj) = Class::OOorNO\->new(); .Ve .IP "\fBClass Inheritance\fR" 4 .IX Item "Class Inheritance" .Vb 4 \& package Your::Class; \& use vars qw( @ISA ); \& use Class::OOorNO; \& @ISA = qw( Class::OOorNO ); .Ve .SH "PURPOSE" .IX Header "PURPOSE" Allows you set up your module so it can \fIeasily\fR provide a standard interface as well as an object-oriented interface to its users. .SH "DESCRIPTION" .IX Header "DESCRIPTION" Class::OOorNO helps your module handle the input for its subroutines whether called in object-oriented style \fI(as object methods or class methods with the arrow syntax \f(CI\*(C`\->\*(C'\fI)\fR, or in functional programming style \&\fI(as subroutines imported to the caller's namespace via Exporter)\fR. .PP The bulk of this module comprises a lightweight, pure-Perl emulation of the Devel::Caller library's \f(CW\*(C`called_as_method()\*(C'\fR routine which is written in C. .PP Devel::Caller dives deep into the internals of of the Perl interpreter \&\fI(see perlguts)\fR to trace stack frames and can get the input for any call in the stack. It's really handy for \fIDevel::\fRopment and debugging. .PP This module is much more lightweight and focuses more on your module's \&\fIClass::\fR methods themselves. .SH "EXPORT" .IX Header "EXPORT" None by default. .SH "EXPORT_OK" .IX Header "EXPORT_OK" All available methods. (see \s-1METHODS\s0 below) .SH "EXPORT_TAGS" .IX Header "EXPORT_TAGS" \&\f(CW\*(C`:all\*(C'\fR (exports all of \f(CW@EXPORT_OK\fR) .SH "METHODS" .IX Header "METHODS" .ie n .SS """myself()""" .el .SS "\f(CWmyself()\fP" .IX Subsection "myself()" .ie n .IP "\fISyntax:\fR ""myself(@_)""" 4 .el .IP "\fISyntax:\fR \f(CWmyself(@_)\fR" 4 .IX Item "Syntax: myself(@_)" If your subroutine has been called as an object method, a reference to the object will be returned. If your subroutine has been called as a class method, the name of class itself will be returned as a string. Otherwise, a value of undef is returned. .ie n .SS """OOorNO()""" .el .SS "\f(CWOOorNO()\fP" .IX Subsection "OOorNO()" .ie n .IP "\fISyntax:\fR ""OOorNO(@_)""" 4 .el .IP "\fISyntax:\fR \f(CWOOorNO(@_)\fR" 4 .IX Item "Syntax: OOorNO(@_)" If your subroutine has been called as an object method or as a class method, a value of 1 will be returned, otherwise a false value (an empty string, eg\- '') will be returned. .ie n .SS """myargs()""" .el .SS "\f(CWmyargs()\fP" .IX Subsection "myargs()" .ie n .IP "\fISyntax:\fR ""myargs(@_)""" 4 .el .IP "\fISyntax:\fR \f(CWmyargs(@_)\fR" 4 .IX Item "Syntax: myargs(@_)" This method retrieves the input sent to your class methods and returns it untouched, with the exception that if a blessed object reference from the same namespace as the caller is found in \f(CW$_\fR[0], it will be not be included with the rest of the arguments when they are returned. \fBMake note\fR that the special variable \f(CW"@_"\fR for your routine \fBis not altered\fR in any way by calling this method. You can still use and manipulate it as you normally would. .ie n .IP "Purpose of ""OOorNO::myargs""" 4 .el .IP "Purpose of \f(CWOOorNO::myargs\fR" 4 .IX Item "Purpose of OOorNO::myargs" This simply allows the methods in your class to get their argment list quickly without having to check if they were called procedurally or with object-oriented notation. .RS 4 .IP "\fICaveat:\fR" 4 .IX Item "Caveat:" \&\fBIf\fR you are expecting a blessed object reference from your package to be in \&\f(CW$_[0]\fR regardless of the way your method was called \-\fIdon't use this method\fR to get your arguments; that reference you're expecting will obviously be excluded from the list you get back from \f(CW\*(C`myargs\*(C'\fR if you do. .RE .RS 4 .Sp .Vb 2 \& package Your::Class; \& use Class::OOorNO qw( myargs ); \& \& sub bar { \& \& my(@args) = myargs(@_); \& ... .Ve .Sp \&\fB\-OR\-\fR .Sp .Vb 3 \& package Your::Class; \& use Class::OOorNO; \& our($onobj) = Class::OOorNO\->new(); \& \& sub foo { \& \& my(@args) = $onobj\->myargs(@_); \& ... .Ve .RE .ie n .SS """coerce_array()""" .el .SS "\f(CWcoerce_array()\fP" .IX Subsection "coerce_array()" .ie n .IP "\fISyntax:\fR ""coerce_array(@array/(list))""" 4 .el .IP "\fISyntax:\fR \f(CWcoerce_array(@array/(list))\fR" 4 .IX Item "Syntax: coerce_array(@array/(list))" This method retrieves input sent to your class methods when called with name-value pairs and returns an anonymous hash reference whose keys and values correspond to the input argument names and their respective values. If nothing is passed to it, an empty hash reference will be returned, eg\- \f(CW\*(C`{ }\*(C'\fR .Sp .Vb 2 \& package Your::Class; \& use Class::OOorNO qw( coerce_array ); \& \& sub bar { \& \& my($args) = coerce_array(@_); \& ... .Ve .Sp \&\fB\-OR\-\fR .Sp .Vb 3 \& package Your::Class; \& use Class::OOorNO; \& our($onobj) = Class::OOorNO\->new(); \& \& sub foo { \& \& my($self) = shift(@_); \& my($args) = $onobj\->coerce_array(@_); \& ... .Ve .Sp \&\fB\-OR\-\fR .Sp .Vb 3 \& package Your::Class; \& use Class::OOorNO; \& use vars qw( @ISA ); \& \& @ISA = qw( Class::OOorNO ); \& \& sub foo { \& \& my($self) = shift(@_); \& my($args) = $self\->coerce_array(@_); \& ... .Ve .ie n .IP "Purpose of ""OOorNO::coerce_array""" 4 .el .IP "Purpose of \f(CWOOorNO::coerce_array\fR" 4 .IX Item "Purpose of OOorNO::coerce_array" It's common practice for Perl modules to accept name-value pairs for their methods, and because \f(CW@_\fR is an array it is easy to encounter warnings and errors when this isn't handled correctly. An example of what this kind of call would look like is shown below in the imaginary subroutine \fI\*(L"\f(BIYour::Class::method()\fI\*(R"\fR .Sp .Vb 6 \& Your::Class\->method \& ( \& \-name => \*(AqJoe\*(Aq, \& \-rank => \*(AqPrivate, First\-Class\*(Aq, \& \-SN => \*(Aq87D91\-35\-713FOO\*(Aq, \& ); .Ve .RS 4 .IP "Avoids Common Pitfalls" 4 .IX Item "Avoids Common Pitfalls" Quite often a class method will use code such as this to handle name-value paired input: .Sp .Vb 1 \& sub foo { \& \& my($class) = shift; \& my(%args) = @_; ... .Ve .Sp \&\fB\-and/or\-\fR .Sp .Vb 1 \& sub bar { \& \& my($args) = { @_ }; ... .Ve .IP "What's Wrong With That?" 4 .IX Item "What's Wrong With That?" While this practice is not evil, it can be error-prone in situations where: .RS 4 .IP "\(bu" 4 Your class method is called in procedural style and expects that the first element in \f(CW@_\fR is a blessed object reference. .IP "\(bu" 4 Your class method is errantly called with an unbalanced set of name-value pairs, or one or more named arguments get passed with undefined values. .IP "\(bu" 4 You want to give your module the ability to export any or all of its methods by using the Exporter module, but still want to maintain an object-oriented interface to your module as well. An example of a well known module which does this is \s-1CGI\s0.pm. It is written to provide both a standard procedural interface as well as an object-oriented one. You can call its methods either way: .Sp .Vb 4 \& # object\-oriented style \& use CGI; \& my($cgi_object) = CGI\->new(); \& my($visitor) = $cgi_object\->param(\*(Aqvisitor name\*(Aq); .Ve .Sp \&\fB\-OR\-\fR .Sp .Vb 3 \& # procedural style \& use CGI qw( param ); \& my($visitor) = param(\*(Aqvisitor name\*(Aq); .Ve .RE .RS 4 .RE .IP "Don't say I didn't \fIwarn\fR you \fB ;o) \fR" 4 .IX Item "Don't say I didn't warn you ;o) " When these situations occur, class methods sorting out name-value paired input using the common problematic technique \fI(demonstrated above in "Pitfalls)\fR" encounter problems such as undesired program behavior, general errors, and warnings \-both fatal and non-fatal. Problems include: .RS 4 .IP "\(bu" 4 Argument sets that get reversed; the argument names become the hash values and the argument values become the hash keys which is exactly the opposite of the desired behavior. .IP "\(bu" 4 The entire arument hash/hashref gets turned into a mess of mixed up keys and values that don't reflect the actual input at all. Instead, you get hash keys containing both argument names and argument values. .IP "\(bu" 4 The argument hash/hashref is created with an uneven number of elements and/or uninitialized values. .RE .RS 4 .Sp Warnings \fI(see perldiag)\fR resulting from the above mentioned situations could include any the following (Some of these don't apply unless you run your program under the warnings pragma) like you \&\fIshould\fR. .ie n .IP """Can\*(Aqt coerce array into hash""" 4 .el .IP "\f(CWCan\*(Aqt coerce array into hash\fR" 4 .IX Item "Cant coerce array into hash" \&\fIThis is a fatal warning, eg\- if you see it your program failed and execution aborted.)\fR .ie n .IP """Odd number of elements in hash assignment""" 4 .el .IP "\f(CWOdd number of elements in hash assignment\fR" 4 .IX Item "Odd number of elements in hash assignment" \&\fInon-fatal.\fR .ie n .IP """Not a %s reference""" 4 .el .IP "\f(CWNot a %s reference\fR" 4 .IX Item "Not a %s reference" \&\-where \f(CW%s\fR is probably \*(L"\s-1HASH\*(R",\s0 though it could be complaining about a non-reference to any data type that your routine may be attempting to treat as a reference. This is often the result of a class method being called in procedural style rather than in the object-oriented style using the arrow \&\f(CW\*(C`\-\e\*(C'\fR> syntax. The class method expects the first argument to be an object reference, when it is clearly not. \fI(This warning is fatal as well.)\fR .ie n .IP """Can\*(Aqt call method %s on unblessed reference""" 4 .el .IP "\f(CWCan\*(Aqt call method %s on unblessed reference\fR" 4 .IX Item "Cant call method %s on unblessed reference" \&\fIThis is another a fatal warning\fR, and will occur under the same circumstances that surround the warning described immediately above. The class method expects the first argument to be an object reference when it's not. .RE .RS 4 .RE .RE .RS 4 .RE .ie n .SS """shave_opts()""" .el .SS "\f(CWshave_opts()\fP" .IX Subsection "shave_opts()" .ie n .IP "\fISyntax:\fR ""shave_opts(\e@_)""" 4 .el .IP "\fISyntax:\fR \f(CWshave_opts(\e@_)\fR" 4 .IX Item "Syntax: shave_opts(@_)" \&\fI\-\- Documentation for this method is not yet complete! \-\-\fR .SH "EXAMPLES" .IX Header "EXAMPLES" \&\fBNote: This is not a complete set of examples. It's still evolving.\fR .ie n .SS "using ""OOorNO()""" .el .SS "using \f(CWOOorNO()\fP" .IX Subsection "using OOorNO()" \&\fIYour module...\fR .PP .Vb 5 \& package Your::Module; \& use strict; \& use Exporter; \& use vars qw( @EXPORT_OK ); \& @EXPORT_OK = qw( show_call_style ); \& \& use Class::OOorNO qw( OOorNO ); \& \& sub new { bless { }, shift } \& \& sub show_call_style { \& \& if (ref OOorNO(@_)) { \& print _\|_PACKAGE_\|_ . "::foo was called as an OBJECT METHOD.\en" \& } \& elsif (OOorNO(@_)) { \& print _\|_PACKAGE_\|_ . "::foo was called as an CLASS METHOD.\en" \& } \& else { \& print _\|_PACKAGE_\|_ . "::foo was called as a SUBROUTINE.\en" \& } \& } .Ve .PP \&\fIUser's code...\fR .PP .Vb 3 \& package main; \& use strict; \& use Your::Module qw( show_call_style ); \& \& my($YM) = Your::Module\->new; \& \& $YM\->show_call_style; # as an object method \& Your::Module\->show_call_style; # as a class method \& &Your::Module::show_call_style; # as a subroutine \& &show_call_style; # as imported subroutine .Ve .PP \&\fIOutput:\fR .PP .Vb 4 \& Your::Module::foo was called as an OBJECT METHOD. \& Your::Module::foo was called as an CLASS METHOD. \& Your::Module::foo was called as a SUBROUTINE. \& Your::Module::foo was called as a SUBROUTINE. .Ve .ie n .SS "using ""myself()""" .el .SS "using \f(CWmyself()\fP" .IX Subsection "using myself()" \&\fIYour module...\fR .PP .Vb 5 \& package Your::Module; \& use strict; \& use Exporter; \& use vars qw( @EXPORT_OK ); \& @EXPORT_OK = qw( print_self_name ); \& \& use Class::OOorNO qw( myself ); \& \& sub new { bless { }, shift } \& \& sub print_self_name { \& print( (ref myself(@_) || myself(@_) || _\|_PACKAGE_\|_), "\en" ) \& } .Ve .PP \&\fIUser's code...\fR .PP .Vb 3 \& package main; \& use strict; \& use Your::Module qw( print_self_name ); \& \& my($YM) = Your::Module\->new; \& \& $YM\->print_self_name; # as an object method \& Your::Module\->print_self_name; # as a class method \& &Your::Module::print_self_name; # as a subroutine \& print_self_name; # as imported subroutine .Ve .PP \&\fIOutput:\fR .PP .Vb 4 \& Your::Module \& Your::Module \& Your::Module \& Your::Module .Ve .PP \&\fIYour module...\fR .PP .Vb 5 \& package Your::Module; \& use strict; \& use Exporter; \& use vars qw( @EXPORT_OK ); \& @EXPORT_OK = qw( show_call_style get_self_ref ); \& \& use Class::OOorNO qw( OOorNO myself ); \& \& sub new { bless { }, shift } \& \& sub show_call_style { \& \& if (ref OOorNO(@_)) { \& print _\|_PACKAGE_\|_ . "::foo was called as an OBJECT METHOD.\en" \& } \& elsif (OOorNO(@_)) { \& print _\|_PACKAGE_\|_ . "::foo was called as an CLASS METHOD.\en" \& } \& else { \& print _\|_PACKAGE_\|_ . "::foo was called as a SUBROUTINE.\en" \& } \& } \& \& sub get_self_ref { \& ref myself(@_) ? myself(@_) : _\|_PACKAGE_\|_\->new \& } .Ve .PP \&\fIUser's code...\fR .PP .Vb 3 \& package main; \& use strict; \& use Your::Module qw( show_call_style get_self_ref ); \& \& my($YM) = Your::Module\->new; \& \& # supports calls that go way down the stack too: \& Your::Module\->new\->get_self_ref\->show_call_style; \& Your::Module\->get_self_ref\->show_call_style; \& &Your::Module::get_self_ref\->show_call_style; \& get_self_ref\->show_call_style; .Ve .PP \&\fIOutput:\fR .PP .Vb 4 \& Your::Module::foo was called as an OBJECT METHOD. \& Your::Module::foo was called as an OBJECT METHOD. \& Your::Module::foo was called as an OBJECT METHOD. \& Your::Module::foo was called as an OBJECT METHOD. .Ve .ie n .SS "using ""myargs()""" .el .SS "using \f(CWmyargs()\fP" .IX Subsection "using myargs()" \&\fIYour module...\fR .PP .Vb 5 \& package Your::Module; \& use strict; \& use Exporter; \& use vars qw( @EXPORT_OK ); \& @EXPORT_OK = qw( print_argument_list ); \& \& use Class::OOorNO qw( myargs ); \& \& sub new { bless { }, shift } \& \& sub print_argument_list { \& print "My argument list: \en" . join("\en", myargs(@_)), "\en"; \& } .Ve .PP \&\fIUser's code...\fR .PP .Vb 3 \& package main; \& use strict; \& use Your::Module qw( print_argument_list ); \& \& my($YM) = Your::Module\->new; \& \& my(@things) = ( \*(Aqfoo\*(Aq, \& 12687.357, \& $YM, \& eval(\*(Aq*bar\*(Aq), \& [ \*(Aqbaz\*(Aq, sub { "wubble" }, \& { \*(Aqflarp\*(Aq => \*(Aqwibble\*(Aq } ] ); \& \& $YM\->print_argument_list(@things); # as an object method \& Your::Module\->print_argument_list(@things); # as a class method \& &Your::Module::print_argument_list(@things); # as a subroutine \& print_argument_list(@things); # as imported subroutine .Ve .PP \&\fIOutput:\fR .PP .Vb 6 \& My argument list: \& foo \& 12687.357 \& Your::Module=HASH(0x9bd858) \& *main::bar \& ARRAY(0x9bd954) \& \& ...repeated four times .Ve .ie n .SS "using ""coerce_array()""" .el .SS "using \f(CWcoerce_array()\fP" .IX Subsection "using coerce_array()" \&\fIYour module...\fR .PP .Vb 5 \& package Your::Module; \& use strict; \& use Exporter; \& use vars qw( @EXPORT_OK ); \& @EXPORT_OK = qw( pass_name_value_pairs ); \& \& use Class::OOorNO qw( coerce_array ); \& \& sub new { bless { }, shift } \& \& sub pass_name_value_pairs { \& my($input) = coerce_array(@_); \& \& my($driver) = $input\->{\*(Aq\-driver\*(Aq} || \*(Aqnobody\*(Aq; \& my($car) = $input\->{\*(Aq\-car\*(Aq} || \*(Aqno car\*(Aq; \& my($bike) = $input\->{\*(Aq\-bike\*(Aq} || \*(Aqno bike\*(Aq; \& my($plane) = $input\->{\*(Aq\-plane\*(Aq} || \*(Aqno plane\*(Aq; \& \& print("$driver drives $car, $bike, and $plane.\en"); \& } .Ve .PP \&\fIUser's code...\fR .PP \&\fIOutput:\fR .ie n .SS "using ""shave_opts()""" .el .SS "using \f(CWshave_opts()\fP" .IX Subsection "using shave_opts()" \&\fIYour module...\fR .PP .Vb 5 \& package Your::Module; \& use strict; \& use Exporter; \& use vars qw( @EXPORT_OK ); \& @EXPORT_OK = qw( print_options ); \& \& use Class::OOorNO qw( shave_opts ); \& \& sub new { bless { }, shift } \& \& sub print_options { \& my($opts) = shave_opts(\e@_); \& print "\en", \& ( map { qq[$_ => $opts\->{$_}] . "\en" } keys %$opts ), \& "\en" \& } .Ve .PP \&\fIUser's code...\fR .PP \&\fIOutput:\fR .SH "PREREQUISITES" .IX Header "PREREQUISITES" None. .SH "BUGS" .IX Header "BUGS" This documentation isn't done yet, as you can see. This is being rectified as quickly as possible. Please excercise caution if you choose to use this code before it can be further documented for you. It is present on \s-1CPAN\s0 at this time despite its unfinished condition in order to provide support for the File::Util module which lists Class::OOorNO among its prerequisites. Please excuse the inconvenience. .SH "AUTHOR" .IX Header "AUTHOR" Tommy Butler > .SH "COPYRIGHT" .IX Header "COPYRIGHT" Copyright(c) 2001\-2003, Tommy Butler. All rights reserved. .SH "LICENSE" .IX Header "LICENSE" This library is free software, you may redistribute and/or modify it under the same terms as Perl itself. .SH "SEE ALSO" .IX Header "SEE ALSO" .IP "Devel::Caller" 4 .IX Item "Devel::Caller" .PD 0 .IP "Class::ParmList" 4 .IX Item "Class::ParmList" .IP "Class::ParamParser" 4 .IX Item "Class::ParamParser" .IP "Exporter" 4 .IX Item "Exporter"