هل هناك ما يعادلها مع Ruby's Method_missing بلغات أخرى؟
-
30-09-2019 - |
سؤال
في روبي ، الكائنات لها طريقة مفيدة تسمى method_missing
الذي يسمح للمرء بالتعامل مع مكالمات الطريقة للطرق التي لم يتم تحديدها (بشكل صريح):
استدعى من قبل Ruby عندما يتم إرسال OBJ رسالة لا يمكن التعامل معها. الرمز هو الرمز للطريقة المسمى ، و args هي أي وسيطات تم تمريرها إليها. بشكل افتراضي ، يرفع المترجم المترجم خطأ عندما يتم استدعاء هذه الطريقة. ومع ذلك ، من الممكن تجاوز طريقة توفير سلوك أكثر ديناميكية. المثال أدناه ينشئ فئة رومانية ، والتي تستجيب للطرق مع أسماء تتكون من الأرقام الرومانية ، وإعادة قيم عدد صحيح المقابلة.
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
, ، وكيف يمكنك تنفيذ ما يعادله في الكود الخاص بك؟
المحلول
بعض حالات استخدام method_missing
يمكن تنفيذها في بيثون باستخدام __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
نصائح أخرى
Smalltalk لديه doesNotUnderstand
الرسالة ، التي ربما تكون التنفيذ الأصلي لهذه الفكرة ، بالنظر إلى أن SmallTalk هو أحد والدي روبي. يعرض التطبيق الافتراضي نافذة خطأ ، ولكن يمكن تجاوزه لفعل شيء أكثر إثارة للاهتمام.
يمكن زيادة تحميل كائنات 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');
?>
جافا سكريبت 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);
}
}
بيرل لديه 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
الهدف-C يدعم نفس الشيء ويطلق عليه إعادة التوجيه.
تم إنجاز هذا في لوا عن طريق ضبط __index
مفتاح أ metatable.
t = {}
meta = {__index = function(_, idx) return function() print(idx) end end}
setmetatable(t, meta)
t.foo()
t.bar()
سيتم إخراج هذا الرمز:
foo
bar
كنت أبحث عن هذا من قبل ، ووجدت أ قائمة مفيدة (يتم تجاوزه بسرعة هنا) كجزء من مشروع 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 ، فقط للكائنات "الديناميكية"
في Lisp المشتركة ، no-applicable-method
يمكن استخدامها لهذا الغرض ، وفقا ل مواصفات شائعة LISP Hyper:
يتم استدعاء الوظيفة العامة التي لا يمكن تطبيقها عندما يتم استدعاء وظيفة عامة ولا توجد طريقة على هذه الوظيفة العامة قابلة للتطبيق. تشير الطريقة الافتراضية إلى خطأ.
الوظيفة العامة لا يمكن أن تُهدف الوظيفة التي لا يمكن تطبيقها للتطبيق إلى أن يطلق عليها المبرمجون. قد يكتب المبرمجون طرقًا لذلك.
على سبيل المثال:
(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))))
ج# لديه الآن TryInvokemmember, ، للكائنات الديناميكية (الوراثة من DynamicObject)
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
}
}
TCL لديه شيء مشابه. في أي وقت تتصل به أي أمر لا يمكن العثور عليه ، الإجراء مجهول وسوف يطلق. على الرغم من أنه ليس شيئًا تستخدمه عادةً ، إلا أنه يمكن أن يكون مفيدًا في بعض الأحيان.
في CFML (Coldfusion ، Railo ، OpenBD) ، onMissingMethod()
سيتلقى معالج الأحداث ، المحدد داخل مكون ، مكالمات غير محددة على هذا المكون. الحجج missingMethodName
و missingMethodArguments
يتم تمريرها تلقائيًا ، مما يتيح التعامل الديناميكي لمكالمة الطريقة المفقودة. هذه هي الآلية التي سهلت إنشاء مخططات Setter/Getter الضمنية قبل أن تبدأ في بناء محركات CFML المختلفة.
ما يعادلها Io
يستخدم forward
طريقة.
من المستندات:
إذا لم يرد كائن على رسالة ، فسوف يستدعي طريقة "الأمام" إذا كان لديه واحد ....
اليك مثال بسيط:
Shout := Object clone do (
forward := method (
method_missing := call message name
method_missing asUppercase
)
)
Shout baz println # => BAZ
/i3az/
بوو لديه IQuackFu
- هناك بالفعل ملخص ممتاز على ذلك في 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