【问题标题】:Having a module singleton extending a class有一个模块单例扩展一个类
【发布时间】:2014-10-27 08:19:46
【问题描述】:

我的应用程序中有一个可以跨应用程序重用的单例。我希望那个单例从我的类中获取一些默认方法,但也能够自定义模块/特征类。最重要的是,我不想在每次调用实用程序单例时都调用 instance

这是一个例子。假设我的默认课程是Universe::Earth。然后我想在我的应用程序中添加一个 Earth 模块来“扩展”该类。

module Universe
  class Earth
    def self.grow!
      @grown = true
    end
  end
end

module Earth
  class < Universe::Earth << self; end

  grow!
end

运行时,grow!NoMethodError

尝试了这些方法:

Class.new(Goodluck::Contest) << self
class < Universe::Earth << self; end
extend Universe::Earth

如何让它发挥作用?

【问题讨论】:

  • 不完全。我正在尝试为它创建一个 DSL。所以每次打电话Earth 会很痛苦。
  • 乔纳森,很抱歉延迟修改我的答案。如果它仍然不能回答您的问题,请告诉我。

标签: ruby eigenclass


【解决方案1】:

这是你要找的东西吗?

module Universe
  class Earth
    def self.grow!
      @grown = true
    end
  end
end

module Earth
  Universe::Earth.class_eval do
    define_method(:instance_howdy) do
      puts "instance_howdy!"
    end
  end
  def (Universe::Earth).class_howdy
    puts "class_howdy!"
  end
end

Universe::Earth.methods(false)          #=> [:grow!, :class_howdy]
Universe::Earth.instance_methods(false) #=> [:instance_howdy]
Universe::Earth.new.instance_howdy      #=> instance_howdy!
Universe::Earth.class_howdy             #=> class_howdy!

[编辑:如果你只想设置@grown =&gt; true,并检索它的值,你只需要:

module Earth
  Universe::Earth.grow! #=> true
end

验证:

Universe::Earth.instance_variable_get("@grown") #=> true

如果您还希望为类实例变量添加访问器,您可以这样做:

def add_class_accessor(c, accessor, var)  
  c.singleton_class.class_eval("#{accessor} :#{var}")
end

Universe::Earth.methods(false)
  #=> [:grow!]

module Earth
  Universe::Earth.grow! #=> true
  add_class_accessor(Universe::Earth, "attr_accessor", "grown")
end

Universe::Earth.methods(false)
  #=> [:grow!, :grown, :grown=]

Universe::Earth.grown
  #=> true
Universe::Earth.grown = "cat"
  #=> "cat"
Universe::Earth.grown
  #=> "cat"

Object#singleton_class 在 Ruby 1.9.2 中添加。对于早期版本,您可以这样做:

def add_class_accessor(c, accessor, var)
  eigenclass = class << c; self; end
  eigenclass.class_eval("#{accessor} :#{var}")
end

您可以考虑将add_class_accessor 放入一个模块中,以便根据需要包含在内。您可能添加到同一模块的其他方法可能是:

add_instance_method(klass, method, &block)
add_class_method(klass, method, &block)
add_instance_accessor(klass, accessor, var)

:tidE

【讨论】:

  • 我正在尝试制作 Earth.grow!; Earth.grown == true(假设 attr 阅读器)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-07
  • 2014-02-18
  • 2020-01-17
  • 2020-10-05
  • 1970-01-01
  • 1970-01-01
  • 2013-05-24
相关资源
最近更新 更多