kirei 0.2.1 → 0.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 +4 -4
- data/README.md +74 -25
- data/bin/kirei +1 -1
- data/kirei.gemspec +5 -3
- data/lib/cli/commands/new_app/base_directories.rb +1 -1
- data/lib/cli/commands/new_app/execute.rb +3 -3
- data/lib/cli/commands/new_app/files/app.rb +16 -3
- data/lib/cli/commands/new_app/files/config_ru.rb +1 -1
- data/lib/cli/commands/new_app/files/db_rake.rb +50 -2
- data/lib/cli/commands/new_app/files/irbrc.rb +1 -1
- data/lib/cli/commands/new_app/files/rakefile.rb +1 -1
- data/lib/cli/commands/new_app/files/routes.rb +49 -12
- data/lib/cli/commands/new_app/files/sorbet_config.rb +1 -1
- data/lib/cli/commands/start.rb +1 -1
- data/lib/kirei/app.rb +76 -56
- data/lib/kirei/config.rb +4 -1
- data/lib/kirei/controller.rb +44 -0
- data/lib/kirei/errors/json_api_error.rb +25 -0
- data/lib/kirei/errors/json_api_error_source.rb +12 -0
- data/lib/kirei/logging/level.rb +33 -0
- data/lib/kirei/logging/logger.rb +198 -0
- data/lib/kirei/logging/metric.rb +40 -0
- data/lib/kirei/model/base_class_interface.rb +55 -0
- data/lib/kirei/{base_model.rb → model/class_methods.rb} +42 -108
- data/lib/kirei/model/human_id_generator.rb +40 -0
- data/lib/kirei/model.rb +52 -0
- data/lib/kirei/routing/base.rb +187 -0
- data/lib/kirei/routing/nilable_hooks_type.rb +10 -0
- data/lib/kirei/{middleware.rb → routing/rack_env_type.rb} +1 -10
- data/lib/kirei/routing/rack_response_type.rb +15 -0
- data/lib/kirei/routing/route.rb +13 -0
- data/lib/kirei/routing/router.rb +56 -0
- data/lib/kirei/routing/verb.rb +37 -0
- data/lib/kirei/services/result.rb +53 -0
- data/lib/kirei/services/runner.rb +47 -0
- data/lib/kirei/version.rb +1 -1
- data/lib/kirei.rb +31 -3
- data/sorbet/rbi/shims/base_model.rbi +1 -1
- data/sorbet/rbi/shims/ruby.rbi +15 -0
- metadata +55 -14
- data/lib/boot.rb +0 -23
- data/lib/kirei/app_base.rb +0 -72
- data/lib/kirei/base_controller.rb +0 -16
- data/lib/kirei/logger.rb +0 -196
- data/lib/kirei/router.rb +0 -61
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kirei
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ludwig Reinmiedl
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: oj
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: statsd-instrument
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: tzinfo-data
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +66,20 @@ dependencies:
|
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '1.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: zeitwerk
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.5'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.5'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: puma
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -123,9 +151,9 @@ dependencies:
|
|
123
151
|
- !ruby/object:Gem::Version
|
124
152
|
version: '1.0'
|
125
153
|
description: |
|
126
|
-
Kirei is a
|
154
|
+
Kirei is a Ruby micro/REST-framework for building scalable and performant microservices.
|
127
155
|
It is built from the ground up to be clean and easy to use.
|
128
|
-
|
156
|
+
It is a Rack app, and uses Sorbet for typing, Sequel as an ORM, Zeitwerk for autoloading, and Puma as a web server.
|
129
157
|
It strives to have zero magic and to be as explicit as possible.
|
130
158
|
email:
|
131
159
|
- lud@reinmiedl.com
|
@@ -140,7 +168,6 @@ files:
|
|
140
168
|
- README.md
|
141
169
|
- bin/kirei
|
142
170
|
- kirei.gemspec
|
143
|
-
- lib/boot.rb
|
144
171
|
- lib/cli.rb
|
145
172
|
- lib/cli/commands/new_app/base_directories.rb
|
146
173
|
- lib/cli/commands/new_app/execute.rb
|
@@ -154,16 +181,30 @@ files:
|
|
154
181
|
- lib/cli/commands/start.rb
|
155
182
|
- lib/kirei.rb
|
156
183
|
- lib/kirei/app.rb
|
157
|
-
- lib/kirei/app_base.rb
|
158
|
-
- lib/kirei/base_controller.rb
|
159
|
-
- lib/kirei/base_model.rb
|
160
184
|
- lib/kirei/config.rb
|
185
|
+
- lib/kirei/controller.rb
|
186
|
+
- lib/kirei/errors/json_api_error.rb
|
187
|
+
- lib/kirei/errors/json_api_error_source.rb
|
161
188
|
- lib/kirei/helpers.rb
|
162
|
-
- lib/kirei/
|
163
|
-
- lib/kirei/
|
164
|
-
- lib/kirei/
|
189
|
+
- lib/kirei/logging/level.rb
|
190
|
+
- lib/kirei/logging/logger.rb
|
191
|
+
- lib/kirei/logging/metric.rb
|
192
|
+
- lib/kirei/model.rb
|
193
|
+
- lib/kirei/model/base_class_interface.rb
|
194
|
+
- lib/kirei/model/class_methods.rb
|
195
|
+
- lib/kirei/model/human_id_generator.rb
|
196
|
+
- lib/kirei/routing/base.rb
|
197
|
+
- lib/kirei/routing/nilable_hooks_type.rb
|
198
|
+
- lib/kirei/routing/rack_env_type.rb
|
199
|
+
- lib/kirei/routing/rack_response_type.rb
|
200
|
+
- lib/kirei/routing/route.rb
|
201
|
+
- lib/kirei/routing/router.rb
|
202
|
+
- lib/kirei/routing/verb.rb
|
203
|
+
- lib/kirei/services/result.rb
|
204
|
+
- lib/kirei/services/runner.rb
|
165
205
|
- lib/kirei/version.rb
|
166
206
|
- sorbet/rbi/shims/base_model.rbi
|
207
|
+
- sorbet/rbi/shims/ruby.rbi
|
167
208
|
homepage: https://github.com/swiknaba/kirei
|
168
209
|
licenses:
|
169
210
|
- MIT
|
@@ -185,9 +226,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
185
226
|
- !ruby/object:Gem::Version
|
186
227
|
version: '0'
|
187
228
|
requirements: []
|
188
|
-
rubygems_version: 3.5.
|
229
|
+
rubygems_version: 3.5.9
|
189
230
|
signing_key:
|
190
231
|
specification_version: 4
|
191
|
-
summary: Kirei is a
|
192
|
-
|
232
|
+
summary: Kirei is a typed Ruby micro/REST-framework for building scalable and performant
|
233
|
+
microservices.
|
193
234
|
test_files: []
|
data/lib/boot.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
# typed: false
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
# This is the entrypoint into the application,
|
5
|
-
# This file loads first, hence we don't have Sorbet loaded yet.
|
6
|
-
|
7
|
-
#
|
8
|
-
# Load Order is important!
|
9
|
-
#
|
10
|
-
|
11
|
-
# First: check if all gems are installed correctly
|
12
|
-
require "bundler/setup"
|
13
|
-
|
14
|
-
# Second: load all gems (runtime dependencies only)
|
15
|
-
require "logger"
|
16
|
-
require "sorbet-runtime"
|
17
|
-
require "oj"
|
18
|
-
require "rack"
|
19
|
-
require "pg"
|
20
|
-
require "sequel" # "sequel_pg" is auto-required by "sequel"
|
21
|
-
|
22
|
-
# Third: load all application code
|
23
|
-
Dir[File.join(__dir__, "kirei/**/*.rb")].each { require(_1) }
|
data/lib/kirei/app_base.rb
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require_relative("app")
|
5
|
-
|
6
|
-
module Kirei
|
7
|
-
class AppBase < Kirei::App
|
8
|
-
class << self
|
9
|
-
extend T::Sig
|
10
|
-
|
11
|
-
# convenience method since "Kirei.configuration" must be nilable since it is nil
|
12
|
-
# at the beginning of initilization of the app
|
13
|
-
sig { returns(Kirei::Config) }
|
14
|
-
def config
|
15
|
-
T.must(Kirei.configuration)
|
16
|
-
end
|
17
|
-
|
18
|
-
sig { returns(Pathname) }
|
19
|
-
def root
|
20
|
-
defined?(::APP_ROOT) ? Pathname.new(::APP_ROOT) : Pathname.new(Dir.pwd)
|
21
|
-
end
|
22
|
-
|
23
|
-
sig { returns(String) }
|
24
|
-
def version
|
25
|
-
@version = T.let(@version, T.nilable(String))
|
26
|
-
@version ||= ENV.fetch("APP_VERSION", nil)
|
27
|
-
@version ||= ENV.fetch("GIT_SHA", nil)
|
28
|
-
@version ||= T.must(
|
29
|
-
`command -v git && git rev-parse --short HEAD`.to_s.split("\n").last,
|
30
|
-
).freeze # localhost
|
31
|
-
end
|
32
|
-
|
33
|
-
sig { returns(String) }
|
34
|
-
def environment
|
35
|
-
ENV.fetch("RACK_ENV", "development")
|
36
|
-
end
|
37
|
-
|
38
|
-
sig { returns(String) }
|
39
|
-
def default_db_name
|
40
|
-
@default_db_name ||= T.let("#{config.app_name}_#{environment}".freeze, T.nilable(String))
|
41
|
-
end
|
42
|
-
|
43
|
-
sig { returns(String) }
|
44
|
-
def default_db_url
|
45
|
-
@default_db_url ||= T.let(
|
46
|
-
ENV.fetch("DATABASE_URL", "postgresql://localhost:5432/#{default_db_name}"),
|
47
|
-
T.nilable(String),
|
48
|
-
)
|
49
|
-
end
|
50
|
-
|
51
|
-
sig { returns(Sequel::Database) }
|
52
|
-
def raw_db_connection
|
53
|
-
@raw_db_connection = T.let(@raw_db_connection, T.nilable(Sequel::Database))
|
54
|
-
return @raw_db_connection unless @raw_db_connection.nil?
|
55
|
-
|
56
|
-
# calling "Sequel.connect" creates a new connection
|
57
|
-
@raw_db_connection = Sequel.connect(AppBase.config.db_url || default_db_url)
|
58
|
-
|
59
|
-
config.db_extensions.each do |ext|
|
60
|
-
T.cast(@raw_db_connection, Sequel::Database).extension(ext)
|
61
|
-
end
|
62
|
-
|
63
|
-
if config.db_extensions.include?(:pg_json)
|
64
|
-
# https://github.com/jeremyevans/sequel/blob/5.75.0/lib/sequel/extensions/pg_json.rb#L8
|
65
|
-
@raw_db_connection.wrap_json_primitives = true
|
66
|
-
end
|
67
|
-
|
68
|
-
@raw_db_connection
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require_relative("app")
|
5
|
-
|
6
|
-
module Kirei
|
7
|
-
class BaseController < Kirei::App
|
8
|
-
extend T::Sig
|
9
|
-
# register(Sinatra::Namespace)
|
10
|
-
|
11
|
-
# before do
|
12
|
-
# Thread.current[:request_id] = request.env["HTTP_X_REQUEST_ID"].presence ||
|
13
|
-
# "req_#{AppBase.environment}_#{SecureRandom.uuid}"
|
14
|
-
# end
|
15
|
-
end
|
16
|
-
end
|
data/lib/kirei/logger.rb
DELETED
@@ -1,196 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module Kirei
|
5
|
-
# rubocop:disable Metrics
|
6
|
-
|
7
|
-
#
|
8
|
-
# Example Usage:
|
9
|
-
#
|
10
|
-
# Kirei::Logger.call(
|
11
|
-
# level: :info,
|
12
|
-
# label: "Request started",
|
13
|
-
# meta: {
|
14
|
-
# key: "value",
|
15
|
-
# },
|
16
|
-
# )
|
17
|
-
#
|
18
|
-
# You can define a custom log transformer to transform the logline:
|
19
|
-
#
|
20
|
-
# Kirei::AppBase.config.log_transformer = Proc.new { _1 }
|
21
|
-
#
|
22
|
-
# By default, "meta" is flattened, and sensitive values are masked using see `Kirei::AppBase.config.sensitive_keys`.
|
23
|
-
# You can also build on top of the provided log transformer:
|
24
|
-
#
|
25
|
-
# Kirei::AppBase.config.log_transformer = Proc.new do |meta|
|
26
|
-
# flattened_meta = Kirei::Logger.flatten_hash_and_mask_sensitive_values(meta)
|
27
|
-
# # Do something with the flattened meta
|
28
|
-
# flattened_meta.map { _1.to_json }
|
29
|
-
# end
|
30
|
-
#
|
31
|
-
# NOTE: The log transformer must return an array of strings to allow emitting multiple lines per log event.
|
32
|
-
#
|
33
|
-
class Logger
|
34
|
-
extend T::Sig
|
35
|
-
|
36
|
-
FILTERED = "[FILTERED]"
|
37
|
-
|
38
|
-
@instance = T.let(nil, T.nilable(Kirei::Logger))
|
39
|
-
|
40
|
-
sig { void }
|
41
|
-
def initialize
|
42
|
-
super
|
43
|
-
@queue = T.let(Thread::Queue.new, Thread::Queue)
|
44
|
-
@thread = T.let(start_logging_thread, Thread)
|
45
|
-
end
|
46
|
-
|
47
|
-
sig { returns(Kirei::Logger) }
|
48
|
-
def self.instance
|
49
|
-
@instance ||= new
|
50
|
-
end
|
51
|
-
|
52
|
-
sig { returns(::Logger) }
|
53
|
-
def self.logger
|
54
|
-
return @logger unless @logger.nil?
|
55
|
-
|
56
|
-
@logger = T.let(nil, T.nilable(::Logger))
|
57
|
-
@logger ||= ::Logger.new($stdout)
|
58
|
-
|
59
|
-
# we want the logline to be parseable to JSON
|
60
|
-
@logger.formatter = proc do |_severity, _datetime, _progname, msg|
|
61
|
-
"#{msg}\n"
|
62
|
-
end
|
63
|
-
|
64
|
-
@logger
|
65
|
-
end
|
66
|
-
|
67
|
-
sig do
|
68
|
-
params(
|
69
|
-
level: T.any(String, Symbol),
|
70
|
-
label: String,
|
71
|
-
meta: T::Hash[Symbol, T.untyped],
|
72
|
-
).void
|
73
|
-
end
|
74
|
-
def self.call(level:, label:, meta: {})
|
75
|
-
return if ENV["LOGGER"] == "disabled"
|
76
|
-
|
77
|
-
instance.call(level: level, label: label, meta: meta)
|
78
|
-
end
|
79
|
-
|
80
|
-
sig do
|
81
|
-
params(
|
82
|
-
level: T.any(String, Symbol),
|
83
|
-
label: String,
|
84
|
-
meta: T::Hash[Symbol, T.untyped],
|
85
|
-
).void
|
86
|
-
end
|
87
|
-
def call(level:, label:, meta: {})
|
88
|
-
Kirei::AppBase.config.log_default_metadata.each_pair do |key, value|
|
89
|
-
meta[key] ||= value
|
90
|
-
end
|
91
|
-
|
92
|
-
#
|
93
|
-
# key names follow OpenTelemetry Semantic Conventions
|
94
|
-
# Source: https://opentelemetry.io/docs/concepts/semantic-conventions/
|
95
|
-
#
|
96
|
-
meta[:"service.instance.id"] ||= Thread.current[:request_id]
|
97
|
-
meta[:"service.name"] ||= Kirei::AppBase.config.app_name
|
98
|
-
|
99
|
-
# The Ruby logger only accepts one string as the only argument
|
100
|
-
@queue << { level: level, label: label, meta: meta }
|
101
|
-
end
|
102
|
-
|
103
|
-
sig { returns(Thread) }
|
104
|
-
def start_logging_thread
|
105
|
-
Thread.new do
|
106
|
-
Kernel.loop do
|
107
|
-
log_data = T.let(@queue.pop, T::Hash[Symbol, T.untyped])
|
108
|
-
level = log_data.fetch(:level)
|
109
|
-
label = log_data.fetch(:label)
|
110
|
-
meta = T.let(log_data.fetch(:meta), T::Hash[Symbol, T.untyped])
|
111
|
-
meta[:"service.version"] ||= Kirei::AppBase.version
|
112
|
-
meta[:timestamp] ||= Time.now.utc.iso8601
|
113
|
-
meta[:level] ||= level.to_s.upcase
|
114
|
-
meta[:label] ||= label
|
115
|
-
|
116
|
-
log_transformer = AppBase.config.log_transformer
|
117
|
-
|
118
|
-
loglines = if log_transformer
|
119
|
-
log_transformer.call(meta)
|
120
|
-
else
|
121
|
-
[Oj.dump(
|
122
|
-
Kirei::Logger.flatten_hash_and_mask_sensitive_values(meta),
|
123
|
-
Kirei::OJ_OPTIONS,
|
124
|
-
)]
|
125
|
-
end
|
126
|
-
|
127
|
-
loglines.each { Kirei::Logger.logger.error(_1) }
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
# rubocop:disable Naming/MethodParameterName
|
133
|
-
sig do
|
134
|
-
params(
|
135
|
-
k: Symbol,
|
136
|
-
v: String,
|
137
|
-
).returns(String)
|
138
|
-
end
|
139
|
-
def self.mask(k, v)
|
140
|
-
return Kirei::Logger::FILTERED if AppBase.config.sensitive_keys.any? { k.match?(_1) }
|
141
|
-
|
142
|
-
v
|
143
|
-
end
|
144
|
-
# rubocop:enable Naming/MethodParameterName
|
145
|
-
|
146
|
-
sig do
|
147
|
-
params(
|
148
|
-
hash: T::Hash[T.any(Symbol, String), T.untyped],
|
149
|
-
prefix: Symbol,
|
150
|
-
).returns(T::Hash[Symbol, T.untyped])
|
151
|
-
end
|
152
|
-
def self.flatten_hash_and_mask_sensitive_values(hash, prefix = :'')
|
153
|
-
result = T.let({}, T::Hash[Symbol, T.untyped])
|
154
|
-
Kirei::Helpers.deep_symbolize_keys!(hash)
|
155
|
-
hash = T.cast(hash, T::Hash[Symbol, T.untyped])
|
156
|
-
|
157
|
-
hash.each do |key, value|
|
158
|
-
new_prefix = Kirei::Helpers.blank?(prefix) ? key : :"#{prefix}.#{key}"
|
159
|
-
|
160
|
-
case value
|
161
|
-
when Hash
|
162
|
-
# Some libraries have a custom Hash class that inhert from Hash, but act differently, e.g. OmniAuth::AuthHash.
|
163
|
-
# This results in `transform_keys` being available but without any effect.
|
164
|
-
value = value.to_h if value.class != Hash
|
165
|
-
result.merge!(flatten_hash_and_mask_sensitive_values(value.transform_keys(&:to_sym), new_prefix))
|
166
|
-
when Array
|
167
|
-
value.each_with_index do |element, index|
|
168
|
-
if element.is_a?(Hash) || element.is_a?(Array)
|
169
|
-
result.merge!(flatten_hash_and_mask_sensitive_values({ index => element }, new_prefix))
|
170
|
-
else
|
171
|
-
result[:"#{new_prefix}.#{index}"] = element.is_a?(String) ? mask(key, element) : element
|
172
|
-
end
|
173
|
-
end
|
174
|
-
when String then result[new_prefix] = mask(key, value)
|
175
|
-
when Numeric, FalseClass, TrueClass, NilClass then result[new_prefix] = value
|
176
|
-
else
|
177
|
-
if value.respond_to?(:serialize)
|
178
|
-
serialized_value = value.serialize
|
179
|
-
if serialized_value.is_a?(Hash)
|
180
|
-
result.merge!(
|
181
|
-
flatten_hash_and_mask_sensitive_values(serialized_value.transform_keys(&:to_sym), new_prefix),
|
182
|
-
)
|
183
|
-
else
|
184
|
-
result[new_prefix] = serialized_value&.to_s
|
185
|
-
end
|
186
|
-
else
|
187
|
-
result[new_prefix] = value&.to_s
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
result
|
193
|
-
end
|
194
|
-
end
|
195
|
-
# rubocop:enable Metrics
|
196
|
-
end
|
data/lib/kirei/router.rb
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require("singleton")
|
5
|
-
|
6
|
-
module Kirei
|
7
|
-
#
|
8
|
-
# Usage:
|
9
|
-
#
|
10
|
-
# Router.add_routes([
|
11
|
-
# Route.new(
|
12
|
-
# verb: "GET",
|
13
|
-
# path: "/livez",
|
14
|
-
# controller: Controllers::HealthController,
|
15
|
-
# action: "livez",
|
16
|
-
# ),
|
17
|
-
# ])
|
18
|
-
#
|
19
|
-
class Router
|
20
|
-
extend T::Sig
|
21
|
-
include ::Singleton
|
22
|
-
|
23
|
-
class Route < T::Struct
|
24
|
-
const :verb, String
|
25
|
-
const :path, String
|
26
|
-
const :controller, T.class_of(BaseController)
|
27
|
-
const :action, String
|
28
|
-
end
|
29
|
-
|
30
|
-
RoutesHash = T.type_alias do
|
31
|
-
T::Hash[String, Route]
|
32
|
-
end
|
33
|
-
|
34
|
-
sig { void }
|
35
|
-
def initialize
|
36
|
-
@routes = T.let({}, RoutesHash)
|
37
|
-
end
|
38
|
-
|
39
|
-
sig { returns(RoutesHash) }
|
40
|
-
attr_reader :routes
|
41
|
-
|
42
|
-
sig do
|
43
|
-
params(
|
44
|
-
verb: String,
|
45
|
-
path: String,
|
46
|
-
).returns(T.nilable(Route))
|
47
|
-
end
|
48
|
-
def get(verb, path)
|
49
|
-
key = "#{verb} #{path}"
|
50
|
-
routes[key]
|
51
|
-
end
|
52
|
-
|
53
|
-
sig { params(routes: T::Array[Route]).void }
|
54
|
-
def self.add_routes(routes)
|
55
|
-
routes.each do |route|
|
56
|
-
key = "#{route.verb} #{route.path}"
|
57
|
-
instance.routes[key] = route
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|