Sub::Meta - handle subroutine meta information
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
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.
Sub::Meta
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
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
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
Accessor for subroutine full name
fullname
method fullname() => Str
A subroutine full name, e.g. main::hello
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.
Accessor for subroutine stash name
stashname
method stashname() => Str
A subroutine stash name, e.g. main
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.
Accessor for subroutine information
subinfo
method subinfo() => Tuple[Str,Str]
A subroutine information, e.g. ['main', 'hello']
['main', 'hello']
set_subinfo([$stashname, $subname])
method set_stashname(Tuple[Str $stashname, Str $subname]) => $self
Setter for subroutine information.
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.
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
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
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.
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.
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
['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
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.
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.
parameters.args
set_args($args)
The alias of parameters.set_args.
parameters.set_args
all_args
The alias of parameters.all_args.
parameters.all_args
nshift
The alias of parameters.nshift.
parameters.nshift
set_nshift($nshift)
The alias of parameters.set_nshift.
parameters.set_nshift
invocant
The alias of parameters.invocant.
parameters.invocant
invocants
The alias of parameters.invocants.
parameters.invocants
set_invocant($invocant)
The alias of parameters.set_invocant.
parameters.set_invocant
slurpy
The alias of parameters.slurpy.
parameters.slurpy
set_slurpy($slurpy)
The alias of parameters.set_slurpy.
parameters.set_slurpy
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)
method apply_meta(InstanceOf[Sub::Meta] $other_meta) => $self
Apply subroutine subname, prototype and attributes of $other_meta.
$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.
Alias for is_same_interface
is_same_interface
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.
$self
strict
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.
is_relaxed_same_interface
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); }
method is_same_interface_inlined(InstanceOf[Sub::Meta] $other_meta) => Str
Alias for is_same_interface_inlined
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
method is_relaxed_same_interface_inlined(InstanceOf[Sub::Meta] $other_meta) => Str
Returns inlined is_relaxed_same_interface string.
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
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.
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'
method parameters_class() => Str
Returns class name of parameters. default: Sub::Meta::Parameters Please override for customization.
method returns_class() => Str
Returns class name of returns. default: Sub::Meta::Returns Please override for customization.
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.
set_xxx
xxx
apply_xxx
Setter methods of Sub::Meta returns meta object. So you can chain setting:
$meta->set_subname('foo') ->set_stashname('Some')
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.
PERL_SUB_META_PP
Sub::Identify, Sub::Util, Sub::Info
Copyright (C) kfly8.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
kfly8 <kfly@cpan.org>
To install Sub::Meta, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Sub::Meta
CPAN shell
perl -MCPAN -e shell install Sub::Meta
For more information on module installation, please visit the detailed CPAN module installation guide.