2016-12-05 62 views
4

這是我的模塊,它試圖設置一個實例變量。我想這兩個初始化和self.included但是當我做了包括在最外層的既不是工作(main)範圍:包含模塊後在主要設置實例變量?

module Asd 
    def initialize 
    @asd = 0 
    end 
    def self.included(base) 
    @asd = 0 
    end 
    attr_reader :asd 
end 

包括它的一類作品,我可以讀實例變量:

class Bsd 
    include Asd 
end 
Bsd.new.asd 
# => 0 

但這樣做在全球範圍內不工作:

include Asd 
@asd 
# => nil 
asd 
# => nil 

我常常知道時間人會質疑動機將他們的代碼在全球水平。在這種情況下,我只想看看它是如何完成的。

+2

我相信'initialize'只在創建實例時才運行。 'Asd'是一個模塊,你不能有一個模塊的實例。然後,當你像你一樣在全球範圍內包含'Asd'時,你就不會'初始化'運行。 –

+0

至於'asd'方法......我真的不知道你爲什麼得到一個'NoMethodError'。 –

+0

我正在運行'ruby 2.3.0p0',並且調用'include asd'然後'asd'給了我'nil',而不是'NoMethodError'。您可以使用[Pry REPL](http://pryrepl.org/)下的'ls -pv'命令來調查方法是否已被定義。 – TeWu

回答

2

@EricDuminil解釋了爲什麼你的方法不起作用。以下是您可以如何在此上下文中工作的方式:直接設置實例變量,而不使用初始化程序。

module Asd 
    def self.extended(base) 
    base.instance_variable_set(:@asd, "Another @asd") 
    end 

    attr_reader :asd 
end 

@asd # => nil # !> instance variable @asd not initialized 

extend Asd # extend, not include. 

@asd # => "Another @asd" 
asd # => "Another @asd" 
+0

艾哈,我正在爲我的答案的第二部分寫這個。不再需要它了! –

+0

@EricDuminil:團隊精神! :) –

3

我希望這個代碼使得它更清楚一點:

module Asd 
    def initialize 
    puts "# Initializing" 
    @asd = "One @asd" 
    end 

    def self.included(base) 
    puts "# Importing into #{base}" 
    @asd = "Another @asd" 
    end 
    attr_reader :asd 
end 

class Bsd 
    include Asd 
    # => # Importing into Bsd 
end 

puts Bsd.new.asd 
# => 
# Initializing 
# One @asd 

puts Asd.instance_variable_get(:@asd) 
# => Another @asd 

include Asd 
# => # Importing into Object 

puts self.asd.inspect # Method is defined for main, @asd hasn't been initialized because main was instantiated before the script was launched 
# => nil 

puts Object.new.asd 
# => 
# Initializing 
# One @asd 

基本上,你的代碼是太晚main。它已經在腳本啓動之前被初始化,所以initialize內部的代碼將不再被啓動。