Search code examples
ruby-on-railsrubyrspecstubbing

Stubbing array responses with rspec


I'm currently working on spec'ing out a rake task that's meant to populate a database using the google_drive gem. The gem allows users to access a spreadsheet ws like so:

# Gets content of A2 cell.
p ws[2, 1]  #==> "hoge"

The function that I'm trying to spec looks like this:

def get_tags(ws, row)
  tags = []
  [1, 21, 22, 23, 26, 29, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40].each do |col|
    tags << ws[row, col] unless ws[row, col].blank?
  end
  tags
end

Fairly self explanatory, it gets passed a row and then adds the column data to tags for each column specified in the array.

My ws array consists of this:

ws = [[nil, 'Good', 'Tultex', '0241', 'Men\s Blend Tee',
            'XS - 3XL', '$3.40', '$4.50', '$4.50', '--', '--', '--',
            'TSC', 'y', 'Adult Unisex', 'Tee Shirt', 'Short Sleeve',
            'Crewneck', '3.2', 'Cotton/Poly (35/36)', 'Fitted', '11',
            '0240 (ladies)', '', 'Std Fitted Crew', 'Tees and Tanks',
            'Nicer - Fashion Fitted', 'Blend', '', '', '', 'Fashionable',
            '', '', '']]

Therefore, I need get_tags to return this:

resultant = ['Good', 'Tee Shirt', 'Short Sleeve', 'Crew Neck',
             'Standard', '', 'Tees and Tanks', 'Least Expensive',
             'Regular Cotton', '', '', '', '', '', '', 'Least Expensive']

My problem is that I have no idea how I can spec an array to accept the type of indexing that ws does (ws[val, val]), since that's usually a range index. I tried creating a two dimensional array but that obviously didn't work. Also tried stubbing it out by doing:

allow(ws).to receive(:[]) do |arg1, arg2|
  ws[arg1][arg2]
end

Which created an infinite loop of stubbiness, so then I tried storing ws into another array called temp and doing this (almost the same thing):

allow(ws).to receive(:[]) do |arg1, arg2|
  temp[arg1][arg2]
end

But I still end up with the same infinite stubbing loop. Any advice on what steps to pursue next would be greatly appreciated! Thanks in advance :)


Solution

  • How about creating a class which handles the needed interface:

    class DBStub
      def initialize(data_store)
        @data_store = data_store
      end
    
      def [](arg1, arg2)
        @data_store[arg1][arg2]
      end
    end
    
    ws = DBStub.new(temp)