如何在Ruby中封装包含的模块方法?

Chr*_*son 6 ruby oop encapsulation module ruby-on-rails

我希望能够在模块中使用包含该模块的类无法访问的方法.给出以下示例:

class Foo
  include Bar

  def do_stuff
    common_method_name
  end
end

module Bar
  def do_stuff
    common_method_name
  end

  private
  def common_method_name
    #blah blah
  end
end
Run Code Online (Sandbox Code Playgroud)

我希望Foo.new.do_stuff爆炸,因为它试图访问模块试图隐藏它的方法.但是,在上面的代码中,Foo.new.do_stuff可以正常工作:(

有没有办法在Ruby中实现我想做的事情?

更新 - 真正的代码

class Place < ActiveRecord::Base
  include RecursiveTreeQueries

  belongs_to :parent, {:class_name => "Place"}
  has_many :children, {:class_name => 'Place', :foreign_key => "parent_id"}
end


module RecursiveTreeQueries

  def self_and_descendants
     model_table = self.class.arel_table
     temp_table = Arel::Table.new :temp
     r = Arel::SelectManager.new(self.class.arel_engine).from(model_table).project(model_table.columns).join(temp_table).on('true').where(model_table[:parent_id].eq(temp_table[:id]))
     nr = Place.scoped.where(:id => id)
     q = Arel::SelectManager.new(self.class.arel_engine)
     as = Arel::Nodes::As.new temp_table, nr.union(r)
     arel = Arel::SelectManager.new(self.class.arel_engine).with(:recursive,as).from(temp_table).project(temp_table[:id])
     self.class.where(model_table[:id].in(arel))
   end  

  def self_and_ascendants
    model_table = self.class.arel_table
    temp_table = Arel::Table.new :temp
    r = Arel::SelectManager.new(self.class.arel_engine).from(model_table).project(model_table.columns).join(temp_table).on('true').where(temp_table[:parent_id].eq(model_table[:id]))
    nr = Place.scoped.where(:id => id)
    q = Arel::SelectManager.new(self.class.arel_engine)
    as = Arel::Nodes::As.new temp_table, nr.union(r)
    arel = Arel::SelectManager.new(self.class.arel_engine).with(:recursive,as).from(temp_table).project(temp_table[:id])
    self.class.where(model_table[:id].in(arel))
 end

end
Run Code Online (Sandbox Code Playgroud)

很明显,这段代码被黑了,并且由于一些严重的重构,我的问题的目的是找出是否有一种方法可以重构这个模块,而不会因为意外覆盖ActiveRecord :: Base或其他任何模块中包含的任何其他模块而不受惩罚. Place.rb.

Bra*_*dan 5

我不相信有任何直接的方法来做到这一点,这是设计的.如果需要封装行为,则可能需要类,而不是模块.

在Ruby中,私有方法和公共方法之间的主要区别是私有方法只能在没有显式接收器的情况下调用.调用MyObject.new.my_private_method将导致错误,但my_private_method在方法定义中调用MyObject将正常工作.

将模块混合到类中时,该模块的方法将"复制"到类中:

[I]如果我们在类定义中包含一个模块,它的方法可以有效地附加到类中,或者"混入"到类中.- Ruby用户指南

就课程而言,该模块不再作为外部实体存在(但请参阅Marc Talbot在下面的评论).您可以在类中调用任何模块的方法而无需指定接收器,因此它们实际上不再是模块的"私有"方法,只是类的私有方法.