【问题标题】:Using overridden class constants in class methods在类方法中使用重写的类常量
【发布时间】:2016-05-25 23:11:58
【问题描述】:

要覆盖子类中的类常量,可以这样做:

class Foo
  CONST = [:foo, :baz]

  def self.const
    self::CONST
  end

end

class Bar < Foo
  CONST = [:foo, :bar]
end

print Foo.const # [:foo, :baz]
print Bar.const # [:foo, :bar]

这按预期工作。问题是当我尝试从类方法调用它时,例如在使用 define_method 时:

class Foo
  CONST = [:foo, :baz]

  def self.const
    self::CONST
  end

  self.const.each do |c|
    define_method("#{c}?") {
      "#{c} exists"
    }
  end
end


foo = Foo.new
print foo.baz? # baz exists.

bar = Bar.new
print bar.bar? # undefined method `bar?'

如何重写类常量,以便在这种情况下定义正确的方法bar?,而不必复制子类中的代码?有没有一种 DRY 方式可以做到这一点,而不必使用类变量而不是类常量?

【问题讨论】:

  • 不清楚您要做什么。不复制子类中的代码不就行了吗?
  • @sawa:是的,但它不起作用:)
  • 怎么不工作了?
  • @sawa: undefined method bar?
  • 你不想这样吗?

标签: ruby


【解决方案1】:

因为 define_method 是在词法范围内运行的,即它内联在 Foo 类定义的主体中,所以没有什么可以让它在 Bar 中运行。

class Foo
  CONST = [:foo, :baz]

  def self.define_const_methods(const)
    const.each do |c|
      define_method("#{c}?") { "#{c} exists" }
    end
  end

  define_const_methods(CONST)
end

class Bar < Foo
  CONST = [:foo, :bar]
  define_const_methods(CONST)
end

这应该可以解决问题。因此,您在其词法范围内的 Foo 类末尾调用 define_const_methods 。你也可以在任何继承它的类上调用它。继承类应该找到它自己的常量版本。

但这很丑陋,因此您可以完全省去常量,只需使用 define_const_methods 来定义它们。就像 ActiveRecord 在定义关联方法(has_one、has_many 等)时所做的那样。因此,您可以将其缩减为;

class Foo
  def self.define_my_methods(meths)
    meths.each do |c|
      define_method("#{c}?") { "#{c} exists" }
    end
  end

  define_my_methods [:foo, :baz]
end

class Bar < Foo
  define_my_methods [:foo, :bar]
end

【讨论】:

  • 我必须这样做self::CONST.each。此外,它可以在没有 self.inherited 方法的情况下工作。难道没有更好的方法来完成我想做的事情吗?
  • 你测试了吗?由于我在我的 cmets 中给出的原因,这不起作用。 Dan,如果你在 IRB 中测试这个,你必须每次都重新加载 IRB。否则,您可能会在 Bar 已经定义时运行它,在这种情况下它看起来可以正常工作。
  • @CarySwoveland:我不是。我从命令行将它作为文件运行。但这不是我正在寻找的解决方案。我应该改用类变量吗?
  • @dan-klasson 是的,继承有点考验。因为常量都是词法的,我想看看在哪里实际调用了继承。我刚刚保存了我的最终编辑。总而言之,不要使用常量。
  • @james2m:现在这是我喜欢的解决方案。我完全是在偷那个。
猜你喜欢
  • 2020-08-13
  • 2019-05-18
  • 2016-01-18
  • 2021-03-13
  • 2017-07-07
  • 1970-01-01
  • 2012-06-15
  • 2014-12-31
  • 1970-01-01
相关资源
最近更新 更多