The Rubyish "self"

作者:   發佈於:  

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.