2014-11-21 3 views
1

Пожалуйста, простите меня, если я неправильно использую терминологию в этом посте. Я подталкиваю свои навыки Perl и программирования выше того, что я делал раньше, поэтому я не уверен, какие правильные термины для некоторых вещей, которые я хочу делать.Как я могу улучшить синтаксис имен моих методов AUTOLOADed?

Я пишу небольшой модуль Perl, чтобы упростить общение с API-интерфейсом XML-RPC. Я создал несколько методов в классе моего модуля для обработки наиболее частых вызовов. Затем я использую AUTOLOAD для создания методов «на лету» для остальной части вызовов API. Это хорошо работает, и я доволен результатом.

Одним из улучшений, которые я надеялся сделать, было улучшение синтаксиса того, как я называю методы API. API имеет свои вызовы, разделенные на пространства имен, и использует период как разделитель пространства имен. Так, например, некоторые из звонков:

  • api.login
  • api.logout
  • user.create
  • user.delete

Я не был в состоянии использовать период в имени метода, когда я вызываю его в Perl, поэтому я заменяю его знаком подчеркивания. Вот мой метод AUTOLOAD.

sub AUTOLOAD { 
    my $self = shift; 
    our $AUTOLOAD; 
    (my $method = $AUTOLOAD) =~ s/.*:://s; # remove package name 
    $method =~ s/_/./g; 
    return if $method =~ /DESTROY/; 
    perform_rpc_call($self, $method, @_); 
} 

Когда я делаю звонки в моем коде Perl они выглядят следующим образом:

$obj->user_delete($username); 

Есть ли более элегантный способ, чтобы написать, что, чем замена период с подчеркиванием? Я бы предпочел использовать метод как $obj->user->delete($username), если это возможно. Существуют ли модули или шаблоны проектирования Perl для обработки этой ситуации? Последние два дня я читал FAQ по Perl, просматривая сеть, и поиск через CPAN бесполезен.

API, с которым я общаюсь, имеет вызов, который вернет список всех поддерживаемых им вызовов. Я думаю, что я мог бы получить это в моем конструкторе и как-то использовать его, чтобы сделать AUTOLOAD делать то, что я хочу. Но мне интересно, есть ли лучший способ.

+1

Это возможно, но не так просто. Вам нужно будет заставить '$ obj-> user' возвращать объект класса (другого, динамически созданного), который имеет метод' delete'. Это не невозможно, но это не просто, и я бы не подумал, что это стоит немного синтаксического восторга. Почему бы не создать метод 'user' и иметь' $ obj-> user ('delete', $ username) '. Или даже забыть о 'AUTOLOAD' вообще и иметь' $ obj-> api_call ('user.delete', $ username); – Borodin

+0

@ikegami: Это правда, если нет теоретического предела для количества точек, которые может иметь идентификатор вызова API. – Borodin

+0

@Borodin, (Преобразовал мой комментарий в ответ) – ikegami

ответ

3

Это возможно, если вы можете сказать, что user является пространством имен или членом, а не вызовом.

package Class; 

sub AUTOLOAD { 
    (my $method = our $AUTOLOAD) =~ s/^.*:://s; 
    return if $method =~ /DESTROY/; 

    my $self = shift; 

    return bless([$self, $method], 'Class::Helper'); 
     if $self->is_namespace($method); 

    perform_rpc_call($self, $method, @_); 
} 


package Class::Helper; 

sub AUTOLOAD { 
    (my $method = our $AUTOLOAD) =~ s/^.*:://s; 
    return if $method =~ /DESTROY/; 

    my ($self, $ns) = @{ shift }; 
    $method = "$ns.$method"; 

    return bless([$self, $method], 'Class::Helper'); 
     if $self->is_namespace($method); 

    perform_rpc_call($self, $method, @_); 
} 

Это будет работать с user.mail.send.


Если вы не можете сказать user, является ли пространство имен или вызов, ваш желаемый синтаксис выиграл»twork. Вы должны были бы использовать

$obj->user->delete->(@args) # Error prone. See below 

или

$obj->user->delete->call(@args) # Same problem, but a little more obvious 

или

$obj->api_call('user.delete', @args) 

Первый вариант очень подвержен ошибкам. Если вы забудете, что последний ->, метод RPC не будет вызван. Я рекомендую против этого.

Это, как будет реализован второй вариант:

package Class; 

sub AUTOLOAD { 
    (my $method = our $AUTOLOAD) =~ s/^.*:://s; 
    return if $method =~ /DESTROY/; 

    my $self = shift; 
    return bless([$self, $method], 'Class::Helper'); 
} 


package Class::Helper; 

sub AUTOLOAD { 
    (my $method = our $AUTOLOAD) =~ s/^.*:://s; 
    return if $method =~ /DESTROY/; 

    my ($self, $ns) = @{ shift }; 
    $method = "$ns.$method"; 
    return bless([$self, $method], 'Class::Helper'); 
} 

sub call { 
    my ($self, $method) = @{ shift }; 
    perform_rpc_call($self, $method, @_); 
} 
+0

Спасибо, ikegami. Это сработало хорошо. Я всегда многому научился, когда читаю ваш код. – Starfish

Смежные вопросы