XS-Framework
view release on metacpan or search on metacpan
lib/XS/Framework/Manual/SVAPI/Stash.pod view on Meta::CPAN
This method creates new C<Object>, which is blessed into to the current package
(C<Stash>).
Object bless (const Sv& what) const;
This C<bless> method version works somewhat similiar to the following Perl
construction
my $class = ...;
my $obj = ...;
return bless $obj => $class;
i.e. if C<what> is already an object, it is blessed into the C<Stash>,
otherwise new C<RV*> created from the C<what> argument, and the
blessed object returned.
=head2 add_const_sub()
void add_const_sub (const panda::string_view& name, const Sv& val);
Creates subroutine C<name> that returns constant C<val> eligible for compile-time inlining (like newCONSTSUB). C<val> is retained and made readonly.
lib/XS/Framework/Manual/Typemap.pod view on Meta::CPAN
In that case SV* pointing to C<undef> is created, and it is blessed into the specified
package name. This is needed to follow standart Perl inheritance model, i.e. respect
when the current class might be derived in Perl or xs-adapter. In other words it
works similar to:
package My::XXX;
sub new {
my $class = shift;
my $obj = {};
return bless $obj => $class;
}
package My::YYY;
use base qw/My::XXX;
my $obj_a = My::XXX->new;
my $obj_b = My::YYY->new;
=item it might be already blessed Perl object
lib/XS/Framework/Manual/recipe07.pod view on Meta::CPAN
=cut
=head1 C3 mixin introduction
Let's assume there is a Server with core functions defined in basic class.
package MyBase {
sub new {
my $class = shift;
return bless {} => $class;
};
sub on_client {
my ($self, $client) = @_;
print "MyBase::on_client\n";
if ($client->{status} eq 'authorized'){ $client->{send} = '[welcome]' }
elsif ($client->{status} eq 'not_authorized') { $client->{send} = '[disconnect]' };
}
}
The package is responsible for constructing object and send to client either
C<[welcome]> string upon successful login and C<[disconnect]> upon login falure.
It is desirable to have dedicated logging and authorizing components.
package MyLogger {
use base qw/MyBase/; # (1)
sub new {
my $class = shift;
my $obj = $class->next::method(@_) // {}; # (2)
return bless $obj => $class;
}
sub on_client {
my ($self, $client) = @_;
print "MyLogger::on_client\n"; # (3)
print "client ", $client->{id}, ", status = ", $client->{status}, "\n";
$self->next::method($client); # (4)
print "client ", $client->{id}, ", status = ", $client->{status}, "\n";
}
}
package MyAuth {
use base qw/MyBase/; # (5)
sub new {
my $class = shift;
my $obj = $class->next::method(@_) // {}; # (6)
return bless $obj => $class;
}
sub on_client {
my ($self, $client) = @_;
print "MyAuth::on_client\n"; # (7)
if ($client->{id} < 0) { $client->{status} = 'not_authorized'; }
else { $client->{status} = 'authorized'; }
$self->next::method($client); # (8)
}
};
lib/XS/Framework/Manual/recipe07.pod view on Meta::CPAN
The real magic happens in C<next::method> (4) and (8): the plugins forwards
call either to base class C<MyBase> or to next plugin. This is not known
at the place of invocation and it is defined at place, where plug-ins are
inherited, i.e. in the I<gather point>:
package MyXServer {
use base qw/MyLogger MyAuth MyBase/; # (9)
sub new {
my $class = shift;
my $obj = $class->next::method(@_) // {};
return bless $obj => $class;
}
};
In (9) it is said that C<MyLogger> plugin's interceptors are executed first,
then C<MyAuth> interceptors are executed, and only then the generic (may be
empty) methods of C<MyBase> will be executed. C3/mro resolves multiple
inheritance problem, i.e. linearizes inheritance tree from most specific
(child) to the most generic (parent) classes.
The sample code
misc/leak1.plx view on Meta::CPAN
use MyTest;
use Devel::Peek;
use BSD::Resource;
{
package MyClass;
sub new {
my ($class, $value) = @_;
my $obj = {_value => $value};
return bless $obj => $class;
}
}
while (1) {
MyTest::test_leaks1("MyClass", "new", 10000);
say BSD::Resource::getrusage()->{"maxrss"};
}
t/cookbook/recipe07.t view on Meta::CPAN
use strict;
use warnings;
BEGIN { require "./t/cookbook/TestCookbook.pm"; }
package MyBase {
sub new {
my $class = shift;
return bless {} => $class;
};
sub on_client {
my ($self, $client) = @_;
print "MyBase::on_client\n";
if ($client->{status} eq 'authorized'){ $client->{send} = '[welcome]' }
elsif ($client->{status} eq 'not_authorized') { $client->{send} = '[disconnect]' };
}
};
package MyLogger {
use base qw/MyBase/;
sub new {
my $class = shift;
my $obj = $class->next::method(@_) // {};
return bless $obj => $class;
}
sub on_client {
my ($self, $client) = @_;
print "MyLogger::on_client\n";
print "client ", $client->{id}, ", status = ", $client->{status}, "\n";
$self->next::method($client);
print "client ", $client->{id}, ", status = ", $client->{status}, "\n";
}
};
package MyAuth {
use base qw/MyBase/;
sub new {
my $class = shift;
my $obj = $class->next::method(@_) // {};
return bless $obj => $class;
}
sub on_client {
my ($self, $client) = @_;
print "MyAuth::on_client\n";
if ($client->{id} < 0) { $client->{status} = 'not_authorized'; }
else { $client->{status} = 'authorized'; }
$self->next::method($client);
}
};
package MyXServer {
use base qw/MyLogger MyAuth MyBase/;
sub new {
my $class = shift;
my $obj = $class->next::method(@_) // {};
return bless $obj => $class;
}
};
my $client = {status => 'connected', id => 10};
my $server = MyXServer->new;
$server->on_client($client);
print "\nLet's try in XS\n";
my $client2 = MyTest::Cookbook::Client07->new(10);
( run in 0.433 second using v1.01-cache-2.11-cpan-65fba6d93b7 )