Spec issue in it block

The code below (src/book.cr) defines 2 classes.

require "sqlite3"

module Book
  alias BookFields = {id: Int64, title: String, author: String}

  class Books
    def initialize(@conn : DB::Connection)
    end

    def add(@author : String, @title : String)
      @conn.exec("INSERT INTO book (title, author) values(?, ?)", @title, @author)
    end

    def fetch
      books = [] of Book
      @conn.query_all("SELECT id FROM book", as: Int64).each do |id|
        books << Book.new(@conn, id)
      end
      books
    end
  end

  class Book
    @book : BookFields? = nil

    {% for method in BookFields.keys %}
      def {{method.id}}
        book[:{{method.id}}]
      end
    {% end %}

    def initialize(@conn : DB::Connection, @id : Int64)
    end

    def book : BookFields
      @book ||= @conn.query_one "SELECT * FROM book WHERE id='#{@id}'", as: BookFields.types
    end

    def to_s(io : IO)
      io << title << " (" << author << ")"
    end
  end
end

and some additional lines to test them.

cnn = DB.connect("sqlite3://%3Amemory%3A")
sql = %(CREATE TABLE IF NOT EXISTS "book" (
           "id"	integer,
           "author"	text NOT NULL UNIQUE COLLATE nocase,
           "title"	text COLLATE nocase,
           PRIMARY KEY("id")
         ))
cnn.exec sql  
books = Book::Books.new(cnn)
books.add("De bello gallico", "Caesar Julius")
books.add("De Brevitate Vitæ", "Seneca")
books.fetch.sort { |a, b| a.author <=> b.author }.each do |bk|
   puts bk.to_s
end
cnn.close

Everything works as expected.

If I use these last lines in a test file (spec/book_spec.cr) by inserting them in a describe block, everything is still OK.

require "sqlite3"
require "./spec_helper"
require "../src/book"

cnn = DB.connect("sqlite3://%3Amemory%3A")
sql = %(CREATE TABLE IF NOT EXISTS "book" (
           "id"	integer,
           "author"	text NOT NULL UNIQUE COLLATE nocase,
           "title"	text COLLATE nocase,
           PRIMARY KEY("id")
         ))
cnn.exec sql
describe Book do
  books = Book::Books.new(cnn)
  books.add("De bello gallico", "Caesar Julius")
  books.add("De Brevitate Vitæ", "Seneca")
  books.fetch.sort { |a, b| a.author <=> b.author }.each do |bk|
    puts bk.to_s
  end
end
cnn.close

However, if I enclose the books.fetch block in an it block, the compilation fails.

describe Book do
  books = Book::Books.new(cnn)
  books.add("De bello gallico", "Caesar Julius")
  books.add("De Brevitate Vitæ", "Seneca")
    it "does not compile" do
    books.fetch.sort { |a, b| a.author <=> b.author }.each do |bk|
      puts bk.to_s
    end
  end
end

$ crystal spec spec/
E

Failures:

  1. Book does not compile

    bad parameter or other API misuse (SQLite3::Exception)
    from lib/sqlite3/src/sqlite3/statement.cr:81:5 in ‘check’
    from lib/sqlite3/src/sqlite3/statement.cr:4:5 in ‘initialize’
    from lib/sqlite3/src/sqlite3/statement.cr:2:3 in ‘new’
    from lib/sqlite3/src/sqlite3/connection.cr:18:5 in ‘build_prepared_statement’
    from lib/db/src/db/connection.cr:40:40 in ‘fetch_or_build_prepared_statement’
    from lib/db/src/db/session_methods.cr:23:9 in ‘build’
    from lib/db/src/db/query_methods.cr:46:7 in ‘query:args’
    from lib/db/src/db/query_methods.cr:61:7 in ‘query_all:as’
    from src/book.cr:22:7 in ‘fetch’
    from spec/book_spec.cr:18:5 in ‘->’
    from /usr/lib/crystal/primitives.cr:266:3 in ‘internal_run’
    from /usr/lib/crystal/spec/example.cr:33:16 in ‘run’
    from /usr/lib/crystal/spec/context.cr:18:23 in ‘internal_run’
    from /usr/lib/crystal/spec/context.cr:339:7 in ‘run’
    from /usr/lib/crystal/spec/context.cr:18:23 in ‘internal_run’
    from /usr/lib/crystal/spec/context.cr:156:7 in ‘run’
    from /usr/lib/crystal/spec/dsl.cr:220:7 in ‘->’
    from /usr/lib/crystal/primitives.cr:266:3 in ‘run’
    from /usr/lib/crystal/crystal/main.cr:50:14 in ‘exit’
    from /usr/lib/crystal/crystal/main.cr:45:5 in ‘main’
    from /usr/lib/crystal/crystal/main.cr:127:3 in ‘main’
    from /usr/lib/libc.so.6 in ‘__libc_start_main’
    from /home/hubert/.cache/crystal/crystal-run-spec.tmp in ‘_start’
    from ???

Finished in 890 microseconds
1 examples, 0 failures, 1 errors, 0 pending

Failed examples:

crystal spec spec/book_spec.cr:17 # Book does not compile

Bug, or did I miss something about the use of Spec?

I think you’re being bit by how specs are executed. All specs run within an at_exit hook. Because of this, I’m thinking it’s running cnn.close before your book.fetch. Try doing everything within an it block. Could use some private methods to make defining/sharing the logic easier as well.

That was the problem, it works now with everything in it block.
Thanks