如何实现DSL以通过方法链动态创建新方法?
我有一个类别和该类的实例:
class Thing
def initialize
@name = name
end
end
a = Thing.new("a")
我想通过像这样的调用DSL来动态创建方法并设置其返回值:
如果我写a.is_a.person
- 。 创建方法
- ?应为
a
A.person
?应该返回true
如果我写a.is_not_a.man
- 创建方法
- 应该为
a
a.man?
a man ? 写
a.is_the.parent_of.joe
- a
parent_of
应该为a
a.parent_of
应该返回<<应该返回<<代码> joe
我尝试执行此操作
class Thing
attr_reader :name
def initialize(name)
@name = name
end
def is_a
Class.new do
def initialize base
@base = base
end
def method_missing name
@base.define_singleton_method "#{name}?" do
true
end
end
end.new self
end
def is_not_a
Class.new do
def initialize base
@base = base
end
def method_missing name
@base.define_singleton_method "#{name}?" do
false
end
end
end.new self
end
end
,它适用于is_a
和is_not_a
,如上所述:
jane = Thing.new('Jane')
jane.is_a.person
jane.person? #=> true
jane.is_a.woman
jane.woman? #=> true
jane.is_not_a.man
jane.man? #=> false
但是对于jane.is_is_the..parent_of.joe.joe.joe < /code>,就像更深层的链接一样,我无法弄清楚如何实现它。
我该如何处理?
I have a class and an instance of that class:
class Thing
def initialize
@name = name
end
end
a = Thing.new("a")
I want to dynamically create methods and set their return values by calling a DSL like this:
If I write a.is_a.person
:
- a
person?
method should be created fora
a.person?
should returntrue
If I write a.is_not_a.man
- a
man?
method should be created fora
a.man?
should returnfalse
If I write a.is_the.parent_of.joe
- a
parent_of
method should be created fora
a.parent_of
should returnjoe
I tried doing this
class Thing
attr_reader :name
def initialize(name)
@name = name
end
def is_a
Class.new do
def initialize base
@base = base
end
def method_missing name
@base.define_singleton_method "#{name}?" do
true
end
end
end.new self
end
def is_not_a
Class.new do
def initialize base
@base = base
end
def method_missing name
@base.define_singleton_method "#{name}?" do
false
end
end
end.new self
end
end
And it works for is_a
and is_not_a
as defined above:
jane = Thing.new('Jane')
jane.is_a.person
jane.person? #=> true
jane.is_a.woman
jane.woman? #=> true
jane.is_not_a.man
jane.man? #=> false
But for the jane.is_the.parent_of.joe
, like more deep chaining ones, I'm not able to figure out how I can implement it.
How do I approach this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
使用
class.new
您每次创建一个新的匿名类is_a
或is_not_a
被调用。尽管这有效,但有一个更轻巧的方法。您可以创建一个辅助器,每次收到消息时都会调用一个给定的块:
示例用法:
使用此助手,可以像这样简化您的课程:
现在,对于链接一个
jane.is_is_is_the.parent_of.joe.joe << /code>,而不是定义新方法右范围,我们必须
调用/返回另一个
MethodCallback
实例以获取额外的方法链接:在上面的代码中,
is_the
将分配给>名称。
,第二个将分配给value
。我们创建的方法将被称为
name
,它将返回value
:另一个:
With
Class.new
you create a new anonymous class each timeis_a
oris_not_a
is called. Although this works, there's amuch more lightweight approach. You can create a helper that will invoke a given block each time it receives a message:
Example usage:
With this helper, your class can be simplified like this:
Now, for the chaining one
jane.is_the.parent_of.joe
, instead of defining a new method right-away, we have toinvoke / return another
MethodCallback
instance in order to get an extra level of method chaining:In the above code, the first method name after
is_the
will be assigned toname
and the second will be assigned tovalue
.The method we create will be called just like
name
and it will returnvalue
:Another one:
如果您不使用方法链条来定义对象,则有很多替代方案。这是一种使用“构建器”方法的方法。
If you are not stuck on using method chaining to define your object, there are lots of alternatives. Here is one that uses a "builder" approach.