我想通過建立一個基本的營火機器人在工作中擰螺絲學習紅寶石。我已經做得非常好(它的工作原理!),並且學到了很多東西(它起作用了!),但現在我試圖通過將要執行的動作分離到他們自己的類中來使它更復雜一點,以便它們破碎時可以更容易編寫/修復。如果你有興趣看到所有(可能是蹩腳的)代碼,那全部是up on GitHub。但爲了這個問題,我會縮小範圍。幫助紅寶石小老虎瞭解類的繼承
理想情況下,我希望能夠輕鬆創建插件,並將它們命名爲類名稱,然後將它們放入項目根目錄中的「actions」目錄中,並在運行時將它們實例化。我希望插件本身儘可能簡單的編寫,所以我希望它們都繼承action
類的一些基本方法和屬性。
這裏是action.rb
,因爲它當前存在:
module CampfireBot
class Action
@handlers = {}
def initialize(room)
@room = room
end
class << self
attr_reader :handlers
attr_reader :room
def hear(pattern, &action)
Action.handlers[pattern] = action
end
end
end
end
凡@room
是房間對象,@handlers
是模式和塊的散列。我有點不明白爲什麼我必須這樣做class << self
調用,但這是我可以讓子插件類看到hear
方法的唯一方法。
然後我試圖創建一個簡單的插件,像這樣(名爲Foo.rb
):
class Foo < CampfireBot::Action
hear /foo/i do
@room.speak "bar"
end
end
然後我有我的實例裏面的插件像bot.rb如此:
def load_handlers(room)
actions = Dir.entries("#{BOT_ROOT}/actions").delete_if {|action| /^\./.match(action)}
action_classes = []
# load the source
actions.each do |action|
load "#{BOT_ROOT}/actions/#{action}"
action_classes.push(action.chomp(".rb"))
end
# and instantiate
action_classes.each do |action_class|
Kernel.const_get(action_class).new(room)
end
@handlers = Action.handlers
end
塊然後當模式由以下內容匹配時,稱爲內部room.rb
:
handlers.each do |pattern, action|
if pattern.match(msg)
action.call($~)
end
end
如果我在Action
的初始化內部做puts @room
,我看到控制檯打印出的房間對象。如果我在Foo.rb
的hear
方法內執行puts "foo"
,我在控制檯上看到foo
打印出來(所以模式匹配正在工作)。但是,我無法讀取來自父類的@room
對象(它作爲零對象出現)。所以很明顯,我錯過了一些關於這應該如何工作的東西。
而且,如果我做了什麼,使插件有點清潔(更大的功能),並把它改寫像這樣:
class Foo < CampfireBot::Action
hear /foo/i do
say_bar
end
def say_bar
@room.speak "bar"
end
end
我得到NoMethodError: undefined method 'say_bar' for Foo:Class
。