मैं कैसे जांचूं कि कक्षा को परिभाषित किया गया है या नहीं?


58

मैं स्ट्रिंग को कक्षा के नाम में कैसे बदलूं, लेकिन केवल तभी वह वर्ग पहले से मौजूद है?

Object.const_get("Amber") 

या (रेल में)

"Amber".constantize 

लेकिन इन दोनों में से किसी के साथ असफल हो जायेगी:

हैं एम्बर पहले से ही एक वर्ग है, मैं एक स्ट्रिंग से दूसरी कक्षा में के माध्यम से प्राप्त कर सकते हैं NameError: uninitialized constant Amber अगर एम्बर पहले से ही कक्षा नहीं है।

मेरी पहली सोचा defined? विधि का उपयोग करने के लिए है, लेकिन यह कक्षाएं कि पहले से ही मौजूद हैं और उन है कि नहीं है के बीच भेदभाव नहीं करता है:

>> defined?("Object".constantize) 
=> "method" 
>> defined?("AClassNameThatCouldNotPossiblyExist".constantize) 
=> "method" 

तो मैं कैसे परीक्षण करते हैं, तो एक स्ट्रिंग के नाम एक वर्ग इससे पहले कि मैं इसे बदलने की कोशिश करता हूँ? (ठीक है, कैसे begin/rescue नाम त्रुटि त्रुटि पकड़ने के लिए ब्लॉक? बहुत बदसूरत? मैं सहमत हूं ...)

  0

'परिभाषित' उदाहरण में वास्तव में क्या कर रही है क्या यह करने के लिए माना जाता है: यह जाँच करता है और यदि 'स्ट्रिंग ऑब्जेक्ट पर constantize' विधि परिभाषित किया गया है। यह परवाह नहीं है कि स्ट्रिंग में "ऑब्जेक्ट" या "AClassNameThatCouldNotPossiblyExist" शामिल है। 08 may. 172017-05-08 15:34:40

105

कैसे const_defined??

रेल में याद रखें, विकास मोड में स्वत: लोड हो रहा है, तो यह मुश्किल हो सकता है जब आप इसे बाहर का परीक्षण कर रहे:

>> Object.const_defined?('Account') 
=> false 
>> Account 
=> Account(id: integer, username: string, google_api_key: string, created_at: datetime, updated_at: datetime, is_active: boolean, randomize_search_results: boolean, contact_url: string, hide_featured_results: boolean, paginate_search_results: boolean) 
>> Object.const_defined?('Account') 
=> true 
+2

सही - धन्यवाद। ऑटो लोडर के लिए, आईआईआरसी को यह पता लगाने का एक तरीका है कि ऑटोलोडर सूची में क्या है। अगर यह एक समस्या साबित हो जाता है तो मैं उसे खोद दूंगा। 22 apr. 112011-04-22 18:36:46

  0

धन्यवाद, बस मुझे क्या चाहिए = डी 17 apr. 152015-04-17 04:55:35

+3

यह उन चीजों से भी मेल खाता है जो कक्षाएं नहीं हैं। 03 sep. 152015-09-03 17:47:26


10

ऊपर @ ctcherry की प्रतिक्रिया से प्रेरित होकर, यहाँ एक 'सुरक्षित वर्ग विधि भेजने है ', जहां class_name एक स्ट्रिंग है। यदि class_name कक्षा का नाम नहीं है, तो यह शून्य लौटाता है।

def class_send(class_name, method, *args) 
    Object.const_defined?(class_name) ? Object.const_get(class_name).send(method, *args) : nil 
end 

इससे भी सुरक्षित संस्करण है जो यह करने के लिए method केवल class_name अगर प्रतिक्रिया का आह्वान:

def class_send(class_name, method, *args) 
    return nil unless Object.const_defined?(class_name) 
    c = Object.const_get(class_name) 
    c.respond_to?(method) ? c.send(method, *args) : nil 
end 
+2

पी।: अगर आपको यह प्रतिक्रिया पसंद है, तो कृपया ctcherry की प्रतिक्रिया को वोट दें, क्योंकि यही मुझे सही दिशा में इंगित करता है। 22 apr. 112011-04-22 18:54:49


0

मैं या अगर एक स्ट्रिंग एक वैध वर्ग के नाम है परीक्षण करने के लिए एक सत्यापनकर्ता बना लिया है (अल्पविराम से अलग किए वैध वर्ग नामों के):

class ClassValidator < ActiveModel::EachValidator 
    def validate_each(record,attribute,value) 
    unless value.split(',').map { |s| s.strip.constantize.is_a?(Class) rescue false }.all? 
     record.errors.add attribute, 'must be a valid Ruby class name (comma-separated list allowed)' 
    end 
    end 
end 

1

एक और दृष्टिकोण, यदि आप कक्षा भी प्राप्त करना चाहते हैं। अगर वर्ग परिभाषित नहीं किया गया है तो शून्य वापस आ जाएगा, इसलिए आपको अपवाद नहीं लेना पड़ेगा।

class String 
    def to_class(class_name) 
    begin 
     class_name = class_name.classify (optional bonus feature if using Rails) 
     Object.const_get(class_name) 
    rescue 
     # swallow as we want to return nil 
    end 
    end 
end 

> 'Article'.to_class 
class Article 

> 'NoSuchThing'.to_class 
nil 

# use it to check if defined 
> puts 'Hello yes this is class' if 'Article'.to_class 
Hello yes this is class 

11

रेल में यह वास्तव में आसान है:

amber = "Amber".constantize rescue nil 
if amber # nil result in false 
    # your code here 
end 
  0

'बचाव' सहायक था क्योंकि कभी-कभी स्थिरांक को अनलोड किया जा सकता है और 'const_defined' के साथ जांच कर गलत होगा। 17 jun. 162016-06-17 18:52:29

  0

अच्छा धन्यवाद! 11 feb. 172017-02-11 12:16:40

  0

अपवादों को दबाने की अनुशंसा नहीं की जाती है, यहां और पढ़ें: https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions 11 sep. 172017-09-11 19:23:25

  0

@AndrewK: रूबी बचाव में वास्तव में अक्सर उपयोग किया जाता है - मैं सहमत हूं कि यह है अच्छा नही; एलिक्सीर दुनिया में हम ऐसा करने की कोशिश नहीं करते हैं, लेकिन ऐसा करने की कोई आवश्यकता नहीं है, लेकिन मैंने देखा कि बहुत से लोग रुबी 12 sep. 172017-09-12 19:43:44

  0

@Eiji में बचाव का उपयोग करते हैं। मैं बस इसका उल्लेख करना चाहता था क्योंकि रूबी के लिए नए लोग यह नहीं जानते कि यह एक विरोधी पैटर्न है और इससे बचा जाना चाहिए। 12 sep. 172017-09-12 20:56:38


2

ऐसा लगता है कि सब Object.const_defined? पद्धति का उपयोग करके जवाब त्रुटिपूर्ण हैं। यदि प्रश्न में वर्ग अभी तक लोड नहीं किया गया है, आलसी लोडिंग के कारण, तो दावा विफल हो जाएगा। इस निश्चित लक्ष्य को हासिल करने का एकमात्र तरीका की तरह है:?

validate :adapter_exists 

    def adapter_exists 
    # cannot use const_defined because of lazy loading it seems 
    Object.const_get("Irs::#{adapter_name}") 
    rescue NameError => e 
    errors.add(:adapter_name, 'does not have an IrsAdapter') 
    end