Perl потребуется небольшая помощь, чтобы сделать это. Потому что он не рассматривает ссылки кода, хранящиеся в хешах, как «методы». Методы реализованы в виде записей в таблице символов пакета. Perl более ориентирован на класс , чем JavaScript, который с гордостью заявляет, что он более объектно-ориентирован (для отдельных объектов).
Чтобы выполнить эту функцию, вам нужно создать класс, который отображал бы ссылки таким образом. Способ обойти методы в таблице символов - метод AUTOLOAD
. Если пакет содержит подпрограмму AUTOLOAD
, то при вызове благословенного объекта, который Perl не может найти в цепочке наследования, он вызовет AUTOLOAD
и установит переменную области пакета (our
) $AUTOLOAD
содержит полное имя функции.
Мы получаем имя вызываемого метода, получая последний узел (после последнего '::') полностью определенного имени. Мы смотрим, есть ли кодовая ссылка в этом месте, и если она есть, мы можем ее вернуть.
package AutoObject;
use strict;
use warnings;
use Carp;
use Params::Util qw<_CODE>;
our $AUTOLOAD;
sub AUTOLOAD {
my $method_name = substr( $AUTOLOAD, index( $AUTOLOAD, '::' ) + 2 );
my ( $self ) = @_;
my $meth = _CODE( $self->{$method_name} );
unless ( $meth ) {
Carp::croak( "object does not support method='$method_name'!" );
}
goto &$meth;
}
1;
Тогда вы бы благословили объект в этот класс:
package main;
my $obj
= bless { foo => 1
, hello => sub { return 'world' }
}, 'AutoObject';
print $obj->hello();
Обычно в AUTOLOAD
sub I "цементирует" поведение. То есть я создаю записи в таблице символов пакета, чтобы избежать AUTOLOAD
в следующий раз. Но это обычно для разумно определенного поведения класса.
Я также разработал QuickClass
, который создает пакет для каждого объявленного объекта, но в нем много разборок таблиц символов, что сейчас дни, вероятно, лучше сделать с Class::MOP
.
Учитывая предложение Эрика Строма, вы можете добавить следующий код в пакет AutoObject. Подставка import
будет вызываться каждый раз, когда кто-нибудь use
-d AutoObject
(с параметром 'object'
).
# Definition:
sub object ($) { return bless $_[0], __PACKAGE__; };
sub import { # gets called when Perl reads 'use AutoObject;'
shift; # my name
return unless $_[0] eq 'object'; # object is it's only export
use Symbol;
*{ Symbol::qualify_to_reference( 'object', scalar caller()) }
= \&object
;
}
И затем, когда вы захотите создать «литерал объекта», вы можете просто сделать:
use AutoObject qw<object>;
И выражение будет:
object { foo => 1, hello => sub { return 'world' } };
Вы могли бы даже сделать:
object { name => 'World'
, hello => sub { return "Hello, $_[0]->{name}"; }
}->hello()
;
И у вас есть выражение "литерал объекта". Возможно, модуль будет лучше называться Object::Literal
.