Skip to content

Commit d648f99

Browse files
committed
fixed a sorbet type issue and got all tests passing
1 parent b8a72d1 commit d648f99

4 files changed

Lines changed: 54 additions & 2 deletions

File tree

DEVELOPMENT.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,34 @@
77
- You do need to `extend T::Helpers` in modules if they use other Sorbet features (e.g `requires_ancestor`)
88
- Never use `LogStruct::` when you're inside the `module LogStruct` scope (same for nested modules/classes.)
99

10+
## Critical: Sorbet Runtime Type Checking and Return Values
11+
12+
**NEVER use `void` return types for methods that need to return values to other code.**
13+
14+
Sorbet runtime type checking will enforce return type signatures and can interfere with method return values. If a method has `sig { ... }.void`, Sorbet will return `T::Private::Types::Void::VOID` instead of the actual method result.
15+
16+
This is especially critical for:
17+
18+
- Rack middleware `call` methods (must return `[status, headers, body]`)
19+
- Methods used in Rails middleware chain (like `logger.tagged`)
20+
- Any method where the return value is used by external code
21+
22+
**Fix:** Use `T.untyped` instead of `void` for return types when the return value matters:
23+
24+
```ruby
25+
# BAD - will return VOID instead of block result
26+
sig { params(block: T.proc.void).void }
27+
def tagged(&block)
28+
# ...
29+
end
30+
31+
# GOOD - returns the actual block result
32+
sig { params(block: T.proc.returns(T.untyped)).returns(T.untyped) }
33+
def tagged(&block)
34+
# ...
35+
end
36+
```
37+
1038
# Core Dependencies
1139

1240
This gem requires Rails 7.0+ and will always have access to these core Rails modules:

lib/log_struct/integrations/rack_error_handler/middleware.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def call(env)
126126

127127
private
128128

129-
sig { params(env: T.untyped).returns(T::Hash[Symbol, T.untyped]) }
129+
sig { params(env: T::Hash[String, T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
130130
def extract_request_context(env)
131131
request = ::ActionDispatch::Request.new(env)
132132
{

lib/log_struct/semantic_logger/logger.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def initialize(name = "Application", level: nil, filter: nil)
8989
end
9090

9191
# Support for tagged logging
92-
sig { params(tags: T.untyped, block: T.proc.void).void }
92+
sig { params(tags: T.untyped, block: T.proc.returns(T.untyped)).returns(T.untyped) }
9393
def tagged(*tags, &block)
9494
# Convert tags to array and pass individually to avoid splat issues
9595
tag_array = tags.flatten
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# typed: strict
2+
# frozen_string_literal: true
3+
4+
module Rack
5+
# Type definitions for Rack middleware
6+
7+
# Standard Rack response tuple: [status, headers, body]
8+
# Status is an Integer HTTP status code
9+
# Headers is a Hash of String keys to String (or Array<String>) values
10+
# Body is an enumerable that yields strings
11+
RackResponse = T.type_alias { [Integer, T::Hash[String, T.untyped], T.any(T::Array[String], T::Enumerable[String])] }
12+
13+
# Rack environment hash
14+
RackEnv = T.type_alias { T::Hash[String, T.untyped] }
15+
16+
# Rack application/middleware callable
17+
# Must respond to #call(env) and return a RackResponse
18+
RackApp = T.type_alias {
19+
T.any(
20+
T.proc.params(env: RackEnv).returns(RackResponse),
21+
T.untyped # For objects with #call method
22+
)
23+
}
24+
end

0 commit comments

Comments
 (0)