从模块内部调用外部 class 实例的方法
Call method of outer class instance from inside module
我想创建一个可以按如下方式调用的 Gem
# initialization
location = DarkSky::Location.new [45, -90]
# calling certain methods
location.current.temperature
location.tomorrow.temperature_high # not shown below
目前,我的代码结构如下(许多方法为此post)
location.rb
module DarkSky
# other methods are here, as this is for a Gem
class Location
def initialize(location)
@location = location
end
def full_data
# return common data between `Current` and `Tomorrow` classes
{
currently: {
temperature: 42
}
}
end
end
end
current.rb
module DarkSky
class Location
module Current
def self.temperature
full_data[:currently][:temperature] # this line
end
end
# alias name for client simplicity
def current
Current
end
end
end
在第二个区块中,我希望从第一个区块调用 full_data
。我遇到的问题是 full_data
是一个实例方法,而我只能从 Location
范围内访问它(而不是内部 Current
范围)
我搜索了很多,但没能找到与此类似的方法,其中方法是 instance 方法,而不是 class方法。
旁注 - Current
是 class 还是模块并不重要。无论哪种方式,我都擅长解决方案。
请记住,每个方法调用除了参数列表中的参数外,还有一个额外的参数,即方法的接收者。如果没有显式写入接收者,则假定 self
为接收者。
关于数据共享,模块DarkSky::Location::Current和classDarkSky::Location之间没有关系。您对 full_data
的方法调用未指定显式接收者,因此它假定 self
作为接收者。在您的情况下,self
等于 DarkSyk::Location::Current
,并且此模块中没有方法 full_data
。
假设您的方法 full_data
确实 需要访问它的 DarkSky::Location 对象;在您发布的代码中,情况并非如此,但我猜您已经精简了代码以便更容易理解您的问题。在这种情况下,您还必须提供这样一个 Location 对象; full_data
还应该如何知道如何计算结果?
当然,如果full_data
确实不需要需要Location
的任何实例变量,它应该是Location的class方法,不是实例方法。
在您的情况下,我猜 Location 对象存储某个位置的(天气)数据,而您的 temperature
方法 return 存储温度。但是 return 温度应该在哪个位置?东京还是维也纳?不知道地方,知道温度就没有意义。使其工作的一种方法是将地点添加为参数:
module Current
# where : Object of class DarkSky::Location
def self.temperature(where)
where.full_data[:currently][:temperature] # this line
end
end
这只是一个例子。适不适合你的应用,我不知道。
鉴于在这种情况下,只有一个 Current
或类似的实例,这可以通过在 Location
初始化时创建一个 class 实例来实现,并使用attr_reader
访问它。
这是工作代码,基于原始 post。
location.rb
module DarkSky
# other methods are here, as this is for a Gem
class Location
attr_reader :current
def initialize(location)
@location = location
@current = Current.new self # here's the "hidden" initialization with the instance as a parameter
end
def full_data
# return common data between `Current` and `Tomorrow` classes
{
currently: {
temperature: 42
}
}
end
end
end
current.rb
module DarkSky
class Location
class Current
def initialize(location)
# keep a reference to the location (for the shared data)
@location = location
end
def apparent_temperature
@location.full_data[:currently][:temperature]
end
end
end
end
这允许看似命名空间,但实际上只是 class 实例的 getter,然后让您获得各个方法。
我想创建一个可以按如下方式调用的 Gem
# initialization
location = DarkSky::Location.new [45, -90]
# calling certain methods
location.current.temperature
location.tomorrow.temperature_high # not shown below
目前,我的代码结构如下(许多方法为此post)
location.rb
module DarkSky
# other methods are here, as this is for a Gem
class Location
def initialize(location)
@location = location
end
def full_data
# return common data between `Current` and `Tomorrow` classes
{
currently: {
temperature: 42
}
}
end
end
end
current.rb
module DarkSky
class Location
module Current
def self.temperature
full_data[:currently][:temperature] # this line
end
end
# alias name for client simplicity
def current
Current
end
end
end
在第二个区块中,我希望从第一个区块调用 full_data
。我遇到的问题是 full_data
是一个实例方法,而我只能从 Location
范围内访问它(而不是内部 Current
范围)
我搜索了很多,但没能找到与此类似的方法,其中方法是 instance 方法,而不是 class方法。
旁注 - Current
是 class 还是模块并不重要。无论哪种方式,我都擅长解决方案。
请记住,每个方法调用除了参数列表中的参数外,还有一个额外的参数,即方法的接收者。如果没有显式写入接收者,则假定 self
为接收者。
关于数据共享,模块DarkSky::Location::Current和classDarkSky::Location之间没有关系。您对 full_data
的方法调用未指定显式接收者,因此它假定 self
作为接收者。在您的情况下,self
等于 DarkSyk::Location::Current
,并且此模块中没有方法 full_data
。
假设您的方法 full_data
确实 需要访问它的 DarkSky::Location 对象;在您发布的代码中,情况并非如此,但我猜您已经精简了代码以便更容易理解您的问题。在这种情况下,您还必须提供这样一个 Location 对象; full_data
还应该如何知道如何计算结果?
当然,如果full_data
确实不需要需要Location
的任何实例变量,它应该是Location的class方法,不是实例方法。
在您的情况下,我猜 Location 对象存储某个位置的(天气)数据,而您的 temperature
方法 return 存储温度。但是 return 温度应该在哪个位置?东京还是维也纳?不知道地方,知道温度就没有意义。使其工作的一种方法是将地点添加为参数:
module Current
# where : Object of class DarkSky::Location
def self.temperature(where)
where.full_data[:currently][:temperature] # this line
end
end
这只是一个例子。适不适合你的应用,我不知道。
鉴于在这种情况下,只有一个 Current
或类似的实例,这可以通过在 Location
初始化时创建一个 class 实例来实现,并使用attr_reader
访问它。
这是工作代码,基于原始 post。
location.rb
module DarkSky
# other methods are here, as this is for a Gem
class Location
attr_reader :current
def initialize(location)
@location = location
@current = Current.new self # here's the "hidden" initialization with the instance as a parameter
end
def full_data
# return common data between `Current` and `Tomorrow` classes
{
currently: {
temperature: 42
}
}
end
end
end
current.rb
module DarkSky
class Location
class Current
def initialize(location)
# keep a reference to the location (for the shared data)
@location = location
end
def apparent_temperature
@location.full_data[:currently][:temperature]
end
end
end
end
这允许看似命名空间,但实际上只是 class 实例的 getter,然后让您获得各个方法。