Есть ли эквиваленты методу Ruby в других языках? - PullRequest
21 голосов
/ 19 мая 2010

В Ruby у объектов есть удобный метод, называемый method_missing, который позволяет обрабатывать вызовы методов для методов, которые даже не были (явно) определены:

Вызывается Ruby, когда obj отправляется сообщение, которое он не может обработать. Символ - это символ для вызываемого метода, а аргументы - любые аргументы, которые были переданы ему. По умолчанию интерпретатор выдает ошибку при вызове этого метода. Однако возможно переопределить метод, чтобы обеспечить более динамичное поведение. В приведенном ниже примере создается класс Roman, который отвечает на методы с именами, состоящими из римских цифр, и возвращает соответствующие целочисленные значения.

class Roman
 def romanToInt(str)
   # ...
 end
 def method_missing(methId)
   str = methId.id2name
   romanToInt(str)
 end
end

r = Roman.new
r.iv      #=> 4
r.xxiii   #=> 23
r.mm      #=> 2000

Например, Ruby on Rails использует это для разрешения вызовов таких методов, как find_by_my_column_name.

У меня вопрос: какие другие языки поддерживают эквивалент method_missing и как вы реализуете эквивалент в своем коде?

Ответы [ 15 ]

15 голосов
/ 19 мая 2010

Smalltalk имеет сообщение doesNotUnderstand, которое, вероятно, является первоначальной реализацией этой идеи, учитывая, что Smalltalk является одним из родителей Руби. Реализация по умолчанию отображает окно ошибки, но его можно переопределить, чтобы сделать что-то более интересное.

12 голосов
/ 19 мая 2010

PHP-объекты могут быть перегружены специальным методом __call.

Например:

<?php
class MethodTest {
    public function __call($name, $arguments) {
        // Note: value of $name is case sensitive.
        echo "Calling object method '$name' "
             . implode(', ', $arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');
?>
11 голосов
/ 19 мая 2010

Некоторые варианты использования method_missing могут быть реализованы в Python с использованием __getattr__, например,

class Roman(object):
  def roman_to_int(self, roman):
    # implementation here

  def __getattr__(self, name):
    return self.roman_to_int(name)

Тогда вы можете сделать:

>>> r = Roman()
>>> r.iv
4
9 голосов
/ 20 мая 2010

JavaScript имеет noSuchMethod , но, к сожалению, это поддерживается только Firefox / Spidermonkey.

Вот пример:

wittyProjectName.__noSuchMethod__ = function __noSuchMethod__ (id, args) {
   if (id == 'errorize') {
    wittyProjectName.log("wittyProjectName.errorize has been deprecated.\n" +
                         "Use wittyProjectName.log(message, " +
                         "wittyProjectName.LOGTYPE_ERROR) instead.",
                         this.LOGTYPE_LOG);
    // just act as a wrapper for the newer log method
    args.push(this.LOGTYPE_ERROR);
    this.log.apply(this, args);
  }
}
9 голосов
/ 19 мая 2010

Perl имеет AUTOLOAD, который работает с подпрограммами и методами класса / объекта.

Пример подпрограммы:

use 5.012;
use warnings;

sub AUTOLOAD {
    my $sub_missing = our $AUTOLOAD;
    $sub_missing =~ s/.*:://;
    uc $sub_missing;
}

say foo();   # => FOO

Пример вызова метода класса / объекта:

use 5.012;
use warnings;

{
    package Shout;

    sub new { bless {}, shift }

    sub AUTOLOAD {
        my $method_missing = our $AUTOLOAD;
        $method_missing =~ s/.*:://;
        uc $method_missing;
    }
}

say Shout->bar;         # => BAR

my $shout = Shout->new;
say $shout->baz;        # => BAZ
8 голосов
/ 20 мая 2010

Это достигается в Lua путем установки клавиши __index метатаблицы .

t = {}
meta = {__index = function(_, idx) return function() print(idx) end end}
setmetatable(t, meta)

t.foo()
t.bar()

Этот код выведет:

foo
bar
8 голосов
/ 19 мая 2010

Objective-C поддерживает то же самое и называет это forwarding .

7 голосов
/ 20 мая 2010

Я искал это раньше и нашел полезный список (здесь его быстро обгоняют) как часть проекта Merd на SourceForge.

<ч />
 Construct                          Language
-----------                        ----------
 AUTOLOAD                           Perl
 AUTOSCALAR, AUTOMETH, AUTOLOAD...  Perl6
 __getattr__                        Python
 method_missing                     Ruby
 doesNotUnderstand                  Smalltalk
 __noSuchMethod__(17)               CoffeeScript, JavaScript
 unknown                            Tcl
 no-applicable-method               Common Lisp
 doesNotRecognizeSelector           Objective-C
 TryInvokeMember(18)                C#
 match [name, args] { ... }         E
 the predicate fail                 Prolog
 forward                            Io

со сносками:

  • (17) Firefox
  • (18) C # 4, только для «динамических» объектов
5 голосов
/ 20 мая 2010

C # теперь имеет TryInvokeMember , для динамических объектов (наследование от DynamicObject )

5 голосов
/ 19 мая 2010

В Common Lisp для этой цели может использоваться no-applicable-method в соответствии с Common Lisp Hyper Spec :

Универсальная функция no-apply-method вызывается, когда универсальная функция вызывается, и никакой метод для этой универсальной функции не применим. Метод по умолчанию сообщает об ошибке.

Универсальная функция no-apply-method не предназначена для вызова программистами. Программисты могут написать методы для этого.

Так, например:

(defmethod no-applicable-method (gf &rest args)
  ;(error "No applicable method for args:~% ~s~% to ~s" args gf)
  (%error (make-condition 'no-applicable-method :generic-function gf :arguments args) '()
        ;; Go past the anonymous frame to the frame for the caller of the generic function
        (parent-frame (%get-frame-ptr))))
...