init III
This commit is contained in:
744
Perl OTRS/Kernel/cpan-lib/Class/Accessor.pm
Normal file
744
Perl OTRS/Kernel/cpan-lib/Class/Accessor.pm
Normal file
@@ -0,0 +1,744 @@
|
||||
package Class::Accessor;
|
||||
require 5.00502;
|
||||
use strict;
|
||||
$Class::Accessor::VERSION = '0.34';
|
||||
|
||||
sub new {
|
||||
my($proto, $fields) = @_;
|
||||
my($class) = ref $proto || $proto;
|
||||
|
||||
$fields = {} unless defined $fields;
|
||||
|
||||
# make a copy of $fields.
|
||||
bless {%$fields}, $class;
|
||||
}
|
||||
|
||||
sub mk_accessors {
|
||||
my($self, @fields) = @_;
|
||||
|
||||
$self->_mk_accessors('rw', @fields);
|
||||
}
|
||||
|
||||
if (eval { require Sub::Name }) {
|
||||
Sub::Name->import;
|
||||
}
|
||||
|
||||
{
|
||||
no strict 'refs';
|
||||
|
||||
sub import {
|
||||
my ($class, @what) = @_;
|
||||
my $caller = caller;
|
||||
for (@what) {
|
||||
if (/^(?:antlers|moose-?like)$/i) {
|
||||
*{"${caller}::has"} = sub {
|
||||
my ($f, %args) = @_;
|
||||
$caller->_mk_accessors(($args{is}||"rw"), $f);
|
||||
};
|
||||
*{"${caller}::extends"} = sub {
|
||||
@{"${caller}::ISA"} = @_;
|
||||
unless (grep $_->can("_mk_accessors"), @_) {
|
||||
push @{"${caller}::ISA"}, $class;
|
||||
}
|
||||
};
|
||||
# we'll use their @ISA as a default, in case it happens to be
|
||||
# set already
|
||||
&{"${caller}::extends"}(@{"${caller}::ISA"});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub follow_best_practice {
|
||||
my($self) = @_;
|
||||
my $class = ref $self || $self;
|
||||
*{"${class}::accessor_name_for"} = \&best_practice_accessor_name_for;
|
||||
*{"${class}::mutator_name_for"} = \&best_practice_mutator_name_for;
|
||||
}
|
||||
|
||||
sub _mk_accessors {
|
||||
my($self, $access, @fields) = @_;
|
||||
my $class = ref $self || $self;
|
||||
my $ra = $access eq 'rw' || $access eq 'ro';
|
||||
my $wa = $access eq 'rw' || $access eq 'wo';
|
||||
|
||||
foreach my $field (@fields) {
|
||||
my $accessor_name = $self->accessor_name_for($field);
|
||||
my $mutator_name = $self->mutator_name_for($field);
|
||||
if( $accessor_name eq 'DESTROY' or $mutator_name eq 'DESTROY' ) {
|
||||
$self->_carp("Having a data accessor named DESTROY in '$class' is unwise.");
|
||||
}
|
||||
if ($accessor_name eq $mutator_name) {
|
||||
my $accessor;
|
||||
if ($ra && $wa) {
|
||||
$accessor = $self->make_accessor($field);
|
||||
} elsif ($ra) {
|
||||
$accessor = $self->make_ro_accessor($field);
|
||||
} else {
|
||||
$accessor = $self->make_wo_accessor($field);
|
||||
}
|
||||
my $fullname = "${class}::$accessor_name";
|
||||
my $subnamed = 0;
|
||||
unless (defined &{$fullname}) {
|
||||
subname($fullname, $accessor) if defined &subname;
|
||||
$subnamed = 1;
|
||||
*{$fullname} = $accessor;
|
||||
}
|
||||
if ($accessor_name eq $field) {
|
||||
# the old behaviour
|
||||
my $alias = "${class}::_${field}_accessor";
|
||||
subname($alias, $accessor) if defined &subname and not $subnamed;
|
||||
*{$alias} = $accessor unless defined &{$alias};
|
||||
}
|
||||
} else {
|
||||
my $fullaccname = "${class}::$accessor_name";
|
||||
my $fullmutname = "${class}::$mutator_name";
|
||||
if ($ra and not defined &{$fullaccname}) {
|
||||
my $accessor = $self->make_ro_accessor($field);
|
||||
subname($fullaccname, $accessor) if defined &subname;
|
||||
*{$fullaccname} = $accessor;
|
||||
}
|
||||
if ($wa and not defined &{$fullmutname}) {
|
||||
my $mutator = $self->make_wo_accessor($field);
|
||||
subname($fullmutname, $mutator) if defined &subname;
|
||||
*{$fullmutname} = $mutator;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sub mk_ro_accessors {
|
||||
my($self, @fields) = @_;
|
||||
|
||||
$self->_mk_accessors('ro', @fields);
|
||||
}
|
||||
|
||||
sub mk_wo_accessors {
|
||||
my($self, @fields) = @_;
|
||||
|
||||
$self->_mk_accessors('wo', @fields);
|
||||
}
|
||||
|
||||
sub best_practice_accessor_name_for {
|
||||
my ($class, $field) = @_;
|
||||
return "get_$field";
|
||||
}
|
||||
|
||||
sub best_practice_mutator_name_for {
|
||||
my ($class, $field) = @_;
|
||||
return "set_$field";
|
||||
}
|
||||
|
||||
sub accessor_name_for {
|
||||
my ($class, $field) = @_;
|
||||
return $field;
|
||||
}
|
||||
|
||||
sub mutator_name_for {
|
||||
my ($class, $field) = @_;
|
||||
return $field;
|
||||
}
|
||||
|
||||
sub set {
|
||||
my($self, $key) = splice(@_, 0, 2);
|
||||
|
||||
if(@_ == 1) {
|
||||
$self->{$key} = $_[0];
|
||||
}
|
||||
elsif(@_ > 1) {
|
||||
$self->{$key} = [@_];
|
||||
}
|
||||
else {
|
||||
$self->_croak("Wrong number of arguments received");
|
||||
}
|
||||
}
|
||||
|
||||
sub get {
|
||||
my $self = shift;
|
||||
|
||||
if(@_ == 1) {
|
||||
return $self->{$_[0]};
|
||||
}
|
||||
elsif( @_ > 1 ) {
|
||||
return @{$self}{@_};
|
||||
}
|
||||
else {
|
||||
$self->_croak("Wrong number of arguments received");
|
||||
}
|
||||
}
|
||||
|
||||
sub make_accessor {
|
||||
my ($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
my $self = shift;
|
||||
|
||||
if(@_) {
|
||||
return $self->set($field, @_);
|
||||
} else {
|
||||
return $self->get($field);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
sub make_ro_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
my $self = shift;
|
||||
|
||||
if (@_) {
|
||||
my $caller = caller;
|
||||
$self->_croak("'$caller' cannot alter the value of '$field' on objects of class '$class'");
|
||||
}
|
||||
else {
|
||||
return $self->get($field);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
sub make_wo_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
my $self = shift;
|
||||
|
||||
unless (@_) {
|
||||
my $caller = caller;
|
||||
$self->_croak("'$caller' cannot access the value of '$field' on objects of class '$class'");
|
||||
}
|
||||
else {
|
||||
return $self->set($field, @_);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
use Carp ();
|
||||
|
||||
sub _carp {
|
||||
my ($self, $msg) = @_;
|
||||
Carp::carp($msg || $self);
|
||||
return;
|
||||
}
|
||||
|
||||
sub _croak {
|
||||
my ($self, $msg) = @_;
|
||||
Carp::croak($msg || $self);
|
||||
return;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Class::Accessor - Automated accessor generation
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Foo->follow_best_practice;
|
||||
Foo->mk_accessors(qw(name role salary));
|
||||
|
||||
# or if you prefer a Moose-like interface...
|
||||
|
||||
package Foo;
|
||||
use Class::Accessor "antlers";
|
||||
has name => ( is => "rw", isa => "Str" );
|
||||
has role => ( is => "rw", isa => "Str" );
|
||||
has salary => ( is => "rw", isa => "Num" );
|
||||
|
||||
# Meanwhile, in a nearby piece of code!
|
||||
# Class::Accessor provides new().
|
||||
my $mp = Foo->new({ name => "Marty", role => "JAPH" });
|
||||
|
||||
my $job = $mp->role; # gets $mp->{role}
|
||||
$mp->salary(400000); # sets $mp->{salary} = 400000 # I wish
|
||||
|
||||
# like my @info = @{$mp}{qw(name role)}
|
||||
my @info = $mp->get(qw(name role));
|
||||
|
||||
# $mp->{salary} = 400000
|
||||
$mp->set('salary', 400000);
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module automagically generates accessors/mutators for your class.
|
||||
|
||||
Most of the time, writing accessors is an exercise in cutting and
|
||||
pasting. You usually wind up with a series of methods like this:
|
||||
|
||||
sub name {
|
||||
my $self = shift;
|
||||
if(@_) {
|
||||
$self->{name} = $_[0];
|
||||
}
|
||||
return $self->{name};
|
||||
}
|
||||
|
||||
sub salary {
|
||||
my $self = shift;
|
||||
if(@_) {
|
||||
$self->{salary} = $_[0];
|
||||
}
|
||||
return $self->{salary};
|
||||
}
|
||||
|
||||
# etc...
|
||||
|
||||
One for each piece of data in your object. While some will be unique,
|
||||
doing value checks and special storage tricks, most will simply be
|
||||
exercises in repetition. Not only is it Bad Style to have a bunch of
|
||||
repetitious code, but it's also simply not lazy, which is the real
|
||||
tragedy.
|
||||
|
||||
If you make your module a subclass of Class::Accessor and declare your
|
||||
accessor fields with mk_accessors() then you'll find yourself with a
|
||||
set of automatically generated accessors which can even be
|
||||
customized!
|
||||
|
||||
The basic set up is very simple:
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Foo->mk_accessors( qw(far bar car) );
|
||||
|
||||
Done. Foo now has simple far(), bar() and car() accessors
|
||||
defined.
|
||||
|
||||
Alternatively, if you want to follow Damian's I<best practice> guidelines
|
||||
you can use:
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Foo->follow_best_practice;
|
||||
Foo->mk_accessors( qw(far bar car) );
|
||||
|
||||
B<Note:> you must call C<follow_best_practice> before calling C<mk_accessors>.
|
||||
|
||||
=head2 Moose-like
|
||||
|
||||
By popular demand we now have a simple Moose-like interface. You can now do:
|
||||
|
||||
package Foo;
|
||||
use Class::Accessor "antlers";
|
||||
has far => ( is => "rw" );
|
||||
has bar => ( is => "rw" );
|
||||
has car => ( is => "rw" );
|
||||
|
||||
Currently only the C<is> attribute is supported.
|
||||
|
||||
=head1 CONSTRUCTOR
|
||||
|
||||
Class::Accessor provides a basic constructor, C<new>. It generates a
|
||||
hash-based object and can be called as either a class method or an
|
||||
object method.
|
||||
|
||||
=head2 new
|
||||
|
||||
my $obj = Foo->new;
|
||||
my $obj = $other_obj->new;
|
||||
|
||||
my $obj = Foo->new(\%fields);
|
||||
my $obj = $other_obj->new(\%fields);
|
||||
|
||||
It takes an optional %fields hash which is used to initialize the
|
||||
object (handy if you use read-only accessors). The fields of the hash
|
||||
correspond to the names of your accessors, so...
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Foo->mk_accessors('foo');
|
||||
|
||||
my $obj = Foo->new({ foo => 42 });
|
||||
print $obj->foo; # 42
|
||||
|
||||
however %fields can contain anything, new() will shove them all into
|
||||
your object.
|
||||
|
||||
=head1 MAKING ACCESSORS
|
||||
|
||||
=head2 follow_best_practice
|
||||
|
||||
In Damian's Perl Best Practices book he recommends separate get and set methods
|
||||
with the prefix set_ and get_ to make it explicit what you intend to do. If you
|
||||
want to create those accessor methods instead of the default ones, call:
|
||||
|
||||
__PACKAGE__->follow_best_practice
|
||||
|
||||
B<before> you call any of the accessor-making methods.
|
||||
|
||||
=head2 accessor_name_for / mutator_name_for
|
||||
|
||||
You may have your own crazy ideas for the names of the accessors, so you can
|
||||
make those happen by overriding C<accessor_name_for> and C<mutator_name_for> in
|
||||
your subclass. (I copied that idea from Class::DBI.)
|
||||
|
||||
=head2 mk_accessors
|
||||
|
||||
__PACKAGE__->mk_accessors(@fields);
|
||||
|
||||
This creates accessor/mutator methods for each named field given in
|
||||
@fields. Foreach field in @fields it will generate two accessors.
|
||||
One called "field()" and the other called "_field_accessor()". For
|
||||
example:
|
||||
|
||||
# Generates foo(), _foo_accessor(), bar() and _bar_accessor().
|
||||
__PACKAGE__->mk_accessors(qw(foo bar));
|
||||
|
||||
See L<CAVEATS AND TRICKS/"Overriding autogenerated accessors">
|
||||
for details.
|
||||
|
||||
=head2 mk_ro_accessors
|
||||
|
||||
__PACKAGE__->mk_ro_accessors(@read_only_fields);
|
||||
|
||||
Same as mk_accessors() except it will generate read-only accessors
|
||||
(ie. true accessors). If you attempt to set a value with these
|
||||
accessors it will throw an exception. It only uses get() and not
|
||||
set().
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Foo->mk_ro_accessors(qw(foo bar));
|
||||
|
||||
# Let's assume we have an object $foo of class Foo...
|
||||
print $foo->foo; # ok, prints whatever the value of $foo->{foo} is
|
||||
$foo->foo(42); # BOOM! Naughty you.
|
||||
|
||||
|
||||
=head2 mk_wo_accessors
|
||||
|
||||
__PACKAGE__->mk_wo_accessors(@write_only_fields);
|
||||
|
||||
Same as mk_accessors() except it will generate write-only accessors
|
||||
(ie. mutators). If you attempt to read a value with these accessors
|
||||
it will throw an exception. It only uses set() and not get().
|
||||
|
||||
B<NOTE> I'm not entirely sure why this is useful, but I'm sure someone
|
||||
will need it. If you've found a use, let me know. Right now it's here
|
||||
for orthoginality and because it's easy to implement.
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Foo->mk_wo_accessors(qw(foo bar));
|
||||
|
||||
# Let's assume we have an object $foo of class Foo...
|
||||
$foo->foo(42); # OK. Sets $self->{foo} = 42
|
||||
print $foo->foo; # BOOM! Can't read from this accessor.
|
||||
|
||||
=head1 Moose!
|
||||
|
||||
If you prefer a Moose-like interface to create accessors, you can use C<has> by
|
||||
importing this module like this:
|
||||
|
||||
use Class::Accessor "antlers";
|
||||
|
||||
or
|
||||
|
||||
use Class::Accessor "moose-like";
|
||||
|
||||
Then you can declare accessors like this:
|
||||
|
||||
has alpha => ( is => "rw", isa => "Str" );
|
||||
has beta => ( is => "ro", isa => "Str" );
|
||||
has gamma => ( is => "wo", isa => "Str" );
|
||||
|
||||
Currently only the C<is> attribute is supported. And our C<is> also supports
|
||||
the "wo" value to make a write-only accessor.
|
||||
|
||||
If you are using the Moose-like interface then you should use the C<extends>
|
||||
rather than tweaking your C<@ISA> directly. Basically, replace
|
||||
|
||||
@ISA = qw/Foo Bar/;
|
||||
|
||||
with
|
||||
|
||||
extends(qw/Foo Bar/);
|
||||
|
||||
=head1 DETAILS
|
||||
|
||||
An accessor generated by Class::Accessor looks something like
|
||||
this:
|
||||
|
||||
# Your foo may vary.
|
||||
sub foo {
|
||||
my($self) = shift;
|
||||
if(@_) { # set
|
||||
return $self->set('foo', @_);
|
||||
}
|
||||
else {
|
||||
return $self->get('foo');
|
||||
}
|
||||
}
|
||||
|
||||
Very simple. All it does is determine if you're wanting to set a
|
||||
value or get a value and calls the appropriate method.
|
||||
Class::Accessor provides default get() and set() methods which
|
||||
your class can override. They're detailed later.
|
||||
|
||||
=head2 Modifying the behavior of the accessor
|
||||
|
||||
Rather than actually modifying the accessor itself, it is much more
|
||||
sensible to simply override the two key methods which the accessor
|
||||
calls. Namely set() and get().
|
||||
|
||||
If you -really- want to, you can override make_accessor().
|
||||
|
||||
=head2 set
|
||||
|
||||
$obj->set($key, $value);
|
||||
$obj->set($key, @values);
|
||||
|
||||
set() defines how generally one stores data in the object.
|
||||
|
||||
override this method to change how data is stored by your accessors.
|
||||
|
||||
=head2 get
|
||||
|
||||
$value = $obj->get($key);
|
||||
@values = $obj->get(@keys);
|
||||
|
||||
get() defines how data is retreived from your objects.
|
||||
|
||||
override this method to change how it is retreived.
|
||||
|
||||
=head2 make_accessor
|
||||
|
||||
$accessor = __PACKAGE__->make_accessor($field);
|
||||
|
||||
Generates a subroutine reference which acts as an accessor for the given
|
||||
$field. It calls get() and set().
|
||||
|
||||
If you wish to change the behavior of your accessors, try overriding
|
||||
get() and set() before you start mucking with make_accessor().
|
||||
|
||||
=head2 make_ro_accessor
|
||||
|
||||
$read_only_accessor = __PACKAGE__->make_ro_accessor($field);
|
||||
|
||||
Generates a subroutine refrence which acts as a read-only accessor for
|
||||
the given $field. It only calls get().
|
||||
|
||||
Override get() to change the behavior of your accessors.
|
||||
|
||||
=head2 make_wo_accessor
|
||||
|
||||
$read_only_accessor = __PACKAGE__->make_wo_accessor($field);
|
||||
|
||||
Generates a subroutine refrence which acts as a write-only accessor
|
||||
(mutator) for the given $field. It only calls set().
|
||||
|
||||
Override set() to change the behavior of your accessors.
|
||||
|
||||
=head1 EXCEPTIONS
|
||||
|
||||
If something goes wrong Class::Accessor will warn or die by calling Carp::carp
|
||||
or Carp::croak. If you don't like this you can override _carp() and _croak() in
|
||||
your subclass and do whatever else you want.
|
||||
|
||||
=head1 EFFICIENCY
|
||||
|
||||
Class::Accessor does not employ an autoloader, thus it is much faster
|
||||
than you'd think. Its generated methods incur no special penalty over
|
||||
ones you'd write yourself.
|
||||
|
||||
accessors:
|
||||
Rate Basic Fast Faster Direct
|
||||
Basic 367589/s -- -51% -55% -89%
|
||||
Fast 747964/s 103% -- -9% -77%
|
||||
Faster 819199/s 123% 10% -- -75%
|
||||
Direct 3245887/s 783% 334% 296% --
|
||||
|
||||
mutators:
|
||||
Rate Acc Fast Faster Direct
|
||||
Acc 265564/s -- -54% -63% -91%
|
||||
Fast 573439/s 116% -- -21% -80%
|
||||
Faster 724710/s 173% 26% -- -75%
|
||||
Direct 2860979/s 977% 399% 295% --
|
||||
|
||||
Class::Accessor::Fast is faster than methods written by an average programmer
|
||||
(where "average" is based on Schwern's example code).
|
||||
|
||||
Class::Accessor is slower than average, but more flexible.
|
||||
|
||||
Class::Accessor::Faster is even faster than Class::Accessor::Fast. It uses an
|
||||
array internally, not a hash. This could be a good or bad feature depending on
|
||||
your point of view.
|
||||
|
||||
Direct hash access is, of course, much faster than all of these, but it
|
||||
provides no encapsulation.
|
||||
|
||||
Of course, it's not as simple as saying "Class::Accessor is slower than
|
||||
average". These are benchmarks for a simple accessor. If your accessors do
|
||||
any sort of complicated work (such as talking to a database or writing to a
|
||||
file) the time spent doing that work will quickly swamp the time spend just
|
||||
calling the accessor. In that case, Class::Accessor and the ones you write
|
||||
will be roughly the same speed.
|
||||
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
Here's an example of generating an accessor for every public field of
|
||||
your class.
|
||||
|
||||
package Altoids;
|
||||
|
||||
use base qw(Class::Accessor Class::Fields);
|
||||
use fields qw(curiously strong mints);
|
||||
Altoids->mk_accessors( Altoids->show_fields('Public') );
|
||||
|
||||
sub new {
|
||||
my $proto = shift;
|
||||
my $class = ref $proto || $proto;
|
||||
return fields::new($class);
|
||||
}
|
||||
|
||||
my Altoids $tin = Altoids->new;
|
||||
|
||||
$tin->curiously('Curiouser and curiouser');
|
||||
print $tin->{curiously}; # prints 'Curiouser and curiouser'
|
||||
|
||||
|
||||
# Subclassing works, too.
|
||||
package Mint::Snuff;
|
||||
use base qw(Altoids);
|
||||
|
||||
my Mint::Snuff $pouch = Mint::Snuff->new;
|
||||
$pouch->strong('Blow your head off!');
|
||||
print $pouch->{strong}; # prints 'Blow your head off!'
|
||||
|
||||
|
||||
Here's a simple example of altering the behavior of your accessors.
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Foo->mk_accessors(qw(this that up down));
|
||||
|
||||
sub get {
|
||||
my $self = shift;
|
||||
|
||||
# Note every time someone gets some data.
|
||||
print STDERR "Getting @_\n";
|
||||
|
||||
$self->SUPER::get(@_);
|
||||
}
|
||||
|
||||
sub set {
|
||||
my ($self, $key) = splice(@_, 0, 2);
|
||||
|
||||
# Note every time someone sets some data.
|
||||
print STDERR "Setting $key to @_\n";
|
||||
|
||||
$self->SUPER::set($key, @_);
|
||||
}
|
||||
|
||||
|
||||
=head1 CAVEATS AND TRICKS
|
||||
|
||||
Class::Accessor has to do some internal wackiness to get its
|
||||
job done quickly and efficiently. Because of this, there's a few
|
||||
tricks and traps one must know about.
|
||||
|
||||
Hey, nothing's perfect.
|
||||
|
||||
=head2 Don't make a field called DESTROY
|
||||
|
||||
This is bad. Since DESTROY is a magical method it would be bad for us
|
||||
to define an accessor using that name. Class::Accessor will
|
||||
carp if you try to use it with a field named "DESTROY".
|
||||
|
||||
=head2 Overriding autogenerated accessors
|
||||
|
||||
You may want to override the autogenerated accessor with your own, yet
|
||||
have your custom accessor call the default one. For instance, maybe
|
||||
you want to have an accessor which checks its input. Normally, one
|
||||
would expect this to work:
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Foo->mk_accessors(qw(email this that whatever));
|
||||
|
||||
# Only accept addresses which look valid.
|
||||
sub email {
|
||||
my($self) = shift;
|
||||
my($email) = @_;
|
||||
|
||||
if( @_ ) { # Setting
|
||||
require Email::Valid;
|
||||
unless( Email::Valid->address($email) ) {
|
||||
carp("$email doesn't look like a valid address.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return $self->SUPER::email(@_);
|
||||
}
|
||||
|
||||
There's a subtle problem in the last example, and it's in this line:
|
||||
|
||||
return $self->SUPER::email(@_);
|
||||
|
||||
If we look at how Foo was defined, it called mk_accessors() which
|
||||
stuck email() right into Foo's namespace. There *is* no
|
||||
SUPER::email() to delegate to! Two ways around this... first is to
|
||||
make a "pure" base class for Foo. This pure class will generate the
|
||||
accessors and provide the necessary super class for Foo to use:
|
||||
|
||||
package Pure::Organic::Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Pure::Organic::Foo->mk_accessors(qw(email this that whatever));
|
||||
|
||||
package Foo;
|
||||
use base qw(Pure::Organic::Foo);
|
||||
|
||||
And now Foo::email() can override the generated
|
||||
Pure::Organic::Foo::email() and use it as SUPER::email().
|
||||
|
||||
This is probably the most obvious solution to everyone but me.
|
||||
Instead, what first made sense to me was for mk_accessors() to define
|
||||
an alias of email(), _email_accessor(). Using this solution,
|
||||
Foo::email() would be written with:
|
||||
|
||||
return $self->_email_accessor(@_);
|
||||
|
||||
instead of the expected SUPER::email().
|
||||
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Copyright 2009 Marty Pauley <marty+perl@kasei.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the same terms as Perl itself. That means either (a) the GNU General Public
|
||||
License or (b) the Artistic License.
|
||||
|
||||
=head2 ORIGINAL AUTHOR
|
||||
|
||||
Michael G Schwern <schwern@pobox.com>
|
||||
|
||||
=head2 THANKS
|
||||
|
||||
Liz and RUZ for performance tweaks.
|
||||
|
||||
Tels, for his big feature request/bug report.
|
||||
|
||||
Various presenters at YAPC::Asia 2009 for criticising the non-Moose interface.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
See L<Class::Accessor::Fast> and L<Class::Accessor::Faster> if speed is more
|
||||
important than flexibility.
|
||||
|
||||
These are some modules which do similar things in different ways
|
||||
L<Class::Struct>, L<Class::Methodmaker>, L<Class::Generate>,
|
||||
L<Class::Class>, L<Class::Contract>, L<Moose>, L<Mouse>
|
||||
|
||||
See L<Class::DBI> for an example of this module in use.
|
||||
|
||||
=cut
|
||||
82
Perl OTRS/Kernel/cpan-lib/Class/Accessor/Chained.pm
Normal file
82
Perl OTRS/Kernel/cpan-lib/Class/Accessor/Chained.pm
Normal file
@@ -0,0 +1,82 @@
|
||||
use strict;
|
||||
package Class::Accessor::Chained;
|
||||
use base 'Class::Accessor';
|
||||
our $VERSION = '0.01';
|
||||
|
||||
sub make_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
# Build a closure around $field.
|
||||
return sub {
|
||||
my($self) = shift;
|
||||
|
||||
if (@_) {
|
||||
$self->set($field, @_);
|
||||
return $self;
|
||||
}
|
||||
else {
|
||||
return $self->get($field);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
sub make_wo_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
my($self) = shift;
|
||||
|
||||
unless (@_) {
|
||||
my $caller = caller;
|
||||
require Carp;
|
||||
Carp::croak("'$caller' cannot access the value of '$field' on ".
|
||||
"objects of class '$class'");
|
||||
}
|
||||
else {
|
||||
$self->set($field, @_);
|
||||
return $self;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Class::Accessor::Chained - make chained accessors
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package Foo;
|
||||
use base qw( Class::Accessor::Chained );
|
||||
__PACKAGE__->mk_accessors(qw( foo bar baz ));
|
||||
|
||||
my $foo = Foo->new->foo(1)->bar(2)->baz(4);
|
||||
print $foo->bar; # prints 2
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
A chained accessor is one that always returns the object when called
|
||||
with parameters (to set), and the value of the field when called with
|
||||
no arguments.
|
||||
|
||||
This module subclasses Class::Accessor in order to provide the same
|
||||
mk_accessors interface.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Richard Clamp <richardc@unixbeard.net>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2003 Richard Clamp. All Rights Reserved.
|
||||
|
||||
This module is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Class::Accessor>, L<Class::Accessor::Chained::Fast>
|
||||
|
||||
=cut
|
||||
70
Perl OTRS/Kernel/cpan-lib/Class/Accessor/Chained/Fast.pm
Normal file
70
Perl OTRS/Kernel/cpan-lib/Class/Accessor/Chained/Fast.pm
Normal file
@@ -0,0 +1,70 @@
|
||||
use strict;
|
||||
package Class::Accessor::Chained::Fast;
|
||||
use base 'Class::Accessor::Fast';
|
||||
|
||||
sub make_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
my $self = shift;
|
||||
if(@_) {
|
||||
$self->{$field} = (@_ == 1 ? $_[0] : [@_]);
|
||||
return $self;
|
||||
}
|
||||
return $self->{$field};
|
||||
};
|
||||
}
|
||||
|
||||
sub make_wo_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
my($self) = shift;
|
||||
|
||||
unless (@_) {
|
||||
my $caller = caller;
|
||||
require Carp;
|
||||
Carp::croak("'$caller' cannot access the value of '$field' on ".
|
||||
"objects of class '$class'");
|
||||
}
|
||||
else {
|
||||
$self->{$field} = (@_ == 1 ? $_[0] : [@_]);
|
||||
return $self;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Class::Accessor::Chained::Fast - Faster, but less expandable, chained accessors
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor::Chained::Fast);
|
||||
|
||||
# The rest as Class::Accessor::Chained except no set() or get().
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
By analogue to Class::Accessor and Class::Accessor::Fast this module
|
||||
provides a faster less-flexible chained accessor maker.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Richard Clamp <richardc@unixbeard.net>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2003 Richard Clamp. All Rights Reserved.
|
||||
|
||||
This module is free software; you can redistribute it and/or modify it
|
||||
under the same terms as Perl itself.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Class::Accessor::Fast>, L<Class::Accessor::Chained>
|
||||
|
||||
=cut
|
||||
93
Perl OTRS/Kernel/cpan-lib/Class/Accessor/Fast.pm
Normal file
93
Perl OTRS/Kernel/cpan-lib/Class/Accessor/Fast.pm
Normal file
@@ -0,0 +1,93 @@
|
||||
package Class::Accessor::Fast;
|
||||
use base 'Class::Accessor';
|
||||
use strict;
|
||||
$Class::Accessor::Fast::VERSION = '0.34';
|
||||
|
||||
sub make_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
return $_[0]->{$field} if scalar(@_) == 1;
|
||||
return $_[0]->{$field} = scalar(@_) == 2 ? $_[1] : [@_[1..$#_]];
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
sub make_ro_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
return $_[0]->{$field} if @_ == 1;
|
||||
my $caller = caller;
|
||||
$_[0]->_croak("'$caller' cannot alter the value of '$field' on objects of class '$class'");
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
sub make_wo_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
if (@_ == 1) {
|
||||
my $caller = caller;
|
||||
$_[0]->_croak("'$caller' cannot access the value of '$field' on objects of class '$class'");
|
||||
}
|
||||
else {
|
||||
return $_[0]->{$field} = $_[1] if @_ == 2;
|
||||
return (shift)->{$field} = \@_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Class::Accessor::Fast - Faster, but less expandable, accessors
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor::Fast);
|
||||
|
||||
# The rest is the same as Class::Accessor but without set() and get().
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is a faster but less expandable version of Class::Accessor.
|
||||
Class::Accessor's generated accessors require two method calls to accompish
|
||||
their task (one for the accessor, another for get() or set()).
|
||||
Class::Accessor::Fast eliminates calling set()/get() and does the access itself,
|
||||
resulting in a somewhat faster accessor.
|
||||
|
||||
The downside is that you can't easily alter the behavior of your
|
||||
accessors, nor can your subclasses. Of course, should you need this
|
||||
later, you can always swap out Class::Accessor::Fast for
|
||||
Class::Accessor.
|
||||
|
||||
Read the documentation for Class::Accessor for more info.
|
||||
|
||||
=head1 EFFICIENCY
|
||||
|
||||
L<Class::Accessor/EFFICIENCY> for an efficiency comparison.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Copyright 2007 Marty Pauley <marty+perl@kasei.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the same terms as Perl itself. That means either (a) the GNU General Public
|
||||
License or (b) the Artistic License.
|
||||
|
||||
=head2 ORIGINAL AUTHOR
|
||||
|
||||
Michael G Schwern <schwern@pobox.com>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Class::Accessor>
|
||||
|
||||
=cut
|
||||
246
Perl OTRS/Kernel/cpan-lib/Class/Accessor/Lite.pm
Normal file
246
Perl OTRS/Kernel/cpan-lib/Class/Accessor/Lite.pm
Normal file
@@ -0,0 +1,246 @@
|
||||
package Class::Accessor::Lite;
|
||||
|
||||
use strict;
|
||||
|
||||
our $VERSION = '0.08';
|
||||
|
||||
sub croak {require Carp; Carp::croak(@_)}
|
||||
|
||||
sub import {
|
||||
shift;
|
||||
my %args = @_;
|
||||
my $pkg = caller(0);
|
||||
my %key_ctor = (
|
||||
rw => \&_mk_accessors,
|
||||
ro => \&_mk_ro_accessors,
|
||||
wo => \&_mk_wo_accessors,
|
||||
);
|
||||
for my $key (sort keys %key_ctor) {
|
||||
if (defined $args{$key}) {
|
||||
croak("value of the '$key' parameter should be an arrayref")
|
||||
unless ref($args{$key}) eq 'ARRAY';
|
||||
$key_ctor{$key}->($pkg, @{$args{$key}});
|
||||
}
|
||||
}
|
||||
_mk_new($pkg)
|
||||
if $args{new};
|
||||
1;
|
||||
}
|
||||
|
||||
sub mk_new_and_accessors {
|
||||
(undef, my @properties) = @_;
|
||||
my $pkg = caller(0);
|
||||
_mk_new($pkg);
|
||||
_mk_accessors($pkg, @properties);
|
||||
}
|
||||
|
||||
sub mk_new {
|
||||
my $pkg = caller(0);
|
||||
_mk_new($pkg);
|
||||
}
|
||||
|
||||
sub mk_accessors {
|
||||
(undef, my @properties) = @_;
|
||||
my $pkg = caller(0);
|
||||
_mk_accessors($pkg, @properties);
|
||||
}
|
||||
|
||||
sub mk_ro_accessors {
|
||||
(undef, my @properties) = @_;
|
||||
my $pkg = caller(0);
|
||||
_mk_ro_accessors($pkg, @properties);
|
||||
}
|
||||
|
||||
sub mk_wo_accessors {
|
||||
(undef, my @properties) = @_;
|
||||
my $pkg = caller(0);
|
||||
_mk_wo_accessors($pkg, @properties);
|
||||
}
|
||||
|
||||
sub _mk_new {
|
||||
my $pkg = shift;
|
||||
no strict 'refs';
|
||||
*{$pkg . '::new'} = __m_new($pkg);
|
||||
}
|
||||
|
||||
sub _mk_accessors {
|
||||
my $pkg = shift;
|
||||
no strict 'refs';
|
||||
for my $n (@_) {
|
||||
*{$pkg . '::' . $n} = __m($n);
|
||||
}
|
||||
}
|
||||
|
||||
sub _mk_ro_accessors {
|
||||
my $pkg = shift;
|
||||
no strict 'refs';
|
||||
for my $n (@_) {
|
||||
*{$pkg . '::' . $n} = __m_ro($pkg, $n);
|
||||
}
|
||||
}
|
||||
|
||||
sub _mk_wo_accessors {
|
||||
my $pkg = shift;
|
||||
no strict 'refs';
|
||||
for my $n (@_) {
|
||||
*{$pkg . '::' . $n} = __m_wo($pkg, $n);
|
||||
}
|
||||
}
|
||||
|
||||
sub __m_new {
|
||||
my $pkg = shift;
|
||||
no strict 'refs';
|
||||
return sub {
|
||||
my $klass = shift;
|
||||
bless {
|
||||
(@_ == 1 && ref($_[0]) eq 'HASH' ? %{$_[0]} : @_),
|
||||
}, $klass;
|
||||
};
|
||||
}
|
||||
|
||||
sub __m {
|
||||
my $n = shift;
|
||||
sub {
|
||||
return $_[0]->{$n} if @_ == 1;
|
||||
return $_[0]->{$n} = $_[1] if @_ == 2;
|
||||
shift->{$n} = \@_;
|
||||
};
|
||||
}
|
||||
|
||||
sub __m_ro {
|
||||
my ($pkg, $n) = @_;
|
||||
sub {
|
||||
if (@_ == 1) {
|
||||
return $_[0]->{$n} if @_ == 1;
|
||||
} else {
|
||||
my $caller = caller(0);
|
||||
croak("'$caller' cannot access the value of '$n' on objects of class '$pkg'");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
sub __m_wo {
|
||||
my ($pkg, $n) = @_;
|
||||
sub {
|
||||
if (@_ == 1) {
|
||||
my $caller = caller(0);
|
||||
croak("'$caller' cannot alter the value of '$n' on objects of class '$pkg'")
|
||||
} else {
|
||||
return $_[0]->{$n} = $_[1] if @_ == 2;
|
||||
shift->{$n} = \@_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Class::Accessor::Lite - a minimalistic variant of Class::Accessor
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package MyPackage;
|
||||
|
||||
use Class::Accessor::Lite (
|
||||
new => 1,
|
||||
rw => [ qw(foo bar) ],
|
||||
ro => [ qw(baz) ],
|
||||
wo => [ qw(hoge) ],
|
||||
);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The module is a variant of C<Class::Accessor>. It is fast and requires less typing, has no dependencies to other modules, and does not mess up the @ISA.
|
||||
|
||||
=head1 THE USE STATEMENT
|
||||
|
||||
The use statement (i.e. the C<import> function) of the module takes a single hash as an argument that specifies the types and the names of the properties. Recognises the following keys.
|
||||
|
||||
=over 4
|
||||
|
||||
=item new => $true_or_false
|
||||
|
||||
the default constructor is created if the value evaluates to true, otherwise nothing is done (the default behaviour)
|
||||
|
||||
=item rw => \@name_of_the_properties
|
||||
|
||||
creates a read / write accessor for the name of the properties passed through as an arrayref
|
||||
|
||||
=item ro => \@name_of_the_properties
|
||||
|
||||
creates a read-only accessor for the name of the properties passed through as an arrayref
|
||||
|
||||
=item wo => \@name_of_the_properties
|
||||
|
||||
creates a write-only accessor for the name of the properties passed through as an arrayref
|
||||
|
||||
=back
|
||||
|
||||
For more detailed explanation read the following section describing the behaviour of each function that actually creates the accessors.
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
As of version 0.04 the properties can be specified as the arguments to the C<use> statement (as can be seen in the SYNOPSIS) which is now the recommended way of using the module, but for compatibility the following functions are provided as well.
|
||||
|
||||
=head2 Class::Accessor::Lite->mk_accessors(@name_of_the_properties)
|
||||
|
||||
Creates an accessor in current package under the name specified by the arguments that access the properties (of a hashref) with the same name.
|
||||
|
||||
=head2 Class::Accessor::Lite->mk_ro_accessors(@name_of_the_properties)
|
||||
|
||||
Same as mk_accessors() except it will generate read-only accessors (i.e. true accessors). If you attempt to set a value with these accessors it will throw an exception.
|
||||
|
||||
=head2 Class::Accessor::Lite->mk_wo_accessors(@name_of_the_properties)
|
||||
|
||||
Same as mk_accessors() except it will generate write-only accessors (i.e. mutators). If you attempt to read a value with these accessors it will throw an exception.
|
||||
|
||||
=head2 Class::Accessor::Lite->mk_new()
|
||||
|
||||
Creates the C<new> function that accepts a hash or a hashref as the initial properties of the object.
|
||||
|
||||
=head2 Class::Accessor::Lite->mk_new_and_accessors(@name_of_the_properties)
|
||||
|
||||
DEPRECATED. Use the new "use Class::Accessor::Lite (...)" style.
|
||||
|
||||
=head1 FAQ
|
||||
|
||||
=head2 Can I use C<Class::Accessor::Lite> in an inherited module?
|
||||
|
||||
Yes in most cases, when the class object in the super class is implemented using a hashref. However you _should_ _not_ create the constructor for the inherited class by calling C<<Class::Accessor::Lite->new()>> or by C<<use Class::Accessor::Lite (new => 1)>>. The only other thing that C<Class::Accessor::Lite> does is to set up the accessor functions for given property names through a blessed hashref.
|
||||
|
||||
=head2 What happens when passing more than one arguments to the accessor?
|
||||
|
||||
When the accessor built by Class::Accessor::Lite is given more than one arguments, a reference to the arguments will be saved as an arrayref. This behaviour might not be necessary but is implemented as is to maintain compatibility with L<Class::Accessor::Fast>.
|
||||
|
||||
my @data = (1, 2, 3);
|
||||
$obj->someproperty(@data);
|
||||
|
||||
$obj->someproperty->[2]++; # $data[3] is incremented
|
||||
|
||||
In general, you should pass an arrayref to set an arrayref to a property.
|
||||
|
||||
my @data = (1, 2, 3);
|
||||
$obj->someproperty([ @data ]); # save a copy using arrayref
|
||||
|
||||
$obj->someproper->[2]++; # @data is not modified
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Class::Accessor>
|
||||
|
||||
L<Class::Accessor::Lite>
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Copyright (C) 2008 - 2010 Kazuho Oku
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.6 or, at your option, any later version of Perl 5 you may have available.
|
||||
|
||||
=cut
|
||||
|
||||
641
Perl OTRS/Kernel/cpan-lib/Class/Inspector.pm
Normal file
641
Perl OTRS/Kernel/cpan-lib/Class/Inspector.pm
Normal file
@@ -0,0 +1,641 @@
|
||||
package Class::Inspector;
|
||||
|
||||
use 5.006;
|
||||
# We don't want to use strict refs anywhere in this module, since we do a
|
||||
# lot of things in here that aren't strict refs friendly.
|
||||
use strict qw{vars subs};
|
||||
use warnings;
|
||||
use File::Spec ();
|
||||
|
||||
# ABSTRACT: Get information about a class and its structure
|
||||
our $VERSION = '1.31'; # VERSION
|
||||
|
||||
|
||||
# If Unicode is available, enable it so that the
|
||||
# pattern matches below match unicode method names.
|
||||
# We can safely ignore any failure here.
|
||||
BEGIN {
|
||||
local $@;
|
||||
eval "require utf8; utf8->import";
|
||||
}
|
||||
|
||||
# Predefine some regexs
|
||||
our $RE_IDENTIFIER = qr/\A[^\W\d]\w*\z/s;
|
||||
our $RE_CLASS = qr/\A[^\W\d]\w*(?:(?:\'|::)\w+)*\z/s;
|
||||
|
||||
# Are we on something Unix-like?
|
||||
our $UNIX = !! ( $File::Spec::ISA[0] eq 'File::Spec::Unix' );
|
||||
|
||||
|
||||
#####################################################################
|
||||
# Basic Methods
|
||||
|
||||
|
||||
sub _resolved_inc_handler {
|
||||
my $class = shift;
|
||||
my $filename = $class->_inc_filename(shift) or return undef;
|
||||
|
||||
foreach my $inc ( @INC ) {
|
||||
if(ref $inc eq 'CODE') {
|
||||
my @ret = $inc->($inc, $filename);
|
||||
if(@ret) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
'';
|
||||
}
|
||||
|
||||
sub installed {
|
||||
my $class = shift;
|
||||
!! ($class->loaded_filename($_[0]) or $class->resolved_filename($_[0]) or $class->_resolved_inc_handler($_[0]));
|
||||
}
|
||||
|
||||
|
||||
sub loaded {
|
||||
my $class = shift;
|
||||
my $name = $class->_class(shift) or return undef;
|
||||
$class->_loaded($name);
|
||||
}
|
||||
|
||||
sub _loaded {
|
||||
my $class = shift;
|
||||
my $name = shift;
|
||||
|
||||
# Handle by far the two most common cases
|
||||
# This is very fast and handles 99% of cases.
|
||||
return 1 if defined ${"${name}::VERSION"};
|
||||
return 1 if @{"${name}::ISA"};
|
||||
|
||||
# Are there any symbol table entries other than other namespaces
|
||||
foreach ( keys %{"${name}::"} ) {
|
||||
next if substr($_, -2, 2) eq '::';
|
||||
return 1 if defined &{"${name}::$_"};
|
||||
}
|
||||
|
||||
# No functions, and it doesn't have a version, and isn't anything.
|
||||
# As an absolute last resort, check for an entry in %INC
|
||||
my $filename = $class->_inc_filename($name);
|
||||
return 1 if defined $INC{$filename};
|
||||
|
||||
'';
|
||||
}
|
||||
|
||||
|
||||
sub filename {
|
||||
my $class = shift;
|
||||
my $name = $class->_class(shift) or return undef;
|
||||
File::Spec->catfile( split /(?:\'|::)/, $name ) . '.pm';
|
||||
}
|
||||
|
||||
|
||||
sub resolved_filename {
|
||||
my $class = shift;
|
||||
my $filename = $class->_inc_filename(shift) or return undef;
|
||||
my @try_first = @_;
|
||||
|
||||
# Look through the @INC path to find the file
|
||||
foreach ( @try_first, @INC ) {
|
||||
my $full = "$_/$filename";
|
||||
next unless -e $full;
|
||||
return $UNIX ? $full : $class->_inc_to_local($full);
|
||||
}
|
||||
|
||||
# File not found
|
||||
'';
|
||||
}
|
||||
|
||||
|
||||
sub loaded_filename {
|
||||
my $class = shift;
|
||||
my $filename = $class->_inc_filename(shift);
|
||||
$UNIX ? $INC{$filename} : $class->_inc_to_local($INC{$filename});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#####################################################################
|
||||
# Sub Related Methods
|
||||
|
||||
|
||||
sub functions {
|
||||
my $class = shift;
|
||||
my $name = $class->_class(shift) or return undef;
|
||||
return undef unless $class->loaded( $name );
|
||||
|
||||
# Get all the CODE symbol table entries
|
||||
my @functions = sort grep { /$RE_IDENTIFIER/o }
|
||||
grep { defined &{"${name}::$_"} }
|
||||
keys %{"${name}::"};
|
||||
\@functions;
|
||||
}
|
||||
|
||||
|
||||
sub function_refs {
|
||||
my $class = shift;
|
||||
my $name = $class->_class(shift) or return undef;
|
||||
return undef unless $class->loaded( $name );
|
||||
|
||||
# Get all the CODE symbol table entries, but return
|
||||
# the actual CODE refs this time.
|
||||
my @functions = map { \&{"${name}::$_"} }
|
||||
sort grep { /$RE_IDENTIFIER/o }
|
||||
grep { defined &{"${name}::$_"} }
|
||||
keys %{"${name}::"};
|
||||
\@functions;
|
||||
}
|
||||
|
||||
|
||||
sub function_exists {
|
||||
my $class = shift;
|
||||
my $name = $class->_class( shift ) or return undef;
|
||||
my $function = shift or return undef;
|
||||
|
||||
# Only works if the class is loaded
|
||||
return undef unless $class->loaded( $name );
|
||||
|
||||
# Does the GLOB exist and its CODE part exist
|
||||
defined &{"${name}::$function"};
|
||||
}
|
||||
|
||||
|
||||
sub methods {
|
||||
my $class = shift;
|
||||
my $name = $class->_class( shift ) or return undef;
|
||||
my @arguments = map { lc $_ } @_;
|
||||
|
||||
# Process the arguments to determine the options
|
||||
my %options = ();
|
||||
foreach ( @arguments ) {
|
||||
if ( $_ eq 'public' ) {
|
||||
# Only get public methods
|
||||
return undef if $options{private};
|
||||
$options{public} = 1;
|
||||
|
||||
} elsif ( $_ eq 'private' ) {
|
||||
# Only get private methods
|
||||
return undef if $options{public};
|
||||
$options{private} = 1;
|
||||
|
||||
} elsif ( $_ eq 'full' ) {
|
||||
# Return the full method name
|
||||
return undef if $options{expanded};
|
||||
$options{full} = 1;
|
||||
|
||||
} elsif ( $_ eq 'expanded' ) {
|
||||
# Returns class, method and function ref
|
||||
return undef if $options{full};
|
||||
$options{expanded} = 1;
|
||||
|
||||
} else {
|
||||
# Unknown or unsupported options
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
|
||||
# Only works if the class is loaded
|
||||
return undef unless $class->loaded( $name );
|
||||
|
||||
# Get the super path ( not including UNIVERSAL )
|
||||
# Rather than using Class::ISA, we'll use an inlined version
|
||||
# that implements the same basic algorithm.
|
||||
my @path = ();
|
||||
my @queue = ( $name );
|
||||
my %seen = ( $name => 1 );
|
||||
while ( my $cl = shift @queue ) {
|
||||
push @path, $cl;
|
||||
unshift @queue, grep { ! $seen{$_}++ }
|
||||
map { s/^::/main::/; s/\'/::/g; $_ }
|
||||
( @{"${cl}::ISA"} );
|
||||
}
|
||||
|
||||
# Find and merge the function names across the entire super path.
|
||||
# Sort alphabetically and return.
|
||||
my %methods = ();
|
||||
foreach my $namespace ( @path ) {
|
||||
my @functions = grep { ! $methods{$_} }
|
||||
grep { /$RE_IDENTIFIER/o }
|
||||
grep { defined &{"${namespace}::$_"} }
|
||||
keys %{"${namespace}::"};
|
||||
foreach ( @functions ) {
|
||||
$methods{$_} = $namespace;
|
||||
}
|
||||
}
|
||||
|
||||
# Filter to public or private methods if needed
|
||||
my @methodlist = sort keys %methods;
|
||||
@methodlist = grep { ! /^\_/ } @methodlist if $options{public};
|
||||
@methodlist = grep { /^\_/ } @methodlist if $options{private};
|
||||
|
||||
# Return in the correct format
|
||||
@methodlist = map { "$methods{$_}::$_" } @methodlist if $options{full};
|
||||
@methodlist = map {
|
||||
[ "$methods{$_}::$_", $methods{$_}, $_, \&{"$methods{$_}::$_"} ]
|
||||
} @methodlist if $options{expanded};
|
||||
|
||||
\@methodlist;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#####################################################################
|
||||
# Search Methods
|
||||
|
||||
|
||||
sub subclasses {
|
||||
my $class = shift;
|
||||
my $name = $class->_class( shift ) or return undef;
|
||||
|
||||
# Prepare the search queue
|
||||
my @found = ();
|
||||
my @queue = grep { $_ ne 'main' } $class->_subnames('');
|
||||
while ( @queue ) {
|
||||
my $c = shift(@queue); # c for class
|
||||
if ( $class->_loaded($c) ) {
|
||||
# At least one person has managed to misengineer
|
||||
# a situation in which ->isa could die, even if the
|
||||
# class is real. Trap these cases and just skip
|
||||
# over that (bizarre) class. That would at limit
|
||||
# problems with finding subclasses to only the
|
||||
# modules that have broken ->isa implementation.
|
||||
local $@;
|
||||
eval {
|
||||
if ( $c->isa($name) ) {
|
||||
# Add to the found list, but don't add the class itself
|
||||
push @found, $c unless $c eq $name;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
# Add any child namespaces to the head of the queue.
|
||||
# This keeps the queue length shorted, and allows us
|
||||
# not to have to do another sort at the end.
|
||||
unshift @queue, map { "${c}::$_" } $class->_subnames($c);
|
||||
}
|
||||
|
||||
@found ? \@found : '';
|
||||
}
|
||||
|
||||
sub _subnames {
|
||||
my ($class, $name) = @_;
|
||||
return sort
|
||||
grep {
|
||||
substr($_, -2, 2, '') eq '::'
|
||||
and
|
||||
/$RE_IDENTIFIER/o
|
||||
}
|
||||
keys %{"${name}::"};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#####################################################################
|
||||
# Children Related Methods
|
||||
|
||||
# These can go undocumented for now, until I decide if its best to
|
||||
# just search the children in namespace only, or if I should do it via
|
||||
# the file system.
|
||||
|
||||
# Find all the loaded classes below us
|
||||
sub children {
|
||||
my $class = shift;
|
||||
my $name = $class->_class(shift) or return ();
|
||||
|
||||
# Find all the Foo:: elements in our symbol table
|
||||
no strict 'refs';
|
||||
map { "${name}::$_" } sort grep { s/::$// } keys %{"${name}::"};
|
||||
}
|
||||
|
||||
# As above, but recursively
|
||||
sub recursive_children {
|
||||
my $class = shift;
|
||||
my $name = $class->_class(shift) or return ();
|
||||
my @children = ( $name );
|
||||
|
||||
# Do the search using a nicer, more memory efficient
|
||||
# variant of actual recursion.
|
||||
my $i = 0;
|
||||
no strict 'refs';
|
||||
while ( my $namespace = $children[$i++] ) {
|
||||
push @children, map { "${namespace}::$_" }
|
||||
grep { ! /^::/ } # Ignore things like ::ISA::CACHE::
|
||||
grep { s/::$// }
|
||||
keys %{"${namespace}::"};
|
||||
}
|
||||
|
||||
sort @children;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#####################################################################
|
||||
# Private Methods
|
||||
|
||||
# Checks and expands ( if needed ) a class name
|
||||
sub _class {
|
||||
my $class = shift;
|
||||
my $name = shift or return '';
|
||||
|
||||
# Handle main shorthand
|
||||
return 'main' if $name eq '::';
|
||||
$name =~ s/\A::/main::/;
|
||||
|
||||
# Check the class name is valid
|
||||
$name =~ /$RE_CLASS/o ? $name : '';
|
||||
}
|
||||
|
||||
# Create a INC-specific filename, which always uses '/'
|
||||
# regardless of platform.
|
||||
sub _inc_filename {
|
||||
my $class = shift;
|
||||
my $name = $class->_class(shift) or return undef;
|
||||
join( '/', split /(?:\'|::)/, $name ) . '.pm';
|
||||
}
|
||||
|
||||
# Convert INC-specific file name to local file name
|
||||
sub _inc_to_local {
|
||||
# Shortcut in the Unix case
|
||||
return $_[1] if $UNIX;
|
||||
|
||||
# On other places, we have to deal with an unusual path that might look
|
||||
# like C:/foo/bar.pm which doesn't fit ANY normal pattern.
|
||||
# Putting it through splitpath/dir and back again seems to normalise
|
||||
# it to a reasonable amount.
|
||||
my $class = shift;
|
||||
my $inc_name = shift or return undef;
|
||||
my ($vol, $dir, $file) = File::Spec->splitpath( $inc_name );
|
||||
$dir = File::Spec->catdir( File::Spec->splitdir( $dir || "" ) );
|
||||
File::Spec->catpath( $vol, $dir, $file || "" );
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Class::Inspector - Get information about a class and its structure
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.31
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Class::Inspector;
|
||||
|
||||
# Is a class installed and/or loaded
|
||||
Class::Inspector->installed( 'Foo::Class' );
|
||||
Class::Inspector->loaded( 'Foo::Class' );
|
||||
|
||||
# Filename related information
|
||||
Class::Inspector->filename( 'Foo::Class' );
|
||||
Class::Inspector->resolved_filename( 'Foo::Class' );
|
||||
|
||||
# Get subroutine related information
|
||||
Class::Inspector->functions( 'Foo::Class' );
|
||||
Class::Inspector->function_refs( 'Foo::Class' );
|
||||
Class::Inspector->function_exists( 'Foo::Class', 'bar' );
|
||||
Class::Inspector->methods( 'Foo::Class', 'full', 'public' );
|
||||
|
||||
# Find all loaded subclasses or something
|
||||
Class::Inspector->subclasses( 'Foo::Class' );
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Class::Inspector allows you to get information about a loaded class. Most or
|
||||
all of this information can be found in other ways, but they aren't always
|
||||
very friendly, and usually involve a relatively high level of Perl wizardry,
|
||||
or strange and unusual looking code. Class::Inspector attempts to provide
|
||||
an easier, more friendly interface to this information.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 installed
|
||||
|
||||
my $bool = Class::Inspector->installed($class);
|
||||
|
||||
The C<installed> static method tries to determine if a class is installed
|
||||
on the machine, or at least available to Perl. It does this by wrapping
|
||||
around C<resolved_filename>.
|
||||
|
||||
Returns true if installed/available, false if the class is not installed,
|
||||
or C<undef> if the class name is invalid.
|
||||
|
||||
=head2 loaded
|
||||
|
||||
my $bool = Class::Inspector->loaded($class);
|
||||
|
||||
The C<loaded> static method tries to determine if a class is loaded by
|
||||
looking for symbol table entries.
|
||||
|
||||
This method it uses to determine this will work even if the class does not
|
||||
have its own file, but is contained inside a single file with multiple
|
||||
classes in it. Even in the case of some sort of run-time loading class
|
||||
being used, these typically leave some trace in the symbol table, so an
|
||||
L<Autoload> or L<Class::Autouse>-based class should correctly appear
|
||||
loaded.
|
||||
|
||||
Returns true if the class is loaded, false if not, or C<undef> if the
|
||||
class name is invalid.
|
||||
|
||||
=head2 filename
|
||||
|
||||
my $filename = Class::Inspector->filename($class);
|
||||
|
||||
For a given class, returns the base filename for the class. This will NOT
|
||||
be a fully resolved filename, just the part of the filename BELOW the
|
||||
C<@INC> entry.
|
||||
|
||||
print Class->filename( 'Foo::Bar' );
|
||||
> Foo/Bar.pm
|
||||
|
||||
This filename will be returned with the right separator for the local
|
||||
platform, and should work on all platforms.
|
||||
|
||||
Returns the filename on success or C<undef> if the class name is invalid.
|
||||
|
||||
=head2 resolved_filename
|
||||
|
||||
my $filename = Class::Inspector->resolved_filename($class);
|
||||
my $filename = Class::Inspector->resolved_filename($class, @try_first);
|
||||
|
||||
For a given class, the C<resolved_filename> static method returns the fully
|
||||
resolved filename for a class. That is, the file that the class would be
|
||||
loaded from.
|
||||
|
||||
This is not necessarily the file that the class WAS loaded from, as the
|
||||
value returned is determined each time it runs, and the C<@INC> include
|
||||
path may change.
|
||||
|
||||
To get the actual file for a loaded class, see the C<loaded_filename>
|
||||
method.
|
||||
|
||||
Returns the filename for the class, or C<undef> if the class name is
|
||||
invalid.
|
||||
|
||||
=head2 loaded_filename
|
||||
|
||||
my $filename = Class::Inspector->loaded_filename($class);
|
||||
|
||||
For a given loaded class, the C<loaded_filename> static method determines
|
||||
(via the C<%INC> hash) the name of the file that it was originally loaded
|
||||
from.
|
||||
|
||||
Returns a resolved file path, or false if the class did not have it's own
|
||||
file.
|
||||
|
||||
=head2 functions
|
||||
|
||||
my $arrayref = Class::Inspector->functions($class);
|
||||
|
||||
For a loaded class, the C<functions> static method returns a list of the
|
||||
names of all the functions in the classes immediate namespace.
|
||||
|
||||
Note that this is not the METHODS of the class, just the functions.
|
||||
|
||||
Returns a reference to an array of the function names on success, or C<undef>
|
||||
if the class name is invalid or the class is not loaded.
|
||||
|
||||
=head2 function_refs
|
||||
|
||||
my $arrayref = Class::Inspector->function_refs($class);
|
||||
|
||||
For a loaded class, the C<function_refs> static method returns references to
|
||||
all the functions in the classes immediate namespace.
|
||||
|
||||
Note that this is not the METHODS of the class, just the functions.
|
||||
|
||||
Returns a reference to an array of C<CODE> refs of the functions on
|
||||
success, or C<undef> if the class is not loaded.
|
||||
|
||||
=head2 function_exists
|
||||
|
||||
my $bool = Class::Inspector->function_exists($class, $functon);
|
||||
|
||||
Given a class and function name the C<function_exists> static method will
|
||||
check to see if the function exists in the class.
|
||||
|
||||
Note that this is as a function, not as a method. To see if a method
|
||||
exists for a class, use the C<can> method for any class or object.
|
||||
|
||||
Returns true if the function exists, false if not, or C<undef> if the
|
||||
class or function name are invalid, or the class is not loaded.
|
||||
|
||||
=head2 methods
|
||||
|
||||
my $arrayref = Class::Inspector->methods($class, @options);
|
||||
|
||||
For a given class name, the C<methods> static method will returns ALL
|
||||
the methods available to that class. This includes all methods available
|
||||
from every class up the class' C<@ISA> tree.
|
||||
|
||||
Returns a reference to an array of the names of all the available methods
|
||||
on success, or C<undef> if the class name is invalid or the class is not
|
||||
loaded.
|
||||
|
||||
A number of options are available to the C<methods> method that will alter
|
||||
the results returned. These should be listed after the class name, in any
|
||||
order.
|
||||
|
||||
# Only get public methods
|
||||
my $method = Class::Inspector->methods( 'My::Class', 'public' );
|
||||
|
||||
=over 4
|
||||
|
||||
=item public
|
||||
|
||||
The C<public> option will return only 'public' methods, as defined by the Perl
|
||||
convention of prepending an underscore to any 'private' methods. The C<public>
|
||||
option will effectively remove any methods that start with an underscore.
|
||||
|
||||
=item private
|
||||
|
||||
The C<private> options will return only 'private' methods, as defined by the
|
||||
Perl convention of prepending an underscore to an private methods. The
|
||||
C<private> option will effectively remove an method that do not start with an
|
||||
underscore.
|
||||
|
||||
B<Note: The C<public> and C<private> options are mutually exclusive>
|
||||
|
||||
=item full
|
||||
|
||||
C<methods> normally returns just the method name. Supplying the C<full> option
|
||||
will cause the methods to be returned as the full names. That is, instead of
|
||||
returning C<[ 'method1', 'method2', 'method3' ]>, you would instead get
|
||||
C<[ 'Class::method1', 'AnotherClass::method2', 'Class::method3' ]>.
|
||||
|
||||
=item expanded
|
||||
|
||||
The C<expanded> option will cause a lot more information about method to be
|
||||
returned. Instead of just the method name, you will instead get an array
|
||||
reference containing the method name as a single combined name, a la C<full>,
|
||||
the separate class and method, and a CODE ref to the actual function ( if
|
||||
available ). Please note that the function reference is not guaranteed to
|
||||
be available. C<Class::Inspector> is intended at some later time, to work
|
||||
with modules that have some kind of common run-time loader in place ( e.g
|
||||
C<Autoloader> or C<Class::Autouse> for example.
|
||||
|
||||
The response from C<methods( 'Class', 'expanded' )> would look something like
|
||||
the following.
|
||||
|
||||
[
|
||||
[ 'Class::method1', 'Class', 'method1', \&Class::method1 ],
|
||||
[ 'Another::method2', 'Another', 'method2', \&Another::method2 ],
|
||||
[ 'Foo::bar', 'Foo', 'bar', \&Foo::bar ],
|
||||
]
|
||||
|
||||
=back
|
||||
|
||||
=head2 subclasses
|
||||
|
||||
my $arrayref = Class::Inspector->subclasses($class);
|
||||
|
||||
The C<subclasses> static method will search then entire namespace (and thus
|
||||
B<all> currently loaded classes) to find all classes that are subclasses
|
||||
of the class provided as a the parameter.
|
||||
|
||||
The actual test will be done by calling C<isa> on the class as a static
|
||||
method. (i.e. C<My::Class-E<gt>isa($class)>.
|
||||
|
||||
Returns a reference to a list of the loaded classes that match the class
|
||||
provided, or false is none match, or C<undef> if the class name provided
|
||||
is invalid.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<http://ali.as/>, L<Class::Handle>, L<Class::Inspector::Functions>
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Original author: Adam Kennedy E<lt>adamk@cpan.orgE<gt>
|
||||
|
||||
Current maintainer: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Tom Wyant
|
||||
|
||||
Steffen Müller
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2016 by Adam Kennedy.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
135
Perl OTRS/Kernel/cpan-lib/Class/Inspector/Functions.pm
Normal file
135
Perl OTRS/Kernel/cpan-lib/Class/Inspector/Functions.pm
Normal file
@@ -0,0 +1,135 @@
|
||||
package Class::Inspector::Functions;
|
||||
|
||||
use 5.006;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Exporter ();
|
||||
use Class::Inspector ();
|
||||
|
||||
# ABSTRACT: Get information about a class and its structure
|
||||
our $VERSION = '1.31'; # VERSION
|
||||
|
||||
BEGIN {
|
||||
our @ISA = 'Exporter';
|
||||
|
||||
|
||||
our @EXPORT = qw(
|
||||
installed
|
||||
loaded
|
||||
|
||||
filename
|
||||
functions
|
||||
methods
|
||||
|
||||
subclasses
|
||||
);
|
||||
|
||||
our @EXPORT_OK = qw(
|
||||
resolved_filename
|
||||
loaded_filename
|
||||
|
||||
function_refs
|
||||
function_exists
|
||||
);
|
||||
#children
|
||||
#recursive_children
|
||||
|
||||
our %EXPORT_TAGS = ( ALL => [ @EXPORT_OK, @EXPORT ] );
|
||||
|
||||
foreach my $meth (@EXPORT, @EXPORT_OK) {
|
||||
my $sub = Class::Inspector->can($meth);
|
||||
no strict 'refs';
|
||||
*{$meth} = sub {&$sub('Class::Inspector', @_)};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Class::Inspector::Functions - Get information about a class and its structure
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 1.31
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Class::Inspector::Functions;
|
||||
# Class::Inspector provides a non-polluting,
|
||||
# method based interface!
|
||||
|
||||
# Is a class installed and/or loaded
|
||||
installed( 'Foo::Class' );
|
||||
loaded( 'Foo::Class' );
|
||||
|
||||
# Filename related information
|
||||
filename( 'Foo::Class' );
|
||||
resolved_filename( 'Foo::Class' );
|
||||
|
||||
# Get subroutine related information
|
||||
functions( 'Foo::Class' );
|
||||
function_refs( 'Foo::Class' );
|
||||
function_exists( 'Foo::Class', 'bar' );
|
||||
methods( 'Foo::Class', 'full', 'public' );
|
||||
|
||||
# Find all loaded subclasses or something
|
||||
subclasses( 'Foo::Class' );
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Class::Inspector::Functions is a function based interface of
|
||||
L<Class::Inspector>. For a thorough documentation of the available
|
||||
functions, please check the manual for the main module.
|
||||
|
||||
=head2 Exports
|
||||
|
||||
The following functions are exported by default.
|
||||
|
||||
installed
|
||||
loaded
|
||||
filename
|
||||
functions
|
||||
methods
|
||||
subclasses
|
||||
|
||||
The following functions are exported only by request.
|
||||
|
||||
resolved_filename
|
||||
loaded_filename
|
||||
function_refs
|
||||
function_exists
|
||||
|
||||
All the functions may be imported using the C<:ALL> tag.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<http://ali.as/>, L<Class::Handle>, L<Class::Inspector>
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Original author: Adam Kennedy E<lt>adamk@cpan.orgE<gt>
|
||||
|
||||
Current maintainer: Graham Ollis E<lt>plicease@cpan.orgE<gt>
|
||||
|
||||
Contributors:
|
||||
|
||||
Tom Wyant
|
||||
|
||||
Steffen Müller
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2016 by Adam Kennedy.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
330
Perl OTRS/Kernel/cpan-lib/Class/ReturnValue.pm
Normal file
330
Perl OTRS/Kernel/cpan-lib/Class/ReturnValue.pm
Normal file
@@ -0,0 +1,330 @@
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
package Class::ReturnValue;
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Class::ReturnValue - A return-value object that lets you treat it
|
||||
as as a boolean, array or object
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Class::ReturnValue is a "clever" return value object that can allow
|
||||
code calling your routine to expect:
|
||||
a boolean value (did it fail)
|
||||
or a list (what are the return values)
|
||||
|
||||
=head1 EXAMPLE
|
||||
|
||||
sub demo {
|
||||
my $value = shift;
|
||||
my $ret = Class::ReturnValue->new();
|
||||
$ret->as_array('0', 'No results found');
|
||||
|
||||
unless($value) {
|
||||
$ret->as_error(errno => '1',
|
||||
message => "You didn't supply a parameter.",
|
||||
do_backtrace => 1);
|
||||
}
|
||||
|
||||
return($ret->return_value);
|
||||
}
|
||||
|
||||
if (demo('foo')){
|
||||
print "the routine succeeded with one parameter";
|
||||
}
|
||||
if (demo()) {
|
||||
print "The routine succeeded with 0 paramters. shouldn't happen";
|
||||
} else {
|
||||
print "The routine failed with 0 parameters (as it should).";
|
||||
}
|
||||
|
||||
|
||||
my $return = demo();
|
||||
if ($return) {
|
||||
print "The routine succeeded with 0 paramters. shouldn't happen";
|
||||
} else {
|
||||
print "The routine failed with 0 parameters (as it should). ".
|
||||
"Stack trace:\n".
|
||||
$return->backtrace;
|
||||
}
|
||||
|
||||
my @return3 = demo('foo');
|
||||
print "The routine got ".join(',',@return3).
|
||||
"when asking for demo's results as an array";
|
||||
|
||||
|
||||
my $return2 = demo('foo');
|
||||
|
||||
unless ($return2) {
|
||||
print "The routine failed with a parameter. shouldn't happen.".
|
||||
"Stack trace:\n".
|
||||
$return2->backtrace;
|
||||
}
|
||||
|
||||
my @return2_array = @{$return2}; # TODO: does this work
|
||||
my @return2_array2 = $return2->as_array;
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
use Exporter;
|
||||
|
||||
use vars qw/$VERSION @EXPORT @ISA/;
|
||||
|
||||
@ISA = qw/Exporter/;
|
||||
@EXPORT = qw /&return_value/;
|
||||
use Carp;
|
||||
use Devel::StackTrace;
|
||||
use Data::Dumper;
|
||||
|
||||
|
||||
$VERSION = '0.55';
|
||||
|
||||
|
||||
use overload 'bool' => \&error_condition;
|
||||
use overload '""' => \&error_condition;
|
||||
use overload 'eq' => \&my_eq;
|
||||
use overload '@{}' => \&as_array;
|
||||
use overload 'fallback' => \&as_array;
|
||||
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=item new
|
||||
|
||||
Instantiate a new Class::ReturnValue object
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my $self = {};
|
||||
bless($self);
|
||||
return($self);
|
||||
}
|
||||
|
||||
sub my_eq {
|
||||
my $self = shift;
|
||||
if (wantarray()) {
|
||||
return($self->as_array);
|
||||
}
|
||||
else {
|
||||
return($self);
|
||||
}
|
||||
}
|
||||
|
||||
=item as_array
|
||||
|
||||
Return the 'as_array' attribute of this object as an array.
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
=item as_array [ARRAY]
|
||||
|
||||
If $self is called in an array context, returns the array specified in ARRAY
|
||||
|
||||
=cut
|
||||
|
||||
sub as_array {
|
||||
|
||||
my $self = shift;
|
||||
if (@_) {
|
||||
@{$self->{'as_array'}} = (@_);
|
||||
}
|
||||
return(@{$self->{'as_array'}});
|
||||
}
|
||||
|
||||
|
||||
=item as_error HASH
|
||||
|
||||
Turns this return-value object into an error return object. TAkes three parameters:
|
||||
|
||||
message
|
||||
do_backtrace
|
||||
errno
|
||||
|
||||
'message' is a human readable error message explaining what's going on
|
||||
|
||||
'do_backtrace' is a boolean. If it's true, a carp-style backtrace will be
|
||||
stored in $self->{'backtrace'}. It defaults to true
|
||||
|
||||
errno and message default to undef. errno _must_ be specified.
|
||||
It's a numeric error number. Any true integer value will cause the
|
||||
object to evaluate to false in a scalar context. At first, this may look a
|
||||
bit counterintuitive, but it means that you can have error codes and still
|
||||
allow simple use of your functions in a style like this:
|
||||
|
||||
|
||||
if ($obj->do_something) {
|
||||
print "Yay! it worked";
|
||||
} else {
|
||||
print "Sorry. there's been an error.";
|
||||
}
|
||||
|
||||
|
||||
as well as more complex use like this:
|
||||
|
||||
my $retval = $obj->do_something;
|
||||
|
||||
if ($retval) {
|
||||
print "Yay. we did something\n";
|
||||
my ($foo, $bar, $baz) = @{$retval};
|
||||
my $human_readable_return = $retval;
|
||||
} else {
|
||||
if ($retval->errno == 20) {
|
||||
die "Failed with error 20 (Not enough monkeys).";
|
||||
} else {
|
||||
die $retval->backtrace; # Die and print out a backtrace
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
sub as_error {
|
||||
my $self = shift;
|
||||
my %args = ( errno => undef,
|
||||
message => undef,
|
||||
do_backtrace => 1,
|
||||
@_);
|
||||
|
||||
unless($args{'errno'}) {
|
||||
carp "$self -> as_error called without an 'errno' parameter";
|
||||
return (undef);
|
||||
}
|
||||
|
||||
$self->{'errno'} = $args{'errno'};
|
||||
$self->{'error_message'} = $args{'message'};
|
||||
if ($args{'do_backtrace'}) {
|
||||
# Use carp's internal backtrace methods, rather than duplicating them ourselves
|
||||
my $trace = Devel::StackTrace->new(ignore_package => 'Class::ReturnValue');
|
||||
|
||||
$self->{'backtrace'} = $trace->as_string; # like carp
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
=item errno
|
||||
|
||||
Returns the errno if there's been an error. Otherwise, return undef
|
||||
|
||||
=cut
|
||||
|
||||
sub errno {
|
||||
my $self = shift;
|
||||
if ($self->{'errno'}) {
|
||||
return ($self->{'errno'});
|
||||
}
|
||||
else {
|
||||
return(undef);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
=item error_message
|
||||
|
||||
If there's been an error return the error message.
|
||||
|
||||
=cut
|
||||
|
||||
sub error_message {
|
||||
my $self = shift;
|
||||
if ($self->{'error_message'}) {
|
||||
return($self->{'error_message'});
|
||||
}
|
||||
else {
|
||||
return(undef);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
=item backtrace
|
||||
|
||||
If there's been an error and we asked for a backtrace, return the backtrace.
|
||||
Otherwise, return undef.
|
||||
|
||||
=cut
|
||||
|
||||
sub backtrace {
|
||||
my $self = shift;
|
||||
if ($self->{'backtrace'}) {
|
||||
return($self->{'backtrace'});
|
||||
}
|
||||
else {
|
||||
return(undef);
|
||||
}
|
||||
}
|
||||
|
||||
=cut
|
||||
|
||||
=item error_condition
|
||||
|
||||
If there's been an error, return undef. Otherwise return 1
|
||||
|
||||
=cut
|
||||
|
||||
sub error_condition {
|
||||
my $self = shift;
|
||||
if ($self->{'errno'}) {
|
||||
return (undef);
|
||||
}
|
||||
elsif (wantarray()) {
|
||||
return(@{$self->{'as_array'}});
|
||||
}
|
||||
else {
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
sub return_value {
|
||||
my $self = shift;
|
||||
if (wantarray) {
|
||||
return ($self->as_array);
|
||||
}
|
||||
else {
|
||||
return ($self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jesse Vincent <jesse@bestpractical.com>
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
This module has, as yet, not been used in production code. I thing
|
||||
it should work, but have never benchmarked it. I have not yet used
|
||||
it extensively, though I do plan to in the not-too-distant future.
|
||||
If you have questions or comments, please write me.
|
||||
|
||||
If you need to report a bug, please send mail to
|
||||
<bug-class-returnvalue@rt.cpan.org> or report your error on the web
|
||||
at http://rt.cpan.org/
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (c) 2002,2003,2005,2007 Jesse Vincent <jesse@bestpractical.com>
|
||||
You may use, modify, fold, spindle or mutilate this module under
|
||||
the same terms as perl itself.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
Class::ReturnValue isn't an exception handler. If it doesn't
|
||||
do what you want, you might want look at one of the exception handlers
|
||||
below:
|
||||
|
||||
Error, Exception, Exceptions, Exceptions::Class
|
||||
|
||||
You might also want to look at Contextual::Return, another implementation
|
||||
of the same concept as this module.
|
||||
|
||||
=cut
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user