我试图使用为我提供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。
问候!
答案 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