spikard 0.13.0 → 0.15.2
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/Steepfile +6 -0
- data/ext/spikard_rb/extconf.rb +1 -2
- data/ext/spikard_rb/{Cargo.lock → native/Cargo.lock} +819 -424
- data/ext/spikard_rb/native/Cargo.toml +24 -0
- data/ext/spikard_rb/src/lib.rs +5366 -3
- data/lib/spikard/native.rb +86 -0
- data/lib/spikard/version.rb +6 -1
- data/lib/spikard.rb +8 -52
- data/lib/spikard_rb.so +0 -0
- data/sig/types.rbs +427 -0
- metadata +14 -243
- data/LICENSE +0 -1
- data/README.md +0 -285
- data/ext/spikard_rb/Cargo.toml +0 -17
- data/lib/spikard/app.rb +0 -458
- data/lib/spikard/background.rb +0 -58
- data/lib/spikard/config.rb +0 -506
- data/lib/spikard/converters.rb +0 -13
- data/lib/spikard/grpc.rb +0 -232
- data/lib/spikard/handler_wrapper.rb +0 -113
- data/lib/spikard/provide.rb +0 -315
- data/lib/spikard/response.rb +0 -198
- data/lib/spikard/schema.rb +0 -243
- data/lib/spikard/sse.rb +0 -111
- data/lib/spikard/streaming_response.rb +0 -44
- data/lib/spikard/testing.rb +0 -474
- data/lib/spikard/upload_file.rb +0 -131
- data/lib/spikard/websocket.rb +0 -59
- data/sig/spikard.rbs +0 -739
- data/vendor/crates/spikard-bindings-shared/Cargo.toml +0 -75
- data/vendor/crates/spikard-bindings-shared/examples/config_extraction.rs +0 -132
- data/vendor/crates/spikard-bindings-shared/src/config_extractor.rs +0 -905
- data/vendor/crates/spikard-bindings-shared/src/conversion_traits.rs +0 -210
- data/vendor/crates/spikard-bindings-shared/src/di_traits.rs +0 -252
- data/vendor/crates/spikard-bindings-shared/src/error_response.rs +0 -404
- data/vendor/crates/spikard-bindings-shared/src/grpc_metadata.rs +0 -199
- data/vendor/crates/spikard-bindings-shared/src/handler_base.rs +0 -252
- data/vendor/crates/spikard-bindings-shared/src/json_conversion.rs +0 -829
- data/vendor/crates/spikard-bindings-shared/src/lazy_cache.rs +0 -587
- data/vendor/crates/spikard-bindings-shared/src/lib.rs +0 -33
- data/vendor/crates/spikard-bindings-shared/src/lifecycle_base.rs +0 -298
- data/vendor/crates/spikard-bindings-shared/src/lifecycle_executor.rs +0 -594
- data/vendor/crates/spikard-bindings-shared/src/response_builder.rs +0 -743
- data/vendor/crates/spikard-bindings-shared/src/response_interpreter.rs +0 -944
- data/vendor/crates/spikard-bindings-shared/src/test_client_base.rs +0 -260
- data/vendor/crates/spikard-bindings-shared/src/validation_helpers.rs +0 -369
- data/vendor/crates/spikard-bindings-shared/tests/config_extractor_behavior.rs +0 -192
- data/vendor/crates/spikard-bindings-shared/tests/error_response_edge_cases.rs +0 -383
- data/vendor/crates/spikard-bindings-shared/tests/full_coverage.rs +0 -459
- data/vendor/crates/spikard-bindings-shared/tests/handler_base_integration.rs +0 -280
- data/vendor/crates/spikard-bindings-shared/tests/integration_tests.rs +0 -669
- data/vendor/crates/spikard-core/Cargo.toml +0 -55
- data/vendor/crates/spikard-core/src/bindings/mod.rs +0 -3
- data/vendor/crates/spikard-core/src/bindings/response.rs +0 -130
- data/vendor/crates/spikard-core/src/debug.rs +0 -127
- data/vendor/crates/spikard-core/src/di/container.rs +0 -711
- data/vendor/crates/spikard-core/src/di/dependency.rs +0 -273
- data/vendor/crates/spikard-core/src/di/error.rs +0 -118
- data/vendor/crates/spikard-core/src/di/factory.rs +0 -548
- data/vendor/crates/spikard-core/src/di/graph.rs +0 -507
- data/vendor/crates/spikard-core/src/di/mod.rs +0 -192
- data/vendor/crates/spikard-core/src/di/resolved.rs +0 -428
- data/vendor/crates/spikard-core/src/di/value.rs +0 -282
- data/vendor/crates/spikard-core/src/errors.rs +0 -72
- data/vendor/crates/spikard-core/src/http.rs +0 -492
- data/vendor/crates/spikard-core/src/lib.rs +0 -29
- data/vendor/crates/spikard-core/src/lifecycle.rs +0 -1273
- data/vendor/crates/spikard-core/src/metadata.rs +0 -378
- data/vendor/crates/spikard-core/src/parameters.rs +0 -2546
- data/vendor/crates/spikard-core/src/problem.rs +0 -358
- data/vendor/crates/spikard-core/src/request_data.rs +0 -1146
- data/vendor/crates/spikard-core/src/router.rs +0 -530
- data/vendor/crates/spikard-core/src/schema_registry.rs +0 -197
- data/vendor/crates/spikard-core/src/type_hints.rs +0 -311
- data/vendor/crates/spikard-core/src/validation/error_mapper.rs +0 -710
- data/vendor/crates/spikard-core/src/validation/mod.rs +0 -470
- data/vendor/crates/spikard-core/tests/bindings_response_tests.rs +0 -136
- data/vendor/crates/spikard-core/tests/di_dependency_defaults.rs +0 -37
- data/vendor/crates/spikard-core/tests/error_mapper.rs +0 -761
- data/vendor/crates/spikard-core/tests/parameters_edge_cases.rs +0 -106
- data/vendor/crates/spikard-core/tests/parameters_full.rs +0 -701
- data/vendor/crates/spikard-core/tests/parameters_schema_and_formats.rs +0 -301
- data/vendor/crates/spikard-core/tests/request_data_roundtrip.rs +0 -67
- data/vendor/crates/spikard-core/tests/validation_coverage.rs +0 -250
- data/vendor/crates/spikard-core/tests/validation_error_paths.rs +0 -45
- data/vendor/crates/spikard-http/Cargo.toml +0 -82
- data/vendor/crates/spikard-http/examples/sse-notifications.rs +0 -148
- data/vendor/crates/spikard-http/examples/websocket-chat.rs +0 -92
- data/vendor/crates/spikard-http/src/auth.rs +0 -301
- data/vendor/crates/spikard-http/src/background.rs +0 -1859
- data/vendor/crates/spikard-http/src/bindings/mod.rs +0 -3
- data/vendor/crates/spikard-http/src/bindings/response.rs +0 -1
- data/vendor/crates/spikard-http/src/body_metadata.rs +0 -8
- data/vendor/crates/spikard-http/src/cors.rs +0 -1026
- data/vendor/crates/spikard-http/src/debug.rs +0 -128
- data/vendor/crates/spikard-http/src/di_handler.rs +0 -1672
- data/vendor/crates/spikard-http/src/grpc/framing.rs +0 -653
- data/vendor/crates/spikard-http/src/grpc/handler.rs +0 -1211
- data/vendor/crates/spikard-http/src/grpc/mod.rs +0 -556
- data/vendor/crates/spikard-http/src/grpc/service.rs +0 -706
- data/vendor/crates/spikard-http/src/grpc/streaming.rs +0 -319
- data/vendor/crates/spikard-http/src/handler_response.rs +0 -901
- data/vendor/crates/spikard-http/src/handler_trait.rs +0 -1015
- data/vendor/crates/spikard-http/src/handler_trait_tests.rs +0 -290
- data/vendor/crates/spikard-http/src/jsonrpc/http_handler.rs +0 -502
- data/vendor/crates/spikard-http/src/jsonrpc/method_registry.rs +0 -648
- data/vendor/crates/spikard-http/src/jsonrpc/mod.rs +0 -60
- data/vendor/crates/spikard-http/src/jsonrpc/openrpc.rs +0 -325
- data/vendor/crates/spikard-http/src/jsonrpc/protocol.rs +0 -1207
- data/vendor/crates/spikard-http/src/jsonrpc/router.rs +0 -2262
- data/vendor/crates/spikard-http/src/lib.rs +0 -566
- data/vendor/crates/spikard-http/src/lifecycle/adapter.rs +0 -230
- data/vendor/crates/spikard-http/src/lifecycle.rs +0 -1193
- data/vendor/crates/spikard-http/src/middleware/mod.rs +0 -560
- data/vendor/crates/spikard-http/src/middleware/multipart.rs +0 -912
- data/vendor/crates/spikard-http/src/middleware/urlencoded.rs +0 -513
- data/vendor/crates/spikard-http/src/middleware/validation.rs +0 -768
- data/vendor/crates/spikard-http/src/openapi/mod.rs +0 -309
- data/vendor/crates/spikard-http/src/openapi/parameter_extraction.rs +0 -535
- data/vendor/crates/spikard-http/src/openapi/schema_conversion.rs +0 -1363
- data/vendor/crates/spikard-http/src/openapi/spec_generation.rs +0 -667
- data/vendor/crates/spikard-http/src/query_parser.rs +0 -793
- data/vendor/crates/spikard-http/src/response.rs +0 -720
- data/vendor/crates/spikard-http/src/server/fast_router.rs +0 -186
- data/vendor/crates/spikard-http/src/server/grpc_routing.rs +0 -1243
- data/vendor/crates/spikard-http/src/server/handler.rs +0 -1661
- data/vendor/crates/spikard-http/src/server/lifecycle_execution.rs +0 -253
- data/vendor/crates/spikard-http/src/server/mod.rs +0 -1717
- data/vendor/crates/spikard-http/src/server/request_extraction.rs +0 -871
- data/vendor/crates/spikard-http/src/server/routing_factory.rs +0 -618
- data/vendor/crates/spikard-http/src/sse.rs +0 -1409
- data/vendor/crates/spikard-http/src/testing/form.rs +0 -52
- data/vendor/crates/spikard-http/src/testing/multipart.rs +0 -64
- data/vendor/crates/spikard-http/src/testing/test_client.rs +0 -825
- data/vendor/crates/spikard-http/src/testing.rs +0 -617
- data/vendor/crates/spikard-http/src/websocket.rs +0 -1477
- data/vendor/crates/spikard-http/tests/auth_integration.rs +0 -645
- data/vendor/crates/spikard-http/tests/background_behavior.rs +0 -832
- data/vendor/crates/spikard-http/tests/common/grpc_helpers.rs +0 -1012
- data/vendor/crates/spikard-http/tests/common/handlers.rs +0 -309
- data/vendor/crates/spikard-http/tests/common/mod.rs +0 -33
- data/vendor/crates/spikard-http/tests/common/test_builders.rs +0 -628
- data/vendor/crates/spikard-http/tests/di_handler_error_responses.rs +0 -162
- data/vendor/crates/spikard-http/tests/di_integration.rs +0 -192
- data/vendor/crates/spikard-http/tests/doc_snippets.rs +0 -5
- data/vendor/crates/spikard-http/tests/grpc_bidirectional_streaming.rs +0 -430
- data/vendor/crates/spikard-http/tests/grpc_client_streaming.rs +0 -738
- data/vendor/crates/spikard-http/tests/grpc_error_handling_test.rs +0 -652
- data/vendor/crates/spikard-http/tests/grpc_integration_test.rs +0 -334
- data/vendor/crates/spikard-http/tests/grpc_metadata_test.rs +0 -532
- data/vendor/crates/spikard-http/tests/grpc_server_integration.rs +0 -495
- data/vendor/crates/spikard-http/tests/grpc_server_streaming.rs +0 -975
- data/vendor/crates/spikard-http/tests/lifecycle_execution.rs +0 -1093
- data/vendor/crates/spikard-http/tests/middleware_stack_integration.rs +0 -389
- data/vendor/crates/spikard-http/tests/multipart_behavior.rs +0 -656
- data/vendor/crates/spikard-http/tests/request_extraction_full.rs +0 -513
- data/vendor/crates/spikard-http/tests/server_auth_middleware_behavior.rs +0 -328
- data/vendor/crates/spikard-http/tests/server_config_builder.rs +0 -335
- data/vendor/crates/spikard-http/tests/server_configured_router_behavior.rs +0 -374
- data/vendor/crates/spikard-http/tests/server_cors_preflight.rs +0 -83
- data/vendor/crates/spikard-http/tests/server_handler_wrappers.rs +0 -464
- data/vendor/crates/spikard-http/tests/server_method_router_additional_behavior.rs +0 -286
- data/vendor/crates/spikard-http/tests/server_method_router_coverage.rs +0 -118
- data/vendor/crates/spikard-http/tests/server_middleware_behavior.rs +0 -99
- data/vendor/crates/spikard-http/tests/server_middleware_branches.rs +0 -204
- data/vendor/crates/spikard-http/tests/server_openapi_jsonrpc_static.rs +0 -427
- data/vendor/crates/spikard-http/tests/server_router_behavior.rs +0 -121
- data/vendor/crates/spikard-http/tests/sse_behavior.rs +0 -620
- data/vendor/crates/spikard-http/tests/sse_full_behavior.rs +0 -584
- data/vendor/crates/spikard-http/tests/sse_handler_behavior.rs +0 -130
- data/vendor/crates/spikard-http/tests/test_client_requests.rs +0 -167
- data/vendor/crates/spikard-http/tests/testing_helpers.rs +0 -87
- data/vendor/crates/spikard-http/tests/testing_module_coverage.rs +0 -155
- data/vendor/crates/spikard-http/tests/urlencoded_content_type.rs +0 -82
- data/vendor/crates/spikard-http/tests/websocket_behavior.rs +0 -663
- data/vendor/crates/spikard-http/tests/websocket_full_behavior.rs +0 -440
- data/vendor/crates/spikard-http/tests/websocket_integration.rs +0 -150
- data/vendor/crates/spikard-rb/Cargo.toml +0 -63
- data/vendor/crates/spikard-rb/build.rs +0 -200
- data/vendor/crates/spikard-rb/src/background.rs +0 -63
- data/vendor/crates/spikard-rb/src/config/mod.rs +0 -5
- data/vendor/crates/spikard-rb/src/config/server_config.rs +0 -401
- data/vendor/crates/spikard-rb/src/conversion.rs +0 -688
- data/vendor/crates/spikard-rb/src/di/builder.rs +0 -100
- data/vendor/crates/spikard-rb/src/di/mod.rs +0 -410
- data/vendor/crates/spikard-rb/src/grpc/handler.rs +0 -875
- data/vendor/crates/spikard-rb/src/grpc/mod.rs +0 -13
- data/vendor/crates/spikard-rb/src/gvl.rs +0 -80
- data/vendor/crates/spikard-rb/src/handler.rs +0 -699
- data/vendor/crates/spikard-rb/src/integration/mod.rs +0 -3
- data/vendor/crates/spikard-rb/src/lib.rs +0 -2268
- data/vendor/crates/spikard-rb/src/lifecycle.rs +0 -334
- data/vendor/crates/spikard-rb/src/metadata/mod.rs +0 -5
- data/vendor/crates/spikard-rb/src/metadata/route_extraction.rs +0 -507
- data/vendor/crates/spikard-rb/src/request.rs +0 -439
- data/vendor/crates/spikard-rb/src/runtime/mod.rs +0 -5
- data/vendor/crates/spikard-rb/src/runtime/server_runner.rs +0 -368
- data/vendor/crates/spikard-rb/src/server.rs +0 -304
- data/vendor/crates/spikard-rb/src/sse.rs +0 -231
- data/vendor/crates/spikard-rb/src/testing/client.rs +0 -698
- data/vendor/crates/spikard-rb/src/testing/mod.rs +0 -7
- data/vendor/crates/spikard-rb/src/testing/sse.rs +0 -108
- data/vendor/crates/spikard-rb/src/testing/websocket.rs +0 -573
- data/vendor/crates/spikard-rb/src/websocket.rs +0 -521
- data/vendor/crates/spikard-rb-macros/Cargo.toml +0 -20
- data/vendor/crates/spikard-rb-macros/src/lib.rs +0 -51
data/lib/spikard/grpc.rb
DELETED
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Spikard
|
|
4
|
-
# gRPC support for Spikard
|
|
5
|
-
#
|
|
6
|
-
# This module provides Ruby bindings for handling gRPC requests through
|
|
7
|
-
# Spikard's Rust-based gRPC runtime. Handlers receive protobuf messages
|
|
8
|
-
# as binary strings and use the google-protobuf gem for serialization.
|
|
9
|
-
#
|
|
10
|
-
# @example Basic gRPC handler
|
|
11
|
-
# require 'spikard/grpc'
|
|
12
|
-
# require 'user_pb' # Generated protobuf
|
|
13
|
-
#
|
|
14
|
-
# class UserServiceHandler < Spikard::Grpc::Handler
|
|
15
|
-
# def handle_request(request)
|
|
16
|
-
# case request.method_name
|
|
17
|
-
# when 'GetUser'
|
|
18
|
-
# # Deserialize request
|
|
19
|
-
# req = Example::GetUserRequest.decode(request.payload)
|
|
20
|
-
#
|
|
21
|
-
# # Process request
|
|
22
|
-
# user = Example::User.new(id: req.id, name: 'John Doe')
|
|
23
|
-
#
|
|
24
|
-
# # Serialize response
|
|
25
|
-
# Spikard::Grpc::Response.new(payload: Example::User.encode(user))
|
|
26
|
-
# else
|
|
27
|
-
# raise "Unknown method: #{request.method_name}"
|
|
28
|
-
# end
|
|
29
|
-
# end
|
|
30
|
-
# end
|
|
31
|
-
module Grpc
|
|
32
|
-
STATUS_CODES = {
|
|
33
|
-
'OK' => '0',
|
|
34
|
-
'CANCELLED' => '1',
|
|
35
|
-
'UNKNOWN' => '2',
|
|
36
|
-
'INVALID_ARGUMENT' => '3',
|
|
37
|
-
'DEADLINE_EXCEEDED' => '4',
|
|
38
|
-
'NOT_FOUND' => '5',
|
|
39
|
-
'ALREADY_EXISTS' => '6',
|
|
40
|
-
'PERMISSION_DENIED' => '7',
|
|
41
|
-
'RESOURCE_EXHAUSTED' => '8',
|
|
42
|
-
'FAILED_PRECONDITION' => '9',
|
|
43
|
-
'ABORTED' => '10',
|
|
44
|
-
'OUT_OF_RANGE' => '11',
|
|
45
|
-
'UNIMPLEMENTED' => '12',
|
|
46
|
-
'INTERNAL' => '13',
|
|
47
|
-
'UNAVAILABLE' => '14',
|
|
48
|
-
'DATA_LOSS' => '15',
|
|
49
|
-
'UNAUTHENTICATED' => '16'
|
|
50
|
-
}.freeze
|
|
51
|
-
|
|
52
|
-
# gRPC request object
|
|
53
|
-
#
|
|
54
|
-
# Represents an incoming gRPC request with service/method information
|
|
55
|
-
# and a binary protobuf payload.
|
|
56
|
-
#
|
|
57
|
-
# @!attribute [r] service_name
|
|
58
|
-
# @return [String] Fully qualified service name (e.g., "mypackage.MyService")
|
|
59
|
-
# @!attribute [r] method_name
|
|
60
|
-
# @return [String] Method name (e.g., "GetUser")
|
|
61
|
-
# @!attribute [r] payload
|
|
62
|
-
# @return [String] Binary string containing serialized protobuf message
|
|
63
|
-
# @!attribute [r] metadata
|
|
64
|
-
# @return [Hash<String, String>] gRPC metadata (headers)
|
|
65
|
-
# rubocop:disable Lint/EmptyClass -- Implementation in Rust via FFI
|
|
66
|
-
class Request
|
|
67
|
-
# These methods are implemented in Rust via Magnus FFI.
|
|
68
|
-
# See: crates/spikard-rb/src/grpc/handler.rs for implementation details.
|
|
69
|
-
end
|
|
70
|
-
# rubocop:enable Lint/EmptyClass
|
|
71
|
-
|
|
72
|
-
# gRPC response object
|
|
73
|
-
#
|
|
74
|
-
# Used to return gRPC responses from handlers. The payload should be
|
|
75
|
-
# a binary string containing a serialized protobuf message.
|
|
76
|
-
#
|
|
77
|
-
# @example Creating a response
|
|
78
|
-
# user = Example::User.new(id: 1, name: 'Alice')
|
|
79
|
-
# response = Spikard::Grpc::Response.new(payload: Example::User.encode(user))
|
|
80
|
-
#
|
|
81
|
-
# @example Adding metadata
|
|
82
|
-
# response = Spikard::Grpc::Response.new(payload: encoded_message)
|
|
83
|
-
# response.metadata = { 'x-custom-header' => 'value' }
|
|
84
|
-
class Response
|
|
85
|
-
# @!attribute [w] metadata
|
|
86
|
-
# @return [Hash<String, String>] gRPC metadata to include in response
|
|
87
|
-
|
|
88
|
-
# Create a new gRPC response
|
|
89
|
-
#
|
|
90
|
-
# @param payload [String] Binary string containing serialized protobuf message
|
|
91
|
-
# @raise [ArgumentError] if payload is not a String
|
|
92
|
-
#
|
|
93
|
-
# Note: Implementation in Rust (Magnus FFI)
|
|
94
|
-
# See: crates/spikard-rb/src/grpc/handler.rs
|
|
95
|
-
|
|
96
|
-
# Create an error response
|
|
97
|
-
#
|
|
98
|
-
# @param message [String] Error message
|
|
99
|
-
# @param status_or_metadata [String, Integer, Hash<String, String>] Optional gRPC
|
|
100
|
-
# status alias/code or metadata hash
|
|
101
|
-
# @param metadata [Hash<String, String>] Optional gRPC metadata when a status is provided
|
|
102
|
-
# @return [Response] A response with error status
|
|
103
|
-
#
|
|
104
|
-
# @example
|
|
105
|
-
# response = Spikard::Grpc::Response.error('Method not implemented')
|
|
106
|
-
def self.error(message, status_or_metadata = {}, metadata = {})
|
|
107
|
-
status = nil
|
|
108
|
-
|
|
109
|
-
if status_or_metadata.is_a?(Hash)
|
|
110
|
-
metadata = status_or_metadata.merge(metadata)
|
|
111
|
-
else
|
|
112
|
-
status = status_or_metadata
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
error_metadata = metadata.transform_keys(&:to_s)
|
|
116
|
-
error_metadata['grpc-status'] =
|
|
117
|
-
normalize_status(status || error_metadata['grpc-status'] || 'INTERNAL')
|
|
118
|
-
error_metadata['grpc-message'] = message
|
|
119
|
-
|
|
120
|
-
response = new(payload: '')
|
|
121
|
-
response.metadata = error_metadata
|
|
122
|
-
response
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def self.normalize_status(status)
|
|
126
|
-
case status
|
|
127
|
-
when Integer
|
|
128
|
-
status.to_s
|
|
129
|
-
when Symbol
|
|
130
|
-
normalize_status(status.to_s)
|
|
131
|
-
when String
|
|
132
|
-
normalized = status.strip
|
|
133
|
-
return normalized if /\A\d+\z/.match?(normalized)
|
|
134
|
-
|
|
135
|
-
STATUS_CODES.fetch(normalized.upcase) do
|
|
136
|
-
raise ArgumentError, "Unknown gRPC status: #{status}"
|
|
137
|
-
end
|
|
138
|
-
else
|
|
139
|
-
raise ArgumentError, "gRPC status must be a String, Symbol, or Integer (got #{status.class})"
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
private_class_method :normalize_status
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
# Base class for gRPC handlers
|
|
146
|
-
#
|
|
147
|
-
# Subclass this to implement gRPC service handlers. Override
|
|
148
|
-
# {#handle_request} to process incoming requests.
|
|
149
|
-
#
|
|
150
|
-
# @example Implementing a handler
|
|
151
|
-
# class MyServiceHandler < Spikard::Grpc::Handler
|
|
152
|
-
# def handle_request(request)
|
|
153
|
-
# case request.method_name
|
|
154
|
-
# when 'MethodOne'
|
|
155
|
-
# # Handle MethodOne
|
|
156
|
-
# req = MyPackage::MethodOneRequest.decode(request.payload)
|
|
157
|
-
# resp = MyPackage::MethodOneResponse.new(...)
|
|
158
|
-
# Spikard::Grpc::Response.new(payload: MyPackage::MethodOneResponse.encode(resp))
|
|
159
|
-
# when 'MethodTwo'
|
|
160
|
-
# # Handle MethodTwo
|
|
161
|
-
# # ...
|
|
162
|
-
# else
|
|
163
|
-
# raise "Unknown method: #{request.method_name}"
|
|
164
|
-
# end
|
|
165
|
-
# end
|
|
166
|
-
# end
|
|
167
|
-
class Handler
|
|
168
|
-
# Handle a gRPC request
|
|
169
|
-
#
|
|
170
|
-
# This method must be overridden by subclasses to implement the
|
|
171
|
-
# actual request handling logic.
|
|
172
|
-
#
|
|
173
|
-
# @param request [Spikard::Grpc::Request] The incoming gRPC request
|
|
174
|
-
# @return [Spikard::Grpc::Response] The gRPC response
|
|
175
|
-
# @raise [NotImplementedError] if not overridden by subclass
|
|
176
|
-
def handle_request(request)
|
|
177
|
-
raise NotImplementedError, "#{self.class}#handle_request must be implemented"
|
|
178
|
-
end
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
# Service registry for gRPC handlers
|
|
182
|
-
#
|
|
183
|
-
# Manages registration and lookup of gRPC service handlers.
|
|
184
|
-
# Handlers are registered by service name and method.
|
|
185
|
-
#
|
|
186
|
-
# @example Registering a handler
|
|
187
|
-
# service = Spikard::Grpc::Service.new
|
|
188
|
-
# handler = UserServiceHandler.new
|
|
189
|
-
# service.register_handler('mypackage.UserService', handler)
|
|
190
|
-
class Service
|
|
191
|
-
def initialize
|
|
192
|
-
@handlers = {}
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
# Register a gRPC handler for a service
|
|
196
|
-
#
|
|
197
|
-
# @param service_name [String] Fully qualified service name
|
|
198
|
-
# @param handler [Spikard::Grpc::Handler] Handler instance
|
|
199
|
-
# @raise [ArgumentError] if service_name is invalid or handler doesn't respond to handle_request
|
|
200
|
-
def register_handler(service_name, handler)
|
|
201
|
-
raise ArgumentError, 'Service name cannot be empty' if service_name.nil? || service_name.empty?
|
|
202
|
-
|
|
203
|
-
raise ArgumentError, 'Handler must respond to :handle_request' unless handler.respond_to?(:handle_request)
|
|
204
|
-
|
|
205
|
-
@handlers[service_name] = handler
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
# Get a handler by service name
|
|
209
|
-
#
|
|
210
|
-
# @param service_name [String] Fully qualified service name
|
|
211
|
-
# @return [Spikard::Grpc::Handler, nil] The handler or nil if not found
|
|
212
|
-
def get_handler(service_name)
|
|
213
|
-
@handlers[service_name]
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
# Get all registered service names
|
|
217
|
-
#
|
|
218
|
-
# @return [Array<String>] List of registered service names
|
|
219
|
-
def service_names
|
|
220
|
-
@handlers.keys
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
# Check if a service is registered
|
|
224
|
-
#
|
|
225
|
-
# @param service_name [String] Fully qualified service name
|
|
226
|
-
# @return [Boolean] true if the service is registered
|
|
227
|
-
def registered?(service_name)
|
|
228
|
-
@handlers.key?(service_name)
|
|
229
|
-
end
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
end
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative 'converters'
|
|
4
|
-
|
|
5
|
-
module Spikard
|
|
6
|
-
# Handler wrapper utilities.
|
|
7
|
-
#
|
|
8
|
-
# UploadFile conversion now happens in the Rust binding, so these wrappers
|
|
9
|
-
# simply forward the already-converted body/params.
|
|
10
|
-
#
|
|
11
|
-
# @example Basic usage with body only
|
|
12
|
-
# app.post('/upload', &wrap_body_handler do |body|
|
|
13
|
-
# {
|
|
14
|
-
# filename: body[:file].filename,
|
|
15
|
-
# content: body[:file].read
|
|
16
|
-
# }
|
|
17
|
-
# end)
|
|
18
|
-
#
|
|
19
|
-
# @example With all parameters
|
|
20
|
-
# app.post('/upload', &wrap_handler do |params, query, body|
|
|
21
|
-
# {
|
|
22
|
-
# id: params[:id],
|
|
23
|
-
# search: query[:q],
|
|
24
|
-
# file: body[:file].filename
|
|
25
|
-
# }
|
|
26
|
-
# end)
|
|
27
|
-
module HandlerWrapper
|
|
28
|
-
module_function
|
|
29
|
-
|
|
30
|
-
# Wrap a handler that receives only the request body
|
|
31
|
-
#
|
|
32
|
-
# Automatically converts file metadata in the body to UploadFile instances.
|
|
33
|
-
#
|
|
34
|
-
# @yield [body] Handler block that receives converted body
|
|
35
|
-
# @yieldparam body [Hash] Request body with file metadata converted to UploadFile
|
|
36
|
-
# @yieldreturn [Hash, Spikard::Response] Response data or Response object
|
|
37
|
-
# @return [Proc] Wrapped handler proc
|
|
38
|
-
#
|
|
39
|
-
# @example
|
|
40
|
-
# app.post('/upload', &wrap_body_handler do |body|
|
|
41
|
-
# { filename: body[:file].filename }
|
|
42
|
-
# end)
|
|
43
|
-
def wrap_body_handler(&handler)
|
|
44
|
-
raise ArgumentError, 'block required for wrap_body_handler' unless handler
|
|
45
|
-
|
|
46
|
-
# Return a proc that matches the signature expected by Spikard::App
|
|
47
|
-
# The actual handler receives path params, query params, and body from Rust
|
|
48
|
-
lambda do |_params, _query, body|
|
|
49
|
-
handler.call(body)
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Wrap a handler that receives path params, query params, and body
|
|
54
|
-
#
|
|
55
|
-
# Automatically converts file metadata in the body to UploadFile instances.
|
|
56
|
-
#
|
|
57
|
-
# @yield [params, query, body] Handler block that receives all request data
|
|
58
|
-
# @yieldparam params [Hash] Path parameters
|
|
59
|
-
# @yieldparam query [Hash] Query parameters
|
|
60
|
-
# @yieldparam body [Hash] Request body with file metadata converted to UploadFile
|
|
61
|
-
# @yieldreturn [Hash, Spikard::Response] Response data or Response object
|
|
62
|
-
# @return [Proc] Wrapped handler proc
|
|
63
|
-
#
|
|
64
|
-
# @example
|
|
65
|
-
# app.post('/users/{id}/upload', &wrap_handler do |params, query, body|
|
|
66
|
-
# {
|
|
67
|
-
# user_id: params[:id],
|
|
68
|
-
# description: query[:desc],
|
|
69
|
-
# file: body[:file].filename
|
|
70
|
-
# }
|
|
71
|
-
# end)
|
|
72
|
-
def wrap_handler(&handler)
|
|
73
|
-
raise ArgumentError, 'block required for wrap_handler' unless handler
|
|
74
|
-
|
|
75
|
-
lambda do |params, query, body|
|
|
76
|
-
handler.call(params, query, body)
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# Wrap a handler that receives a context hash with all request data
|
|
81
|
-
#
|
|
82
|
-
# Automatically converts file metadata in the body to UploadFile instances.
|
|
83
|
-
# Useful when you want all request data in a single hash.
|
|
84
|
-
#
|
|
85
|
-
# @yield [context] Handler block that receives context hash
|
|
86
|
-
# @yieldparam context [Hash] Request context with:
|
|
87
|
-
# - :params [Hash] Path parameters
|
|
88
|
-
# - :query [Hash] Query parameters
|
|
89
|
-
# - :body [Hash] Request body with file metadata converted to UploadFile
|
|
90
|
-
# @yieldreturn [Hash, Spikard::Response] Response data or Response object
|
|
91
|
-
# @return [Proc] Wrapped handler proc
|
|
92
|
-
#
|
|
93
|
-
# @example
|
|
94
|
-
# app.post('/upload', &wrap_handler_with_context do |ctx|
|
|
95
|
-
# {
|
|
96
|
-
# file: ctx[:body][:file].filename,
|
|
97
|
-
# query_params: ctx[:query]
|
|
98
|
-
# }
|
|
99
|
-
# end)
|
|
100
|
-
def wrap_handler_with_context(&handler)
|
|
101
|
-
raise ArgumentError, 'block required for wrap_handler_with_context' unless handler
|
|
102
|
-
|
|
103
|
-
lambda do |params, query, body|
|
|
104
|
-
context = {
|
|
105
|
-
params: params,
|
|
106
|
-
query: query,
|
|
107
|
-
body: body
|
|
108
|
-
}
|
|
109
|
-
handler.call(context)
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
end
|
data/lib/spikard/provide.rb
DELETED
|
@@ -1,315 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Spikard
|
|
4
|
-
# Wrapper class for dependency providers
|
|
5
|
-
#
|
|
6
|
-
# This class wraps factory functions and configuration for dependency injection.
|
|
7
|
-
# It provides a consistent API across Python, Node.js, and Ruby bindings.
|
|
8
|
-
#
|
|
9
|
-
# @example Factory with caching
|
|
10
|
-
# app.provide("db", Spikard::Provide.new(method("create_db"), cacheable: true))
|
|
11
|
-
#
|
|
12
|
-
# @example Factory with dependencies
|
|
13
|
-
# app.provide("auth", Spikard::Provide.new(
|
|
14
|
-
# method("create_auth_service"),
|
|
15
|
-
# depends_on: ["db", "cache"],
|
|
16
|
-
# singleton: true
|
|
17
|
-
# ))
|
|
18
|
-
class Provide
|
|
19
|
-
attr_reader :factory, :depends_on, :singleton, :cacheable
|
|
20
|
-
|
|
21
|
-
# Create a new dependency provider
|
|
22
|
-
#
|
|
23
|
-
# @param factory [Proc, Method] The factory function that creates the dependency value
|
|
24
|
-
# @param depends_on [Array<String, Symbol>] List of dependency keys this factory depends on
|
|
25
|
-
# @param singleton [Boolean] Whether to cache the value globally (default: false)
|
|
26
|
-
# @param cacheable [Boolean] Whether to cache the value per-request (default: true)
|
|
27
|
-
def initialize(factory, depends_on: [], singleton: false, cacheable: true)
|
|
28
|
-
@factory = factory
|
|
29
|
-
@depends_on = Array(depends_on).map(&:to_s)
|
|
30
|
-
@singleton = singleton
|
|
31
|
-
@cacheable = cacheable
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# Check if the factory is async (based on method arity or other heuristics)
|
|
35
|
-
#
|
|
36
|
-
# @return [Boolean] True if the factory appears to be async
|
|
37
|
-
def async?
|
|
38
|
-
# Ruby doesn't have explicit async/await like Python/JS
|
|
39
|
-
# We could check if it returns a Thread or uses Fiber
|
|
40
|
-
false
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Check if the factory is an async generator
|
|
44
|
-
#
|
|
45
|
-
# @return [Boolean] True if the factory is an async generator
|
|
46
|
-
def async_generator?
|
|
47
|
-
false
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Dependency Injection support for Spikard applications
|
|
52
|
-
#
|
|
53
|
-
# Provides methods for registering and managing dependencies that can be
|
|
54
|
-
# automatically injected into route handlers.
|
|
55
|
-
#
|
|
56
|
-
# @example Registering a value dependency
|
|
57
|
-
# app.provide("database_url", "postgresql://localhost/mydb")
|
|
58
|
-
#
|
|
59
|
-
# @example Registering a factory dependency
|
|
60
|
-
# app.provide("db_pool", depends_on: ["database_url"]) do |database_url:|
|
|
61
|
-
# ConnectionPool.new(database_url)
|
|
62
|
-
# end
|
|
63
|
-
#
|
|
64
|
-
# @example Singleton dependency (shared across all requests)
|
|
65
|
-
# app.provide("config", singleton: true) do
|
|
66
|
-
# Config.load_from_file("config.yml")
|
|
67
|
-
# end
|
|
68
|
-
#
|
|
69
|
-
# @example Using Provide wrapper
|
|
70
|
-
# app.provide("db", Spikard::Provide.new(method("create_db"), cacheable: true))
|
|
71
|
-
module ProvideSupport
|
|
72
|
-
# Register a dependency in the DI container
|
|
73
|
-
#
|
|
74
|
-
# This method supports three patterns:
|
|
75
|
-
# 1. **Value dependency**: Pass a value directly (e.g., string, number, object)
|
|
76
|
-
# 2. **Factory dependency**: Pass a block that computes the value
|
|
77
|
-
# 3. **Provide wrapper**: Pass a Spikard::Provide instance
|
|
78
|
-
#
|
|
79
|
-
# @param key [String, Symbol] Unique identifier for the dependency
|
|
80
|
-
# @param value [Object, Provide, nil] Static value, Provide instance, or nil
|
|
81
|
-
# @param depends_on [Array<String, Symbol>] List of dependency keys this factory depends on
|
|
82
|
-
# @param singleton [Boolean] Whether to cache the value globally (default: false)
|
|
83
|
-
# @param cacheable [Boolean] Whether to cache the value per-request (default: true)
|
|
84
|
-
# @yield Optional factory block that receives dependencies as keyword arguments
|
|
85
|
-
# @yieldparam **deps [Hash] Resolved dependencies as keyword arguments
|
|
86
|
-
# @yieldreturn [Object] The computed dependency value
|
|
87
|
-
# @return [self] Returns self for method chaining
|
|
88
|
-
#
|
|
89
|
-
# @example Value dependency
|
|
90
|
-
# app.provide("app_name", "MyApp")
|
|
91
|
-
# app.provide("port", 8080)
|
|
92
|
-
#
|
|
93
|
-
# @example Factory with dependencies
|
|
94
|
-
# app.provide("database", depends_on: ["config"]) do |config:|
|
|
95
|
-
# Database.connect(config["db_url"])
|
|
96
|
-
# end
|
|
97
|
-
#
|
|
98
|
-
# @example Singleton factory
|
|
99
|
-
# app.provide("thread_pool", singleton: true) do
|
|
100
|
-
# ThreadPool.new(size: 10)
|
|
101
|
-
# end
|
|
102
|
-
#
|
|
103
|
-
# @example Non-cacheable factory (resolves every time)
|
|
104
|
-
# app.provide("request_id", cacheable: false) do
|
|
105
|
-
# SecureRandom.uuid
|
|
106
|
-
# end
|
|
107
|
-
#
|
|
108
|
-
# @example Using Provide wrapper
|
|
109
|
-
# app.provide("db", Spikard::Provide.new(method("create_db"), cacheable: true))
|
|
110
|
-
def provide(key, value = nil, depends_on: [], singleton: false, cacheable: true, &block)
|
|
111
|
-
key_str = key.to_s
|
|
112
|
-
registry = ensure_native_dependencies!
|
|
113
|
-
|
|
114
|
-
# Handle Provide wrapper instances
|
|
115
|
-
if value.is_a?(Provide)
|
|
116
|
-
registry.register_factory(key_str, value.factory, value.depends_on, value.singleton, value.cacheable)
|
|
117
|
-
elsif block
|
|
118
|
-
registry.register_factory(key_str, block, Array(depends_on).map(&:to_s), singleton, cacheable)
|
|
119
|
-
else
|
|
120
|
-
raise ArgumentError, 'Either provide a value or a block, not both' if value.nil?
|
|
121
|
-
|
|
122
|
-
registry.register_value(key_str, value)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
self
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
# Get all registered dependencies
|
|
129
|
-
#
|
|
130
|
-
# @return [Hash] Dictionary mapping dependency keys to their definitions
|
|
131
|
-
# @api private
|
|
132
|
-
def dependencies
|
|
133
|
-
ensure_native_dependencies!
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
private
|
|
137
|
-
|
|
138
|
-
def ensure_native_dependencies!
|
|
139
|
-
registry = (@native_dependencies if instance_variable_defined?(:@native_dependencies) && @native_dependencies)
|
|
140
|
-
raise 'Spikard native dependency registry unavailable' unless registry
|
|
141
|
-
|
|
142
|
-
registry
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
# Internal helpers for resolving and caching DI dependencies.
|
|
147
|
-
module DependencyResolutionHelpers
|
|
148
|
-
UNRESOLVED_DEPENDENCY = Object.new.freeze
|
|
149
|
-
|
|
150
|
-
module_function
|
|
151
|
-
|
|
152
|
-
def build_resolution_context(*resolution_args)
|
|
153
|
-
dependencies, request_cache, singleton_cache, stack = resolution_args
|
|
154
|
-
{
|
|
155
|
-
dependencies:,
|
|
156
|
-
request_cache: request_cache || {},
|
|
157
|
-
singleton_cache: singleton_cache || {},
|
|
158
|
-
stack: stack || []
|
|
159
|
-
}
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def resolve_factory_dependency(dep_def, request, context, resolver)
|
|
163
|
-
factory = dep_def[:factory]
|
|
164
|
-
depends_on = Array(dep_def[:depends_on]).map(&:to_s)
|
|
165
|
-
resolved_kwargs = resolver.call(
|
|
166
|
-
depends_on,
|
|
167
|
-
context[:dependencies],
|
|
168
|
-
request,
|
|
169
|
-
context[:request_cache],
|
|
170
|
-
context[:singleton_cache],
|
|
171
|
-
context[:stack]
|
|
172
|
-
)
|
|
173
|
-
invoke_factory(factory, depends_on, resolved_kwargs)
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def fetch_dependency_definition(key, dependencies, stack)
|
|
177
|
-
dep_def = dependencies[key]
|
|
178
|
-
raise KeyError, "Missing dependency: #{key}" unless dep_def
|
|
179
|
-
raise ArgumentError, "Circular dependency detected: #{(stack + [key]).join(' -> ')}" if stack.include?(key)
|
|
180
|
-
|
|
181
|
-
dep_def
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def lookup_cached_dependency(key, dep_def, request_cache, singleton_cache)
|
|
185
|
-
return singleton_cache[key] if dep_def[:singleton] && singleton_cache.key?(key)
|
|
186
|
-
return request_cache[key] if dep_def.fetch(:cacheable, true) && request_cache.key?(key)
|
|
187
|
-
|
|
188
|
-
UNRESOLVED_DEPENDENCY
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
def cache_dependency_value(key, dep_def, value, request_cache, singleton_cache)
|
|
192
|
-
singleton_cache[key] = value if dep_def[:singleton]
|
|
193
|
-
request_cache[key] = value if dep_def.fetch(:cacheable, true)
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
def invoke_factory(factory, depends_on, resolved_kwargs)
|
|
197
|
-
return factory.call if depends_on.empty?
|
|
198
|
-
|
|
199
|
-
parameters = factory.parameters
|
|
200
|
-
ordered_values = depends_on.map { |dependency_key| resolved_kwargs.fetch(dependency_key.to_sym) }
|
|
201
|
-
|
|
202
|
-
if parameters.any? { |type, _name| %i[key keyreq keyrest].include?(type) }
|
|
203
|
-
factory.call(**resolved_kwargs)
|
|
204
|
-
else
|
|
205
|
-
factory.call(*ordered_values)
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
# Dependency injection handler wrapper
|
|
211
|
-
#
|
|
212
|
-
# Wraps a route handler to inject dependencies based on parameter names.
|
|
213
|
-
# Dependencies are resolved from the DI container and passed as keyword arguments.
|
|
214
|
-
#
|
|
215
|
-
# @api private
|
|
216
|
-
module DIHandlerWrapper
|
|
217
|
-
# Wrap a handler to inject dependencies
|
|
218
|
-
#
|
|
219
|
-
# @param handler [Proc] The original route handler
|
|
220
|
-
# @param dependencies [Hash] Available dependencies from the app
|
|
221
|
-
# @return [Proc] Wrapped handler with DI support
|
|
222
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
223
|
-
def self.wrap_handler(handler, dependencies)
|
|
224
|
-
# Extract parameter names from the handler
|
|
225
|
-
params = handler.parameters.map { |_type, name| name.to_s }
|
|
226
|
-
singleton_cache = {}
|
|
227
|
-
|
|
228
|
-
# Find which parameters match registered dependencies
|
|
229
|
-
injectable_params = params & dependencies.keys
|
|
230
|
-
|
|
231
|
-
if injectable_params.empty?
|
|
232
|
-
# No DI needed, return original handler
|
|
233
|
-
return handler
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
# Create wrapped handler that injects dependencies
|
|
237
|
-
lambda do |request|
|
|
238
|
-
# Build kwargs with injected dependencies
|
|
239
|
-
kwargs = {}
|
|
240
|
-
request_cache = {}
|
|
241
|
-
|
|
242
|
-
injectable_params.each do |param_name|
|
|
243
|
-
kwargs[param_name.to_sym] = resolve_dependency_by_key(
|
|
244
|
-
param_name,
|
|
245
|
-
dependencies,
|
|
246
|
-
request,
|
|
247
|
-
request_cache,
|
|
248
|
-
singleton_cache,
|
|
249
|
-
[]
|
|
250
|
-
)
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
# Call original handler with injected dependencies
|
|
254
|
-
if handler.arity.zero?
|
|
255
|
-
# Handler takes no arguments (dependencies injected via closure or instance vars)
|
|
256
|
-
handler.call
|
|
257
|
-
elsif injectable_params.length == params.length
|
|
258
|
-
# All parameters are dependencies
|
|
259
|
-
handler.call(**kwargs)
|
|
260
|
-
else
|
|
261
|
-
# Mix of request data and dependencies
|
|
262
|
-
handler.call(request, **kwargs)
|
|
263
|
-
end
|
|
264
|
-
end
|
|
265
|
-
end
|
|
266
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
267
|
-
|
|
268
|
-
# Resolve a dependency definition
|
|
269
|
-
#
|
|
270
|
-
# @param dep_def [Hash] Dependency definition
|
|
271
|
-
# @param request [Hash] Request context (unused for now, future: per-request deps)
|
|
272
|
-
# @return [Object] Resolved dependency value
|
|
273
|
-
# @api private
|
|
274
|
-
def self.resolve_dependency(dep_def, request, *resolution_args)
|
|
275
|
-
context = DependencyResolutionHelpers.build_resolution_context(*resolution_args)
|
|
276
|
-
return dep_def[:value] if dep_def[:type] == :value
|
|
277
|
-
raise ArgumentError, "Unknown dependency type: #{dep_def[:type].inspect}" unless dep_def[:type] == :factory
|
|
278
|
-
|
|
279
|
-
DependencyResolutionHelpers.resolve_factory_dependency(
|
|
280
|
-
dep_def,
|
|
281
|
-
request,
|
|
282
|
-
context,
|
|
283
|
-
method(:resolve_factory_dependencies)
|
|
284
|
-
)
|
|
285
|
-
end
|
|
286
|
-
|
|
287
|
-
def self.resolve_dependency_by_key(key, dependencies, request, request_cache, singleton_cache, stack)
|
|
288
|
-
key = key.to_s
|
|
289
|
-
dep_def = DependencyResolutionHelpers.fetch_dependency_definition(key, dependencies, stack)
|
|
290
|
-
cached_value = DependencyResolutionHelpers.lookup_cached_dependency(key, dep_def, request_cache, singleton_cache)
|
|
291
|
-
return cached_value unless cached_value.equal?(DependencyResolutionHelpers::UNRESOLVED_DEPENDENCY)
|
|
292
|
-
|
|
293
|
-
value = resolve_dependency(dep_def, request, dependencies, request_cache, singleton_cache, stack + [key])
|
|
294
|
-
DependencyResolutionHelpers.cache_dependency_value(key, dep_def, value, request_cache, singleton_cache)
|
|
295
|
-
value
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
def self.resolve_factory_dependencies(depends_on, dependencies, request, request_cache, singleton_cache, stack)
|
|
299
|
-
return {} if depends_on.empty?
|
|
300
|
-
|
|
301
|
-
raise ArgumentError, 'Dependency registry is required for nested dependency resolution' unless dependencies
|
|
302
|
-
|
|
303
|
-
depends_on.to_h do |dependency_key|
|
|
304
|
-
[dependency_key.to_sym, resolve_dependency_by_key(
|
|
305
|
-
dependency_key,
|
|
306
|
-
dependencies,
|
|
307
|
-
request,
|
|
308
|
-
request_cache,
|
|
309
|
-
singleton_cache,
|
|
310
|
-
stack
|
|
311
|
-
)]
|
|
312
|
-
end
|
|
313
|
-
end
|
|
314
|
-
end
|
|
315
|
-
end
|