ruby - 跨模块共享一个类

时间:2014-05-30 22:39:30

标签: ruby module metaprogramming

我正在尝试使用一组简单的ruby对象模仿ActiveRecord来运行原始sql查询。以下是我一直在试验的峰值:

module Runable
  def run
    return self::Results.new
  end
end

module Query
  class Results  
    def initialize
      @results = Object.find_by_sql()
    end

    def to_a
      #code
    end
  end
end

module Scored
  extend Runable
  include Query

  QUERY = 'a raw sql query string'
end

module Unseen
  extend Runable
  include Query

  QUERY = 'a different raw sql query string'
end

我希望能够为我将要运行的每种原始sql查询创建简单的模块,将它们放入上面的ScoredUnseen等文件中并调用{ {1}}在他们身上找回结果对象。像这样:

.run

但我得到了这个......

Scored.run #=> #<Scored::Results:0x0000000000>
Unseen.run #=> #<Unseen::Results:0x0000000000>

我一直在做红宝石和铁轨超过一年但我刚刚开始使用更高级的红宝石用法。这是我使用模块和mixins的第一步。

据我所知,问题是模块类方法的自定义范围是它们定义的模块。所以我得到Scored.run #=> #<Query::Results:0x0000000000> Unseen.run #=> #<Query::Results:0x0000000000> 因为结果的initialize方法在Query模块中定义。这有道理吗?

感谢您的帮助!

更新5/30 16:45

基本上,我想将一些原始SQL语句包装到这样的模块中:

Query::Results

并与这样的查询互动:

module ScoredUsers
  include Queryable

  QUERY="SELECT * FROM users ..."
end

我希望将所有内容保存在模块和类中,这是红宝石的方式(我认为?)所以当我想创建一个新的查询对象时,我可以简单地使用上面的r = ScoredUsers.run #=> ScoredUsers::Results r.ids r.load_objects REDIS.zadd user:5:cache, r.to_a 这样的样板模块。

1 个答案:

答案 0 :(得分:1)

您获得此类结果的原因是类Results只创建一次。当包含模块时,在包含类(Scored::Results)的内部创建新常量,但它指向与常量Query::Results相同的内存空间。

你需要的是你必须为这个模块所包含的每个类创建一个新类。这是使用included方法的绝佳机会:

module Query
  def self.included(mod)
    results = Class.new do  
      def initialize
        @results = Object.find_by_sql()
      end

      def to_a
        #code
      end
    end
    mod.const_set('Results', results)        
  end
end

现在我们当然还有问题 - 我们真的需要这样做吗?这取决于您计划如何使用这些类。