Ruby 从模块内部调用外部类实例的方法

Ruby 从模块内部调用外部类实例的方法,ruby,scope,rubygems,Ruby,Scope,Rubygems,我希望创造一个宝石,可以称为如下 # initialization location = DarkSky::Location.new [45, -90] # calling certain methods location.current.temperature location.tomorrow.temperature_high # not shown below 目前,我的代码的结构是这样的(本文中有许多方法) location.rb module DarkSky # other m

我希望创造一个宝石,可以称为如下

# initialization
location = DarkSky::Location.new [45, -90]

# calling certain methods
location.current.temperature
location.tomorrow.temperature_high # not shown below
目前,我的代码的结构是这样的(本文中有许多方法)

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
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
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
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
current.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
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
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
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
在第二个块中,我希望从第一个块调用
full_data
。我遇到的问题是,
full\u data
是一个实例方法,而我只能从
位置
范围内访问它(而不是内部
当前
范围)

我已经搜索了很多,但是没有找到类似的方法,其中的方法是实例方法,而不是类方法


旁注-无论
Current
是类还是模块。无论哪种方法,我都能很好地找到解决方案。

请记住,除了参数列表中的参数外,每个方法调用都有一个额外的参数,即方法的接收者。如果没有明确写入接收器,
self
被假定为接收器

关于数据共享,模块DarkSky::Location::Current和类DarkSky::Location之间没有关系。您对
full_data
的方法调用没有指定显式接收器,因此它假定
self
为接收器。在您的情况下,
self
等于
DarkSyk::Location::Current
,并且此模块中没有方法
完整的\u数据

让我们假设您的方法
完整的\u数据
确实需要访问其DarkSky::Location对象;在您发布的代码中,情况并非如此,但我想您已经精简了代码,以便更容易理解您的问题。在这种情况下,还必须提供这样的位置对象;除此之外,
full_data
还应该如何计算结果

当然,如果
full_data
确实需要
Location
中的任何实例变量,那么它应该是Location的类方法,而不是实例方法

在您的例子中,我猜Location对象存储某个位置的(天气)数据,而您的
温度
方法返回温度。但它应该返回哪个位置的温度?东京还是维也纳?如果不知道地点,知道温度是没有意义的。使其工作的一种方法是添加位置作为参数:

module Current
  # where  : Object of class DarkSky::Location
  def self.temperature(where)
    where.full_data[:currently][:temperature] # this line
  end
end

这只是一个例子。我不知道它是否适合您的应用程序。

鉴于在这种情况下,
Current
或类似的实例将只有一个,这可以通过在
Location
初始化时创建一个类实例,并使用
attr\u reader
访问它来实现

这是基于原始帖子的工作代码

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
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
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
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
current.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
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
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
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

这允许出现一个名称空间,但实际上只是类实例的一个getter,然后让您获得各个方法。

类方法
temperature
必须创建
Location
的实例才能调用
full\u data
。我怀疑那是你的意图。为什么要将
full_data
作为实例方法?@CarySwoveland每个位置都有自己的数据。我之所以使用
Current
,完全是出于名称空间的目的。我的想法是,它必须创建一个实例,而这个实例不允许我在文章的开头实现所需的行为。缓存
位置
数据以避免许多请求,这就是为什么实例化多个类不是解决问题的正确方法。“从模块内部调用外部类实例的方法”——Ruby中没有“外部类”这样的东西。Ruby没有像Beta或Newspeak那样的嵌套类。为什么这是一个模块呢。由于完整的_数据是一项要求,因此绑定将非常紧密。为什么不让这些实例方法成为
Location
?@engineersmnky的目的是匹配第一个代码块中的API。我完全可以用
current\u temperature
作为一种方法,但我不喜欢这样称呼它(“current”应该是一个名称空间,因为它的数据是独立的)。读者是成年人,不需要用粗体字来理解他们在读什么。此外,这里使用的“真的”是一个无足轻重的词。也许我还没有这样的智力水平,但至少对我来说,如果用某种方式强调单词,如果人们应该特别注意它们,它会有所帮助。也谢谢你指出,“真的”在这里是不合适的;由于不是以英语为母语的人,我犯了一个错误,从我的语言中把它翻译得有点太字面了。如果我理解正确,我可以省略这个词,而不改变整个句子的意思。在日常会话中,人们可能会说“X真的需要Y”,以表明如果X没有得到Y,它将有一个大问题(不仅仅是一个问题:-)。在这里,如果需要对编码问题做出准确的回答,X要么“需要”是的,不是的。至于用粗体字,这不仅是没有必要的,而且表明读者可能不理解你写的没有重点的内容,而有些读者可能不会欣赏。例如,在笔记中突出显示单词是可以的,但前提是它们是你的笔记。