1. ホーム
  2. ruby

[解決済み] Rubyでリフレクション?

2022-02-18 20:34:14

質問

この仕組みが気になります。例えば、ファクトリーパターンに基づいたクラスを作成し、後で使用するクラスを登録し、次のようなことを行うとします。

FactoryClass.register('YourClassName', [param, param, ...]);
FactoryClass.create('your_class_name').call_method_from_this_object

ここで 'class_name' は値にマップされるハッシュのキーです。 ClassName

のようなものはありますか? phpリフレクション 文字列名に基づいてクラスのインスタンスを作成し、引数を渡すことができるのでしょうか?(phpでは、引数はそれらの配列になり、phpはそれをどのように扱うか知っています)

では、実際の例を挙げてみると。

class Foo
  attr_reader :something

  def initialize(input)
    @something = input
  end

  def get_something
    return @something
  end
end

# In the factory class, foo is then placed in a hash: {'foo' => 'Foo'}
# This step might not be required??
FactoryClass.create('Foo', ['hello'])

# Some where in your code:
FactoryClass.create('foo').get_something # => hello

これはrubyで可能なのでしょうか?しかし、このような文字列名からクラスインスタンスを作成し、オブジェクトを渡すためのAPIやドキュメントを見たことがありません。

上のハッシュについては、今考えると、おそらく次のようなことをしなければならないでしょう。

{'foo' => {'class' => 'Foo', 'params' => [param, param, ...]}}

この方法では .create の上で FactoryClass をインスタンス化することができます。 Foo を、関連するパラメータと一緒に指定します。

もし、私の考えが大きく外れていたら、遠慮なくご教示ください。

解決方法は?

を使用しない回答があります。 eval .

PHPの Reflection というのは Metaprogramming というように、Rubyとは全く異なるものです。Rubyではすべてがオープンで、アクセスすることができる。

次のようなコードを考えてみましょう。

class Foo
  attr_reader :something

  def initialize(input)
    @something = input
  end

  def get_something
    return @something
  end
end

@registered = { }
def register(reference_name, class_name, params=[])
  @registered[reference_name] = { class_name: class_name, params: [params].flatten }
end

def create(reference_name)
  h = @registered[reference_name]
  Object.const_get(h[:class_name]).new(*(h[:params]))
end

register('foo', 'Foo', ['something'])
puts create('foo').get_something

を使用することができます。 Object#const_get を使って、文字列からオブジェクトを取得することができます。 Object.const_get('Foo') はオブジェクトを与えます。 Foo .

しかし、クラス名を文字列で送る必要はありません。クラス名をオブジェクトとして渡し、それを直接使用することもできます。

class Foo
  attr_reader :something

  def initialize(input)
    @something = input
  end

  def get_something
    return @something
  end
end

@registered = { }
def register(reference_name, class_name, params=[])
  @registered[reference_name] = { class_name: class_name, params: [params].flatten }
end

def create(reference_name)
  h = @registered[reference_name]
  h[:class_name].new(*(h[:params]))
end

register('foo', Foo, ['something else'])
puts create('foo').get_something