kirei 0.0.2 → 0.1.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/kirei.gemspec +6 -5
- data/lib/boot.rb +2 -9
- data/lib/cli/commands/new_app/execute.rb +3 -2
- data/lib/cli/commands/start.rb +3 -3
- data/lib/kirei/app_base.rb +6 -1
- data/lib/kirei/base_model.rb +90 -3
- data/lib/kirei/config.rb +4 -2
- data/lib/kirei/helpers.rb +90 -0
- data/lib/kirei/logger.rb +29 -10
- data/lib/kirei/version.rb +1 -1
- data/lib/kirei.rb +12 -3
- data/sorbet/rbi/shims/base_model.rbi +7 -0
- metadata +8 -34
- data/sorbet/rbi/dsl/active_support/callbacks.rbi +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cea2982351607eeafadd7e8ee3bb3ce13ba2c7e1e37eed22fa2f5a124b625022
|
4
|
+
data.tar.gz: 84a47be77945fa7a2faf5950441290fde74293388467729f2eb52c1c6041d29b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b420ea6cbfce60bf741bfd85cbfeb310dfd71031519a6d5fcc330bff788d24a0df1ef7268abbdbe49a2f373f4ff5df413dc6cf1b83589f96a6f8867164ffcef
|
7
|
+
data.tar.gz: 061a15d94de3e73dcd8d41db48601bfa5390d59aa1438c322d590ec3c33db9da4dd38d1f9258bf37a13c248ded433883a6da9ff52d41ee5873ca13b0cda414ca
|
data/kirei.gemspec
CHANGED
@@ -13,10 +13,12 @@ Gem::Specification.new do |spec|
|
|
13
13
|
"oss@dbl.works",
|
14
14
|
]
|
15
15
|
|
16
|
-
spec.summary = "Kirei is a strictly typed Ruby micro/REST-framework for building scaleable and performant
|
16
|
+
spec.summary = "Kirei is a strictly typed Ruby micro/REST-framework for building scaleable and performant microservices." # rubocop:disable Layout/LineLength
|
17
17
|
spec.description = <<~TXT
|
18
|
-
Kirei
|
19
|
-
It
|
18
|
+
Kirei is a strictly typed Ruby micro/REST-framework for building scaleable and performant microservices.
|
19
|
+
It is built from the ground up to be clean and easy to use.
|
20
|
+
Kirei is based on Sequel as an ORM, Sorbet for typing, and Sinatra for routing.
|
21
|
+
It strives to have zero magic and to be as explicit as possible.
|
20
22
|
TXT
|
21
23
|
spec.homepage = "https://github.com/swiknaba/kirei"
|
22
24
|
spec.license = "MIT"
|
@@ -29,6 +31,7 @@ Gem::Specification.new do |spec|
|
|
29
31
|
"kirei.gemspec",
|
30
32
|
".irbrc",
|
31
33
|
"lib/**/*",
|
34
|
+
# do not include RBIs for gems, because users might use different verions
|
32
35
|
"sorbet/rbi/dsl/**/*.rbi",
|
33
36
|
"sorbet/rbi/shims/**/*.rbi",
|
34
37
|
"LICENSE",
|
@@ -41,14 +44,12 @@ Gem::Specification.new do |spec|
|
|
41
44
|
spec.require_paths = ["lib"]
|
42
45
|
|
43
46
|
# Utilities
|
44
|
-
spec.add_dependency "activesupport", "~> 6.0"
|
45
47
|
spec.add_dependency "oj", "~> 3.0"
|
46
48
|
spec.add_dependency "rake", "~> 13.0"
|
47
49
|
spec.add_dependency "sorbet-runtime", "~> 0.5"
|
48
50
|
spec.add_dependency "tzinfo-data", "~> 1.0" # for containerized environments, e.g. on AWS ECS
|
49
51
|
|
50
52
|
# Web server & routing
|
51
|
-
spec.add_dependency "puma", "~> 6.0"
|
52
53
|
spec.add_dependency "sinatra", "~> 3.0"
|
53
54
|
spec.add_dependency "sinatra-contrib", "~> 3.0"
|
54
55
|
|
data/lib/boot.rb
CHANGED
@@ -12,20 +12,13 @@
|
|
12
12
|
require "bundler/setup"
|
13
13
|
|
14
14
|
# Second: load all gems (runtime dependencies only)
|
15
|
+
require "logger"
|
15
16
|
require "sorbet-runtime"
|
16
17
|
require "oj"
|
17
|
-
require "active_support/all"
|
18
|
-
require "puma"
|
19
18
|
require "sinatra"
|
20
19
|
require "sinatra/namespace" # from sinatra-contrib
|
21
20
|
require "pg"
|
22
|
-
require "sequel"
|
23
|
-
# "sequel_pg" should be auto-required by "sequel"
|
24
|
-
|
25
|
-
Oj.default_options = {
|
26
|
-
mode: :compat, # required to dump hashes with symbol-keys
|
27
|
-
symbol_keys: false, # T::Struct.new works only with string-keys
|
28
|
-
}
|
21
|
+
require "sequel" # "sequel_pg" is auto-required by "sequel"
|
29
22
|
|
30
23
|
# Third: load all application code
|
31
24
|
Dir[File.join(__dir__, "kirei/**/*.rb")].each { require(_1) }
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# typed: false
|
2
2
|
|
3
3
|
require "fileutils"
|
4
|
-
require "active_support/all"
|
5
4
|
|
6
5
|
module Cli
|
7
6
|
module Commands
|
@@ -12,7 +11,9 @@ module Cli
|
|
12
11
|
Files::App.call(app_name)
|
13
12
|
Files::Irbrc.call
|
14
13
|
|
15
|
-
|
14
|
+
Kirei::Logger.logger.info(
|
15
|
+
"Kirei app '#{app_name}' scaffolded successfully!",
|
16
|
+
)
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
data/lib/cli/commands/start.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: true
|
2
2
|
|
3
3
|
require "fileutils"
|
4
|
-
require "active_support/all"
|
5
4
|
|
6
5
|
module Cli
|
7
6
|
module Commands
|
@@ -10,10 +9,11 @@ module Cli
|
|
10
9
|
case args[0]
|
11
10
|
when "new"
|
12
11
|
app_name = args[1] || "MyApp"
|
12
|
+
# @TODO(lud, 31.12.2023): classify is from ActiveSupport -> remove this?
|
13
13
|
app_name = app_name.gsub(/[-\s]/, "_").classify
|
14
14
|
NewApp::Execute.call(app_name: app_name)
|
15
15
|
else
|
16
|
-
|
16
|
+
Kirei::Logger.logger.info("Unknown command")
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
data/lib/kirei/app_base.rb
CHANGED
@@ -55,7 +55,12 @@ module Kirei
|
|
55
55
|
@raw_db_connection = Sequel.connect(AppBase.config.db_url || default_db_url)
|
56
56
|
|
57
57
|
config.db_extensions.each do |ext|
|
58
|
-
@raw_db_connection.extension(ext)
|
58
|
+
T.cast(@raw_db_connection, Sequel::Database).extension(ext)
|
59
|
+
end
|
60
|
+
|
61
|
+
if config.db_extensions.include?(:pg_json)
|
62
|
+
# https://github.com/jeremyevans/sequel/blob/5.75.0/lib/sequel/extensions/pg_json.rb#L8
|
63
|
+
@raw_db_connection.wrap_json_primitives = true
|
59
64
|
end
|
60
65
|
|
61
66
|
@raw_db_connection
|
data/lib/kirei/base_model.rb
CHANGED
@@ -16,10 +16,37 @@ module Kirei
|
|
16
16
|
).returns(T.self_type)
|
17
17
|
end
|
18
18
|
def update(hash)
|
19
|
+
hash[:updated_at] = Time.now.utc if respond_to?(:updated_at) && hash[:updated_at].nil?
|
20
|
+
self.class.wrap_jsonb_non_primivitives!(hash)
|
19
21
|
self.class.db.where({ id: id }).update(hash)
|
20
22
|
self.class.find_by({ id: id })
|
21
23
|
end
|
22
24
|
|
25
|
+
# Delete keeps the original object intact. Returns true if the record was deleted.
|
26
|
+
# Calling delete multiple times will return false after the first (successful) call.
|
27
|
+
sig { returns(T::Boolean) }
|
28
|
+
def delete
|
29
|
+
count = self.class.db.where({ id: id }).delete
|
30
|
+
count == 1
|
31
|
+
end
|
32
|
+
|
33
|
+
# warning: this is not concurrency-safe
|
34
|
+
# save keeps the original object intact, and returns a new object with the updated values.
|
35
|
+
sig { returns(T.self_type) }
|
36
|
+
def save
|
37
|
+
previous_record = self.class.find_by({ id: id })
|
38
|
+
|
39
|
+
hash = serialize
|
40
|
+
Helpers.deep_symbolize_keys!(hash)
|
41
|
+
hash = T.cast(hash, T::Hash[Symbol, T.untyped])
|
42
|
+
|
43
|
+
if previous_record.nil?
|
44
|
+
self.class.create(hash)
|
45
|
+
else
|
46
|
+
update(hash)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
23
50
|
module BaseClassInterface
|
24
51
|
extend T::Sig
|
25
52
|
extend T::Helpers
|
@@ -33,6 +60,14 @@ module Kirei
|
|
33
60
|
def where(hash)
|
34
61
|
end
|
35
62
|
|
63
|
+
sig { abstract.params(hash: T.untyped).returns(T.untyped) }
|
64
|
+
def create(hash)
|
65
|
+
end
|
66
|
+
|
67
|
+
sig { abstract.params(attributes: T.untyped).void }
|
68
|
+
def wrap_jsonb_non_primivitives!(attributes)
|
69
|
+
end
|
70
|
+
|
36
71
|
sig { abstract.params(hash: T.untyped).returns(T.untyped) }
|
37
72
|
def resolve(hash)
|
38
73
|
end
|
@@ -62,9 +97,16 @@ module Kirei
|
|
62
97
|
|
63
98
|
include BaseClassInterface
|
64
99
|
|
100
|
+
# defaults to a pluralized, underscored version of the class name
|
65
101
|
sig { override.returns(String) }
|
66
102
|
def table_name
|
67
|
-
T.
|
103
|
+
@table_name ||= T.let(
|
104
|
+
begin
|
105
|
+
table_name_ = Kirei::Helpers.underscore(T.must(name.split("::").last))
|
106
|
+
"#{table_name_}s"
|
107
|
+
end,
|
108
|
+
T.nilable(String),
|
109
|
+
)
|
68
110
|
end
|
69
111
|
|
70
112
|
sig { override.returns(Sequel::Dataset) }
|
@@ -81,6 +123,49 @@ module Kirei
|
|
81
123
|
resolve(db.where(hash))
|
82
124
|
end
|
83
125
|
|
126
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
127
|
+
# default values defined in the model are used, if omitted in the hash
|
128
|
+
sig do
|
129
|
+
override.params(
|
130
|
+
hash: T::Hash[Symbol, T.untyped],
|
131
|
+
).returns(T.attached_class)
|
132
|
+
end
|
133
|
+
def create(hash)
|
134
|
+
# instantiate a new object to ensure we use default values defined in the model
|
135
|
+
without_id = !hash.key?(:id)
|
136
|
+
hash[:id] = "kirei-fake-id" if without_id
|
137
|
+
new_record = from_hash(Helpers.deep_stringify_keys(hash))
|
138
|
+
all_attributes = T.let(new_record.serialize, T::Hash[String, T.untyped])
|
139
|
+
all_attributes.delete("id") if without_id && all_attributes["id"] == "kirei-fake-id"
|
140
|
+
|
141
|
+
wrap_jsonb_non_primivitives!(all_attributes)
|
142
|
+
|
143
|
+
if new_record.respond_to?(:created_at) && all_attributes["created_at"].nil?
|
144
|
+
all_attributes["created_at"] = Time.now.utc
|
145
|
+
end
|
146
|
+
if new_record.respond_to?(:updated_at) && all_attributes["updated_at"].nil?
|
147
|
+
all_attributes["updated_at"] = Time.now.utc
|
148
|
+
end
|
149
|
+
|
150
|
+
pkey = T.let(db.insert(all_attributes), String)
|
151
|
+
|
152
|
+
T.must(find_by({ id: pkey }))
|
153
|
+
end
|
154
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
155
|
+
|
156
|
+
sig { override.params(attributes: T::Hash[T.any(Symbol, String), T.untyped]).void }
|
157
|
+
def wrap_jsonb_non_primivitives!(attributes)
|
158
|
+
# setting `@raw_db_connection.wrap_json_primitives = true`
|
159
|
+
# only works on JSON primitives, but not on blank hashes/arrays
|
160
|
+
return unless AppBase.config.db_extensions.include?(:pg_json)
|
161
|
+
|
162
|
+
attributes.each_pair do |key, value|
|
163
|
+
next unless value.is_a?(Hash) || value.is_a?(Array)
|
164
|
+
|
165
|
+
attributes[key] = T.unsafe(Sequel).pg_jsonb_wrap(value)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
84
169
|
sig do
|
85
170
|
override.params(
|
86
171
|
hash: T::Hash[Symbol, T.untyped],
|
@@ -106,7 +191,7 @@ module Kirei
|
|
106
191
|
|
107
192
|
query.map do |row|
|
108
193
|
row = T.cast(row, T::Hash[Symbol, T.untyped])
|
109
|
-
row.
|
194
|
+
row.transform_keys!(&:to_s) # sequel returns symbolized keys
|
110
195
|
from_hash(row, strict_loading)
|
111
196
|
end
|
112
197
|
end
|
@@ -118,7 +203,9 @@ module Kirei
|
|
118
203
|
).returns(T.nilable(T.attached_class))
|
119
204
|
end
|
120
205
|
def resolve_first(query, strict = nil)
|
121
|
-
|
206
|
+
strict_loading = strict.nil? ? AppBase.config.db_strict_type_resolving : strict
|
207
|
+
|
208
|
+
resolve(query.limit(1), strict_loading).first
|
122
209
|
end
|
123
210
|
end
|
124
211
|
|
data/lib/kirei/config.rb
CHANGED
@@ -17,16 +17,18 @@ module Kirei
|
|
17
17
|
|
18
18
|
prop :logger, ::Logger, factory: -> { ::Logger.new($stdout) }
|
19
19
|
prop :log_transformer, T.nilable(T.proc.params(msg: T::Hash[Symbol, T.untyped]).returns(T::Array[String]))
|
20
|
+
prop :log_default_metadata, T::Hash[Symbol, String], default: {}
|
21
|
+
|
20
22
|
# dup to allow the user to extend the existing list of sensitive keys
|
21
23
|
prop :sensitive_keys, T::Array[Regexp], factory: -> { SENSITIVE_KEYS.dup }
|
24
|
+
|
22
25
|
prop :app_name, String, default: "kirei"
|
23
|
-
prop :db_url, T.nilable(String)
|
24
26
|
|
25
27
|
# must use "pg_json" to parse jsonb columns to hashes
|
26
28
|
#
|
27
29
|
# Source: https://github.com/jeremyevans/sequel/blob/5.75.0/lib/sequel/extensions/pg_json.rb
|
28
30
|
prop :db_extensions, T::Array[Symbol], default: %i[pg_json pg_array]
|
29
|
-
|
31
|
+
prop :db_url, T.nilable(String)
|
30
32
|
# Extra or unknown properties present in the Hash do not raise exceptions at runtime
|
31
33
|
# unless the optional strict argument to from_hash is passed
|
32
34
|
#
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Kirei
|
5
|
+
module Helpers
|
6
|
+
class << self
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
# Simplified version from Rails' ActiveSupport::Inflector#underscore
|
10
|
+
sig { params(string: String).returns(String) }
|
11
|
+
def underscore(string)
|
12
|
+
string.gsub!(/([A-Z])(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) do
|
13
|
+
T.must((::Regexp.last_match(1) || ::Regexp.last_match(2))) << "_"
|
14
|
+
end
|
15
|
+
string.tr!("-", "_")
|
16
|
+
string.downcase!
|
17
|
+
string
|
18
|
+
end
|
19
|
+
|
20
|
+
# Simplified version from Rails' ActiveSupport
|
21
|
+
sig { params(string: T.any(String, Symbol)).returns(T::Boolean) }
|
22
|
+
def blank?(string)
|
23
|
+
string.nil? || string.to_s.empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
sig { params(object: T.untyped).returns(T.untyped) }
|
27
|
+
def deep_stringify_keys(object)
|
28
|
+
deep_transform_keys(object) { _1.to_s rescue _1 } # rubocop:disable Style/RescueModifier
|
29
|
+
end
|
30
|
+
|
31
|
+
sig { params(object: T.untyped).returns(T.untyped) }
|
32
|
+
def deep_stringify_keys!(object)
|
33
|
+
deep_transform_keys!(object) { _1.to_s rescue _1 } # rubocop:disable Style/RescueModifier
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { params(object: T.untyped).returns(T.untyped) }
|
37
|
+
def deep_symbolize_keys(object)
|
38
|
+
deep_transform_keys(object) { _1.to_sym rescue _1 } # rubocop:disable Style/RescueModifier
|
39
|
+
end
|
40
|
+
|
41
|
+
sig { params(object: T.untyped).returns(T.untyped) }
|
42
|
+
def deep_symbolize_keys!(object)
|
43
|
+
deep_transform_keys!(object) { _1.to_sym rescue _1 } # rubocop:disable Style/RescueModifier
|
44
|
+
end
|
45
|
+
|
46
|
+
# Simplified version from Rails' ActiveSupport
|
47
|
+
sig do
|
48
|
+
params(
|
49
|
+
object: T.untyped, # could be anything due to recursive calls
|
50
|
+
block: Proc,
|
51
|
+
).returns(T.untyped) # could be anything due to recursive calls
|
52
|
+
end
|
53
|
+
private def deep_transform_keys(object, &block)
|
54
|
+
case object
|
55
|
+
when Hash
|
56
|
+
object.each_with_object({}) do |(key, value), result|
|
57
|
+
result[yield(key)] = deep_transform_keys(value, &block)
|
58
|
+
end
|
59
|
+
when Array
|
60
|
+
object.map { |e| deep_transform_keys(e, &block) }
|
61
|
+
else
|
62
|
+
object
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
sig do
|
67
|
+
params(
|
68
|
+
object: T.untyped, # could be anything due to recursive calls
|
69
|
+
block: Proc,
|
70
|
+
).returns(T.untyped) # could be anything due to recursive calls
|
71
|
+
end
|
72
|
+
private def deep_transform_keys!(object, &block)
|
73
|
+
case object
|
74
|
+
when Hash
|
75
|
+
# using `each_key` results in a `RuntimeError: can't add a new key into hash during iteration`
|
76
|
+
# which is, because the receiver here does not necessarily have a `Hash` type
|
77
|
+
object.keys.each do |key| # rubocop:disable Style/HashEachMethods
|
78
|
+
value = object.delete(key)
|
79
|
+
object[yield(key)] = deep_transform_keys!(value, &block)
|
80
|
+
end
|
81
|
+
object
|
82
|
+
when Array
|
83
|
+
object.map! { |e| deep_transform_keys!(e, &block) }
|
84
|
+
else
|
85
|
+
object
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/kirei/logger.rb
CHANGED
@@ -17,12 +17,12 @@ module Kirei
|
|
17
17
|
#
|
18
18
|
# You can define a custom log transformer to transform the logline:
|
19
19
|
#
|
20
|
-
# Kirei.config.log_transformer = Proc.new { _1 }
|
20
|
+
# Kirei::AppBase.config.log_transformer = Proc.new { _1 }
|
21
21
|
#
|
22
|
-
# By default, "meta" is flattened, and sensitive values are masked using see `Kirei.config.sensitive_keys`.
|
22
|
+
# By default, "meta" is flattened, and sensitive values are masked using see `Kirei::AppBase.config.sensitive_keys`.
|
23
23
|
# You can also build on top of the provided log transformer:
|
24
24
|
#
|
25
|
-
# Kirei.config.log_transformer = Proc.new do |meta|
|
25
|
+
# Kirei::AppBase.config.log_transformer = Proc.new do |meta|
|
26
26
|
# flattened_meta = Kirei::Logger.flatten_hash_and_mask_sensitive_values(meta)
|
27
27
|
# # Do something with the flattened meta
|
28
28
|
# flattened_meta.map { _1.to_json }
|
@@ -83,7 +83,16 @@ module Kirei
|
|
83
83
|
).void
|
84
84
|
end
|
85
85
|
def call(level:, label:, meta: {})
|
86
|
+
Kirei::AppBase.config.log_default_metadata.each_pair do |key, value|
|
87
|
+
meta[key] ||= value
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# key names follow OpenTelemetry Semantic Conventions
|
92
|
+
# Source: https://opentelemetry.io/docs/concepts/semantic-conventions/
|
93
|
+
#
|
86
94
|
meta[:"service.instance.id"] ||= Thread.current[:request_id]
|
95
|
+
meta[:"service.name"] ||= Kirei::AppBase.config.app_name
|
87
96
|
|
88
97
|
# The Ruby logger only accepts one string as the only argument
|
89
98
|
@queue << { level: level, label: label, meta: meta }
|
@@ -98,7 +107,7 @@ module Kirei
|
|
98
107
|
label = log_data.fetch(:label)
|
99
108
|
meta = T.let(log_data.fetch(:meta), T::Hash[Symbol, T.untyped])
|
100
109
|
meta[:"service.version"] ||= Kirei::AppBase.version
|
101
|
-
meta[:timestamp] ||= Time.
|
110
|
+
meta[:timestamp] ||= Time.now.utc.iso8601
|
102
111
|
meta[:level] ||= level.to_s.upcase
|
103
112
|
meta[:label] ||= label
|
104
113
|
|
@@ -107,7 +116,10 @@ module Kirei
|
|
107
116
|
loglines = if log_transformer
|
108
117
|
log_transformer.call(meta)
|
109
118
|
else
|
110
|
-
[Oj.dump(
|
119
|
+
[Oj.dump(
|
120
|
+
Kirei::Logger.flatten_hash_and_mask_sensitive_values(meta),
|
121
|
+
Kirei::OJ_OPTIONS,
|
122
|
+
)]
|
111
123
|
end
|
112
124
|
|
113
125
|
loglines.each { Kirei::Logger.logger.error(_1) }
|
@@ -131,19 +143,24 @@ module Kirei
|
|
131
143
|
|
132
144
|
sig do
|
133
145
|
params(
|
134
|
-
hash: T::Hash[Symbol, T.untyped],
|
146
|
+
hash: T::Hash[T.any(Symbol, String), T.untyped],
|
135
147
|
prefix: Symbol,
|
136
148
|
).returns(T::Hash[Symbol, T.untyped])
|
137
149
|
end
|
138
150
|
def self.flatten_hash_and_mask_sensitive_values(hash, prefix = :'')
|
139
151
|
result = T.let({}, T::Hash[Symbol, T.untyped])
|
140
|
-
|
152
|
+
Kirei::Helpers.deep_symbolize_keys!(hash)
|
153
|
+
hash = T.cast(hash, T::Hash[Symbol, T.untyped])
|
141
154
|
|
142
155
|
hash.each do |key, value|
|
143
|
-
new_prefix =
|
156
|
+
new_prefix = Kirei::Helpers.blank?(prefix) ? key : :"#{prefix}.#{key}"
|
144
157
|
|
145
158
|
case value
|
146
|
-
when Hash
|
159
|
+
when Hash
|
160
|
+
# Some libraries have a custom Hash class that inhert from Hash, but act differently, e.g. OmniAuth::AuthHash.
|
161
|
+
# This results in `transform_keys` being available but without any effect.
|
162
|
+
value = value.to_h if value.class != Hash
|
163
|
+
result.merge!(flatten_hash_and_mask_sensitive_values(value.transform_keys(&:to_sym), new_prefix))
|
147
164
|
when Array
|
148
165
|
value.each_with_index do |element, index|
|
149
166
|
if element.is_a?(Hash) || element.is_a?(Array)
|
@@ -158,7 +175,9 @@ module Kirei
|
|
158
175
|
if value.respond_to?(:serialize)
|
159
176
|
serialized_value = value.serialize
|
160
177
|
if serialized_value.is_a?(Hash)
|
161
|
-
result.merge!(
|
178
|
+
result.merge!(
|
179
|
+
flatten_hash_and_mask_sensitive_values(serialized_value.transform_keys(&:to_sym), new_prefix),
|
180
|
+
)
|
162
181
|
else
|
163
182
|
result[new_prefix] = serialized_value&.to_s
|
164
183
|
end
|
data/lib/kirei/version.rb
CHANGED
data/lib/kirei.rb
CHANGED
@@ -1,13 +1,22 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
puts "Booting Kirei..." # rubocop:disable all
|
5
|
-
|
6
4
|
require "boot"
|
7
5
|
|
8
6
|
module Kirei
|
9
7
|
extend T::Sig
|
10
8
|
|
9
|
+
# we don't know what Oj does under the hood with the options hash, so don't freeze it
|
10
|
+
# rubocop:disable Style/MutableConstant
|
11
|
+
OJ_OPTIONS = T.let(
|
12
|
+
{
|
13
|
+
mode: :compat, # required to dump hashes with symbol-keys
|
14
|
+
symbol_keys: false, # T::Struct.new works only with string-keys
|
15
|
+
},
|
16
|
+
T::Hash[Symbol, T.untyped],
|
17
|
+
)
|
18
|
+
# rubocop:enable Style/MutableConstant
|
19
|
+
|
11
20
|
GEM_ROOT = T.let(
|
12
21
|
Gem::Specification.find_by_name("kirei").gem_dir,
|
13
22
|
String,
|
@@ -33,4 +42,4 @@ end
|
|
33
42
|
|
34
43
|
Kirei.configure(&:itself)
|
35
44
|
|
36
|
-
|
45
|
+
Kirei::Logger.logger.info("Kirei (#{Kirei::VERSION}) booted successfully!")
|
@@ -3,6 +3,9 @@
|
|
3
3
|
# rubocop:disable Style/EmptyMethod
|
4
4
|
module Kirei
|
5
5
|
module BaseModel
|
6
|
+
include Kernel # "self" is a class since we include the module in a class
|
7
|
+
include T::Props::Serializable
|
8
|
+
|
6
9
|
sig { returns(T.any(String, Integer)) }
|
7
10
|
def id; end
|
8
11
|
|
@@ -12,6 +15,10 @@ module Kirei
|
|
12
15
|
sig { returns(String) }
|
13
16
|
def name; end
|
14
17
|
end
|
18
|
+
|
19
|
+
module BaseClassInterface
|
20
|
+
# include T::Props::Serializable::ClassMethods
|
21
|
+
end
|
15
22
|
end
|
16
23
|
end
|
17
24
|
# rubocop:enable Style/EmptyMethod
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kirei
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.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:
|
11
|
+
date: 2024-01-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: activesupport
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '6.0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '6.0'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: oj
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,20 +66,6 @@ dependencies:
|
|
80
66
|
- - "~>"
|
81
67
|
- !ruby/object:Gem::Version
|
82
68
|
version: '1.0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: puma
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - "~>"
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '6.0'
|
90
|
-
type: :runtime
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - "~>"
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '6.0'
|
97
69
|
- !ruby/object:Gem::Dependency
|
98
70
|
name: sinatra
|
99
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -165,8 +137,10 @@ dependencies:
|
|
165
137
|
- !ruby/object:Gem::Version
|
166
138
|
version: '1.0'
|
167
139
|
description: |
|
168
|
-
Kirei
|
169
|
-
It
|
140
|
+
Kirei is a strictly typed Ruby micro/REST-framework for building scaleable and performant microservices.
|
141
|
+
It is built from the ground up to be clean and easy to use.
|
142
|
+
Kirei is based on Sequel as an ORM, Sorbet for typing, and Sinatra for routing.
|
143
|
+
It strives to have zero magic and to be as explicit as possible.
|
170
144
|
email:
|
171
145
|
- lud@reinmiedl.com
|
172
146
|
- oss@dbl.works
|
@@ -193,9 +167,9 @@ files:
|
|
193
167
|
- lib/kirei/base_controller.rb
|
194
168
|
- lib/kirei/base_model.rb
|
195
169
|
- lib/kirei/config.rb
|
170
|
+
- lib/kirei/helpers.rb
|
196
171
|
- lib/kirei/logger.rb
|
197
172
|
- lib/kirei/version.rb
|
198
|
-
- sorbet/rbi/dsl/active_support/callbacks.rbi
|
199
173
|
- sorbet/rbi/shims/base_model.rbi
|
200
174
|
homepage: https://github.com/swiknaba/kirei
|
201
175
|
licenses:
|
@@ -222,5 +196,5 @@ rubygems_version: 3.5.3
|
|
222
196
|
signing_key:
|
223
197
|
specification_version: 4
|
224
198
|
summary: Kirei is a strictly typed Ruby micro/REST-framework for building scaleable
|
225
|
-
and performant
|
199
|
+
and performant microservices.
|
226
200
|
test_files: []
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# typed: true
|
2
|
-
|
3
|
-
# DO NOT EDIT MANUALLY
|
4
|
-
# This is an autogenerated file for dynamic methods in `ActiveSupport::Callbacks`.
|
5
|
-
# Please instead update this file by running `bin/tapioca dsl ActiveSupport::Callbacks`.
|
6
|
-
|
7
|
-
module ActiveSupport::Callbacks
|
8
|
-
include GeneratedInstanceMethods
|
9
|
-
|
10
|
-
mixes_in_class_methods GeneratedClassMethods
|
11
|
-
|
12
|
-
module GeneratedClassMethods
|
13
|
-
def __callbacks; end
|
14
|
-
def __callbacks=(value); end
|
15
|
-
def __callbacks?; end
|
16
|
-
end
|
17
|
-
|
18
|
-
module GeneratedInstanceMethods
|
19
|
-
def __callbacks; end
|
20
|
-
def __callbacks?; end
|
21
|
-
end
|
22
|
-
end
|