ratatui_ruby 1.3.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 859d136b449ee3babaa09dd80f9bfa1507f08146a632564369c6ab2aa3b937c8
4
- data.tar.gz: dd7e5cf58b04c81e2b5a0c2eb75e796dbfdcbcdc925d4ee6d6f5eda3fdb15df9
3
+ metadata.gz: 3e12c46f758cf25eb436da52bbdcbf46f5cd256b804cb3f67a2d6edeeb8d4062
4
+ data.tar.gz: c4aa2e4c6251a6a75b8ac57e3c7f6133c88066185ee5e9cd1633fbc459edf612
5
5
  SHA512:
6
- metadata.gz: 75ccfaca2381095492f89c37abfc04530391e6ff31691253cdcd7feb93f12c81bb71bf011dbe00ef34f7cf9a580cf601d5939e592e22949390ebde29721bf05f
7
- data.tar.gz: d498466df9bb6af3f4e2c76ce6db58c379a684a8670fa01df1912c621306dc35bdb30c4d1481196b6b493751546d0a03f88bf3be9ac1a888cd80c4c478ae8adc
6
+ metadata.gz: dca9adc8ecef9e432c163b5b7b9e2488d42f9f1db98212a5c140a70bf21dc6c19fa687a97fb30d52ef9cadf8c5dd34a3aecbe471562ba5d9bfdb8c1ff85b99bf
7
+ data.tar.gz: 5f1e347a863736fae0ea9854a37402bd3115c311a228c23b24848113c23a21beeb97b5a33a9177611cd83c7e9d61ed6b4c4c9cf85c110e89f358e805f456465c
@@ -1059,7 +1059,7 @@ dependencies = [
1059
1059
 
1060
1060
  [[package]]
1061
1061
  name = "ratatui_ruby"
1062
- version = "1.3.2"
1062
+ version = "1.4.0"
1063
1063
  dependencies = [
1064
1064
  "bumpalo",
1065
1065
  "lazy_static",
@@ -3,7 +3,7 @@
3
3
 
4
4
  [package]
5
5
  name = "ratatui_ruby"
6
- version = "1.3.2"
6
+ version = "1.4.0"
7
7
  edition = "2021"
8
8
 
9
9
  [lib]
@@ -99,7 +99,62 @@ module RatatuiRuby
99
99
  #--
100
100
  # SPDX-SnippetEnd
101
101
  #++
102
+ #
103
+ # === Class-Wide Normalization
104
+ #
105
+ # When every test in a class faces the same dynamic content, override
106
+ # <tt>normalize_snapshots</tt> instead of repeating the block. Return a callable
107
+ # (or Array of callables) that transforms lines. The hook runs before any per-call
108
+ # block, so the two compose naturally. See <tt>normalize_snapshots</tt> for details.
102
109
  module Snapshot
110
+ # Override this method to normalize all snapshots in a test class.
111
+ #
112
+ # Snapshot assertions compare screen content against stored files. Dynamic content
113
+ # (timestamps, temp paths, random IDs) breaks those comparisons. Passing a normalization
114
+ # block to each assertion fixes one test but creates duplication when every test in a
115
+ # class faces the same dynamic content.
116
+ #
117
+ # Override <tt>normalize_snapshots</tt> in your test class to define class-wide
118
+ # normalization. Accept an Array of Strings (lines) and return the transformed Array.
119
+ #
120
+ # The hook runs before any per-call normalization block, so the two compose naturally:
121
+ # the hook handles class-wide concerns and the block handles one-off masking.
122
+ #
123
+ # Returns <tt>lines</tt> unchanged by default (no normalization).
124
+ #
125
+ # === Example
126
+ #
127
+ #--
128
+ # SPDX-SnippetBegin
129
+ # SPDX-FileCopyrightText: 2026 Kerrick Long
130
+ # SPDX-License-Identifier: MIT-0
131
+ #++
132
+ # class TestFileExplorer < Minitest::Test
133
+ # include RatatuiRuby::TestHelper
134
+ #
135
+ # private def normalize_snapshots(lines)
136
+ # lines.map { |l| l.gsub(Dir.pwd, "STABLE_PATH") }
137
+ # end
138
+ #
139
+ # def test_initial_render
140
+ # # normalize_snapshots runs automatically — no block needed
141
+ # assert_snapshots("initial_render")
142
+ # end
143
+ #
144
+ # def test_after_scroll
145
+ # # Per-call block composes with the hook (hook runs first)
146
+ # assert_snapshots("after_scroll") do |lines|
147
+ # lines.map { |l| l.gsub(/\d{2}:\d{2}/, "XX:XX") }
148
+ # end
149
+ # end
150
+ # end
151
+ #
152
+ #--
153
+ # SPDX-SnippetEnd
154
+ #++
155
+ private def normalize_snapshots(lines)
156
+ lines
157
+ end
103
158
  ##
104
159
  # Asserts that the current screen content matches a stored plain text snapshot.
105
160
  #
@@ -181,7 +236,7 @@ module RatatuiRuby
181
236
  # Ensure your render logic is deterministic by seeding random number generators and stubbing
182
237
  # time where necessary.
183
238
  def assert_screen_matches(expected, msg = nil)
184
- actual_lines = buffer_content
239
+ actual_lines = normalize_snapshots(buffer_content)
185
240
 
186
241
  if block_given?
187
242
  actual_lines = yield(actual_lines)
@@ -203,9 +258,6 @@ module RatatuiRuby
203
258
 
204
259
  # Write with explicit mode to ensure clean write
205
260
  File.write(snapshot_path, content_to_write, mode: "w")
206
-
207
- # Flush filesystem buffers to ensure durability
208
- File.open(snapshot_path, "r", &:fsync) if File.exist?(snapshot_path)
209
261
  rescue => e
210
262
  warn "Failed to write snapshot #{snapshot_path}: #{e.message}"
211
263
  raise
@@ -269,12 +321,11 @@ module RatatuiRuby
269
321
 
270
322
  actual_content = _render_buffer_with_ansi
271
323
 
324
+ lines = normalize_snapshots(actual_content.split("\n"))
272
325
  if block_given?
273
- lines = actual_content.split("\n")
274
- # Yield lines to user block for modification (e.g. masking IDs/Times)
275
326
  lines = yield(lines)
276
- actual_content = "#{lines.join("\n")}\n"
277
327
  end
328
+ actual_content = "#{lines.join("\n")}\n"
278
329
 
279
330
  update_snapshots = ENV["UPDATE_SNAPSHOTS"] == "1" || ENV["UPDATE_SNAPSHOTS"] == "true"
280
331
 
@@ -287,9 +338,6 @@ module RatatuiRuby
287
338
 
288
339
  # Write with explicit mode to ensure clean write
289
340
  File.write(snapshot_path, actual_content, mode: "w")
290
-
291
- # Flush filesystem buffers to ensure durability
292
- File.open(snapshot_path, "r", &:fsync) if File.exist?(snapshot_path)
293
341
  rescue => e
294
342
  warn "Failed to write rich snapshot #{snapshot_path}: #{e.message}"
295
343
  raise
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ require "timeout"
9
+
10
+ module RatatuiRuby
11
+ module TestHelper
12
+ ##
13
+ # Portable subprocess timeout helper.
14
+ module SubprocessTimeout
15
+ private def popen_with_timeout(env, cmd, timeout: 2)
16
+ output = +""
17
+ IO.popen(env, cmd, err: [:child, :out]) do |io|
18
+ deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + timeout
19
+ loop do
20
+ remaining = deadline - Process.clock_gettime(Process::CLOCK_MONOTONIC)
21
+ break if remaining <= 0
22
+ break unless io.wait_readable(remaining)
23
+
24
+ chunk = io.read_nonblock(4096, exception: false)
25
+ break if chunk.nil? || chunk == :wait_readable
26
+
27
+ output << chunk
28
+ end
29
+ Process.kill("KILL", io.pid) rescue nil # rubocop:disable Style/RescueModifier
30
+ end
31
+ output.strip
32
+ end
33
+ end
34
+ end
35
+ end
@@ -12,6 +12,7 @@ require_relative "test_helper/event_injection"
12
12
  require_relative "test_helper/style_assertions"
13
13
  require_relative "test_helper/test_doubles"
14
14
  require_relative "test_helper/global_state"
15
+ require_relative "test_helper/subprocess_timeout"
15
16
 
16
17
  module RatatuiRuby
17
18
  ##
@@ -109,5 +110,6 @@ module RatatuiRuby
109
110
  include StyleAssertions
110
111
  include TestDoubles
111
112
  include GlobalState
113
+ include SubprocessTimeout
112
114
  end
113
115
  end
@@ -8,5 +8,5 @@
8
8
  module RatatuiRuby
9
9
  # The version of the ratatui_ruby gem.
10
10
  # See https://semver.org/spec/v2.0.0.html
11
- VERSION = "1.3.2"
11
+ VERSION = "1.4.0"
12
12
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ratatui_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kerrick Long
@@ -298,7 +298,7 @@ description: |2-
298
298
  RatatuiRuby renders. For complex applications, add a framework that manages
299
299
  state and composition.
300
300
 
301
- ==== Rooibos[https://git.sr.ht/~kerrick/rooibos] (Framework)
301
+ ==== Rooibos[https://www.rooibos.run] (Framework)
302
302
 
303
303
  Model-View-Update architecture. Inspired by Elm, Bubble Tea, and React +
304
304
  Redux. Your UI is a pure function of state.
@@ -371,26 +371,26 @@ description: |2-
371
371
  {API Reference}[https://www.ratatui-ruby.dev/docs/v0.10/],
372
372
  {Guides}[https://www.ratatui-ruby.dev/docs/v0.10/doc/index_md.html]
373
373
  [Ecosystem]
374
- Rooibos[https://git.sr.ht/~kerrick/rooibos],
374
+ Rooibos[https://www.rooibos.run],
375
375
  {Kit}[https://sr.ht/~kerrick/ratatui_ruby/#chapter-3-the-object-path--kit] (Planned),
376
376
  {Framework}[https://sr.ht/~kerrick/ratatui_ruby/#chapter-5-the-framework] (Planned),
377
377
  {UI Widgets}[https://sr.ht/~kerrick/ratatui_ruby/#chapter-6-licensing] (Planned)
378
378
  [Community]
379
- {Discuss and Chat}[https://lists.sr.ht/~kerrick/ratatui_ruby-discuss],
380
- {Announcements}[https://lists.sr.ht/~kerrick/ratatui_ruby-announce],
381
- {Development}[https://lists.sr.ht/~kerrick/ratatui_ruby-devel],
382
- {Bug Tracker}[https://todo.sr.ht/~kerrick/ratatui_ruby]
379
+ {Forum}[https://forum.setdef.com/c/ratatui-ruby/6],
380
+ {Announcements}[https://forum.setdef.com/tags/c/ratatui-ruby/6/announcement],
381
+ {Discussion}[https://forum.setdef.com/tags/c/ratatui-ruby/6/discussion],
382
+ {Bug Tracker}[https://forum.setdef.com/tags/c/ratatui-ruby/6/bug]
383
383
  [Contribute]
384
384
  {Contributing Guide}[https://man.sr.ht/~kerrick/ratatui_ruby/contributing.md],
385
385
  {Code of Conduct}[https://man.sr.ht/~kerrick/ratatui_ruby/code_of_conduct.md],
386
386
  {Project History}[https://man.sr.ht/~kerrick/ratatui_ruby/history/index.md],
387
- {Pull Requests}[https://lists.sr.ht/~kerrick/ratatui_ruby-devel/patches]
387
+ {Pull Requests}[https://forum.setdef.com/tags/c/ratatui-ruby/6/patch]
388
388
 
389
389
 
390
390
  ---
391
391
 
392
392
  [Website] https://www.ratatui-ruby.dev
393
- [Source] https://git.sr.ht/~kerrick/ratatui_ruby
393
+ [Source] https://github.com/setdef/RatatuiRuby
394
394
  [RubyGems] https://rubygems.org/gems/ratatui_ruby
395
395
  [Upstream] https://ratatui.rs
396
396
  [Build Status] https://builds.sr.ht/~kerrick/ratatui_ruby
@@ -535,6 +535,7 @@ files:
535
535
  - lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.ansi
536
536
  - lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.txt
537
537
  - lib/ratatui_ruby/test_helper/style_assertions.rb
538
+ - lib/ratatui_ruby/test_helper/subprocess_timeout.rb
538
539
  - lib/ratatui_ruby/test_helper/terminal.rb
539
540
  - lib/ratatui_ruby/test_helper/test_doubles.rb
540
541
  - lib/ratatui_ruby/text.rb
@@ -692,17 +693,17 @@ files:
692
693
  - sig/ratatui_ruby/widgets/table.rbs
693
694
  - sig/ratatui_ruby/widgets/tabs.rbs
694
695
  - vendor/goodcop/base.yml
695
- homepage: https://sr.ht/~kerrick/ratatui_ruby/
696
+ homepage: https://www.ratatui-ruby.dev
696
697
  licenses:
697
698
  - LGPL-3.0-or-later
698
699
  metadata:
699
700
  allowed_push_host: https://rubygems.org
700
- homepage_uri: https://sr.ht/~kerrick/ratatui_ruby/
701
- bug_tracker_uri: https://todo.sr.ht/~kerrick/ratatui_ruby
702
- changelog_uri: https://git.sr.ht/~kerrick/ratatui_ruby/tree/stable/item/CHANGELOG.md
703
- mailing_list_uri: https://lists.sr.ht/~kerrick/ratatui_ruby-discuss
704
- source_code_uri: https://git.sr.ht/~kerrick/ratatui_ruby
705
- documentation_uri: https://git.sr.ht/~kerrick/ratatui_ruby/tree/HEAD/doc/index.md
701
+ homepage_uri: https://www.ratatui-ruby.dev
702
+ bug_tracker_uri: https://forum.setdef.com/tags/c/ratatui-ruby/6/bug
703
+ changelog_uri: https://github.com/setdef/RatatuiRuby/blob/stable/CHANGELOG.md
704
+ mailing_list_uri: https://forum.setdef.com/c/ratatui-ruby/6
705
+ source_code_uri: https://github.com/setdef/RatatuiRuby
706
+ documentation_uri: https://www.ratatui-ruby.dev/docs/
706
707
  wiki_uri: https://man.sr.ht/~kerrick/ratatui_ruby/
707
708
  funding_uri: https://opencollective.com/ratatui
708
709
  rdoc_options: []