2016-12-05 33 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内部的代码将不再被启动。