You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby中扩展模块及测试类(或实例)方法的技术问题

解决Ruby模块扩展与测试方法的问题

Hey there! Let's break down what's going wrong with your code and fix it step by step. I see you're trying to build a where method similar to ActiveRecord's, but hitting issues when extending the module into your test class.

问题根源

When you extend Where in your WhereTest class, you're turning the module's where method into a class method of WhereTest. But inside the where method, you call self.select — and WhereTest (a plain class) doesn't have a select method! The select method comes from the Enumerable module, which is included by objects like arrays, hashes, and other collection types, not regular classes.

That's why you're getting a NoMethodError when trying to run your tests. Let's fix this with two common approaches depending on what you want to achieve.


方案1:让所有可枚举对象都能用where(推荐)

If you want your where method to work with any collection (like arrays of hashes), modify your Where module to extend Enumerable so every enumerable object gets the method:

Where.rb

module Where
  def where(hash = {})
    select do |fixture|
      hash.all? do |key, value|
        value === fixture[key]
      end
    end
  end
end

# Make the where method available to all Enumerable objects
Enumerable.include(Where)

Then update your test class to use an array of fixtures (since arrays are enumerable) and test the method on that array:

test.rb

require 'minitest/autorun'
require './where.rb'

class WhereTest < Minitest::Test
  def setup
    @fixtures = [
      {:name => 'Boris The Blade', :quote => "Heavy is good. Heavy is reliable."},
      {:name => 'Franky Four Fingers', :quote => "Don't be a cunt, Harry."},
      {:name => 'Bullet Tooth Tony', :quote => "You should never underestimate the predictability of stupidity."}
    ]
  end

  def test_where_matches_exact_name
    result = @fixtures.where(name: 'Boris The Blade')
    assert_equal 1, result.size
    assert_equal "Heavy is good. Heavy is reliable.", result.first[:quote]
  end

  def test_where_matches_with_regex
    result = @fixtures.where(name: /Tony/)
    assert_equal 1, result.size
    assert_equal "Bullet Tooth Tony", result.first[:name]
  end
end

方案2:让测试类本身拥有where方法

If you specifically want the WhereTest class to have a class-level where method that operates on class-specific data, you'll need to define a data source in the class and adjust the module to use it:

Where.rb

module Where
  def where(hash = {})
    # Assume the extending class has a @@fixtures class variable (an enumerable collection)
    @@fixtures.select do |fixture|
      hash.all? do |key, value|
        value === fixture[key]
      end
    end
  end
end

test.rb

require 'minitest/autorun'
require './where.rb'

class WhereTest < Minitest::Test
  extend Where
  # Define class-level fixtures for the where method to operate on
  @@fixtures = [
    {:name => 'Boris The Blade', :quote => "Heavy is good. Heavy is reliable."},
    {:name => 'Franky Four Fingers', :quote => "Don't be a cunt, Harry."}
  ]

  def test_class_level_where
    result = WhereTest.where(name: 'Franky Four Fingers')
    assert_equal 1, result.size
    assert_equal "Don't be a cunt, Harry.", result.first[:quote]
  end
end

额外小提示

  • Remember the difference between include and extend:
    • include adds module methods as instance methods to a class/object.
    • extend adds module methods as class methods to a class.
  • Your use of value === fixture[key] is smart! This lets you match not just exact values, but also regex patterns, ranges, and even classes (e.g., value: String would match any string value for that key).

内容的提问来源于stack exchange,提问作者Warren Mui

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:38:16