2010-07-02 4 views
46

einen String mit dem Modul und den Namen einer Klasse zu haben, wie:Erhalten Sie eine Klasse mit Namen in Ruby?

"Admin::MetaDatasController" 

wie kann ich die tatsächliche Klasse bekommen?

Der folgende Code funktioniert, wenn kein Modul ist:

Kernel.const_get("MetaDatasController") 

aber es bricht mit dem Modul:

ruby-1.8.7-p174 > Kernel.const_get("Admin::MetaDatasController") 
NameError: wrong constant name Admin::MetaDatasController 
     from (irb):34:in `const_get' 
     from (irb):34 
ruby-1.8.7-p174 > 
+0

Duplizieren von http://stackoverflow.com/ Fragen/1448670/Ruby-String-to-Klasse –

Antwort

88

Wenn Sie etwas einfach wollen, dass nur Ihre speziellen Griffe können Sie schreiben

Object.const_get("Admin").const_get("MetaDatasController") 

Aber wenn Sie etwas allgemeiner wollen, teilen Sie die Zeichenfolge auf :: und die Namen nacheinander lösen:

def class_from_string(str) 
    str.split('::').inject(Object) do |mod, class_name| 
    mod.const_get(class_name) 
    end 
end 

the_class = class_from_string("Admin::MetaDatasController") 

Auf der ersten Iteration Object für die Konstante Admin und gibt den Admin Modul oder Klasse gefragt wird, dann auf die zweite Iteration dieses Modul oder Klasse ist für die ständige gefragt MetaDatasController und gibt diese Klasse zurück. Da es keine weiteren Komponenten gibt, wird die Klasse von der Methode zurückgegeben (wenn es mehr Komponenten gegeben hätte, würde sie wiederholt werden, bis sie die letzte gefunden hätte).

+1

Interessant, warum verwenden Sie 'Kernel' als Empfänger? Eine Top-Level-Konstante ist auf "Object" definiert, nicht auf "Kernel". – horseyguy

+0

Das OP verwendet es, und ich habe nicht aufgehört zu suchen, was das eigentliche Modul sein könnte, das die wichtigsten Konstanten definiert. Ich habe es geändert. – Theo

1

ich könnte weit weg von der Basis sein, aber würde nicht die Klasse zurückgeben?

eval("Admin::MetaDatasController") 

so würde eval("Admin::MetaDatasController").new die gleiche sein wie Admin::MetaDatasController.new

+8

Ja, aber es kommt mit viel Gepäck. Nämlich, Sicherheit und Geschwindigkeit. Eine gute allgemeine Regel ist, Kavalier-Gebrauch von Eval zu vermeiden. Achte auch darauf, wen du dir hier vorschlägst, sonst könntest du dich auf dem Scheiterhaufen verbrannt sehen, wenn du mit dem Bösen verbrüderst (es ist eher ein heikles Thema). –

+20

:-) hab es. eval = böse mit einem Rechtschreibfehler. – potatopeelings

42

Active bietet eine Methode namens constantize, die dies tun wird. Wenn Sie auf Rails sind, von denen ich annehme, dass Sie auf dem Namen Ihrer Konstante basieren, dann haben Sie bereits ActiveSupport geladen.

require 'active_support/core_ext/string' 

class Admin 
    class MetaDatasController 
    end 
end 

"Admin::MetaDatasController".constantize # => Admin::MetaDatasController 

Um zu sehen, wie das Verfahren durchgeführt wird, überprüfen https://github.com/rails/rails/blob/85c2141fe3d7edb636a0b5e1d203f05c70db39dc/activesupport/lib/active_support/inflector/methods.rb#L230-L253

+2

Wenn Sie einen Link zu einer GitHub-Datei hinzufügen, drücken Sie y, um eine direkte Verknüpfung zu diesem bestimmten Commit zu erhalten. – Ashitaka

+1

Sie können auch 'ActiveSupport :: Inflector # constantize' verwenden, bei dem Sie nicht die gesamte String-Core-Erweiterung benötigen. – hololeap

18

In Ruby 2.x, können Sie diese einfach tun:

Object.const_get('Admin::MetaDatasController') 
=> Admin::MetaDatasController 
+1

Wenn Sie nicht wissen, ob die Konstante existiert, können Sie entweder 'Object.const_get (str) rescue nil' oder' Object.const_defined? (Str) && Object.const_get (str) ' – Phrogz

Verwandte Themen