Bir sınıfın tanımlanıp tanımadığını nasıl kontrol ederim?


58

Bir dizeyi sınıf adına nasıl dönüştürebilirim, ancak yalnızca bu sınıf zaten varsa?

Object.const_get("Amber") 

veya

"Amber".constantize 

(Rails) Ancak bu biriyle başarısız olur: Kehribar zaten bir sınıftır, ben üzerinden sınıfa bir dizeden

alabilirsiniz Amber zaten bir sınıf değilse NameError: uninitialized constant Amber.

ilk düşüncem defined? yöntemi kullanmak, ama zaten mevcut sınıflar ve bu bilmediğimiz arasında ayrım yapmaz: test ederim nasıl

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

Yani bir dize adları, bir sınıf ise dönüştürmeye çalışmadan önce? (Tamam, peki ya ben kabul? Çok çirkin NameError hataları? Yakalamak için bir begin/rescue bloğu ... hakkında)

  0

'tanımlanan' örnekte aynen bunu yapmak için ne gerekiyor yapıyor: String nesne üzerinde 'constantize' yöntem tanımlanmıştır eğer denetler. Dize "Object" veya "AClassNameThatCouldNotPossiblyExist" içeriyorsa umurumda değil. 08 may. 172017-05-08 15:34:40

105

ne dersiniz const_defined??

geliştirme modunda otomatik yükleme var, Rails hatırlayın, bu nedenle dışarı test ediyoruz ne zaman yanıltıcı olabilir:

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

mükemmel - teşekkürler. otomatik yükleyici için, IIRC otomatik yükleyici listesinde ne olduğunu öğrenmenin bir yolu var. Bir problem olduğu ortaya çıkarsa, bunu kazacağım. 22 nis. 112011-04-22 18:36:46

  0

teşekkürler, sadece neye ihtiyacım var = D 17 nis. 152015-04-17 04:55:35

+3

Bu, aynı zamanda sınıf olmayan şeyler ile de eşleşir. 03 eyl. 152015-09-03 17:47:26


10

yukarıda @ ctcherry tepki esinlenerek burada 'güvenli sınıf yöntemi gönderme var 'class_name bir dizedir. class_name bir sınıf adını vermezse, nil değerini döndürür. buna method sadece class_name eğer kişi yanıt çağırır

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

Bir daha güvenli sürümü:

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

p.s.: Eğer bu cevabı beğenirseniz, lütfen oy-oylama cetvelinin cevabı, çünkü doğru yönde beni işaret eden şey budur. 22 nis. 112011-04-22 18:54:49


0

Ben bir dize geçerli bir sınıf adı ise test etmek için bir doğrulayıcı oluşturulan (veya virgülle ayrılmış listesi ettik) geçerli bir sınıf isimleri:

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

başka yaklaşımda, eğer çok sınıfını almak istiyorum. Sınıf tanımlanmamışsa sıfırlanır, böylece bir istisna yakalamak zorunda kalmazsınız. raylar ise

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

gerçekten kolay:

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

'Kurtarma 'yardımcı oldu, çünkü bazen sabitler kaldırılabilir ve const_defined ile kontrol edilebilir? 17 haz. 162016-06-17 18:52:29

  0

Nice teşekkür ederiz! 11 şub. 172017-02-11 12:16:40

  0

İstisnaları kaldırmak tavsiye edilmez, daha fazla bilgiyi burada bulabilirsiniz: https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions 11 eyl. 172017-09-11 19:23:25

  0

@AndrewK: Ruby kurtarmada sık sık kullanılır - ofc iyi değil; Elixir dünyasında bunu yapmaya gerek yoksa bunu yapmaya çalışmayız, ama çok sayıda insan Ruby'yi 12 eyl. 172017-09-12 19:43:44

  0

@Eiji, Agreed'de kurtarmayı gördüm. Sadece Ruby'den yeni insanlar olarak bahsetmek istedim, bunun bir anti-örüntü olduğunu bilmemeli ve kaçınılmalıdır. 12 eyl. 172017-09-12 20:56:38


2

O Object.const_defined? yöntemi kullanarak tüm cevaplar kusurlu olan görünür. Söz konusu sınıf henüz yüklenmediyse, tembel yükleme nedeniyle, o zaman onaylama başarısız olur. kesin bunu başarmak için tek yol bu yüzden gibidir:?

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