NAME
Sub::Meta - handle subroutine meta information
SYNOPSIS
use Sub::Meta;
sub hello($) :method { }
my $meta = Sub::Meta->new(sub => \&hello);
$meta->subname; # => hello
$meta->sub; # \&hello
$meta->subname; # hello
$meta->fullname # main::hello
$meta->stashname # main
$meta->file # path/to/file.pl
$meta->line # 5
$meta->is_constant # !!0
$meta->prototype # $
$meta->attribute # ['method']
$meta->is_method # undef
$meta->parameters # undef
$meta->returns # undef
$meta->display # 'sub hello'
# setter
$meta->set_subname('world');
$meta->subname; # world
$meta->fullname; # main::world
# apply to sub
$meta->apply_prototype('$@');
$meta->prototype; # $@
Sub::Util::prototype($meta->sub); # $@
And you can hold meta information of parameter type and return type. See also Sub::Meta::Parameters and Sub::Meta::Returns.
$meta->set_parameters(args => ['Str']));
$meta->parameters->args; # [ Sub::Meta::Param->new({ type => 'Str' }) ]
$meta->set_args(['Str']);
$meta->args; # [ Sub::Meta::Param->new({ type => 'Str' }) ]
$meta->set_returns('Str');
$meta->returns->scalar; # 'Str'
$meta->returns->list; # 'Str'
And you can compare meta informations:
my $other = Sub::Meta->new(subname => 'hello');
$meta->is_same_interface($other); # 1
$meta eq $other; # 1
DESCRIPTION
Sub::Meta
provides methods to handle subroutine meta information. In addition to information that can be obtained from subroutines using module B etc., subroutines can have meta information such as arguments and return values.
METHODS
new
Constructor of Sub::Meta
.
use Sub::Meta;
use Types::Standard -types;
# sub Greeting::hello(Str) -> Str
Sub::Meta->new(
fullname => 'Greeting::hello',
is_constant => 0,
prototype => '$',
attribute => ['method'],
is_method => 1,
parameters => { args => [{ type => Str }]},
returns => Str,
);
Others are as follows:
# sub add(Int, Int) -> Int
Sub::Meta->new(
subname => 'add',
args => [Int, Int],
returns => Int,
);
# method hello(Str) -> Str
Sub::Meta->new(
subname => 'hello',
args => [{ message => Str }],
is_method => 1,
returns => Str,
);
# sub twice(@numbers) -> ArrayRef[Int]
Sub::Meta->new(
subname => 'twice',
args => [],
slurpy => { name => '@numbers' },
returns => ArrayRef[Int],
);
# Named parameters:
# sub foo(Str :a) -> Str
Sub::Meta->new(
subname => 'foo',
args => { a => Str },
returns => Str,
);
# is equivalent to
Sub::Meta->new(
subname => 'foo',
args => [{ name => 'a', isa => Str, named => 1 }],
returns => Str,
);
Another way to create a Sub::Meta is to use Sub::Meta::Creator:
use Sub::Meta::Creator;
use Sub::Meta::Finder::FunctionParameters;
my $creator = Sub::Meta::Creator->new(
finders => [ \&Sub::Meta::Finder::FunctionParameters::find_materials ],
);
use Function::Parameters;
use Types::Standard -types;
method hello(Str $msg) { }
my $meta = $creator->create(\&hello);
# =>
# Sub::Meta
# args [
# [0] Sub::Meta::Param->new(name => '$msg', type => Str)
# ],
# invocant Sub::Meta::Param->(name => '$self', invocant => 1),
# nshift 1,
# slurpy !!0
ACCESSORS
sub
Accessor for subroutine.
sub
-
method sub() => Maybe[CodeRef]
Return a subroutine.
has_sub
-
method has_sub() => Bool
Whether Sub::Meta has subroutine or not.
set_sub($sub)
-
method set_sub(CodeRef $sub) => $self
Setter for subroutine.
sub hello { ... } $meta->set_sub(\&hello); $meta->sub # => \&hello # And set subname, stashname $meta->subname; # hello $meta->stashname; # main
subname
Accessor for subroutine name
subname
-
method subname() => Str
has_subname
-
method has_subname() => Bool
Whether Sub::Meta has subroutine name or not.
set_subname($subname)
-
method set_subname(Str $subname) => $self
Setter for subroutine name.
$meta->subname; # hello $meta->set_subname('world'); $meta->subname; # world Sub::Util::subname($meta->sub); # hello (NOT apply to sub)
apply_subname($subname)
-
method apply_subname(Str $subname) => $self
Sets subroutine name and apply to the subroutine reference.
$meta->subname; # hello $meta->apply_subname('world'); $meta->subname; # world Sub::Util::subname($meta->sub); # world
fullname
Accessor for subroutine full name
fullname
-
method fullname() => Str
A subroutine full name, e.g.
main::hello
has_fullname
-
method has_fullname() => Bool
Whether Sub::Meta has subroutine full name or not.
set_fullname($fullname)
-
method set_fullname(Str $fullname) => $self
Setter for subroutine full name.
stashname
Accessor for subroutine stash name
stashname
-
method stashname() => Str
A subroutine stash name, e.g.
main
has_stashname
-
method has_stashname() => Bool
Whether Sub::Meta has subroutine stash name or not.
set_stashname($stashname)
-
method set_stashname(Str $stashname) => $self
Setter for subroutine stash name.
subinfo
Accessor for subroutine information
subinfo
-
method subinfo() => Tuple[Str,Str]
A subroutine information, e.g.
['main', 'hello']
set_subinfo([$stashname, $subname])
-
method set_stashname(Tuple[Str $stashname, Str $subname]) => $self
Setter for subroutine information.
file, line
Accessor for filename and line where subroutine is defined
file
-
method file() => Maybe[Str]
A filename where subroutine is defined, e.g.
path/to/main.pl
. has_file
-
method has_file() => Bool
Whether Sub::Meta has a filename where subroutine is defined.
set_file($filepath)
-
method set_file(Str $filepath) => $self
Setter for
file
. line
-
method line() => Maybe[Int]
A line where the definition of subroutine started, e.g.
5
has_line
-
method has_line() => Bool
Whether Sub::Meta has a line where the definition of subroutine started.
set_line($line)
-
method set_line(Int $line) => $self
Setter for
line
.
is_constant
is_constant
-
method is_constant() => Maybe[Bool]
If the subroutine is set, it returns whether it is a constant or not, if not set, it returns undef.
set_is_constant($bool)
-
method set_is_constant(Bool $bool) => $self
Setter for
is_constant
.
prototype
Accessor for prototype of subroutine reference.
prototype
-
method prototype() => Maybe[Str]
If the subroutine is set, it returns a prototype of subroutine, if not set, it returns undef. e.g.
$@
has_prototype
-
method has_prototype() => Bool
Whether Sub::Meta has prototype or not.
set_prototype($prototype)
-
method set_prototype(Str $prototype) => $self
Setter for
prototype
. apply_prototype($prototype)
-
method apply_prototype(Str $prototype) => $self
Sets subroutine prototype and apply to the subroutine reference.
attribute
Accessor for attribute of subroutine reference.
attribute
-
method attribute() => Maybe[ArrayRef[Str]]
If the subroutine is set, it returns a attribute of subroutine, if not set, it returns undef. e.g.
['method']
,undef
has_attribute
-
method has_attribute() => Bool
Whether Sub::Meta has attribute or not.
set_attribute($attribute)
-
method set_attribute(ArrayRef[Str] $attribute) => $self
Setter for
attribute
. apply_attribute(@attribute)
-
method apply_attribute(Str @attribute) => $self
Sets subroutine attributes and apply to the subroutine reference.
is_method
is_method
-
method is_method() => Bool
Whether the subroutine is a method or not.
set_is_method($bool)
-
method set_is_method(Bool $bool) => Bool
Setter for
is_method
.
parameters
Accessor for parameters object of Sub::Meta::Parameters
parameters
-
method parameters() => InstanceOf[Sub::Meta::Parameters]
If the parameters is set, it returns the parameters object.
set_parameters($parameters)
-
method set_parameters(InstanceOf[Sub::Meta::Parameters] $parameters) => $self method set_parameters(@sub_meta_parameters_args) => $self
Sets the parameters object of Sub::Meta::Parameters.
my $meta = Sub::Meta->new; my $parameters = Sub::Meta::Parameters->new(args => ['Str']); $meta->set_parameters($parameters); # or $meta->set_parameters(args => ['Str']); $meta->parameters; # => Sub::Meta::Parameters->new(args => ['Str']); # alias $meta->set_args(['Str']);
args
-
The alias of
parameters.args
. set_args($args)
-
The alias of
parameters.set_args
. all_args
-
The alias of
parameters.all_args
. nshift
-
The alias of
parameters.nshift
. set_nshift($nshift)
-
The alias of
parameters.set_nshift
. invocant
-
The alias of
parameters.invocant
. invocants
-
The alias of
parameters.invocants
. set_invocant($invocant)
-
The alias of
parameters.set_invocant
. slurpy
-
The alias of
parameters.slurpy
. set_slurpy($slurpy)
-
The alias of
parameters.set_slurpy
.
returns
Accessor for returns object of Sub::Meta::Returns
returns
-
method returns() => InstanceOf[Sub::Meta::Returns]
If the returns is set, it returns the returns object.
set_returns($returns)
-
method set_returns(InstanceOf[Sub::Meta::Returns] $returns) => $self method set_returns(@sub_meta_returns_args) => $self
Sets the returns object of Sub::Meta::Returns or any object.
my $meta = Sub::Meta->new; $meta->set_returns({ type => 'Type'}); $meta->returns; # => Sub::Meta::Returns->new({type => 'Type'}); # or $meta->set_returns(Sub::Meta::Returns->new(type => 'Foo')); $meta->set_returns(MyReturns->new)
METHODS
apply_meta($other_meta)
method apply_meta(InstanceOf[Sub::Meta] $other_meta) => $self
Apply subroutine subname, prototype and attributes of $other_meta
.
is_same_interface($other_meta)
method is_same_interface(InstanceOf[Sub::Meta] $other_meta) => Bool
A boolean value indicating whether the subroutine's interface is same or not. Specifically, check whether subname
, is_method
, parameters
and returns
are equal.
is_strict_same_interface($other_meta)
Alias for is_same_interface
is_relaxed_same_interface($other_meta)
method is_relaxed_same_interface(InstanceOf[Sub::Meta] $other_meta) => Bool
A boolean value indicating whether the subroutine's interface is relaxed same or not. Specifically, check whether subname
, is_method
, parameters
and returns
satisfy the condition of $self
side.
Difference between strict
and relaxed
If it is is_relaxed_same_interface
method, the conditions can be many. For example, the number of arguments can be many. The following code is a test to show the difference between strict and relaxed.
my @tests = (
{}, { subname => 'foo' },
{}, { args => [Int] },
{ args => [Int] }, { args => [Int, Str] },
{ args => [Int] }, { args => [Int], slurpy => Str },
{ args => [Int] }, { args => [{ type => Int, name => '$a' }] },
{}, { returns => Int },
{ returns => { scalar => Int } }, { returns => { scalar => Int, list => Int } },
);
while (@tests) {
my ($a, $b) = splice @tests, 0, 2;
my $meta = Sub::Meta->new($a);
my $other = Sub::Meta->new($b);
ok !$meta->is_strict_same_interface($other);
ok $meta->is_relaxed_same_interface($other);
}
is_same_interface_inlined($other_meta_inlined)
method is_same_interface_inlined(InstanceOf[Sub::Meta] $other_meta) => Str
is_strict_same_interface_inlined($other_meta)
Alias for is_same_interface_inlined
Returns inlined is_same_interface
string:
use Sub::Meta;
my $meta = Sub::Meta->new(subname => 'hello');
my $inline = $meta->is_same_interface_inlined('$_[0]');
# $inline looks like this:
# Scalar::Util::blessed($_[0]) && $_[0]->isa('Sub::Meta')
# && defined $_[0]->subname && 'hello' eq $_[0]->subname
# && !$_[0]->is_method
# && !$_[0]->parameters
# && !$_[0]->returns
my $check = eval "sub { $inline }";
$check->(Sub::Meta->new(subname => 'hello')); # => OK
$check->(Sub::Meta->new(subname => 'world')); # => NG
is_relaxed_same_interface_inlined($other_meta_inlined)
method is_relaxed_same_interface_inlined(InstanceOf[Sub::Meta] $other_meta) => Str
Returns inlined is_relaxed_same_interface
string.
error_message($other_meta)
method error_message(InstanceOf[Sub::Meta] $other_meta) => Str
Return the error message when the interface is not same. If same, then return empty string
relaxed_error_message($other_meta)
method relaxed_error_message(InstanceOf[Sub::Meta] $other_meta) => Str
Return the error message when the interface does not satisfy the $self
meta. If match, then return empty string.
display
method display() => Str
Returns the display of Sub::Meta:
use Sub::Meta;
use Types::Standard qw(Str);
my $meta = Sub::Meta->new(
subname => 'hello',
is_method => 1,
args => [Str],
returns => Str,
);
$meta->display; # 'method hello(Str) => Str'
OTHERS
parameters_class
method parameters_class() => Str
Returns class name of parameters. default: Sub::Meta::Parameters Please override for customization.
returns_class
method returns_class() => Str
Returns class name of returns. default: Sub::Meta::Returns Please override for customization.
NOTE
setter
You can set meta information of subroutine. set_xxx
sets xxx
and does not affect subroutine reference. On the other hands, apply_xxx
sets xxx
and apply xxx
to subroutine reference.
Setter methods of Sub::Meta
returns meta object. So you can chain setting:
$meta->set_subname('foo')
->set_stashname('Some')
Pure-Perl version
By default Sub::Meta
tries to load an XS implementation for speed. If that fails, or if the environment variable PERL_SUB_META_PP
is defined to a true value, it will fall back to a pure perl implementation.
SEE ALSO
Sub::Identify, Sub::Util, Sub::Info
LICENSE
Copyright (C) kfly8.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
AUTHOR
kfly8 <kfly@cpan.org>