The Rubyish "self"
作者:gugod 發佈於:More about Rubyish.pm today.
In a ruby program, when you see the word self
, it means either the current topic object,
if that expression is inside the body of an instance method, or it means the current class.
For example, when you run this piece of code in ruby:
class Foo puts self def puts_self puts self end end Foo.new.puts_self
You will first see Foo
coming out, then something like
#<Foo:0x5e85d0>
, which is the default stringification form of
objects.
In Perl, it's actually trivial to let self
refer to the current package name:
package Foo; sub self { __PACKAGE__ } say self; # outpus Foo
Well, this is useless, of course. Here's the re-usable form that
I implemented in Rubyish::Syntax::self
:
package Rubyish::Syntax::self; sub import { my $package = caller; *{$package ."::self"} = sub() { $package }; }
The module that use Rubyish::Syntax::self
will then have a self
keyword, just like __PACKAGE__
:
package Foo; use Rubyish::Syntax::self; say self; # outputs Foo # Furthermore... use base 'Class::Accessor'; self->mk_accessors(qw(bar baz/));
That's the first part, and the second one is to let self
refer to the topic object. That's
what I've already done in self.pm with @DB::args
.
Quote from the documentation of caller
(perldoc -f caller
):
Furthermore, when called from within the DB package, caller returns more detailed information: it sets the list variable @DB::args to be the arguments with which the subroutine was invoked.
Simon Cozens implemented this and named it DB::uplevel_args
in his rubyisms.pm. Maybe this should become part of Perl core someday.
The integrated implementation of Rubyish::Syntax::self
is then:
sub import { my $package = caller; *{$package.'::self'} = sub() { return (caller(1))[3] ? (_uplevel_args)[0] : $package; }; }
(caller(1))[3]
means the caller sub-routine. If it's called
from a sub-routine, then self
should refer to the topic
subject, which is the frist element of the caller arguments,
otherwise, self
means the current package.
The next experiment in Rubyish.pm would be this class-method declaration syntax:
class Foo def self.bar puts self end end # outputs "Foo" Foo.bar
This looks like an interesting one and it should be do-able with
Devel::Declare
.