Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 具有类名的动态类定义_Ruby_Class_Dynamic_Metaprogramming - Fatal编程技术网

Ruby 具有类名的动态类定义

Ruby 具有类名的动态类定义,ruby,class,dynamic,metaprogramming,Ruby,Class,Dynamic,Metaprogramming,如何在Ruby中用名称动态定义类? 我知道如何动态创建一个类,而不使用类似以下内容的名称: dynamic_class = Class.new do def method1 end end 但不能指定类名。我想用一个名字动态创建一个类 下面是我想做的一个例子,但当然它实际上不起作用。 (请注意,我不是在创建类的实例,而是在创建类定义) 实际产量: dummy: TestEval dummy2: 期望输出: dummy: TestEval dummy2: TestEval2 ===

如何在Ruby中用名称动态定义类?

我知道如何动态创建一个类,而不使用类似以下内容的名称:

dynamic_class = Class.new do
  def method1
  end
end
但不能指定类名。我想用一个名字动态创建一个类

下面是我想做的一个例子,但当然它实际上不起作用。
(请注意,我不是在创建类的实例,而是在创建类定义)

实际产量:

dummy: TestEval
dummy2: 
期望输出:

dummy: TestEval
dummy2: TestEval2
======================================================

回答:使用sepp2k方法的完全动态解决方案

dynamic_name = "TestEval2"

Object.const_set(dynamic_name, Class.new) # If inheriting, use Class.new( superclass )
dummy2 = eval("#{dynamic_name}")
puts "dummy2: #{dummy2}"

类的名称只是引用它的第一个常量的名称

也就是说,如果我执行
myclass=Class.new
,然后执行
myclass=myclass
,则类的名称将变为
myclass
。但是,如果在运行时之前我不知道类的名称,我就不能执行
MyClass=

因此,您可以使用
模块#const_set
,它可以动态设置const的值。例如:

dynamic_name = "ClassName"
Object.const_set(dynamic_name, Class.new { def method1() 42 end })
ClassName.new.method1 #=> 42

我也一直在胡闹。在我的例子中,我试图测试ActiveRecord::Base的扩展。我需要能够动态创建一个类,并且因为活动记录根据类名查找表,所以该类不能是匿名的

我不确定这是否有助于你的案子,但我想到的是:

test_model_class = Class.new(ActiveRecord::Base) do
  def self.name
    'TestModel'
  end

  attr_accessor :foo, :bar
end
就ActiveRecord而言,定义self.name就足够了。我猜这实际上适用于所有不能匿名的类


(我刚刚读了sepp2k的答案,我认为他的更好。无论如何,我将把这个留在这里。)

下面的代码如何:

dynamic_name = "TestEval2"
class_string = """
class #{dynamic_name}
  def method1
  end
end
"""
eval(class_string)
dummy2 = Object.const_get(dynamic_name)
puts "dummy2: #{dummy2}"

Eval不会重新运行运行时类对象,至少在我的电脑上不会。使用Object.const_get获取类对象。

我知道这是一个非常老的问题,其他一些Rubyists可能会因此避开我,但我正在创建一个非常薄的包装器gem,它用ruby类包装一个流行的java项目。基于@sepp2k的答案,我创建了两个helper方法,因为我必须在一个项目中多次这样做。注意,我给这些方法命名了名称空间,这样它们就不会污染像对象或内核这样的顶级名称空间

module Redbeam
  # helper method to create thin class wrappers easily within the given namespace
  # 
  # @param  parent_klass [Class] parent class of the klasses
  # @param  klasses [Array[String, Class]] 2D array of [class, superclass]
  #   where each class is a String name of the class to create and superclass
  #   is the class the new class will inherit from
  def self.create_klasses(parent_klass, klasses)
    parent_klass.instance_eval do
      klasses.each do |klass, superklass|
        parent_klass.const_set klass, Class.new(superklass)
      end
    end
  end

  # helper method to create thin module wrappers easily within the given namespace
  # 
  # @param parent_klass [Class] parent class of the modules
  # @param modules [Array[String, Module]] 2D array of [module, supermodule]
  #   where each module is a String name of the module to create and supermodule
  #   is the module the new module will extend
  def self.create_modules(parent_klass, modules)
    parent_klass.instance_eval do
      modules.each do |new_module, supermodule|
        parent_klass.const_set new_module, Module.new { extend supermodule }
      end
    end
  end
end
要使用这些方法(请注意,这是JRuby):

为什么??

这允许我创建一个使用Java项目的JRubyGem,并允许开源社区和我在将来根据需要装饰这些类。它还创建了一个更友好的名称空间来使用中的类。因为我的gem是一个非常非常薄的包装器,所以我必须创建很多很多子类和模块来扩展其他模块


正如我们在J.D.Power所说,“这是道歉驱动的发展:我很抱歉”。

我真的没有得到你想要实现的目标。有一个类TestEval2,您可以在之后执行test_eval2=TestEval2.new。和:A级。。。end总是产生nil,所以我想您的输出是可以的;-)这是一个TDD测试步骤。我需要动态创建一个测试类,然后引用它的名称,因为这就是它在野外的使用方式。sepp2K做对了。@Philip:
class-A。。。end
的计算结果不是
nil
,它的计算结果是在它内部计算的最后一个表达式的值,就像Ruby中的所有其他复合表达式(块、方法、模块定义、表达式组)一样。恰好在许多类定义体中,最后一个表达式是方法定义表达式,其计算结果为
nil
。但是,有时让类定义体计算为特定值是有用的,例如在
类中!谢谢这正是我需要的。谢谢。这对我很有帮助:哇。对我来说,(常量)赋值有这样的副作用似乎很奇怪。出于某种原因,这在开发中对我有效,但在生产中无效。我尝试在新类本身上设置常量,但没有任何效果。有了对象,它就工作了。谢谢。不过,它可以在不使用
eval
的情况下完成。使用
eval
,您必须清理输入以防止恶意代码执行。顺便说一句,您可以明确设置类的表名,如下所示:
self.table\u name=“my\u things”
@EarlJenkins,如果此类中定义了关联(例如,属于),
self.name
是必需的,否则
#demodulize
将在尝试遵循关联时在nil上失败:(至少我在Rails 5.2.3中就是这样)。
module Redbeam
  # helper method to create thin class wrappers easily within the given namespace
  # 
  # @param  parent_klass [Class] parent class of the klasses
  # @param  klasses [Array[String, Class]] 2D array of [class, superclass]
  #   where each class is a String name of the class to create and superclass
  #   is the class the new class will inherit from
  def self.create_klasses(parent_klass, klasses)
    parent_klass.instance_eval do
      klasses.each do |klass, superklass|
        parent_klass.const_set klass, Class.new(superklass)
      end
    end
  end

  # helper method to create thin module wrappers easily within the given namespace
  # 
  # @param parent_klass [Class] parent class of the modules
  # @param modules [Array[String, Module]] 2D array of [module, supermodule]
  #   where each module is a String name of the module to create and supermodule
  #   is the module the new module will extend
  def self.create_modules(parent_klass, modules)
    parent_klass.instance_eval do
      modules.each do |new_module, supermodule|
        parent_klass.const_set new_module, Module.new { extend supermodule }
      end
    end
  end
end
module Redbeam::Options
  Redbeam.create_klasses(self, [
    ['PipelineOptionsFactory', org.apache.beam.sdk.options.PipelineOptionsFactory]
  ])
  Redbeam.create_modules(self, [
    ['PipelineOptions', org.apache.beam.sdk.options.PipelineOptions]
  ])
end