所以我有这种情况,我想以编程方式定义一堆类.我在下面使用的方法工作正常,除了我从这里继承的第三方类不喜欢这个类是匿名定义的事实(基本上,它没有它需要的信息,即在我有机会将匿名类设置为常量之前,在’继承’钩子中的类名.
['one','two','three'].each do |model| cls = Class.new(ThirdPartyClass) do define_method :model do model end end ThirdPartyClass.const_set(model.capitalize,cls) end
我可以简单地使用eval并将类定义为:
['one','three'].each do |model| eval "class ThirdPartyClass::#{model.capitalize} < ThirdPartyClass; ...; end" end
但我不喜欢它,因为那时它是凌乱的字符串插值.基于块的方法似乎“更好”,从美学角度讲.
有没有什么方法可以使用基于块的语法非匿名地定义该类(即从头开始使用名称),或者我注定要留在eval凌乱的字符串输入的土地上?
解决方法
创建类时,将调用Class#inherited callback.在实例化匿名类时,这将始终在将类分配给常量之前,为其指定名称.我看不出有什么方法可以解决这个问题.您可以通过使用eval创建一个空类来最小化字符串eval中的代码量,该类使用在继承之前使名称可见的特殊类语法,然后以块形式跟进class_eval来定义方法.
class Super def self.inherited(child) puts "#{self.name} inherited by #{child.inspect} named '#{child.name}'" end end # Your way,inherited can't see name ['one','three'].each do |model| klassname = model.capitalize klass = Class.new(Super) do puts "defining #{model} inheriting from Super" define_method :model do model end end Super.const_set(klassname,klass) end # this way inherited sees name because we use special class definition Syntax in minimal string eval ['four','five','six'].each do |model| klassname = model.capitalize eval %Q{ class Super::#{klassname} < Super puts %Q[defining Super::#{klassname} inheriting from Super] end } Super.const_get(klassname).class_eval do puts "defining methods for Super::#{klassname} inheriting from Super" define_method :model do model end end end # produces: Super inherited by #<Class:0x0000010084c988> named '' defining one inheriting from Super Super inherited by #<Class:0x0000010084c640> named '' defining two inheriting from Super Super inherited by #<Class:0x0000010084c320> named '' defining three inheriting from Super Super inherited by Super::Four named 'Super::Four' defining Super::Four inheriting from Super defining methods for Super::Four inheriting from Super Super inherited by Super::Five named 'Super::Five' defining Super::Five inheriting from Super defining methods for Super::Five inheriting from Super Super inherited by Super::Six named 'Super::Six' defining Super::Six inheriting from Super defining methods for Super::Six inheriting from Super