ratatui_ruby 1.1.0 → 1.1.1
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 +4 -4
- data/ext/ratatui_ruby/Cargo.lock +1 -1
- data/ext/ratatui_ruby/Cargo.toml +1 -1
- data/lib/ratatui_ruby/version.rb +1 -1
- metadata +1 -255
- data/.builds/ruby-3.2.yml +0 -54
- data/.builds/ruby-3.3.yml +0 -54
- data/.builds/ruby-3.4.yml +0 -54
- data/.builds/ruby-4.0.0.yml +0 -54
- data/.pre-commit-config.yaml +0 -16
- data/.rubocop.yml +0 -10
- data/AGENTS.md +0 -147
- data/CHANGELOG.md +0 -736
- data/README.md +0 -187
- data/README.rdoc +0 -302
- data/Rakefile +0 -11
- data/Steepfile +0 -50
- data/doc/concepts/application_architecture.md +0 -321
- data/doc/concepts/application_testing.md +0 -193
- data/doc/concepts/async.md +0 -190
- data/doc/concepts/custom_widgets.md +0 -247
- data/doc/concepts/debugging.md +0 -401
- data/doc/concepts/event_handling.md +0 -162
- data/doc/concepts/interactive_design.md +0 -146
- data/doc/contributors/auditing/parity.md +0 -239
- data/doc/contributors/design/ruby_frontend.md +0 -448
- data/doc/contributors/design/rust_backend.md +0 -434
- data/doc/contributors/design.md +0 -11
- data/doc/contributors/developing_examples.md +0 -400
- data/doc/contributors/documentation_style.md +0 -121
- data/doc/contributors/index.md +0 -21
- data/doc/contributors/releasing.md +0 -215
- data/doc/contributors/todo/align/api_completeness_audit-finished.md +0 -381
- data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +0 -200
- data/doc/contributors/todo/align/term.md +0 -351
- data/doc/contributors/todo/align/terminal.md +0 -647
- data/doc/contributors/todo/future_work.md +0 -169
- data/doc/contributors/upstream_requests/paragraph_span_rects.md +0 -259
- data/doc/contributors/upstream_requests/tab_rects.md +0 -173
- data/doc/contributors/upstream_requests/title_rects.md +0 -132
- data/doc/custom.css +0 -22
- data/doc/getting_started/quickstart.md +0 -291
- data/doc/getting_started/why.md +0 -93
- data/doc/images/app_all_events.png +0 -0
- data/doc/images/app_cli_rich_moments.gif +0 -0
- data/doc/images/app_color_picker.png +0 -0
- data/doc/images/app_debugging_showcase.gif +0 -0
- data/doc/images/app_debugging_showcase.png +0 -0
- data/doc/images/app_external_editor.gif +0 -0
- data/doc/images/app_login_form.png +0 -0
- data/doc/images/app_stateful_interaction.png +0 -0
- data/doc/images/verify_quickstart_dsl.png +0 -0
- data/doc/images/verify_quickstart_layout.png +0 -0
- data/doc/images/verify_quickstart_lifecycle.png +0 -0
- data/doc/images/verify_readme_usage.png +0 -0
- data/doc/images/widget_barchart.png +0 -0
- data/doc/images/widget_block.png +0 -0
- data/doc/images/widget_box.png +0 -0
- data/doc/images/widget_calendar.png +0 -0
- data/doc/images/widget_canvas.png +0 -0
- data/doc/images/widget_cell.png +0 -0
- data/doc/images/widget_center.png +0 -0
- data/doc/images/widget_chart.png +0 -0
- data/doc/images/widget_gauge.png +0 -0
- data/doc/images/widget_layout_split.png +0 -0
- data/doc/images/widget_line_gauge.png +0 -0
- data/doc/images/widget_list.png +0 -0
- data/doc/images/widget_map.png +0 -0
- data/doc/images/widget_overlay.png +0 -0
- data/doc/images/widget_popup.png +0 -0
- data/doc/images/widget_ratatui_logo.png +0 -0
- data/doc/images/widget_ratatui_mascot.png +0 -0
- data/doc/images/widget_rect.png +0 -0
- data/doc/images/widget_render.png +0 -0
- data/doc/images/widget_rich_text.png +0 -0
- data/doc/images/widget_scroll_text.png +0 -0
- data/doc/images/widget_scrollbar.png +0 -0
- data/doc/images/widget_sparkline.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/images/widget_table.png +0 -0
- data/doc/images/widget_tabs.png +0 -0
- data/doc/images/widget_text_width.png +0 -0
- data/doc/index.md +0 -34
- data/doc/troubleshooting/async.md +0 -4
- data/doc/troubleshooting/terminal_limitations.md +0 -131
- data/doc/troubleshooting/tui_output.md +0 -197
- data/examples/app_all_events/README.md +0 -114
- data/examples/app_all_events/app.rb +0 -98
- data/examples/app_all_events/model/app_model.rb +0 -159
- data/examples/app_all_events/model/event_color_cycle.rb +0 -43
- data/examples/app_all_events/model/event_entry.rb +0 -94
- data/examples/app_all_events/model/msg.rb +0 -39
- data/examples/app_all_events/model/timestamp.rb +0 -56
- data/examples/app_all_events/update.rb +0 -75
- data/examples/app_all_events/view/app_view.rb +0 -80
- data/examples/app_all_events/view/controls_view.rb +0 -54
- data/examples/app_all_events/view/counts_view.rb +0 -61
- data/examples/app_all_events/view/live_view.rb +0 -72
- data/examples/app_all_events/view/log_view.rb +0 -57
- data/examples/app_all_events/view.rb +0 -9
- data/examples/app_cli_rich_moments/README.md +0 -81
- data/examples/app_cli_rich_moments/app.rb +0 -189
- data/examples/app_color_picker/README.md +0 -156
- data/examples/app_color_picker/app.rb +0 -76
- data/examples/app_color_picker/clipboard.rb +0 -86
- data/examples/app_color_picker/color.rb +0 -193
- data/examples/app_color_picker/controls.rb +0 -92
- data/examples/app_color_picker/copy_dialog.rb +0 -168
- data/examples/app_color_picker/export_pane.rb +0 -128
- data/examples/app_color_picker/harmony.rb +0 -58
- data/examples/app_color_picker/input.rb +0 -176
- data/examples/app_color_picker/main_container.rb +0 -180
- data/examples/app_color_picker/palette.rb +0 -111
- data/examples/app_debugging_showcase/README.md +0 -119
- data/examples/app_debugging_showcase/app.rb +0 -318
- data/examples/app_external_editor/README.md +0 -62
- data/examples/app_external_editor/app.rb +0 -344
- data/examples/app_login_form/README.md +0 -58
- data/examples/app_login_form/app.rb +0 -109
- data/examples/app_stateful_interaction/README.md +0 -35
- data/examples/app_stateful_interaction/app.rb +0 -328
- data/examples/timeout_demo.rb +0 -45
- data/examples/verify_quickstart_dsl/README.md +0 -55
- data/examples/verify_quickstart_dsl/app.rb +0 -49
- data/examples/verify_quickstart_layout/README.md +0 -77
- data/examples/verify_quickstart_layout/app.rb +0 -73
- data/examples/verify_quickstart_lifecycle/README.md +0 -68
- data/examples/verify_quickstart_lifecycle/app.rb +0 -62
- data/examples/verify_readme_usage/README.md +0 -49
- data/examples/verify_readme_usage/app.rb +0 -42
- data/examples/verify_website_managed/README.md +0 -48
- data/examples/verify_website_managed/app.rb +0 -36
- data/examples/verify_website_menu/README.md +0 -60
- data/examples/verify_website_menu/app.rb +0 -84
- data/examples/verify_website_spinner/README.md +0 -44
- data/examples/verify_website_spinner/app.rb +0 -34
- data/examples/widget_barchart/README.md +0 -58
- data/examples/widget_barchart/app.rb +0 -240
- data/examples/widget_block/README.md +0 -44
- data/examples/widget_block/app.rb +0 -258
- data/examples/widget_box/README.md +0 -54
- data/examples/widget_box/app.rb +0 -255
- data/examples/widget_calendar/README.md +0 -48
- data/examples/widget_calendar/app.rb +0 -115
- data/examples/widget_canvas/README.md +0 -31
- data/examples/widget_canvas/app.rb +0 -130
- data/examples/widget_cell/README.md +0 -45
- data/examples/widget_cell/app.rb +0 -112
- data/examples/widget_center/README.md +0 -33
- data/examples/widget_center/app.rb +0 -118
- data/examples/widget_chart/README.md +0 -50
- data/examples/widget_chart/app.rb +0 -220
- data/examples/widget_gauge/README.md +0 -50
- data/examples/widget_gauge/app.rb +0 -229
- data/examples/widget_layout_split/README.md +0 -53
- data/examples/widget_layout_split/app.rb +0 -260
- data/examples/widget_line_gauge/README.md +0 -50
- data/examples/widget_line_gauge/app.rb +0 -219
- data/examples/widget_list/README.md +0 -58
- data/examples/widget_list/app.rb +0 -382
- data/examples/widget_map/README.md +0 -48
- data/examples/widget_map/app.rb +0 -95
- data/examples/widget_overlay/README.md +0 -45
- data/examples/widget_overlay/app.rb +0 -250
- data/examples/widget_popup/README.md +0 -45
- data/examples/widget_popup/app.rb +0 -106
- data/examples/widget_ratatui_logo/README.md +0 -43
- data/examples/widget_ratatui_logo/app.rb +0 -104
- data/examples/widget_ratatui_mascot/README.md +0 -43
- data/examples/widget_ratatui_mascot/app.rb +0 -95
- data/examples/widget_rect/README.md +0 -53
- data/examples/widget_rect/app.rb +0 -222
- data/examples/widget_render/README.md +0 -46
- data/examples/widget_render/app.rb +0 -186
- data/examples/widget_render/app.rbs +0 -41
- data/examples/widget_rich_text/README.md +0 -44
- data/examples/widget_rich_text/app.rb +0 -193
- data/examples/widget_scroll_text/README.md +0 -46
- data/examples/widget_scroll_text/app.rb +0 -109
- data/examples/widget_scrollbar/README.md +0 -46
- data/examples/widget_scrollbar/app.rb +0 -155
- data/examples/widget_sparkline/README.md +0 -51
- data/examples/widget_sparkline/app.rb +0 -277
- data/examples/widget_style_colors/README.md +0 -43
- data/examples/widget_style_colors/app.rb +0 -83
- data/examples/widget_table/README.md +0 -57
- data/examples/widget_table/app.rb +0 -285
- data/examples/widget_tabs/README.md +0 -50
- data/examples/widget_tabs/app.rb +0 -183
- data/examples/widget_text_width/README.md +0 -44
- data/examples/widget_text_width/app.rb +0 -117
- data/migrate_to_buffer.rb +0 -145
- data/mise.toml +0 -8
- data/tasks/autodoc/examples.rb +0 -87
- data/tasks/autodoc/member.rb +0 -58
- data/tasks/autodoc/name.rb +0 -21
- data/tasks/autodoc.rake +0 -21
- data/tasks/bump/bump_workflow.rb +0 -49
- data/tasks/bump/cargo_lockfile.rb +0 -21
- data/tasks/bump/changelog.rb +0 -104
- data/tasks/bump/header.rb +0 -32
- data/tasks/bump/history.rb +0 -32
- data/tasks/bump/links.rb +0 -69
- data/tasks/bump/manifest.rb +0 -33
- data/tasks/bump/patch_release.rb +0 -19
- data/tasks/bump/release_branch.rb +0 -17
- data/tasks/bump/release_from_trunk.rb +0 -49
- data/tasks/bump/repository.rb +0 -54
- data/tasks/bump/ruby_gem.rb +0 -29
- data/tasks/bump/sem_ver.rb +0 -44
- data/tasks/bump/unreleased_section.rb +0 -73
- data/tasks/bump.rake +0 -61
- data/tasks/doc/documentation.rb +0 -59
- data/tasks/doc/link/file_url.rb +0 -30
- data/tasks/doc/link/relative_path.rb +0 -61
- data/tasks/doc/link/web_url.rb +0 -55
- data/tasks/doc/link.rb +0 -52
- data/tasks/doc/link_audit.rb +0 -116
- data/tasks/doc/problem.rb +0 -40
- data/tasks/doc/source_file.rb +0 -93
- data/tasks/doc.rake +0 -905
- data/tasks/example_viewer.html.erb +0 -172
- data/tasks/extension.rake +0 -14
- data/tasks/license/headers_md.rb +0 -223
- data/tasks/license/headers_rb.rb +0 -210
- data/tasks/license/license_utils.rb +0 -130
- data/tasks/license/snippets_md.rb +0 -315
- data/tasks/license/snippets_rdoc.rb +0 -150
- data/tasks/license.rake +0 -91
- data/tasks/lint.rake +0 -170
- data/tasks/rbs_predicates/predicate_catalog.rb +0 -52
- data/tasks/rbs_predicates/predicate_tests.rb +0 -124
- data/tasks/rbs_predicates/rbs_signature.rb +0 -63
- data/tasks/rbs_predicates.rake +0 -31
- data/tasks/rdoc_config.rb +0 -29
- data/tasks/resources/build.yml.erb +0 -60
- data/tasks/resources/index.html.erb +0 -141
- data/tasks/resources/rubies.yml +0 -7
- data/tasks/sourcehut.rake +0 -110
- data/tasks/steep.rake +0 -11
- data/tasks/terminal_preview/app_screenshot.rb +0 -45
- data/tasks/terminal_preview/crash_report.rb +0 -54
- data/tasks/terminal_preview/example_app.rb +0 -27
- data/tasks/terminal_preview/launcher_script.rb +0 -48
- data/tasks/terminal_preview/preview_collection.rb +0 -60
- data/tasks/terminal_preview/preview_timing.rb +0 -24
- data/tasks/terminal_preview/safety_confirmation.rb +0 -58
- data/tasks/terminal_preview/saved_screenshot.rb +0 -56
- data/tasks/terminal_preview/system_appearance.rb +0 -13
- data/tasks/terminal_preview/terminal_window.rb +0 -138
- data/tasks/terminal_preview/window_id.rb +0 -16
- data/tasks/terminal_preview.rake +0 -30
- data/tasks/test.rake +0 -36
- data/tasks/website/index_page.rb +0 -30
- data/tasks/website/version.rb +0 -122
- data/tasks/website/version_menu.rb +0 -68
- data/tasks/website/versioned_documentation.rb +0 -83
- data/tasks/website/website.rb +0 -53
- data/tasks/website.rake +0 -28
data/tasks/bump/patch_release.rb
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
require_relative "bump_workflow"
|
|
9
|
-
|
|
10
|
-
# PatchRelease performs a patch release on the current release branch.
|
|
11
|
-
class PatchRelease < BumpWorkflow
|
|
12
|
-
private def prepare(segment)
|
|
13
|
-
puts "Bumping #{segment}: #{@gem.version} -> #{target}"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
private def finalize
|
|
17
|
-
puts "\nCommitted. Push and run: bundle exec rake release"
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
# ReleaseBranch represents a release/X.Y branch for a version series.
|
|
9
|
-
class ReleaseBranch < Data.define(:major, :minor)
|
|
10
|
-
def self.for_version(semver)
|
|
11
|
-
new(semver.major, semver.minor)
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def name
|
|
15
|
-
"release/#{major}.#{minor}"
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
require_relative "bump_workflow"
|
|
9
|
-
require_relative "release_branch"
|
|
10
|
-
|
|
11
|
-
# ReleaseFromTrunk creates a release branch, releases there, syncs trunk, returns to release branch.
|
|
12
|
-
class ReleaseFromTrunk < BumpWorkflow
|
|
13
|
-
private def prepare(segment)
|
|
14
|
-
@branch = ReleaseBranch.for_version(target)
|
|
15
|
-
|
|
16
|
-
puts "Creating release branch: #{@branch.name}"
|
|
17
|
-
puts "Bumping #{segment}: #{@gem.version} -> #{target}"
|
|
18
|
-
|
|
19
|
-
@repository.create_branch(@branch.name)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
private def release_on_branch
|
|
23
|
-
super
|
|
24
|
-
puts "\nCommitted on #{@branch.name}."
|
|
25
|
-
|
|
26
|
-
# Capture for trunk import
|
|
27
|
-
@released_changelog_content = File.read("CHANGELOG.md")
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
private def finalize
|
|
31
|
-
sync_trunk
|
|
32
|
-
return_to_release_branch
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
private def sync_trunk
|
|
36
|
-
@repository.checkout("trunk")
|
|
37
|
-
trunk_changelog = Changelog.new
|
|
38
|
-
trunk_changelog.import_release(target, @released_changelog_content)
|
|
39
|
-
@gem.update_version(target)
|
|
40
|
-
generate_ci_manifests
|
|
41
|
-
@repository.commit_all("chore: import v#{target} to trunk")
|
|
42
|
-
puts "Committed on trunk."
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
private def return_to_release_branch
|
|
46
|
-
@repository.checkout(@branch.name)
|
|
47
|
-
puts "\nBack on #{@branch.name}. Review, push both branches, then: bundle exec rake release"
|
|
48
|
-
end
|
|
49
|
-
end
|
data/tasks/bump/repository.rb
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
require "shellwords"
|
|
9
|
-
require "tmpdir"
|
|
10
|
-
|
|
11
|
-
class Repository
|
|
12
|
-
TRUNK = "trunk"
|
|
13
|
-
|
|
14
|
-
def on_trunk? = current_branch == TRUNK
|
|
15
|
-
|
|
16
|
-
def current_branch
|
|
17
|
-
`git branch --show-current`.strip
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def create_branch(name)
|
|
21
|
-
system("git checkout -b #{name}", exception: true)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def checkout(name)
|
|
25
|
-
system("git checkout #{name}", exception: true)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def assert_can_bump!(segment)
|
|
29
|
-
assert_pristine!
|
|
30
|
-
|
|
31
|
-
if on_trunk? && segment == :patch
|
|
32
|
-
raise ArgumentError, "Cannot bump:patch from trunk. Use a release branch."
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
if !on_trunk? && [:minor, :major].include?(segment)
|
|
36
|
-
raise ArgumentError, "Cannot bump:#{segment} from #{current_branch}. Switch to trunk first."
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def assert_pristine!
|
|
41
|
-
return if `git status --porcelain`.strip.empty?
|
|
42
|
-
|
|
43
|
-
raise ArgumentError, "Working tree is not clean. Commit or stash changes first."
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def commit_all(message)
|
|
47
|
-
msg_file = File.join(Dir.tmpdir, "ratatui_ruby_commit_msg_#{$$}.txt")
|
|
48
|
-
system("git add -A", exception: true)
|
|
49
|
-
File.write(msg_file, message)
|
|
50
|
-
system("git commit -F #{msg_file.shellescape}", exception: true)
|
|
51
|
-
ensure
|
|
52
|
-
File.delete(msg_file) if msg_file && File.exist?(msg_file)
|
|
53
|
-
end
|
|
54
|
-
end
|
data/tasks/bump/ruby_gem.rb
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
# RubyGem knows how to update its version: manifests, lockfiles.
|
|
9
|
-
class RubyGem
|
|
10
|
-
def initialize(manifests:, lockfile:)
|
|
11
|
-
raise ArgumentError, "Must have exactly one primary manifest" unless manifests.count(&:primary) == 1
|
|
12
|
-
@manifests = manifests
|
|
13
|
-
@lockfile = lockfile
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def version
|
|
17
|
-
@manifests.find(&:primary).version
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def update_version(target)
|
|
21
|
-
@manifests.each { |manifest| manifest.write(target) }
|
|
22
|
-
@lockfile.refresh
|
|
23
|
-
refresh_bundler_lockfile
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
private def refresh_bundler_lockfile
|
|
27
|
-
system("bundle install", exception: true)
|
|
28
|
-
end
|
|
29
|
-
end
|
data/tasks/bump/sem_ver.rb
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
# See https://semver.org/spec/v2.0.0.html
|
|
9
|
-
class SemVer
|
|
10
|
-
SEGMENTS = [:major, :minor, :patch].freeze
|
|
11
|
-
|
|
12
|
-
def self.parse(string)
|
|
13
|
-
require "rubygems"
|
|
14
|
-
# Extract prerelease suffix (e.g., "-beta.1", "-alpha.2", "-rc.1")
|
|
15
|
-
base, prerelease = string.split("-", 2)
|
|
16
|
-
segments = Gem::Version.new(base).segments.fill(0, 3).first(3)
|
|
17
|
-
new(segments, prerelease:)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def initialize(segments, prerelease: nil)
|
|
21
|
-
@segments = segments
|
|
22
|
-
@prerelease = prerelease
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def major = @segments[0]
|
|
26
|
-
def minor = @segments[1]
|
|
27
|
-
def patch = @segments[2]
|
|
28
|
-
|
|
29
|
-
def next(segment)
|
|
30
|
-
index = SEGMENTS.index(segment)
|
|
31
|
-
raise ArgumentError, "Invalid segment: #{segment}" unless index
|
|
32
|
-
|
|
33
|
-
new_segments = @segments.dup
|
|
34
|
-
new_segments[index] += 1
|
|
35
|
-
new_segments.fill(0, (index + 1)..2)
|
|
36
|
-
|
|
37
|
-
SemVer.new(new_segments)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def to_s
|
|
41
|
-
base = @segments.join(".")
|
|
42
|
-
@prerelease ? "#{base}-#{@prerelease}" : base
|
|
43
|
-
end
|
|
44
|
-
end
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
require "date"
|
|
9
|
-
require "rdoc"
|
|
10
|
-
|
|
11
|
-
# UnreleasedSection manages the [Unreleased] section of the changelog.
|
|
12
|
-
class UnreleasedSection
|
|
13
|
-
PATTERN = /^(## \[Unreleased\].*?)(?=## \[\d)/m
|
|
14
|
-
|
|
15
|
-
# Extracts the unreleased section from the given content.
|
|
16
|
-
def self.parse(content)
|
|
17
|
-
match = content.match(PATTERN)
|
|
18
|
-
new(match[1].strip) if match
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Creates a new UnreleasedSection from the given unreleased content.
|
|
22
|
-
def initialize(content)
|
|
23
|
-
@content = content.dup
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# Returns the unreleased content as a versioned section.
|
|
27
|
-
def as_version(new_version)
|
|
28
|
-
date = Date.today.iso8601
|
|
29
|
-
@content.sub(/^## \[Unreleased\]/, "## [#{new_version}] - #{date}")
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Returns a fresh unreleased section.
|
|
33
|
-
def self.fresh
|
|
34
|
-
new("## [Unreleased]\n\n### Added\n\n### Changed\n\n### Fixed\n\n### Removed")
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Returns the current state of the section as a string.
|
|
38
|
-
def to_s
|
|
39
|
-
@content
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def commit_body
|
|
43
|
-
formatter = Class.new { include RDoc::Text }.new
|
|
44
|
-
@content
|
|
45
|
-
.sub(/^## \[Unreleased\].*$/, "")
|
|
46
|
-
.gsub(/^### (Added|Changed|Fixed|Removed)\n*$/, "")
|
|
47
|
-
.gsub(/^- \*\*([^*]+)\*\*:/, '\1:')
|
|
48
|
-
.gsub(/`([^`]+)`/, '\1')
|
|
49
|
-
.strip
|
|
50
|
-
.lines
|
|
51
|
-
.map { |line| line.gsub(/^- /, "").strip }
|
|
52
|
-
.reject(&:empty?)
|
|
53
|
-
.map { |line| formatter.wrap(line, 72) }
|
|
54
|
-
.join("\n\n")
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# Returns all changelog entry lines (lines starting with "- ")
|
|
58
|
-
def entries
|
|
59
|
-
@content.lines.select { |line| line.strip.start_with?("- ") }.map(&:strip)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
# Returns a new UnreleasedSection with entries removed that appear in the given list.
|
|
63
|
-
def without_entries(entries_to_remove)
|
|
64
|
-
return self if entries_to_remove.empty?
|
|
65
|
-
|
|
66
|
-
new_lines = @content.lines.reject do |line|
|
|
67
|
-
stripped = line.strip
|
|
68
|
-
entries_to_remove.include?(stripped)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
self.class.new(new_lines.join)
|
|
72
|
-
end
|
|
73
|
-
end
|
data/tasks/bump.rake
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
require "rubygems"
|
|
9
|
-
|
|
10
|
-
require_relative "bump/sem_ver"
|
|
11
|
-
require_relative "bump/manifest"
|
|
12
|
-
require_relative "bump/cargo_lockfile"
|
|
13
|
-
require_relative "bump/ruby_gem"
|
|
14
|
-
require_relative "bump/release_from_trunk"
|
|
15
|
-
require_relative "bump/patch_release"
|
|
16
|
-
|
|
17
|
-
namespace :bump do
|
|
18
|
-
gem = RubyGem.new(
|
|
19
|
-
manifests: [
|
|
20
|
-
Manifest.new(
|
|
21
|
-
path: "lib/ratatui_ruby/version.rb",
|
|
22
|
-
pattern: /(?<=VERSION = ")[^"]+(?=")/,
|
|
23
|
-
primary: true
|
|
24
|
-
),
|
|
25
|
-
Manifest.new(
|
|
26
|
-
path: "ext/ratatui_ruby/Cargo.toml",
|
|
27
|
-
pattern: /(?<=^version = ")[^"]+(?=")/,
|
|
28
|
-
primary: false
|
|
29
|
-
),
|
|
30
|
-
],
|
|
31
|
-
lockfile: CargoLockfile.new(
|
|
32
|
-
path: "ext/ratatui_ruby/Cargo.lock",
|
|
33
|
-
dir: "ext/ratatui_ruby",
|
|
34
|
-
name: "ratatui_ruby"
|
|
35
|
-
)
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
desc "Bump major version"
|
|
39
|
-
task :major do
|
|
40
|
-
ReleaseFromTrunk.new(gem:).call(:major)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
desc "Bump minor version"
|
|
44
|
-
task :minor do
|
|
45
|
-
ReleaseFromTrunk.new(gem:).call(:minor)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
desc "Bump patch version"
|
|
49
|
-
task :patch do
|
|
50
|
-
PatchRelease.new(gem:).call(:patch)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
desc "Set exact version (e.g. rake bump:exact[0.1.0])"
|
|
54
|
-
task :exact, [:version] do |_, args|
|
|
55
|
-
target = SemVer.parse(args[:version])
|
|
56
|
-
changelog = Changelog.new
|
|
57
|
-
changelog.release(target)
|
|
58
|
-
gem.update_version(target)
|
|
59
|
-
Rake::Task["sourcehut"].invoke
|
|
60
|
-
end
|
|
61
|
-
end
|
data/tasks/doc/documentation.rb
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
require "pathname"
|
|
9
|
-
require_relative "source_file"
|
|
10
|
-
|
|
11
|
-
# All documentation files in the project.
|
|
12
|
-
#
|
|
13
|
-
# Projects contain many files. Only some are documentation: Ruby source with
|
|
14
|
-
# RDoc, Markdown guides, RDoc text files. Finding them manually is tedious.
|
|
15
|
-
# Missing files means missing broken links.
|
|
16
|
-
#
|
|
17
|
-
# Documentation enumerates all relevant files. It excludes vendor and temp
|
|
18
|
-
# directories. It wraps each path in a SourceFile for link extraction.
|
|
19
|
-
#
|
|
20
|
-
# === Example
|
|
21
|
-
#
|
|
22
|
-
# docs = Documentation.new("/project/root")
|
|
23
|
-
# docs.each do |file|
|
|
24
|
-
# file.links.each { |link| puts link.raw }
|
|
25
|
-
# end
|
|
26
|
-
# docs.count # => 392
|
|
27
|
-
#
|
|
28
|
-
class Documentation
|
|
29
|
-
include Enumerable
|
|
30
|
-
|
|
31
|
-
# File extensions to scan for links.
|
|
32
|
-
EXTENSIONS = %w[rb md rdoc].freeze
|
|
33
|
-
|
|
34
|
-
# Directories to skip.
|
|
35
|
-
EXCLUDES = %w[/vendor/ /tmp/].freeze
|
|
36
|
-
|
|
37
|
-
# Creates a new Documentation collection.
|
|
38
|
-
#
|
|
39
|
-
# [root] Project root directory to scan.
|
|
40
|
-
def initialize(root)
|
|
41
|
-
@root = Pathname.new(root)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Yields each SourceFile in the project.
|
|
45
|
-
def each(&)
|
|
46
|
-
files.each(&)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
private def files # :nodoc:
|
|
50
|
-
@files ||= EXTENSIONS.flat_map { |ext| glob(ext) }
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
private def glob(extension) # :nodoc:
|
|
54
|
-
Dir.glob(@root.join("**/*.#{extension}")).filter_map do |path|
|
|
55
|
-
next if EXCLUDES.any? { |exclude| path.include?(exclude) }
|
|
56
|
-
SourceFile.new(path, @root)
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
data/tasks/doc/link/file_url.rb
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
require_relative "../problem"
|
|
9
|
-
|
|
10
|
-
# A <tt>file://</tt> URL in documentation.
|
|
11
|
-
#
|
|
12
|
-
# IDEs generate these links for local file access. They work on your machine.
|
|
13
|
-
# They break for everyone else. Published docs cannot contain local paths.
|
|
14
|
-
#
|
|
15
|
-
# FileUrl always returns a Problem. There is no valid use case for
|
|
16
|
-
# <tt>file://</tt> URLs in published documentation.
|
|
17
|
-
#
|
|
18
|
-
# === Example
|
|
19
|
-
#
|
|
20
|
-
# link = FileUrl.new("file:///path/to/file.rb", 10, source_file)
|
|
21
|
-
# link.problem(root) # => Problem (always)
|
|
22
|
-
#
|
|
23
|
-
class FileUrl < Link
|
|
24
|
-
# Returns a Problem. <tt>file://</tt> URLs never work in published docs.
|
|
25
|
-
#
|
|
26
|
-
# [_root] Unused. Present for interface compatibility.
|
|
27
|
-
def problem(_root)
|
|
28
|
-
Problem.new(self, "file:// URLs won't work when published")
|
|
29
|
-
end
|
|
30
|
-
end
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
require "pathname"
|
|
9
|
-
|
|
10
|
-
require_relative "../problem"
|
|
11
|
-
|
|
12
|
-
# A relative path to a local file.
|
|
13
|
-
#
|
|
14
|
-
# Documentation references sibling files: images, other docs, source code.
|
|
15
|
-
# Files get renamed. Directories restructure. These paths silently break.
|
|
16
|
-
#
|
|
17
|
-
# RelativePath resolves the path against the project root and checks if the
|
|
18
|
-
# target exists. It also handles RDoc's HTML naming convention (converting
|
|
19
|
-
# <tt>foo_rb.html</tt> back to <tt>foo.rb</tt> for validation).
|
|
20
|
-
#
|
|
21
|
-
# === Example
|
|
22
|
-
#
|
|
23
|
-
# link = RelativePath.new("../images/diagram.png", 20, source_file)
|
|
24
|
-
# link.problem(root) # => nil (file exists) or Problem (missing)
|
|
25
|
-
#
|
|
26
|
-
class RelativePath < Link
|
|
27
|
-
# Returns a Problem if the target file does not exist. Returns <tt>nil</tt>
|
|
28
|
-
# if the path resolves to an existing file or directory.
|
|
29
|
-
#
|
|
30
|
-
# [root] Project root directory for resolving absolute paths.
|
|
31
|
-
def problem(root)
|
|
32
|
-
root = Pathname.new(root)
|
|
33
|
-
resolved = resolve(root)
|
|
34
|
-
return nil unless resolved
|
|
35
|
-
|
|
36
|
-
Problem.new(self, "File not found: #{resolved.relative_path_from(root)}") unless exists?(resolved)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
private def exists?(resolved) # :nodoc:
|
|
40
|
-
return true if resolved.exist?
|
|
41
|
-
|
|
42
|
-
# RDoc generates foo_rb.html from foo.rb
|
|
43
|
-
if raw.end_with?("_rb.html")
|
|
44
|
-
source = Pathname.new(resolved.to_s.sub(/_rb\.html$/, ".rb"))
|
|
45
|
-
return true if source.exist?
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
resolved.directory? if raw.end_with?("/")
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
private def resolve(root) # :nodoc:
|
|
52
|
-
path = raw.split("#").first&.split("?")&.first
|
|
53
|
-
return nil if path.nil? || path.empty? || path.length < 4
|
|
54
|
-
|
|
55
|
-
if path.start_with?("/")
|
|
56
|
-
root.join(path.delete_prefix("/"))
|
|
57
|
-
else
|
|
58
|
-
source_file.path.dirname.join(path)
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
data/tasks/doc/link/web_url.rb
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
require "net/http"
|
|
9
|
-
require "uri"
|
|
10
|
-
|
|
11
|
-
require_relative "../problem"
|
|
12
|
-
|
|
13
|
-
# An HTTP or HTTPS URL in documentation.
|
|
14
|
-
#
|
|
15
|
-
# External links rot. Servers go offline. Pages move. A link that worked last
|
|
16
|
-
# year may 404 today. Manual verification is slow and error-prone.
|
|
17
|
-
#
|
|
18
|
-
# WebUrl checks reachability by making a HEAD request. It returns a Problem if
|
|
19
|
-
# the server responds with an error or is unreachable.
|
|
20
|
-
#
|
|
21
|
-
# === Example
|
|
22
|
-
#
|
|
23
|
-
# link = WebUrl.new("https://example.com", 15, source_file)
|
|
24
|
-
# link.web? # => true
|
|
25
|
-
# link.problem(root) # => nil (site is up) or Problem (site is down)
|
|
26
|
-
#
|
|
27
|
-
class WebUrl < Link
|
|
28
|
-
# Whether this link points to a web URL. Always <tt>true</tt> for WebUrl.
|
|
29
|
-
def web?
|
|
30
|
-
true
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Returns a Problem if the URL is unreachable. Returns <tt>nil</tt> if the
|
|
34
|
-
# server responds with a 2xx or 3xx status.
|
|
35
|
-
#
|
|
36
|
-
# [_root] Unused. Present for interface compatibility.
|
|
37
|
-
def problem(_root)
|
|
38
|
-
Problem.new(self, "URL returned error or is unreachable") unless reachable?
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private def reachable? # :nodoc:
|
|
42
|
-
uri = URI.parse(raw)
|
|
43
|
-
return false unless uri.is_a?(URI::HTTP) || uri.is_a?(URI::HTTPS)
|
|
44
|
-
|
|
45
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
|
46
|
-
http.use_ssl = uri.scheme == "https"
|
|
47
|
-
http.open_timeout = 5
|
|
48
|
-
http.read_timeout = 5
|
|
49
|
-
|
|
50
|
-
response = http.request_head(uri.request_uri)
|
|
51
|
-
response.code.to_i < 400
|
|
52
|
-
rescue
|
|
53
|
-
false
|
|
54
|
-
end
|
|
55
|
-
end
|
data/tasks/doc/link.rb
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
# Base class for links found in documentation.
|
|
9
|
-
#
|
|
10
|
-
# Documentation contains links: URLs, file paths, images. These links break.
|
|
11
|
-
# Pages move. Files get renamed. Servers go offline. Manual checking is tedious.
|
|
12
|
-
#
|
|
13
|
-
# Link is the base type. It holds the raw text, line number, and source file.
|
|
14
|
-
# Subclasses (FileUrl, WebUrl, RelativePath) implement <tt>problem</tt> to
|
|
15
|
-
# detect specific breakage.
|
|
16
|
-
#
|
|
17
|
-
# Use <tt>Link.build</tt> to create the correct subclass based on the raw text.
|
|
18
|
-
#
|
|
19
|
-
# === Example
|
|
20
|
-
#
|
|
21
|
-
# link = Link.build("https://example.com", 42, source_file)
|
|
22
|
-
# link.web? # => true
|
|
23
|
-
# link.problem(root) # => nil or Problem
|
|
24
|
-
#
|
|
25
|
-
class Link < Data.define(:raw, :line, :source_file)
|
|
26
|
-
# Creates the appropriate Link subclass based on the raw text.
|
|
27
|
-
#
|
|
28
|
-
# [raw] The raw link text extracted from the file.
|
|
29
|
-
# [line] Line number where the link appears.
|
|
30
|
-
# [source_file] The SourceFile containing this link.
|
|
31
|
-
def self.build(raw, line, source_file)
|
|
32
|
-
if raw.start_with?("file://")
|
|
33
|
-
FileUrl.new(raw, line, source_file)
|
|
34
|
-
elsif raw.start_with?("https://", "http://")
|
|
35
|
-
WebUrl.new(raw, line, source_file)
|
|
36
|
-
else
|
|
37
|
-
RelativePath.new(raw, line, source_file)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# Whether this link points to a web URL.
|
|
42
|
-
#
|
|
43
|
-
# WebUrl overrides this to return <tt>true</tt>. Other link types return
|
|
44
|
-
# <tt>false</tt>. The audit uses this to decide whether to skip verification.
|
|
45
|
-
def web?
|
|
46
|
-
false
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
require_relative "link/file_url"
|
|
51
|
-
require_relative "link/web_url"
|
|
52
|
-
require_relative "link/relative_path"
|