0
votes

How can the nested array be checked using rspecs expect syntax?

This code block works using rspecs should syntax:

subject.cell_grid.each do |row|
  row.is_a?(Array).should be_true
end

...and I think I've got the syntax correct on lines 22 & 23 of the "spec_game_of_life.rb" file, but, when I check the file with rspec I get the following error:

user@ubuntu:~/Ruby/GameOfLife$ rspec spec_game_of_life.rb
..F

Failures:

  1) Game of Life world should create proper cell_grid upon initialization
     Failure/Error:
       expect(subject.cell_grid.each) do |row|
         row.is_a?(Array).to be true
       end

     ArgumentError:
       You cannot pass both an argument and a block to `expect`.
     # ./spec_game_of_life.rb:22:in `block (3 levels) in <top (required)>'

Finished in 0.0019 seconds (files took 0.11777 seconds to load)
3 examples, 1 failure

Failed examples:

rspec ./spec_game_of_life.rb:19 # Game of Life world should create proper cell_grid upon initialization

I understand that rspec's "should" has been replaced with "expect" per: http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/

Initializing a class with a (rows, cols) cell grid - Ruby script, "game_of_life.rb":

  1 # basic file
  2 
  3 class World
  4   attr_accessor :rows, :cols, :cell_grid
  5   def initialize(rows=3, cols=3)
  6     @rows      = rows
  7     @cols      = cols
  8     @cell_grid = Array.new(rows) do |row|
  9                    Array.new(cols) do |col|
 10                    end
 11                  end
 12   end
 13 end

Ruby spec file, "spec_game_of_life.rb":

  1 # spec file
  2 
  3 require 'rspec'
  4 require_relative 'game_of_life.rb'
  5 
  6 describe 'Game of Life' do
  7 
  8   context 'world' do
  9     subject { World.new }
 10 
 11     it 'should create a new world object' do
 12       expect(subject.is_a?(World)).to be true
 13     end
 14     it 'should respond to proper methods' do
 15       expect(subject.respond_to?(:rows))
 16       expect(subject.respond_to?(:cols))
 17       expect(subject.respond_to?(:cell_grid))
 18     end
 19     it 'should create proper cell_grid upon initialization' do
 20       expect(subject.cell_grid.is_a?(Array)).to be true
 21 
 22       expect(subject.cell_grid.each) do |row|
 23         row.is_a?(Array).to be true
 24       end
 25     end
 26 
 27   end
 28 
 29 end

FWIW: Ubuntu 14.04, Ruby 2.3.0, rspec 3.5.3 & I'm following along with this "Game of Life" tutorial which uses "should": https://www.youtube.com/watch?v=Tzs3_pl410M&list=PLMC91Ry9EhRKUn0MIdgXrZiptF7nVyYoQ&index=4

EDIT per answer from Bartek Gladys:

expect{ subject.cell_grid.all? { |k| k.is_a?(Array) } }.to eq true

..F

Failures:

  1) Game of Life world should create proper cell_grid upon initialization
     Failure/Error: expect{ subject.cell_grid.all? { |k| k.is_a?(Array) } }.to eq true
       You must pass an argument rather than a block to use the provided matcher (eq true), or the matcher must implement `supports_block_expectations?`.
     # ./spec_game_of_life.rb:22:in `block (3 levels) in <top (required)>'

NOTE:

expect{ subject.cell_grid.all? { |k| k.is_a?(Array) } }.to be true

 Failure/Error: expect{ subject.cell_grid.all? { |k| k.is_a?(Array) } }.to be true
   You must pass an argument rather than a block to use the provided matcher (equal true), or the matcher must implement `supports_block_expectations?`.

So... how to implement supports_block_expectations??
Researching per: http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/
https://www.relishapp.com/rspec/rspec-expectations/docs/custom-matchers/define-a-matcher-supporting-block-expectations
http://www.relishapp.com/rspec/rspec-expectations/v/3-5/docs
http://rspec.info/

3
There's a lot of irrelevant info here, yet subject.cell_grid is never shown, which is the most relevant piece so future visitors can easily evaluate the answers to determine if this question even matches their use case.ggorlen

3 Answers

1
votes

The expect version of your spec is

subject.cell_grid.each do |row|
  expect(row.is_a?(Array)).to be_truthy
end

(The be_true matcher no longer exists)

Slightly more naturally you would write

subject.cell_grid.each do |row|
  expect(row).to be_an(Array)
end

You could use all? to have only one call to expect but this will lead to less helpful failure messages.

You wouldn't usually pass a block to expect just to make an assertion about a value - typically this is used to check for side effects (such as raising an exception).

1
votes

try this:

expect{ subject.cell_grid.all? { |k| k.is_a?(Array) } }.to eq true
0
votes

Not exactly the answer, but as I struggled to find how to define the supports_block_expectations thing, it's below:

Say, we are to give block support to matcher be (can be anything like eq, or equal or even your own matcher thing)

CAUTION: Using existing matchers kinda redefine it. Better name it with something new to avoid trouble.

Definition:

Short hand definition:

RSpec::Matchers.define :be do
  match do |actual|
    actual.is_a? Proc
  end

  supports_block_expectations
end

Full definition

RSpec::Matchers.define :equal do
  match do |actual|
    actual.is_a? Proc
  end

  def supports_block_expectations?
    true # or some logic
  end
end

Usage:

RSpec.describe "a custom block matcher" do
  it { expect { subject.name }.to be('abc') }
end