2013-07-01 60 views
2

我正在爲我的項目工作。我想Shell類重寫殼運行時,所有打印功能,所以我這樣做:如何暫時覆蓋打印和放置課程?

# WARNING: Blocks until the user exits. 
def start 
    # Override Kernel print functions. 
    master_print = Kernel.method :print 
    master_puts = Kernel.method :puts 

    Kernel.module_exec { 
    define_method(:print) { |text = ""| 
     self.send(:print_override, master_print, text) 
    } 
    define_method(:puts) { |text = ""| 
     self.send(:puts_override, master_puts, text) 
    } 
    define_method(:puts_padded) { |text = ""| 
     self.send(:puts_override, master_puts, "") 
     self.send(:puts_override, master_puts, text) 
     self.send(:puts_override, master_puts, "") 
    } 
    } 

    # Readline loop and command parsing here... 
end 

這工作得很好,只要僅Shell類輸出任何文字,但只要一命令類嘗試puts我得到這個:

NoMethodError: undefined method `puts_override' for #<AddressKit::CLI::Interactiv 
e::Commands::LoadTable:0x000000027735b0> 

我認爲打印,並把我上面寫的塊會留在這個範圍內,而不是在執行其有史以來發生的範圍從調用。是否有可能解決這個問題?


獎金的問題:我如何把原來的打印功能恢復?我本來計劃這個:

Kernel.module_exec { 
    define_method(:print, &master_print) 
    define_method(:puts, &master_puts) 
    undef_method(:puts_padded) 
} 

但我還沒有嘗試過,我不知道這是否會離開Kernel正是因爲我發現它。

回答

4

雖然塊確實保留範圍,self是特殊的,並指的是運行該方法的實例(我假設,因爲這是更有用)。

另一種策略是使用的事實,Kernel#puts少了點$stdout.puts,所以不是重寫puts,設置$stdout你的類之一,可以將它們傳遞給puts對前$標準輸出之前按摩值。

完成後,將$stdout恢復到其原始值。

+0

我明白了!這清除了一些事情。 – Hubro

0

嗯,我想我解決了這個問題,但我不確定它爲什麼起作用。我是猜測這些塊在它被調用的範圍以及它們被定義的範圍內,但是在前者的優先級上。這意味着我不能使用self,並期望它指向shell。相反,我這樣做:

shell = self 

Kernel.module_exec { 
    define_method(:print) { |text = ""| 
    shell.send(:print_override, master_print, text) 
    } 
    define_method(:puts) { |text = ""| 
    shell.send(:puts_override, master_puts, text) 
    } 
    define_method(:puts_padded) { |text = ""| 
    shell.send(:puts_override, master_puts, "") 
    shell.send(:puts_override, master_puts, text) 
    shell.send(:puts_override, master_puts, "") 
    } 
} 

其中一期工程完美,但(如果我是正確的),將盡快打破一樣,存在於同一範圍變量shellprintputs從調用。但它不會中斷,我測試了它!我真的不知道發生了什麼,我會很感激,如果有人可以解釋它:-)