如何使用 ruby 提取和排序一个 class 的实例变量,这些实例变量存储在另一个 class 的实例变量内的数组中?

How do I extract and sort the instance variables of one class, that are stored in an array inside of an instance variable in another class using ruby?

在进一步了解 Ruby 的同时,我目前 运行 陷入困境。我正在尝试提取和排序一个 class 的实例变量的值,该实例变量存储在另一个 class 的实例变量内的数组中。我似乎只能获取 class 本身的实例,而不是 class.

中的特定实例变量

下面是两个class。

product.rb

class Product
  attr_reader :name,
              :price

  def initialize(name, price)
    @name = name
    @price = price
  end
end

catalogue.rb

class Catalogue
  attr_reader :contents

  def initialize
    @contents = []
  end

  def cheapest
    @contents.product.first
  end

  def <<(product)
    @contents << product
  end
end

以下测试证实我没有正确提取和排序 @name@price 的实例 Product 存储在 @contents 实例中 Catalogue.

catalogue_test.rb

gem 'minitest', '~> 5.2'                                                             
require 'minitest/autorun'                                                           
require 'minitest/pride'  
require 'catalogue'
require 'product'

class CatalogueTest < Minitest::Test                                                 
  def test_cheapest_of_one                                                           
    catalogue = Catalogue.new                                                        
    catalogue << Product.new('scissors', 8)                                          
    assert_equal 'scissors', catalogue.cheapest                                      
  end                                                                          
end

这是失败的原因:

Failure:
CatalogueTest#test_cheapest_of_one [catalogue_test.rb:16]:
--- expected
+++ actual
@@ -1 +1 @@
-"scissors"
+[#<Product:0xXXXXXX @name="scissors", @price=8>]

理想情况下,我希望能够在多个实例中根据价格对产品进行提取和排序。我意识到我将需要进一步扩展现有代码以确保我获取最便宜的代码(当数组中有多个对象时),但我只是试图从一个基本函数开始以访问其中的元素。

到目前为止,我已经尝试了一些不同的方法,例如 sortfirst,但是,我无法超越上述输出 [#<Product:0xXXXXXX @name="scissors", @price=8>],并深入研究实例变量。 ‍♂️

我需要在 catalogue.rb 中添加什么才能使 test_cheapest_of_onecatalogue_test.rb 中通过?

我认为您的测试将适用于以下方法定义:

def cheapest
  @contents.sort_by(&:price).reverse.first.name
end

或者

def cheapest
  @contents.sort_by { |product| produce.price * -1 }.first.name
end

目前您正在尝试调用 @contents.product,这实际上是在调用 Array#product - 不是您想要的。

在你的问题中,你问:

What would I need to add to catalogue.rb to make test_cheapest_of_one in catalogue_test.rb pass?

但是,这个问题问错了!正如我在 中提到的,您的问题是 在您的测试 中,您正在测试 Product 是否等于 String,这可以 永远不会 true,因为 Product 永远不会等于 String。一个产品将只等于一个产品,一个字符串将只等于一个字符串。

所以,问题是你的测试,而不是生产代码。

如果您要修改生产代码,则必须将 cheapest 方法更改为 return 最便宜产品的 名称 。但那是错误的。它应该 return 最便宜的 产品 。如果它 return 是名字,那对你没有帮助,因为你可以用这个名字做任何有用的事情。你无法打印出最便宜的产品多少钱,例如,因为你不知道最便宜的产品是什么,你只知道它叫什么。

正确的解决方案是修改测试,以便测试正确的产品是 returned,而不是名称:

def test_cheapest_of_one
  catalogue = Catalogue.new
  scissors  = Product.new('scissors', 8)
  catalogue << scissors

  assert_equal scissors, catalogue.cheapest
end