在类定义之外调用Private方法

时间:2017-08-01 00:38:16

标签: ruby oop private-methods

我试图使用为我提供DSL的Gem,我需要在我的某些课程上申请。但直接使用它使我的类定义不像我想要的那样干净,所以我想将其他地方使用DSL的代码移动,这让我想到了这个问题,我将以抽象/一般的方式描述:

如果我有一个ruby类,其中包含来自另一个gem的方法作为私有,并且在docs中他们告诉在类定义中调用这些方法。

例如:

class A
  include ModuleB::PrivateMethods
end

class B < A
  do_z :param do
    set_property 'a', :x, :y, false
    set_property 'b', :x, :y, false
    set_property 'only for class B', :x, :y, true
  end

  def whatever
  end
end
# this is from the gem
module ModuleZ
  module PrivateMethods
    def self.included(base)
      base.extend Zmethods
    end
    module Zmethods
      private
      def do_z(param1, &block)
        # this method do something and calls the block
      end
    end
  end
end

例如,有没有办法干掉那些对do_z的调用 任何从A继承的类都必须这样做:

  do_z :param do
    set_property 'a', :x, :y, false
    set_property 'b', :x, :y, false
  end

  do_z :param do
    set_property 'only for class B', :x, :y, true
  end
只有B级才需要

,我不想在类定义中写这个调用但是在其他地方?

就像另一个模块一样,当包含这些调用时,即使这些方法是私有的吗?

所以我可以用这样的东西编写类定义吗?

class B < A
  include TheModuleForAllClases::AndTheOneForBclass

  def whatever
  end
end

我可以在基类上调用#do_z,然后再为每个专用类调用每个实现所需的调用,但它们仍然很多而且块非常大,所以我的类定义变得非常长,并且该类的实际方法实现隐藏在这些调用之后。

如果想知道,Gem在Rails上是swagger-docs look: documenting-a-controller

问候!

1 个答案:

答案 0 :(得分:0)

这样的事情应该有效

module AllClassesMethods
  def self.included(base)
    base.class_eval do
      do_z :param do
        set_property 'a', :x, :y, false
        set_property 'b', :x, :y, false
      end
    end
  end
end

module OnlyBMethods
  def self.included(base)
    base.class_eval do
      do_z :param do
        set_property 'only for class B', :x, :y, true
      end
    end
  end
end

class A
  include ModuleB::PrivateMethods
  include AllClassesMethods

  def self.inherited(klass)
    klass.include AllClassesMethods
  end
end

class B < A
  include OnlyBMethods
end

A,任何继承自A的类都将包含AllClassesMethods,并在其included方法中运行代码。它必须明确地包含在每个继承的类中,否则只会为父included调用A方法。 class_eval块在包含类的上下文中执行,因此就像在类定义中打开类一样。只有B包括OnlyBMethods,因此是唯一一个触发included两个模块实施的人。

您可以使用另一种方法。如果在extend ed模块中定义类方法宏,则类方法将在类上下文中执行,也可以让您轻松访问它的私有方法(我说“简单”访问,因为在Ruby中你总是可以使用send

从任何上下文访问对象的私有方法
module AllClassesMethods
  def does_z
    do_z :param do
      set_property 'a', :x, :y, false
      set_property 'b', :x, :y, false
    end
  end

  def does_z_for_b
    do_z :param do
      set_property 'only for class B', :x, :y, true
    end
  end
end

class A
  include ModuleB::PrivateMethods
  extend AllClassesMethods

  does_z

  def self.inherited(klass)
    klass.does_z
  end
end

class B < A
  does_z_for_b
end