Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/kfly8/p5-sub-meta
handle subroutine meta information
https://github.com/kfly8/p5-sub-meta
perl perl5 perl5-module
Last synced: 6 days ago
JSON representation
handle subroutine meta information
- Host: GitHub
- URL: https://github.com/kfly8/p5-sub-meta
- Owner: kfly8
- License: other
- Created: 2019-06-22T09:57:06.000Z (over 5 years ago)
- Default Branch: main
- Last Pushed: 2022-06-07T02:47:58.000Z (over 2 years ago)
- Last Synced: 2024-10-30T16:39:46.128Z (about 2 months ago)
- Topics: perl, perl5, perl5-module
- Language: Perl
- Homepage:
- Size: 313 KB
- Stars: 3
- Watchers: 5
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: Changes
- License: LICENSE
Awesome Lists containing this project
README
[![Actions Status](https://github.com/kfly8/p5-Sub-Meta/workflows/test/badge.svg)](https://github.com/kfly8/p5-Sub-Meta/actions) [![Coverage Status](https://img.shields.io/coveralls/kfly8/p5-Sub-Meta/main.svg?style=flat)](https://coveralls.io/r/kfly8/p5-Sub-Meta?branch=main) [![MetaCPAN Release](https://badge.fury.io/pl/Sub-Meta.svg)](https://metacpan.org/release/Sub-Meta)
# NAMESub::Meta - handle subroutine meta information
# SYNOPSIS
```perl
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](https://metacpan.org/pod/Sub%3A%3AMeta%3A%3AParameters) and [Sub::Meta::Returns](https://metacpan.org/pod/Sub%3A%3AMeta%3A%3AReturns).
```perl
$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:
```perl
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](https://metacpan.org/pod/B) etc., subroutines can have meta information such as arguments and return values.
# METHODS
## new
Constructor of `Sub::Meta`.
```perl
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:
```perl
# 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](https://metacpan.org/pod/Sub%3A%3AMeta%3A%3ACreator):
```perl
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`
```perl
method sub() => Maybe[CodeRef]
```Return a subroutine.
- `has_sub`
```perl
method has_sub() => Bool
```Whether Sub::Meta has subroutine or not.
- `set_sub($sub)`
```perl
method set_sub(CodeRef $sub) => $self
```Setter for subroutine.
```perl
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`
```perl
method subname() => Str
```- `has_subname`
```perl
method has_subname() => Bool
```Whether Sub::Meta has subroutine name or not.
- `set_subname($subname)`
```perl
method set_subname(Str $subname) => $self
```Setter for subroutine name.
```perl
$meta->subname; # hello
$meta->set_subname('world');
$meta->subname; # world
Sub::Util::subname($meta->sub); # hello (NOT apply to sub)
```- `apply_subname($subname)`
```perl
method apply_subname(Str $subname) => $self
```Sets subroutine name and apply to the subroutine reference.
```perl
$meta->subname; # hello
$meta->apply_subname('world');
$meta->subname; # world
Sub::Util::subname($meta->sub); # world
```### fullname
Accessor for subroutine full name
- `fullname`
```perl
method fullname() => Str
```A subroutine full name, e.g. `main::hello`
- `has_fullname`
```perl
method has_fullname() => Bool
```Whether Sub::Meta has subroutine full name or not.
- `set_fullname($fullname)`
```perl
method set_fullname(Str $fullname) => $self
```Setter for subroutine full name.
### stashname
Accessor for subroutine stash name
- `stashname`
```perl
method stashname() => Str
```A subroutine stash name, e.g. `main`
- `has_stashname`
```perl
method has_stashname() => Bool
```Whether Sub::Meta has subroutine stash name or not.
- `set_stashname($stashname)`
```perl
method set_stashname(Str $stashname) => $self
```Setter for subroutine stash name.
### subinfo
Accessor for subroutine information
- `subinfo`
```perl
method subinfo() => Tuple[Str,Str]
```A subroutine information, e.g. `['main', 'hello']`
- `set_subinfo([$stashname, $subname])`
```perl
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`
```perl
method file() => Maybe[Str]
```A filename where subroutine is defined, e.g. `path/to/main.pl`.
- `has_file`
```perl
method has_file() => Bool
```Whether Sub::Meta has a filename where subroutine is defined.
- `set_file($filepath)`
```perl
method set_file(Str $filepath) => $self
```Setter for `file`.
- `line`
```perl
method line() => Maybe[Int]
```A line where the definition of subroutine started, e.g. `5`
- `has_line`
```perl
method has_line() => Bool
```Whether Sub::Meta has a line where the definition of subroutine started.
- `set_line($line)`
```perl
method set_line(Int $line) => $self
```Setter for `line`.
### is\_constant
- `is_constant`
```perl
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)`
```perl
method set_is_constant(Bool $bool) => $self
```Setter for `is_constant`.
### prototype
Accessor for prototype of subroutine reference.
- `prototype`
```perl
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`
```perl
method has_prototype() => Bool
```Whether Sub::Meta has prototype or not.
- `set_prototype($prototype)`
```perl
method set_prototype(Str $prototype) => $self
```Setter for `prototype`.
- `apply_prototype($prototype)`
```perl
method apply_prototype(Str $prototype) => $self
```Sets subroutine prototype and apply to the subroutine reference.
### attribute
Accessor for attribute of subroutine reference.
- `attribute`
```perl
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`
```perl
method has_attribute() => Bool
```Whether Sub::Meta has attribute or not.
- `set_attribute($attribute)`
```perl
method set_attribute(ArrayRef[Str] $attribute) => $self
```Setter for `attribute`.
- `apply_attribute(@attribute)`
```perl
method apply_attribute(Str @attribute) => $self
```Sets subroutine attributes and apply to the subroutine reference.
### is\_method
- `is_method`
```perl
method is_method() => Bool
```Whether the subroutine is a method or not.
- `set_is_method($bool)`
```perl
method set_is_method(Bool $bool) => Bool
```Setter for `is_method`.
### parameters
Accessor for parameters object of [Sub::Meta::Parameters](https://metacpan.org/pod/Sub%3A%3AMeta%3A%3AParameters)
- `parameters`
```perl
method parameters() => InstanceOf[Sub::Meta::Parameters]
```If the parameters is set, it returns the parameters object.
- `set_parameters($parameters)`
```perl
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](https://metacpan.org/pod/Sub%3A%3AMeta%3A%3AParameters).
```perl
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](https://metacpan.org/pod/Sub%3A%3AMeta%3A%3AReturns)
- `returns`
```perl
method returns() => InstanceOf[Sub::Meta::Returns]
```If the returns is set, it returns the returns object.
- `set_returns($returns)`
```perl
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](https://metacpan.org/pod/Sub%3A%3AMeta%3A%3AReturns) or any object.
```perl
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)
```perl
method apply_meta(InstanceOf[Sub::Meta] $other_meta) => $self
```Apply subroutine subname, prototype and attributes of `$other_meta`.
### is\_same\_interface($other\_meta)
```perl
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)
```perl
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.```perl
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)
```perl
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:
```perl
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)
```perl
method is_relaxed_same_interface_inlined(InstanceOf[Sub::Meta] $other_meta) => Str
```Returns inlined `is_relaxed_same_interface` string.
### error\_message($other\_meta)
```perl
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)
```perl
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
```perl
method display() => Str
```Returns the display of Sub::Meta:
```perl
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
```perl
method parameters_class() => Str
```Returns class name of parameters. default: Sub::Meta::Parameters
Please override for customization.### returns\_class
```perl
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:
```perl
$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](https://metacpan.org/pod/Sub%3A%3AIdentify), [Sub::Util](https://metacpan.org/pod/Sub%3A%3AUtil), [Sub::Info](https://metacpan.org/pod/Sub%3A%3AInfo)
# 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