我有興趣在Ruby中構建用於解析微博更新的DSL。具體來說,我認爲我可以將文本翻譯成Ruby字符串,就像Rails gem允許「4.days.ago」一樣。我已經有正則表達式的代碼,將文本在Ruby中構建「半自然語言」DSL
@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類的問題。我有以下的stub類(刪除了所有的錯誤檢查和替換了一些與意見,以儘量減少糊):
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和正則表達式,我認爲這是最簡單的方法,但我可能是錯的。
我要補充一點,我用鏈式方法做了這個,只是因爲我不知道如何使用像eval這樣的裸字符串來發送它(「由於我不知道如何獲得空間 - 字符串放入方法參數列表中。對此的想法是非常受歡迎的。 – JohnMetta 2010-02-08 19:17:08