我希望创建一种方法,使子类在类级别上表达一些业务定义。
我试图使用类变量来实现这个目的,但是我发现它们在所有类之间共享状态,所以一旦我定义了第二个类,“@”属性类变量就为所有相邻的类实例更改其值。

class Parent
  def self.type(value)
    @@_type = value
  end

  def render
    puts @@_type
  end
end

class Children < Parent
  type "name"
end

Children.new.render # Result: name. Expected: name

class Children2 < Parent
  type "title"
end

Children2.new.render # Result: title. Expected: title
Children.new.render # Result: title. Expected: name

如何以最简单直接的方式创建这个dsl?
这是几种红宝石的常见模式,如HTTParty、Virtus等。
我甚至试着看看他们的源代码来理解它是如何完成的,但是对于我想要的来说,它似乎太复杂了。
谢谢你的帮助!

最佳答案

类变量是Ruby工具的三元组之一,大多数有经验的Rubiest很少使用。相反,您希望使用类级实例变量,Parent是类的实例。

class Parent
  def self.type=(value)
    @type = value
  end

  def self.type
    @type
  end

  def render
    puts self.class.type
  end
end

class Children < Parent
  self.type = "name"
end

Children.new.render
  #=> "name"

class Children2 < Parent
  self.type = "title"
end

Children2.new.render
  #=> "title"
Children.new.render
  #=> "name"

首先,类方法Class称为“setter”,类方法“type”称为“getter”。你有个二传手,在争论如果你这样做,你怎么才能得到它的价值呢要同时使用它作为一个getter,您必须执行以下操作:
  def self.type=(value=nil)
    if value.nil?
      @type
    else
      @type = value
    end
  end

在这里,定义一个getter更有意义
  def self.type
    @type
  end

没有setter,只是写,例如,type=
这是不可靠的,只有当您不想将type设置为@type = "name"时才有效您也可以将方法保留为setter并使用@type获取其值,但这同样糟糕最好有一个二传手和一个盖特手。
当使用setter时,我们需要在nil前面加上self.class.instance_variable_get(:@type)来告诉ruby我们希望调用getter,而不是将局部变量type设置为给定值。当然,我们可以只写,例如,`@type=“title”。
创建setter和getter的传统方法是编写self.(调用类方法Module#attr_accessor)由于类方法存储在类的singleton类中,可以按以下方式执行2:
class Parent
  class << self
    attr_accessor :type
  end
  def render
    puts self.class.type
  end
end

class Children < Parent
  self.type = "name"
end

Children.new.render
  #=> "name"

class Children2 < Parent
  self.type = "title"
end

现在考虑实例方法type作为实例方法,它的接收者是类(或子类)的实例,比如attr_accessor :type这意味着当在方法Parent#render中调用parent = Parent.new时,等于render。但是,我们想调用类方法self。因此,我们必须将parent转换为type,这是用parent实现的。
一另外两个(当然,在我看来)是全局变量和Parent循环。他们在ruby新手中的受欢迎程度可能是因为他们倾向于在许多学习ruby的书籍的第一章中首次亮相。
2在self.class的单例类中有很多定义for的方法。另外两个是attr_accessorParent

10-05 21:06
查看更多