2011-01-27 43 views
1

我想通過建立一個基本的營火機器人在工作中擰螺絲學習紅寶石。我已經做得非常好(它的工作原理!),並且學到了很多東西(它起作用了!),但現在我試圖通過將要執行的動作分離到他們自己的類中來使它更復雜一點,以便它們破碎時可以更容易編寫/修復。如果你有興趣看到所有(可能是蹩腳的)代碼,那全部是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.rbhear方法內執行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

回答

1

hear的定義可以被拉出class << self塊的和更改爲:

def self.hear(pattern, &action) 
    Action.handlers[pattern] = action 
end 

,得到完全相同的結果。這也立即解釋了這個問題。 hear是一種類方法。 say_bar是一個實例方法。您不能從類方法調用實例方法,因爲沒有可用的類的實例。

要了解class << self位,你必須做自己的閱讀和實驗:我不會試圖改進已經說過的內容。我只會說在class << self .. end區塊內,self是指CampfireBot::Action類的本徵類元類。這是持有CampfireBot :: Action類定義的Class類的實例。