Wie erstelle ich eine Klasseninstanz aus einem Stringnamen in Ruby?

121

Ich habe den Namen einer Klasse und möchte eine Instanz dieser Klasse erstellen, damit ich jedes Rails-Attribut durchlaufen kann, das im Schema dieser Klasse vorhanden ist.

Wie würde ich das machen?

  1. Ich habe den Namen als Zeichenfolge der Klasse, die ich überprüfen möchte
  2. Ich denke, ich muss eine Klasseninstanz instanziieren, damit ich kann
  3. Durchlaufen Sie die Attribute und drucken Sie sie aus.
Mhenrixon
quelle
1
Das ist eine gute Frage. Danke, dass du es gefragt und mich vor der Verwendung bewahrt hasteval
David West

Antworten:

219

In Schienen können Sie einfach tun:

clazz = 'ExampleClass'.constantize

In reinem Rubin:

clazz = Object.const_get('ExampleClass')

mit Modulen:

module Foo
  class Bar
  end
end

du würdest verwenden

> clazz = 'Foo::Bar'.split('::').inject(Object) {|o,c| o.const_get c}
  => Foo::Bar 
> clazz.new
  => #<Foo::Bar:0x0000010110a4f8> 
Wir s
quelle
4
Beachten Sie, dass dies Object.const_get('Foo::Bar')nicht funktioniert constantize.
Marc-André Lafortune
Danke, bin aufgewacht, um wegen eines Admin :: User-Problems danach zu fragen :) Schlage mich dazu.
Mhenrixon
Hey @Wes, das war hilfreich, danke! Kurze Frage - würde dies auch für verschachtelte Module funktionieren? Zum Beispielclazz = 'Foo::Bar::Uber'
iaacp
@iaacp Ja, es funktioniert für so viele verschachtelte Ebenen wie Sie.
Wes
15

Sehr einfach in Rails: verwenden String#constantize

class_name = "MyClass"
instance = class_name.constantize.new
Kantenläufer
quelle
6
Für Rails nicht Ruby :(
Ethicalhack3r
Kopieren Sie die ActiveSupport-Implementierung schamlos, wenn Sie Rails noch nicht verwenden
edgerunner
6

Versuche dies:

Kernel.const_get("MyClass").new

So durchlaufen Sie die Instanzvariablen eines Objekts:

obj.instance_variables.each do |v|
  # do something
end
mbreining
quelle
Vielen Dank, da ich wirklich die Spalten des aktiven Datensatzmodells durchlaufen muss, funktioniert dies nicht für mich, aber es wird in meinen "reinen" Ruby-Apps nützlich sein :)
Mhenrixon
1
Überprüfen Sie die ActiveRecord # -Attribute () und / oder ActiveRecord # -Attributnamen ().
Mbreining
5
module One
  module Two
    class Three
      def say_hi
        puts "say hi"
      end
    end
  end
end

one = Object.const_get "One"

puts one.class # => Module

three = One::Two.const_get "Three"

puts three.class # => Class

three.new.say_hi # => "say hi"

In Ruby 2.0 und möglicherweise früheren Versionen Object.const_getwird rekursiv eine Suche in Namespaces wie durchgeführt Foo::Bar. Das obige Beispiel ist, wenn der Namespace im Voraus bekannt ist und die Tatsache hervorhebt, dass const_getModule direkt und nicht ausschließlich aufgerufen werden können Object.

A-Dubb
quelle
Sie sollten eine Erklärung hinzufügen. Ab sofort ist es nur ein Codeblock.
Josh Crozier