Extract DB setup into an injectable app container
DB connected at require time, coupling tests to DATABASE_URL.
Domus::App makes the connection injectable.

Assisted-by: Claude Sonnet 4.6 via Claude Code
change vmltrtqtmxwrxmnnpoxswonsukvmyvxv
commit a18a4b989ac86969fed4c9ea80e7aa0cddc28639
author Alpha Chen <alpha@kejadlen.dev>
date
parent ukkxmwxp
diff --git a/Rakefile b/Rakefile
index f3575f0..85686fc 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,8 +1,11 @@
 # frozen_string_literal: true
 
 require "minitest/test_task"
+require_relative "lib/app"
+require "sequel/extensions/migration"
 
-require_relative "lib/db"
+DOMUS_APP = Domus::App.new
+DB = DOMUS_APP.db
 
 BUNDLE_INSTALL_MARKER = Pathname.new(".bundle/installed")
 
@@ -19,10 +22,8 @@ Minitest::TestTask.create(:test)
 
 task default: :test
 
-desc "Start dev server with pre-seeded in-memory database"
+desc "Start dev server"
 task :dev do
-  Sequel::Migrator.run(Domus::DB, "db/migrate") unless Dir.empty?("db/migrate")
-
   require "rack"
   Rack::Server.start(config: "config.ru", Port: 9292)
 end
@@ -33,19 +34,24 @@ namespace :db do
     if Dir.empty?("db/migrate")
       puts "No migrations."
     else
-      Sequel::Migrator.run(Domus::DB, "db/migrate")
+      Sequel::Migrator.run(DB, "db/migrate")
       puts "Migrated."
     end
   end
 
   desc "Rollback the last migration"
   task :rollback do
-    version = Domus::DB[:schema_migrations].order(Sequel.desc(:filename)).limit(1).get(:filename)
+    version = DB[:schema_migrations].order(Sequel.desc(:filename)).limit(1).get(:filename)
     if version
-      Sequel::Migrator.run(Domus::DB, "db/migrate", target: 0, current: version.sub(/\.rb$/, ""))
+      Sequel::Migrator.run(DB, "db/migrate", target: 0, current: version.sub(/\.rb$/, ""))
       puts "Rolled back #{version}."
     else
       puts "Nothing to rollback."
     end
   end
+
+  desc "Seed the database with development data"
+  task :seed do
+    # Add seed data here
+  end
 end
diff --git a/config.ru b/config.ru
index 2f617a8..e3b802c 100644
--- a/config.ru
+++ b/config.ru
@@ -1,5 +1,10 @@
 # frozen_string_literal: true
 
 require_relative "lib/app"
+require_relative "lib/web"
+require "sequel/extensions/migration"
 
-run Domus::App
+app = Domus::App.new
+Sequel::Migrator.run(app.db, "db/migrate") unless Dir.empty?("db/migrate")
+Domus::Web.opts[:app] = app
+run Domus::Web
diff --git a/db/migrate/.gitkeep b/db/migrate/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/app.rb b/lib/app.rb
index 6306b52..268a48c 100644
--- a/lib/app.rb
+++ b/lib/app.rb
@@ -1,20 +1,15 @@
 # frozen_string_literal: true
 
-require "roda"
-require_relative "views/layout"
+require "sequel"
+require_relative "config"
 
 module Domus
-  class App < Roda
-    route do |r|
-      r.root do
-        render_with_layout { "ok" }
-      end
-    end
-
-    private
+  class App
+    attr_reader :config, :db
 
-    def render_with_layout(&block)
-      Views::Layout.new(&block).call
+    def initialize(config = Config.env)
+      @config = config
+      @db = Sequel.sqlite(config.database_url)
     end
   end
 end
diff --git a/lib/config.rb b/lib/config.rb
index a2d12b4..a454210 100644
--- a/lib/config.rb
+++ b/lib/config.rb
@@ -2,8 +2,6 @@
 
 module Domus
   class Config < Data.define(:database_url)
-    def self.from_env
-      new(database_url: ENV.fetch("DATABASE_URL"))
-    end
+    def self.env = new(database_url: ENV.fetch("DATABASE_URL") { "db/domus.db" })
   end
 end
diff --git a/lib/db.rb b/lib/db.rb
deleted file mode 100644
index 362481f..0000000
--- a/lib/db.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# frozen_string_literal: true
-
-require "sequel"
-require "sequel/extensions/migration"
-
-require_relative "config"
-
-module Domus
-  DB = Sequel.sqlite(Config.from_env.database_url)
-end
diff --git a/lib/web.rb b/lib/web.rb
new file mode 100644
index 0000000..d4d1f86
--- /dev/null
+++ b/lib/web.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require "roda"
+require_relative "views/layout"
+
+module Domus
+  class Web < Roda
+    route do |r|
+      r.root do
+        render_with_layout { "ok" }
+      end
+    end
+
+    private
+
+    def db = opts[:db] || opts[:app].db
+
+    def render_with_layout(&block)
+      Views::Layout.new(&block).call
+    end
+  end
+end
diff --git a/test/test_app.rb b/test/test_app.rb
index bc36c87..4359efc 100644
--- a/test/test_app.rb
+++ b/test/test_app.rb
@@ -2,13 +2,12 @@
 
 require_relative "test_helper"
 require "rack/test"
-require_relative "../lib/app"
 
 class TestApp < Minitest::Test
   include Rack::Test::Methods
 
   def app
-    Domus::App
+    Domus::Web
   end
 
   def test_root
diff --git a/test/test_helper.rb b/test/test_helper.rb
index a93651f..cb093a3 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -1,3 +1,11 @@
 # frozen_string_literal: true
 
 require "minitest/autorun"
+
+require_relative "../lib/app"
+require_relative "../lib/web"
+
+app = Domus::App.new(Domus::Config.new(database_url: ":memory:"))
+migrate_dir = File.expand_path("../db/migrate", __dir__)
+Sequel::Migrator.run(app.db, migrate_dir) unless Dir.empty?(migrate_dir)
+Domus::Web.opts[:app] = app