Jak utworzyć instancję klasy na podstawie nazwy ciągu w języku Ruby?

121

Mam nazwę klasy i chcę utworzyć wystąpienie tej klasy, aby móc przechodzić przez każdy atrybut rails obecny w schemacie tej klasy.

Jak bym to zrobił?

  1. Mam nazwę jako ciąg klasy, którą chcę sprawdzić
  2. Wydaje mi się, że muszę utworzyć instancję klasy, aby móc
  3. Przejrzyj jego atrybuty i wydrukuj je.
mhenrixon
źródło
1
To świetne pytanie. Dzięki za pytanie i uratowanie mnie przed używaniemeval
David West,

Odpowiedzi:

219

W szynach możesz po prostu zrobić:

clazz = 'ExampleClass'.constantize

W czystym rubinie:

clazz = Object.const_get('ExampleClass')

z modułami:

module Foo
  class Bar
  end
end

użyłbyś

> clazz = 'Foo::Bar'.split('::').inject(Object) {|o,c| o.const_get c}
  => Foo::Bar 
> clazz.new
  => #<Foo::Bar:0x0000010110a4f8> 
Wes
źródło
4
Zauważ, że Object.const_get('Foo::Bar')to nie zadziała, a constantizebędzie.
Marc-André Lafortune
Dzięki, obudziłem się, żeby o to zapytać z powodu problemu z Admin :: User :) Pobij mnie.
mhenrixon
Hej @Wes, to było pomocne, dzięki! Szybkie pytanie - czy to zadziała również w przypadku modułów zagnieżdżonych? Na przykładclazz = 'Foo::Bar::Uber'
iaacp
@iaacp Tak, będzie działać na tylu zagnieżdżonych poziomach, ile masz.
Wes
15

Bardzo proste w Railsach: użyj String#constantize

class_name = "MyClass"
instance = class_name.constantize.new
edgerunner
źródło
6
Dla Rails not Ruby :(
ethicalhack3r
Bezwstydnie skopiuj implementację ActiveSupport, jeśli nie używasz jeszcze Railsów
edgerunner
6

Spróbuj tego:

Kernel.const_get("MyClass").new

Następnie, aby przejść przez zmienne instancji obiektu:

obj.instance_variables.each do |v|
  # do something
end
mbreining
źródło
Dziękuję, ponieważ naprawdę muszę przeglądać kolumny modelu aktywnego rekordu, to nie zadziała dla mnie, ale przyda się w moich „czystych” aplikacjach rubinowych :)
mhenrixon
1
Sprawdź ActiveRecord # attribute () i / lub ActiveRecord # attribute_names ().
żerowanie
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"

W Ruby 2.0 i prawdopodobnie we wcześniejszych wersjach Object.const_getbędzie rekurencyjnie wyszukiwać przestrzenie nazw, takie jak Foo::Bar. Powyższy przykład dotyczy sytuacji, w których przestrzeń nazw jest znana z wyprzedzeniem i podkreśla fakt, że const_getmożna ją wywoływać bezpośrednio w modułach, a nie wyłącznie na Object.

A-Dubb
źródło
Powinieneś dodać do tego wyjaśnienie. Na razie jest to tylko blok kodu.
Josh Crozier,