Подтвердить что ты не робот

Существуют ли эквиваленты Ruby method_missing на других языках?

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

Вызывается Ruby, когда obj отправляется сообщение, которое он не может обработать. символ - это символ вызываемого метода, а args - любые аргументы, которые были переданы ему. По умолчанию интерпретатор вызывает ошибку при вызове этого метода. Тем не менее, можно переопределить метод, чтобы обеспечить более динамичное поведение. В приведенном ниже примере создается класс 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, и как вы реализуете эквивалент в своем коде?

4b9b3361

Ответ 1

Некоторые примеры использования 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

Ответ 2

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

Ответ 3

Объекты 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');
?>

Ответ 4

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);
  }
}

Ответ 5

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

Ответ 6

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

Ответ 7

Это выполняется в Lua, установив ключ __index metatable.

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

t.foo()
t.bar()

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

foo
bar

Ответ 8

Я искал это раньше и нашел полезный список (быстро настигнутый здесь) как часть проекта 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) С# 4, только для "динамических" объектов

Ответ 9

В 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))))

Ответ 10

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

Ответ 11

ActionScript 3.0 имеет класс Proxy, который можно расширить, чтобы обеспечить эту функциональность.

dynamic class MyProxy extends Proxy {
  flash_proxy override function callProperty(name:*, ...rest):* {
    try {
      // custom code here
    }
    catch (e:Error) {
      // respond to error here
    }
}  

Ответ 12

Tcl имеет нечто подобное. Каждый раз, когда вы вызываете любую команду, которая не может быть найдена, вызывается процедура unknown. Хотя это не то, что вы обычно используете, иногда это может быть удобно.

Ответ 13

В CFML (ColdFusion, Railo, OpenBD) обработчик событий onMissingMethod(), определенный внутри компонента, будет получать вызовы метода undefined для этого компонента. Аргументы missingMethodName и missingMethodArguments автоматически передаются, что позволяет динамически обрабатывать вызов отсутствующего метода. Это механизм, который облегчил создание неявных схем setter/getter до того, как они стали встроены в различные механизмы CFML.

Ответ 14

Его эквивалент в Io использует метод forward.

Из документов:

Если объект не отвечает на сообщение, он будет вызывать свой метод "вперед", если он имеет один....

Вот простой пример:

Shout := Object clone do (
    forward := method (
        method_missing := call message name
        method_missing asUppercase
    )
)

Shout baz println     # => BAZ

/I3az/

Ответ 15

Boo имеет IQuackFu - уже существует превосходное резюме SO на how-can-i-intercept-a-method-call-in-boo

Вот пример:

class XmlObject(IQuackFu):
_element as XmlElement 

def constructor(element as XmlElement):
    _element = element 

def QuackInvoke(name as string, args as (object)) as object:
    pass # ignored 

def QuackSet(name as string, parameters as (object), value) as object:
    pass # ignored 

def QuackGet(name as string, parameters as (object)) as object:
    elements = _element.SelectNodes(name)
    if elements is not null:
        return XmlObject(elements[0]) if elements.Count == 1
        return XmlObject(e) for e as XmlElement in elements 

override def ToString():
    return _element.InnerText