【问题标题】:ruby : how can I avoid hardcoding the classes names?ruby:如何避免对类名进行硬编码?
【发布时间】:2020-05-28 21:50:05
【问题描述】:

我正在学习 Ruby 以及类变量和实例变量之间的区别。

我正在编写一段代码,其中有(很多)类继承了其他类。

class childImporter < parentImporter

  def self.infos
    parentImporter.infos.merge({
      :name=>           'My Importer',
    })
  end

  def self.schema
    schema = parentImporter.schema.deep_merge({
      'selectors' => {
        'track' => {
          'artist'=>  {'path'=>{'default'=>'//creator'}},
          'title'=>   {'path'=>{'default'=>['//name'}},
        }
      }
    })

    @@schema = schema
  end


  def initialize(params = {})
    super(params,childImporter.schema)
  end

end

我有两个类变量:infos(进口商信息)和schema(json 模式)。

我需要它们能够将它们放到实例之外(这就是它们是类变量的原因),并成为它们父值的扩展(这就是我deep_merge它们的原因),和

我的示例确实有效,但我想知道是否有办法不对类名 childImporter 和 parentImporter 进行硬编码,而是使用对父类的引用,例如具有

schema = PARENTCLASS.schema.deep_merge({

而不是

schema = parentImporter.schema.deep_merge({

super(params,THISCLASS.schema)

而不是

super(params,childImporter.schema).

有没有办法做到这一点?

目前,如果我尝试

超级(参数,@@schema)

我明白了

NameError:childImporter 中未初始化的类变量@@schema

谢谢

【问题讨论】:

  • Ruby 中的类名必须以大写字母开头。您的{'default'=&gt;['//name'} 中有语法错误。除此之外,您可能希望将您的代码转换为 minimal reproducible example,以便我们可以实际运行它。

标签: ruby instance-variables class-variables


【解决方案1】:

我想知道是否有办法不对类名 childImporter 和 parentImporter 进行硬编码,而是使用对父类的引用,例如有

schema = PARENTCLASS.schema.deep_merge({

而不是

schema = parentImporter.schema.deep_merge({

您正在寻找的方法是superclass——它返回接收者的父类。在类主体或类方法中,您可以在没有显式接收者的情况下调用它:

class ParentImporter
  def self.infos
    { name: 'Parent Importer', type: 'Importer' }
  end
end

class ChildImporter < ParentImporter
  def self.infos
    superclass.infos.merge(name: 'Child Importer')
  end
end

ParentImporter.infos #=> {:name=>"Parent Importer", :type=>"Importer"}
ChildImporter.infos  #=> {:name=>"Child Importer", :type=>"Importer"}

但还有一种更简单的方法。类inherit 两者,类方法和来自其父类的实例方法。在这两种变体中,您都可以简单地调用 super 来调用父级的实现:

class ChildImporter < ParentImporter
  def self.infos
    super.merge(name: 'Child Importer')
  end
end

ParentImporter.infos #=> {:name=>"Parent Importer", :type=>"Importer"}
ChildImporter.infos  #=> {:name=>"Child Importer", :type=>"Importer"}

此外,您可能希望memoize 这些值,这样就不会在每次调用方法时都重新创建它们:

class ParentImporter
  def self.infos
    @infos ||= { name: 'Parent Importer', type: 'Importer' }
  end
end

class ChildImporter < ParentImporter
  def self.infos
    @infos ||= super.merge(name: 'Child Importer')
  end
end

那些@infos 是所谓的类实例变量,即类对象范围内的实例变量。它们的行为与临时实例中的实例变量完全相同。特别是ParentImporter中的@infosChildImporter中的@infos之间没有任何联系。


super(params,THISCLASS.schema)

而不是

super(params,childImporter.schema).

要获取一个对象的类,可以调用它的class方法:

importer = ChildImporter.new

importer.class       #=> ChildImporter
importer.class.infos #=> {:name=>"Child Importer", :type=>"Importer"}

在实例方法中也是如此:

  def initialize(params = {})
    super(params, self.class.schema)
  end

请注意,class 方法必须始终使用显式接收器调用。省略接收者而只写class.schema 会导致错误。


底部注释:我根本不会使用@@ 类变量。只需调用您的类方法即可。

【讨论】:

    【解决方案2】:

    这可能会有所帮助 - 您可以像这样访问类和超类:

     class Parent
        
     end
        
     class Child < Parent
        
       def self.print_classes
         p itself
         p superclass
       end
      end
        
     Child.print_classes
    

    这将打印出来

    孩子

    父母

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-19
      • 1970-01-01
      • 2022-10-31
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      • 1970-01-01
      相关资源
      最近更新 更多