【发布时间】:2026-02-24 07:05:01
【问题描述】:
我对在 Ruby 中构建用于解析微博更新的 DSL 很感兴趣。具体来说,我认为我可以将文本转换为 Ruby 字符串,就像 Rails gem 允许“4.days.ago”一样。我已经有了可以翻译文本的正则表达式代码
@USER_A: give X points to @USER_B for accomplishing some task
@USER_B: take Y points from @USER_A for not giving me enough points
变成类似的东西
Scorekeeper.new.give(x).to("USER_B").for("accomplishing some task").giver("USER_A")
Scorekeeper.new.take(x).from("USER_A").for("not giving me enough points").giver("USER_B")
我可以接受将更新的语法形式化,以便只提供和解析标准化的文本,从而使我能够巧妙地处理更新。因此,似乎更多的是如何实现 DSL 类的问题。我有以下存根类(删除了所有错误检查并用 cmets 替换了一些以最小化粘贴):
class Scorekeeper
attr_accessor :score, :user, :reason, :sender
def give(num)
# Can 'give 4' or can 'give a -5'; ensure 'to' called
self.score = num
self
end
def take(num)
# ensure negative and 'from' called
self.score = num < 0 ? num : num * -1
self
end
def plus
self.score > 0
end
def to (str)
self.user = str
self
end
def from(str)
self.user = str
self
end
def for(str)
self.reason = str
self
end
def giver(str)
self.sender = str
self
end
def command
str = plus ? "giving @#{user} #{score} points" : "taking #{score * -1} points from @#{user}"
"@#{sender} is #{str} for #{reason}"
end
end
运行以下命令:
t = eval('Scorekeeper.new.take(4).from("USER_A").for("not giving me enough points").giver("USER_B")')
p t.command
p t.inspect
产生预期结果:
"@USER_B is taking 4 points from @USER_A for not giving me enough points"
"#<Scorekeeper:0x100152010 @reason=\"not giving me enough points\", @user=\"USER_A\", @score=4, @sender=\"USER_B\">"
所以我的问题主要是,在此实现的基础上,我有没有做任何事情让自己自责? 有没有人有任何改进 DSL 类本身的示例或对我的任何警告?
顺便说一句,要获取 eval 字符串,我主要使用 sub/gsub 和 regex,我认为这是最简单的方法,但我可能错了。
【问题讨论】:
-
我应该补充一点,我使用链式方法这样做只是因为我不知道如何使用像 eval("Scorekeeper give 4 to USER_A for doing something") 这样的裸字符串发送它,因为我不知道如何将包含空格的字符串放入方法参数列表中。非常欢迎对此提出想法。