这里的代码是对更大解决方案的简化。我试图找出方法 做一个红宝石DSL,#34;读取"很好。第一个代码块;作品(现在有效) 我想知道如何编写DSL
问题的核心是,在处理类时,它没有一个实例变量供我使用。 IE:@match_code
有谁知道更简单更优雅的解决方案?整个代码必须保留在一个类中。
class MatchStuff
include ProcessBase
match 'account' do | event |
pp event
end
end
matcher = MatchStuff.new
matcher.accept 'account'
class ProcessBase
def initialize
@match_code = []
end
def match(string_match, &block)
@match_code.push([string_match, block])
end
def accept(test_str)
@match_code.each do | test_block |
if test_str == test_block[0])
test_block[1].call test
end
end
end
end
class MatchStuff < ProcessBase
def initialize
super
match 'account' do | event |
pp event
end
end
end
test = MatchStuff.new
test.accept 'account'
答案 0 :(得分:1)
为了使用ProcessBase
正文中class MatchStuff
的方法,除了extend
或继承它之外,您还可以include
:
class MatchStuff
include ProcessBase
extend ProcessBase
match 'account' do |event|
pp event
end
end
但是你遇到的问题是@match_code
引用match
中的类实例变量,而accept
中的常规实例变量。我将一个阅读器方法添加到ProcessBase
并在accept
中的类上使用它,因此您始终使用类实例变量。然后,您可以使用||=
来避免使用initialize
方法(extend
时不会为该类调用。)
module ProcessBase
# reader method, autovivifying to empty Array
def match_code
@match_code ||= []
end
def match(string_match, &block)
# using the reader here, on self, which is the class
match_code.push([string_match, block])
end
def accept(test_str)
# here, self is the instance, so we have to explicitly get the class
# and access match_code from there
self.class.match_code.each do | test_block |
if test_str == test_block[0])
test_block[1].call test
end
end
end
end
或者,您可以将match
(使用match_code
读者)和accept
放在单独的模块中,extend
一个,include
另一个。这样做的好处是不会为您的实例提供一个不起作用的match
方法(因为它使用了错误的match_code
)。你甚至可以定义一个included
或extended
方法,当你做另一个时,它会做一个。
module ProcessClassBase
def match_code
# as above
end
def match
# as above
end
end
module ProcessInstanceBase
def accept
# as above
end
def included(other_mod)
other_mod.extend(ProcessClassBase)
end
end
class MatchStuff
include ProcessInstanceBase # now this also extends ProcessClassBase
match 'account' do |event|
pp event
end
end
值得注意的是,如果你继承MatchStuff
,这一切都会中断。调用MatchStuffSub
时,子类的实例(称之为accept
)将尝试访问MatchStuffSub.match_code
而不是MatchStuff.match_code
(其中match
放置内容)。
答案 1 :(得分:0)
将MatchStuff
定义为
class MatchStuff < ProcessBase
def set_match
match 'account' do |event|
pp event
end
end
end
并从set_match
构造函数中调用ProcessBase
:
class ProcessBase
def initialize
@match_code = []
set_match # Must be defined in derived class
end
...
end
由于您没有为MatchStuff
指定构造函数,它将自动调用父类构造函数。
这实现了我对您的目标的理解,即尽可能以最小的方式在'account'
中指定MatchStuff
字符串和关联的块。
答案 2 :(得分:0)
您可以尝试不使用实例变量。目前尚不清楚匹配字符串的可能值是什么样的,所以我给出了一个例子,说明如何使它们对这种方法“安全”。
module ProcessBase
def self.included(c)
c.extend(ClassMethods)
end
module ClassMethods
def match(string_match, &block)
method = string_match.downcase.gsub(/\s+/,'_').to_sym
define_method(method, &block)
end
end
def accept(string_match)
method = string_match.downcase.gsub(/\s+/,'_').to_sym
self.send(method, 'test')
end
end
class MatchStuff
include ProcessBase
match 'account' do | event |
pp event
end
end
test = MatchStuff.new
test.accept 'account'