使方法调用可链接

时间:2013-06-06 05:44:14

标签: ruby arrays chaining

我有一个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 < 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

1 个答案:

答案 0 :(得分:1)

您可以覆盖method_missing来处理此问题 在selfin_country方法中返回in_town。然后,当它被调用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