एक वर्ग को देखते हुए, देखें कि क्या उदाहरण विधि (रूबी) है


227

मैं रूबी में जानता हूं कि मैं यह respond_to?जांचने के लिए उपयोग कर सकता हूं कि क्या कोई वस्तु एक निश्चित विधि है।

लेकिन, कक्षा को देखते हुए, अगर उदाहरण के लिए एक निश्चित विधि है तो मैं कैसे जांच सकता हूं?

यानी, जैसे कुछ

Foo.new.respond_to?(:bar)

लेकिन मुझे लगता है कि वहाँ एक नया उदाहरण पल की तुलना में एक बेहतर तरीका होगा।

जवाबों:


364

मुझे नहीं पता कि क्यों हर कोई आपको सुझाव दे रहा है कि आपको किसका उपयोग करना चाहिए instance_methodsऔर include?कब method_defined?काम करना चाहिए ।

class Test
  def hello; end
end

Test.method_defined? :hello #=> true

ध्यान दें

यदि आप रूबी से किसी अन्य OO भाषा में आ रहे हैं या आपको लगता है कि method_definedइसका अर्थ केवल वे विधियाँ हैं जिनसे आपने स्पष्ट रूप से परिभाषित किया है:

def my_method
end

तो यह पढ़ें:

रूबी में, आपके मॉडल पर एक संपत्ति (विशेषता) मूल रूप से एक विधि भी है। तो method_defined?गुणों के लिए भी सही वापस आएगा, न कि सिर्फ तरीके।

उदाहरण के लिए:

स्ट्रिंग की विशेषता वाले वर्ग के उदाहरण को देखते हुए first_name:

<instance>.first_name.class #=> String

<instance>.class.method_defined?(:first_name) #=> true

चूंकि first_nameएक विशेषता और एक विधि (और स्ट्रिंग का एक प्रकार) दोनों है।


9
method_defined? सबसे अच्छा समाधान है क्योंकि उदाहरण_मथोड्स रूबी 1.8 और 1.9 के बीच बदल गया है। 1.8 स्ट्रिंग्स की एक सरणी देता है और 1.9 प्रतीकों की एक सरणी देता है। method_defined? 1.8 और 1.9 दोनों में एक प्रतीक लेता है।
जेसन

2
यह उल्लेख करने के लिए नहीं कि: Inst_methods हर कॉल के लिए एक नई सरणी बनाएगा और इसमें शामिल है:? फिर बताने के लिए सरणी चलना होगा। इसके विपरीत: method_defined? आंतरिक रूप से लुकअप टेबल्स को क्वेरी करेगा (एक हैश लुकअप जो कि C में है) और आपको कोई नई वस्तु बनाए बिना पता चलेगा।
अशर

4
जब आप इस तरह का उपयोग करते हैं तो कम से कम एक फायदा होता है String.instance_methods(false).include? :freeze, लेकिन झूठा तर्क बिल्कुल बता सकता है कि क्या freezeस्ट्रींग क्लास में विधि को परिभाषित किया गया है या नहीं। इस स्थिति में यह गलत हो जाएगा क्योंकि freezeविधि स्ट्रिंग द्वारा कर्नेल मॉड्यूल से विरासत में मिली है, लेकिन String.method_defined? :freezeहमेशा सही लौटेगी, जो इस तरह के उद्देश्य से बहुत मदद नहीं कर सकता है।
13:२३

1
@ आप जिस वर्ग के उदाहरणों पर उपलब्ध विधियों के साथ तरीकों को भ्रमित कर रहे हैं। method_defined?वर्ग (जैसे Array) पर उपयोग किया जाना चाहिए , लेकिन आप इसे उदाहरणों पर उपयोग करने का प्रयास कर रहे हैं (उदाहरण के लिए [])

@banister बिल्कुल सही। स्पष्टीकरण के लिए धन्यवाद, यह इसे पढ़ने पर सही समझ में आता है। :) मैंने अपनी टिप्पणी को हटा दिया है ताकि भ्रमित न हो।
बैन

45

आप method_defined?निम्नानुसार उपयोग कर सकते हैं :

String.method_defined? :upcase # => true

instance_methods.include?बाकी सभी की तुलना में बहुत आसान, पोर्टेबल और कुशल सुझाव देना प्रतीत होता है।

ध्यान रखें कि आप यह नहीं जान पाएंगे कि कोई क्लास डायनेमिक रूप से कुछ कॉलों का जवाब देती है method_missing, उदाहरण के लिए respond_to?रिडिफाइनिंग द्वारा, या रूबी 1.9.2 डिफाइन करने के बाद से respond_to_missing?


2
ध्यान दें कि यदि आपके हाथ में एक उदाहरण है और आपको नहीं पता कि यह कक्षा है, तो आप कर सकते हैंinstance.class.method_defined? :upcase
jaydel

25

वास्तव में यह ऑब्जेक्ट्स और क्लासेस दोनों के लिए काम नहीं करता है।

यह करता है:

class TestClass
  def methodName
  end
end

तो दिए गए जवाब के साथ, यह काम करता है:

TestClass.method_defined? :methodName # => TRUE

लेकिन यह काम नहीं करता है:

t = TestClass.new
t.method_defined? : methodName  # => ERROR!

इसलिए मैं इसका उपयोग वर्गों और वस्तुओं दोनों के लिए करता हूं:

क्लास:

TestClass.methods.include? 'methodName'  # => TRUE

वस्तुओं:

t = TestClass.new
t.methods.include? 'methodName'  # => TRUE

3
उदाहरणों के लिए आप 'inst.class.method_defined' का उपयोग कर सकते हैं?
१०:१६ पर Lu११

यह माणिक के आपके संस्करण पर निर्भर करता है। उपरोक्त यह विधि 1.8.7 सहित सभी संस्करणों के लिए काम करती है।
एलेक्स वी।

10

" एक वर्ग को देखते हुए, उदाहरण है कि उदाहरण के लिए विधि (रूबी) है " बेहतर है। जाहिरा तौर पर रूबी के पास यह बिल्ट-इन है, और मैंने किसी तरह इसे याद किया। मेरा जवाब संदर्भ के लिए छोड़ दिया गया है, भले ही।

रूबी कक्षाएं विधियों का जवाब देती हैं instance_methodsऔर public_instance_methods। रूबी 1.8 में, पहली सूची स्ट्रिंग के एक सरणी में सभी इंस्टेंस विधि नामों को सूचीबद्ध करती है, और दूसरा इसे सार्वजनिक विधियों में प्रतिबंधित करता है। दूसरा व्यवहार वह है जो आप सबसे अधिक चाहते हैं, क्योंकि respond_to?डिफ़ॉल्ट रूप से सार्वजनिक तरीकों से ही प्रतिबंधित होता है।

Foo.public_instance_methods.include?('bar')

रूबी 1.9 में, हालांकि, वे विधियां प्रतीकों के सरणियों को लौटाती हैं।

Foo.public_instance_methods.include?(:bar)

यदि आप अक्सर ऐसा करने की योजना बना रहे हैं, तो आप Moduleशॉर्टकट विधि को शामिल करने के लिए विस्तार करना चाह सकते हैं । (इसके Moduleबजाय इसे असाइन करना अजीब लग सकता है Class, लेकिन चूंकि यह वही है जहाँ instance_methodsविधियाँ रहती हैं, इसलिए उस पैटर्न के अनुरूप रखना सबसे अच्छा है।)

class Module
  def instance_respond_to?(method_name)
    public_instance_methods.include?(method_name)
  end
end

यदि आप रूबी 1.8 और रूबी 1.9 दोनों का समर्थन करना चाहते हैं, तो यह दोनों तार और प्रतीकों की खोज करने के लिए तर्क को जोड़ने के लिए एक सुविधाजनक स्थान होगा।


1
method_defined?बेहतर है :)
घोड़े का जूड़ा

@banister - ओह, मेरी, और मैं किसी भी तरह इसे याद किया! xD ने @ मार्क के उत्तर के पीछे एक +1 फेंका, और यह सुनिश्चित करने के लिए एक लिंक जोड़ा कि यह मिस नहीं है :)
माचिस


3

निश्चित नहीं है कि यह सबसे अच्छा तरीका है, लेकिन आप हमेशा ऐसा कर सकते हैं:

Foo.instance_methods.include? 'bar'

3

मुझे लगता है कि method_defined?रेल में कुछ गड़बड़ है । यह असंगत या कुछ और हो सकता है, इसलिए यदि आप रेल का उपयोग करते हैं, तो कुछ का उपयोग करना बेहतर हैattribute_method?(attribute)

ActiveRecord कक्षाओं में तात्कालिकता तक काम नहीं करता है, " method_defined के लिए परीक्षण " असंगति के बारे में एक प्रश्न है।


3

यदि आप यह देखने के लिए जाँच कर रहे हैं कि क्या कोई ऑब्जेक्ट कई तरीकों से जवाब दे सकता है, तो आप कुछ ऐसा कर सकते हैं:

methods = [:valid?, :chase, :test]

def has_methods?(something, methods)
  methods & something.methods == methods
end

methods & something.methodsउनकी आम / मिलान तत्वों पर दो सरणियों में शामिल हो जाएगा। some.methods में वे सभी विधियाँ शामिल हैं जिनकी आप जाँच कर रहे हैं, यह समान विधियाँ हैं। उदाहरण के लिए:

[1,2] & [1,2,3,4,5]
==> [1,2]

इसलिए

[1,2] & [1,2,3,4,5] == [1,2]
==> true

इस स्थिति में, आप प्रतीकों का उपयोग करना चाहते हैं, क्योंकि जब आप .methods कहते हैं, तो यह प्रतीकों की एक सरणी देता है और यदि आप उपयोग करते हैं ["my", "methods"], तो यह गलत होगा।


2

klass.instance_methods.include :method_nameया "method_name", मुझे लगता है कि रूबी संस्करण पर निर्भर करता है।


2
class Foo
 def self.fclass_method
 end
 def finstance_method
 end
end

foo_obj = Foo.new
foo_obj.class.methods(false)
=> [:fclass_method] 

foo_obj.class.instance_methods(false)
=> [:fclass_method] 

आशा है कि यह आपकी मदद करता है!


1

माणिक 2.5.3 के साथ काम कर रहे मेरे मामले पर निम्नलिखित वाक्यों ने पूरी तरह से काम किया है:

value = "hello world"

value.methods.include? :upcase

यह एक बूलियन मान को सही या गलत लौटाएगा।


1

जबकि respond_to?केवल सार्वजनिक तरीकों के लिए ही सही, एक वर्ग पर "विधि परिभाषा" के लिए जाँच करना भी निजी तरीकों से संबंधित हो सकता है।

रूबी v2.0 + पर दोनों सार्वजनिक और निजी सेटों की जाँच के साथ प्राप्त किया जा सकता है

Foo.private_instance_methods.include?(:bar) || Foo.instance_methods.include?(:bar)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.