Skip to content

Instantly share code, notes, and snippets.

@maraigue
Created May 15, 2011 09:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save maraigue/972998 to your computer and use it in GitHub Desktop.
Save maraigue/972998 to your computer and use it in GitHub Desktop.
Rubyのクラス名を文字列で与えて(例:"Hoge::Piyo")そのクラスのインスタンスを生成する方法
#!/usr/bin/ruby
#
# = 元ネタ
#
# Kawaz - Pythonで文字列からクラスインスタンスを生成したりメソッドを呼ぶ方法
#
# http://www.kawaz.org/blogs/miiojp/2011/05/15/106/
#
# 上記ページでは、Pythonで "hogehoge.hogenoho.HogeClass" のような文字列に
# 対して、そのクラスを利用するためのimportを行い、さらにそのクラスの
# インスタンスを生成する、という処理を記述している。
#
# これをRubyでやってみたいと思ったので挑戦してみた。
#
# = 補足
#
# ただRubyはPythonと異なり、「ライブラリを外部ファイルから読み出すときの
# 名前の指定」が、コード中でそのクラスをどう利用するかには(一般には)
# 反映されない。例えば
#
# require "foo/bar"
# Hoge::Piyo.new
#
# のようなこともあり得る。
#
# このため以下では、「そのクラスを利用するためのimportを行う」という処理に
# 対応する処理は行っておらず、単に "Hoge::Piyo" という文字列に対し、
# Hoge::Piyoクラスのインスタンスを生成する、という処理を行うことを考える。
#
# = 結論
#
# 結論から言うと、以下のようになる。
#
module Hoge
class Piyo
def initialize(x, y)
@x = x; @y = y
end
end
end
def create_instance_of(classname, *init_args)
classname.split("::").inject(Object){ |oldclass, name| oldclass.const_get(name) }.new(*init_args)
end
if $0 == __FILE__
p create_instance_of("Hoge::Piyo", 3, 5)
# Hoge::Piyo.new(3, 5)と同じ効果。
# 「#<Hoge::Piyo:0xXXXXXX @x=3, @y=5>」のような結果が出る(はず)。
end
#
# = 解説
#
# このコードを読んだだけでは、わけがわからないかもしれません。
#
# キーポイントは「oldclass.const_get(name)」である。
# これは意味としては、クラス名oldclassに対し、そのクラスに定義されている
# 定数を、名前nameを指定して取得するものである。
# (Pythonと同様、Rubyでは「クラス名」を変数に代入できる。
#  またRubyでは、クラスというのは定数の一種である。)
#
# また effect_list.inject(something){ |source, effect| ... } というのは、
# effect_listの各要素について、somethingに ... の内容を順次適用することを
# 繰り返し、最終的な結果を返すものである。例えば
#
# [1, 7, 3, 2, 7].inject(0){ |current, next_value| current + next_value }
#
# は、配列の各要素を合計したものを返す。
#
# この場合については、Object(トップレベルに定義されたクラスは、この下に
# 属する)を起点にクラス名を辿っていき、目的のクラスまで探索している。
#
# = おまけ
#
# 同ページに書いてあった、インスタンスinstに対してメソッド名がmethodnameで
# あるメソッドを呼び出す方法は、Pythonだと
#
# inst.__getattribute__(methodname)(arg1, arg2, arg3)
#
# であるが、Rubyでは
#
# inst.__send__(methodname, arg1, arg2, arg3)
#
# である。
#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment