【一人 Ruby Advent Calendar 2017】文字列から任意のクラスオブジェクトを取得する【2日目】

一人 Ruby Advent Calendar 2017 2日目の記事になります。
今回は "Integer" みたいな文字列からその名前のクラスオブジェクトを参照する方法を書いてみます。

定義したクラスは誰が保持するのか

Ruby でクラスを定義すると『そのスコープの定数』としてクラスオブジェクトが保持されます。
例えば、下記のように Hoge クラスのサブクラスとして定義した場合は Hoge クラスの定数として定義されます。

class Hoge
    PI = 3.14

    class Foo
    end
end

p Hoge.constants
# => [:PI, :Foo]
p Hoge.const_get "Foo"
# => Hoge::Foo

なのでサブクラスの場合は Hoge.const_get "クラス名" のような形でクラスオブジェクトを取得する事ができます。

トップレベルで定義されているクラスオブジェクトを取得する

トップレベルで定義されているクラスは Object クラスが保持しているので、Object クラスの定数から取得することができます。

p Object.constants
# => [:Binding, :Math, :StringIO, :Integer, :Float, :String, :Array, :Hash, :NilClass, :STDOUT, :STDIN, :NIL, :STDERR, :ARGF, :UncaughtThrowError, :SimpleDelegator, :FileTest, :File, :Delegator, :GC, :Fiber, :FiberError, :Data, :TrueClass, :TRUE, :FalseClass, :FALSE, :Encoding, :ZeroDivisionError, :FloatDomainError, :Numeric, :Rational, :Hoge, :ObjectSpace, :Gem, :DidYouMean, :ENV, :Complex, :Struct, :RegexpError, :Comparable, :Enumerator, :Enumerable, :Regexp, :RUBY_VERSION, :RUBY_RELEASE_DATE, :StopIteration, :RUBY_PLATFORM, :Fixnum, :RubyVM, :Thread, :RUBY_REVISION, :RUBY_DESCRIPTION, :RUBY_PATCHLEVEL, :RUBY_ENGINE, :RUBY_ENGINE_VERSION, :RUBY_COPYRIGHT, :TracePoint, :MatchData, :TOPLEVEL_BINDING, :CROSS_COMPILING, :Bignum, :ARGV, :ThreadGroup, :Dir, :ThreadError, :Mutex, :Queue, :ClosedQueueError, :SizedQueue, :ConditionVariable, :Marshal, :Time, :Range, :IOError, :EOFError, :Process, :Monitor, :IO, :RbConfig, :MonitorMixin, :Random, :Symbol, :Exception, :Signal, :SystemExit, :BasicObject, :Object, :Module, :Class, :Kernel, :Interrupt, :StandardError, :SignalException, :Proc, :IndexError, :TypeError, :ArgumentError, :ScriptError, :KeyError, :RangeError, :NotImplementedError, :SyntaxError, :LoadError, :SystemStackError, :NoMethodError, :Method, :RuntimeError, :SecurityError, :NoMemoryError, :EncodingError, :NameError, :SystemCallError, :UnboundMethod, :Errno, :Warning, :LocalJumpError, :RUBYGEMS_ACTIVATION_MONITOR]

p Object.const_get "Integer"
# => Integer


class Hoge
    class Foo
    end
end


# サブクラスの場合は A::B という風に取得することが出来る
p Object.const_get "Hoge::Foo"
# => Hoge::Foo

ネストしてるサブクラスも A::B で取得することができるので便利ですね。