rage-rb 1.26.1 → 1.28.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: 1dab3bd5fbff6c838ff8bb686e7f81251f10a3734330f4788990791822484371
4
- data.tar.gz: c7d03259c16c307078ed3f01f70cf5505b7ce70a49726f52a109377ec9f3ee44
3
+ metadata.gz: bbfe0ad2460e5d9f51317d8be527259b500e28de3dd2817fe50017d6d44558fe
4
+ data.tar.gz: d55249b98d2daad91122eb8f1a0f47618df0775edeaaee1203576d034fc32a18
5
5
  SHA512:
6
- metadata.gz: 1d2d40b1bc876cfaf50fed91c34764798261f85c90e0ca8ffdd12f5039e4a4aa20b16e372be366ddbb9af07eb4de5a5a9b39c5bc603e604593255df347ef089f
7
- data.tar.gz: 952f48b476cc8dcd1c6b604b771e565f1298d14e5c2857f24881f2a22abb7b32bd67b7c3d75497516ca3b72ce6e61165086ac4979471bbcf0c1d7140fd6eb1ef
6
+ metadata.gz: 3d7a3af0e96961ff51803cb02e4e5d15de02e92d076a76a6cc3f8f27c2e0ae0d6e413f97079db7590a1b476c2feace91795f1ea2c46d01aab1e16ff35581a4b0
7
+ data.tar.gz: 77852270e3ef3c276f0941ce346741b69f28595e03ff53d6350ca4e58423b88527baa81701365599b2fbeec3d823b6e816f37772a5c1e7d62f94936c66701db7
data/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.28.0] - 2026-09-15
4
+
5
+ ### Added
6
+
7
+ - [OpenAPI] Add `openapi:validate` Rake task for OpenAPI tags validation (#163).
8
+ - [Logger] Add `config.log_redact_keys=` for redacting structured log context (#386).
9
+ - [Telemetry] Add `Rage::Telemetry::Capacity` (#396).
10
+ - [Telemetry] Add `Rage::Telemetry.every` (#381).
11
+ - Add `Rage::Configuration.after_reload` (#398).
12
+
13
+ ### Fixed
14
+
15
+ - Correctly enqueue deferred tasks with only positional arguments on Ruby < 3.3.4 (#385).
16
+ - Improve restart logs in daemon (#391).
17
+ - Ensure no duplicate daemons or error reporters can be registered (#392).
18
+
19
+ ## [1.27.0] - 2026-08-06
20
+
21
+ ### Added
22
+
23
+ - [OpenAPI] Add support for the `root:` option in Blueprinter response annotations (#343).
24
+ - Add `FiberScheduler#timeout_after` (#374).
25
+
26
+ ### Fixed
27
+
28
+ - [OpenAPI] Avoid caching a request-specific spec URL in the HTML docs page.
29
+ - [Router] Compose and restore `SCRIPT_NAME` correctly for mounted Rack apps.
30
+ - [OpenAPI] Fix schema registry key collisions for Blueprinter classes referenced under different views.
31
+ - Fixed RbNaCl dependency check to produce correct error message (#361).
32
+
3
33
  ## [1.26.1] - 2026-07-17
4
34
 
5
35
  ### Fixed
@@ -22,7 +52,6 @@
22
52
 
23
53
  ### Fixed
24
54
 
25
- - [CI] Check all changed PR file pages when requiring changelog updates.
26
55
  - [API] Ignore `If-Modified-Since` when `If-None-Match` is present.
27
56
  - [API] Use weak comparison for `If-None-Match` validation.
28
57
  - [Deferred] Ignore missing temp files during async disk storage cleanup.
data/CONTRIBUTING.md CHANGED
@@ -6,6 +6,7 @@ This guide is designed to help contributors understand the project's internals,
6
6
 
7
7
  - [Design Principles](#design-principles)
8
8
  - [Documentation Standards](#documentation-standards)
9
+ - [Changelog](#changelog)
9
10
  - [Dynamic Code Generation](#dynamic-code-generation)
10
11
  - [Iodine Integration](#iodine-integration)
11
12
  - [The Fiber Runtime](#the-fiber-runtime)
@@ -81,6 +82,14 @@ The `@private` tag signals to contributors:
81
82
  - It can be modified or removed without deprecation
82
83
  - It can be used freely within the framework codebase
83
84
 
85
+ ## Changelog
86
+
87
+ Pull requests that introduce new features or change existing behavior must include an entry in `CHANGELOG.md`. This helps users understand what changed between versions.
88
+
89
+ Not all changes require a changelog entry. For changes that don't affect users, a maintainer will add the `skip-changelog` label to your PR instead. This includes:
90
+ - Internal refactoring, CI updates, and documentation fixes
91
+ - Intermediary changes for larger features that aren't used yet - the changelog entry should be added when the feature is complete
92
+
84
93
  ## Dynamic Code Generation
85
94
 
86
95
  Rage relies heavily on dynamic code generation for both performance and flexibility. Understanding this pattern is essential for contributing to the framework.
@@ -223,7 +232,7 @@ end
223
232
  1. Wraps every request in a Fiber
224
233
  2. Implements the defer protocol for pausing/resuming async requests
225
234
 
226
- When a request encounters blocking I/O (database query, HTTP request, etc.), the fiber yields. `FiberWrapper` detects this (`fiber.alive?`) and returns a special `:__http_defer__` signal to Iodine, which pauses the connection.
235
+ When a request encounters blocking I/O (database query, HTTP request, etc.), the fiber yields. `FiberWrapper` detects this (`fiber.alive?`) and returns the special `[:__http_defer__, fiber]` tuple to Iodine, which pauses the connection.
227
236
 
228
237
  When the I/O completes, the fiber resumes and publishes a message to notify Iodine that the response is ready. This is the mechanism that enables transparent, non-blocking concurrency.
229
238
 
data/README.md CHANGED
@@ -145,7 +145,7 @@ Rage prioritizes stable public APIs, long deprecation cycles, and minimal extern
145
145
 
146
146
  ## Learn More
147
147
 
148
- - Documentation: [https://rage-rb.dev](https://rage-rb.dev/docs/intro)
148
+ - Documentation: [https://rage-rb.dev/docs/intro](https://rage-rb.dev/docs/intro)
149
149
  - API Reference: [https://rage-rb.dev/api](https://rage-rb.dev/api)
150
150
  - Architecture: [ARCHITECTURE.md](https://github.com/rage-rb/rage/blob/main/ARCHITECTURE.md)
151
151
  - Contributing: [CONTRIBUTING.md](https://github.com/rage-rb/rage/blob/main/CONTRIBUTING.md)
data/exe/rage CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require_relative "../lib/rage/cli"
4
- Rage::CLI.start
4
+ Rage::CLI::App.start
@@ -169,6 +169,12 @@ class Rage::Cable::Channel
169
169
  ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
170
170
  RUBY
171
171
  end}
172
+
173
+ #{if is_subscribing
174
+ <<~RUBY
175
+ @__is_subscribing = false
176
+ RUBY
177
+ end}
172
178
  end
173
179
  RUBY
174
180
 
@@ -302,17 +308,7 @@ class Rage::Cable::Channel
302
308
 
303
309
  # @private
304
310
  def __stream_name_for(streamables)
305
- stream_name = Array(streamables).map do |streamable|
306
- if streamable.respond_to?(:id)
307
- "#{streamable.class.name}:#{streamable.id}"
308
- elsif streamable.is_a?(String) || streamable.is_a?(Symbol) || streamable.is_a?(Numeric)
309
- streamable
310
- else
311
- raise ArgumentError, "Unable to generate stream name. Expected an object that responds to `id`, got: #{streamable.class}"
312
- end
313
- end
314
-
315
- "#{name}:#{stream_name.join(":")}"
311
+ "#{name}:#{Rage::Internal.stream_name_for(streamables)}"
316
312
  end
317
313
 
318
314
  protected
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rage::CLI
4
+ class Base < Thor
5
+ private
6
+
7
+ def environment
8
+ require File.expand_path("config/application.rb", Dir.pwd)
9
+
10
+ if Rage.config.internal.rails_mode
11
+ require File.expand_path("config/environment.rb", Dir.pwd)
12
+ end
13
+ end
14
+
15
+ def set_env(options)
16
+ if options[:environment]
17
+ ENV["RAGE_ENV"] = ENV["RAILS_ENV"] = options[:environment]
18
+ elsif ENV["RAGE_ENV"]
19
+ ENV["RAILS_ENV"] = ENV["RAGE_ENV"]
20
+ elsif ENV["RAILS_ENV"]
21
+ ENV["RAGE_ENV"] = ENV["RAILS_ENV"]
22
+ else
23
+ ENV["RAGE_ENV"] = ENV["RAILS_ENV"] = "development"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rage::CLI
4
+ class CodeGenerator < Base
5
+ include Thor::Actions
6
+
7
+ def self.source_root
8
+ File.expand_path("../templates", __dir__)
9
+ end
10
+
11
+ desc "migration NAME", "Generate a new migration"
12
+ def migration(name = nil)
13
+ return help("migration") if name.nil?
14
+
15
+ setup
16
+ Rake::Task["db:new_migration"].invoke(name)
17
+ end
18
+
19
+ desc "model NAME", "Generate a new model"
20
+ def model(name = nil)
21
+ return help("model") if name.nil?
22
+
23
+ setup
24
+ migration("create_#{name.pluralize}")
25
+ @model_name = name.classify
26
+ template("model-template/model.rb", "app/models/#{name.singularize.underscore}.rb")
27
+ end
28
+
29
+ desc "controller NAME", "Generate a new controller"
30
+ def controller(name = nil)
31
+ return help("controller") if name.nil?
32
+
33
+ setup
34
+ unless defined?(ActiveSupport::Inflector)
35
+ raise LoadError, <<~ERR
36
+ ActiveSupport::Inflector is required to run this command. Add the following line to your Gemfile:
37
+ gem "activesupport", require: "active_support/inflector"
38
+ ERR
39
+ end
40
+
41
+ # remove trailing Controller if already present
42
+ normalized_name = name.sub(/_?controller$/i, "")
43
+ @controller_name = "#{normalized_name.camelize}Controller"
44
+ file_name = "#{normalized_name.underscore}_controller.rb"
45
+
46
+ template("controller-template/controller.rb", "app/controllers/#{file_name}")
47
+ end
48
+
49
+ private
50
+
51
+ def setup
52
+ @setup ||= begin
53
+ require "rake"
54
+ load "Rakefile"
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rage::CLI
4
+ class NewAppGenerator < Thor::Group
5
+ include Thor::Actions
6
+ argument :path, type: :string
7
+ argument :database, type: :string, required: false
8
+
9
+ def self.source_root
10
+ File.expand_path("../templates", __dir__)
11
+ end
12
+
13
+ def setup
14
+ @use_database = !database.nil?
15
+ end
16
+
17
+ def create_directory
18
+ empty_directory(path)
19
+ end
20
+
21
+ def copy_files
22
+ inject_templates
23
+ end
24
+
25
+ def install_database
26
+ return unless @use_database
27
+
28
+ @app_name = path.tr("-", "_").downcase
29
+ append_to_file "#{path}/Gemfile", <<~RUBY
30
+
31
+ gem "#{get_db_gem_name}"
32
+ gem "activerecord"
33
+ gem "standalone_migrations", require: false
34
+ RUBY
35
+
36
+ inject_templates("db-templates")
37
+ inject_templates("db-templates/#{database}")
38
+ end
39
+
40
+ private
41
+
42
+ def inject_templates(from = nil)
43
+ root = "#{self.class.source_root}/#{from}"
44
+
45
+ Dir.glob("*", base: root).each do |template|
46
+ next if File.directory?("#{root}/#{template}")
47
+
48
+ *template_path_parts, template_name = template.split("-")
49
+ template("#{root}/#{template}", [path, *template_path_parts, template_name].join("/"))
50
+ end
51
+ end
52
+
53
+ def get_db_gem_name
54
+ case database
55
+ when "mysql"
56
+ "mysql2"
57
+ when "trilogy"
58
+ "trilogy"
59
+ when "postgresql"
60
+ "pg"
61
+ when "sqlite3"
62
+ "sqlite3"
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rage::CLI
4
+ class OpenAPI < Base
5
+ desc "validate", "Validate OpenAPI tags and fail if any warnings were produced"
6
+ def validate
7
+ environment
8
+
9
+ abort "OpenAPI validation requires a booted application." unless Rage.config.internal.initialized?
10
+
11
+ warnings = Rage::OpenAPI.__collect_warnings { Rage::OpenAPI.build }
12
+
13
+ if warnings.any?
14
+ abort "#{set_color("𐄂", :red, :bold)} OpenAPI validation failed with #{warnings.size} warning(s)."
15
+ else
16
+ say "#{set_color("✓", :green, :bold)} OpenAPI validation passed without warnings."
17
+ end
18
+ end
19
+ end
20
+ end