【问题标题】:Make method calls chainable使方法调用可链接
【发布时间】:2013-06-06 05:44:13
【问题描述】:

我有一个 Ruby 类,它上面的每个方法都根据特定条件保存哈希数组的索引。

例如(代码自原始发布以来已被编辑

module Dronestream
  class Strike

    class << self

    ...
    def strike
      @strike ||= all
    end

    def all
      response['strike'] # returns an array of hashes, each individual strike
    end

    def in_country(country)
      strike.keep_if { |strike| strike['country'] == country }
      self
    end

    def in_town(town)
      strike.keep_if { |strike| strike['town'] == town }
      self
    end
    ...
  end
end  

这样,你可以做Dronestream::Strike.in_country('Yemen'),或者Dronestream::Strike.in_town('Taizz'),每个都返回一个数组。但我希望能够做到Dronestream::Strike.in_country('Yemen').in_town('Taizz'),并让它只返回也门那个城镇的罢工。

但到目前为止,每个单独的方法都返回一个数组。我知道如果我让他们返回self,他们就会有我需要的方法。但是它们不会返回一个数组,我也不能调用它们,例如,firsteach,就像我可以调用一个数组一样,我需要这样做。我试图使Strike &lt; Array,但是,firstArray 上的实例方法,而不是类方法。

我该怎么办?

编辑

这是我的测试套件的一部分。按照下面的答案,测试单独通过,但随后失败。

describe Dronestream::Strike do

  let(:strike) { Dronestream::Strike }

  before :each do
    VCR.insert_cassette 'strike', :record => :new_episodes
    @strike = nil
  end

  after do
    VCR.eject_cassette
  end
  ...
  # passes when run by itself and when the whole file runs together
  describe '#country' do
    let(:country_name) { 'Yemen' }
    it 'takes a country and returns strikes from that country' do
      expect(strike.in_country(country_name).first['country']).to eq(country_name)
    end
  end

  # passes when run by itself, but fails when the whole file runs together
  describe '#in_town' do
    let(:town_name) { 'Wadi Abida' }
    it 'returns an array of strikes for a given town' do
      expect(strike.in_town(town_name).first['town'].include?(town_name)).to be_true 
    end
  end
  ...
end

【问题讨论】:

    标签: ruby arrays chaining


    【解决方案1】:

    您可以覆盖method_missing 来处理这个问题。
    在您的 in_countryin_town 方法中返回 self。然后当调用first给它时,将它传递给all数组来处理。
    代码可能是这样的:

    module Dronestream
      class Strike
    
      class << self
    
      ...
      def all
        ...
      end
    
      def in_country(country)
        all.keep_if { |strike| strike['country'] == country }
        self
      end
    
      def in_town(town)
        all.keep_if { |strike| strike['town'] == town }
        self
      end
      ...
    
      def method_missing(name,*args,&block)
        return all.send(name.to_sym, *args, &block) if all.respond_to? name.to_sym
        super
      end
    end
    

    【讨论】:

    • 这给了我我需要的方法,但all 实际上是所有罢工的数组。因此,如果我将method_missing 传递给它,它不会缩小范围。所以我有def strike; @strike || all; end,并在罢工时打电话给keep_if,以为每个方法链都会缩小它,但事实并非如此。我是不是做错了什么?
    • 好的,我明白发生了什么。由于您的@strike 为零,因此罢工总是返回全部,@strike 永远不会获得价值。你应该像这样定义它:def strike; @strike ||= all; end
    • 这似乎适用于每种方法。但是当我运行测试套件时,它们开始失败,因为@strike 继续变小直到它为零,并且没有[] 方法。我应该在before 块中重置它吗?我试过了,它似乎不起作用。
    • 你是怎么重置的?我认为 set @strike = nil 应该可以工作。
    • 也许你应该在 Dronestrea::Strike 中定义一个 strike=def clear; @strike = nil; end 方法。并在before :each 方法中调用strike.strike = nil(或strike.clear)。我对 rspec 不是很熟悉,所以不太确定。
    猜你喜欢
    • 2012-08-19
    • 2017-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-27
    • 2016-12-26
    • 2011-07-14
    相关资源
    最近更新 更多