admin: silence phlex's warnings at require time
Replaces 3b716c88's Warning.warn filter, which worked but was heavier
than the job asked for.

Assisted-by: GLM-5.3 via pi
change qxtssvkwskovzqlxqomxnkyqqqykkqmo
commit 9d9dc03ff6057e9f026094b0c8107feeff613e30
author Alpha Chen <alpha@kejadlen.dev>
date
parent zzznlltx
diff --git a/lib/pro_tacts/admin/contacts_index.rb b/lib/pro_tacts/admin/contacts_index.rb
index 6e24a8a..93ecf32 100644
--- a/lib/pro_tacts/admin/contacts_index.rb
+++ b/lib/pro_tacts/admin/contacts_index.rb
@@ -1,4 +1,4 @@
-require "phlex"
+require "pro_tacts/admin/phlex"
 
 require "pro_tacts/admin/format"
 require "pro_tacts/admin/layout"
diff --git a/lib/pro_tacts/admin/contacts_show.rb b/lib/pro_tacts/admin/contacts_show.rb
index 5c38654..b67dedb 100644
--- a/lib/pro_tacts/admin/contacts_show.rb
+++ b/lib/pro_tacts/admin/contacts_show.rb
@@ -1,4 +1,4 @@
-require "phlex"
+require "pro_tacts/admin/phlex"
 
 require "pro_tacts/admin/format"
 require "pro_tacts/admin/layout"
diff --git a/lib/pro_tacts/admin/layout.rb b/lib/pro_tacts/admin/layout.rb
index 85aaf21..29e6405 100644
--- a/lib/pro_tacts/admin/layout.rb
+++ b/lib/pro_tacts/admin/layout.rb
@@ -1,4 +1,4 @@
-require "phlex"
+require "pro_tacts/admin/phlex"
 
 module ProTacts
   module Admin
diff --git a/lib/pro_tacts/admin/phlex.rb b/lib/pro_tacts/admin/phlex.rb
new file mode 100644
index 0000000..387c04f
--- /dev/null
+++ b/lib/pro_tacts/admin/phlex.rb
@@ -0,0 +1,27 @@
+require "pro_tacts/warnings"
+
+# The admin's phlex require. Phlex lazy-loads: `require "phlex"`
+# registers autoloads and the files that warn -- a page of
+# mismatched-indentation and method-redefined warnings under `ruby
+# -w`, which the test task runs -- compile only when Phlex::HTML is
+# first referenced, by then outside any block. So this loads phlex's
+# own files eagerly inside the silence; the views require this file
+# instead of phlex, and every later require or autoload hit is a
+# no-op. sgml/state is in the set because it loads later still, at
+# the first render, and carries its own warning.
+ProTacts.silence_warnings do
+  require "phlex"
+  require "phlex/html"
+  require "phlex/sgml/state"
+
+  # Two warnings survive the requires: sgml.rb passes &block to
+  # before_template and after_template, methods that ignore it, and
+  # Ruby warns once per process at the first render carrying a
+  # content block -- the render(Layout.new) { ... } shape every
+  # screen here uses. Spending that first render now, on a throwaway
+  # component whose output is discarded, means no later one warns.
+  inner = Class.new(Phlex::HTML) { def view_template; h1 { "warm" }; end }
+  Class.new(Phlex::HTML) do
+    define_method(:view_template) { render inner.new { nil } }
+  end.new.call
+end
diff --git a/lib/pro_tacts/admin/upcoming_birthdays.rb b/lib/pro_tacts/admin/upcoming_birthdays.rb
index 4a7ecc8..8343f6e 100644
--- a/lib/pro_tacts/admin/upcoming_birthdays.rb
+++ b/lib/pro_tacts/admin/upcoming_birthdays.rb
@@ -1,4 +1,4 @@
-require "phlex"
+require "pro_tacts/admin/phlex"
 
 require "pro_tacts/admin/format"
 
diff --git a/lib/pro_tacts/warnings.rb b/lib/pro_tacts/warnings.rb
new file mode 100644
index 0000000..c0463cb
--- /dev/null
+++ b/lib/pro_tacts/warnings.rb
@@ -0,0 +1,17 @@
+module ProTacts
+  # Turns the interpreter's warnings off for the block and restores
+  # them after -- including on raise -- so code that is noisy under
+  # -w can run quietly without silencing anything else. $VERBOSE is
+  # the global switch the interpreter reads, not a thread-local one,
+  # so this belongs at boot-time requires and not on request paths.
+  # Used to require phlex, whose files warn by the page (see
+  # admin/phlex.rb).
+  #: [T] () { () -> T } -> T
+  def self.silence_warnings
+    verbose = $VERBOSE
+    $VERBOSE = nil
+    yield
+  ensure
+    $VERBOSE = verbose
+  end
+end
diff --git a/test/pro_tacts/test_warnings.rb b/test/pro_tacts/test_warnings.rb
new file mode 100644
index 0000000..e769baa
--- /dev/null
+++ b/test/pro_tacts/test_warnings.rb
@@ -0,0 +1,21 @@
+require_relative "../test_helper"
+
+# ProTacts.silence_warnings, the block helper behind the quiet phlex
+# requires: warnings off inside, back on after — including when the
+# block raises, which is the half a missing ensure would get wrong
+# only when something has already failed.
+class ProTactsWarningsTest < Minitest::Test
+  def test_silences_warnings_for_the_block_and_restores_them_after
+    verbose = $VERBOSE
+    ProTacts.silence_warnings { assert_nil $VERBOSE }
+    assert_equal verbose, $VERBOSE
+  end
+
+  def test_restores_warnings_when_the_block_raises
+    verbose = $VERBOSE
+
+    assert_raises(RuntimeError) { ProTacts.silence_warnings { raise "boom" } }
+
+    assert_equal verbose, $VERBOSE
+  end
+end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 236c589..29cb674 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -42,35 +42,6 @@ Minitest.after_run { FileUtils.rm_rf(unhandled_dir) }
 ENV["PRO_TACTS_DEBUG_LOG"] ||= "log/test.log"
 File.truncate("log/test.log", 0) if File.exist?("log/test.log")
 
-# The interpreter runs with -w (the test task's flag), and phlex's own
-# files compile under it into a stream of warnings — mismatched
-# indentations, a method-redefined pair for every void element — none
-# of it app code. Suppressed here, path-scoped to the gem's install
-# directory rather than globally, so this suite's own warnings (an
-# ambiguous `/` in test_store.rb, say) still surface. Defined after the
-# ENV block but before the first require that loads phlex: the spec
-# lookup finds the path without requiring the gem, and the override is
-# in place before phlex's files ever compile. Nothing later in this
-# file or the suite re-overrides Warning.warn, so the chain holds.
-module PhlexWarningFilter
-  PHLEX_PATH = Gem::Specification.find_by_name("phlex").full_gem_path
-
-  #: (String message) -> bool
-  def self.from_phlex?(message)
-    message.start_with?("#{PHLEX_PATH}/")
-  end
-end
-
-module Warning
-  class << self
-    alias_method :warn_without_phlex_filter, :warn
-  end
-
-  def self.warn(message, **kwargs)
-    warn_without_phlex_filter(message, **kwargs) unless PhlexWarningFilter.from_phlex?(message)
-  end
-end
-
 require_relative "fixture_data"
 require "pro_tacts/web"
 require "minitest/autorun"
diff --git a/test/test_phlex_warning_filter.rb b/test/test_phlex_warning_filter.rb
deleted file mode 100644
index 9276959..0000000
--- a/test/test_phlex_warning_filter.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require_relative "test_helper"
-
-# The path predicate behind the Warning.warn override in test_helper:
-# phlex's install directory and nothing else. The trailing slash in the
-# comparison is what keeps a hypothetical neighboring gem (a phlex-foo,
-# installed beside phlex) from matching on prefix alone. The override's
-# wiring is not asserted here — calling Warning.warn from a test would
-# print the very warnings this suite suppresses — so the wiring is
-# verified by the test run's own output instead.
-class PhlexWarningFilterTest < Minitest::Test
-  def test_matches_only_messages_from_phlex_install_path
-    phlex = "#{PhlexWarningFilter::PHLEX_PATH}/lib/phlex/html.rb:84: " \
-      "warning: mismatched indentations at 'elsif' with 'if' at 58"
-    assert PhlexWarningFilter.from_phlex?(phlex)
-
-    app = "test/pro_tacts/test_store.rb:626: warning: ambiguous `/`"
-    refute PhlexWarningFilter.from_phlex?(app)
-  end
-end