Skip to content

Commit 03335a6

Browse files
feat: expose recursive #to_h conversion
1 parent 9c271ed commit 03335a6

File tree

3 files changed

+71
-40
lines changed

3 files changed

+71
-40
lines changed

lib/finch_api/internal/type/base_model.rb

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,39 @@ def dump(value, state:)
313313
end
314314
end
315315

316+
class << self
317+
# @api private
318+
#
319+
# @param model [FinchAPI::Internal::Type::BaseModel]
320+
# @param convert [Boolean]
321+
#
322+
# @return [Hash{Symbol=>Object}]
323+
def recursively_to_h(model, convert:)
324+
rec = ->(x) do
325+
case x
326+
in FinchAPI::Internal::Type::BaseModel
327+
if convert
328+
fields = x.class.known_fields
329+
x.to_h.to_h do |key, val|
330+
[key, rec.call(fields.key?(key) ? x.public_send(key) : val)]
331+
rescue FinchAPI::Errors::ConversionError
332+
[key, rec.call(val)]
333+
end
334+
else
335+
rec.call(x.to_h)
336+
end
337+
in Hash
338+
x.transform_values(&rec)
339+
in Array
340+
x.map(&rec)
341+
else
342+
x
343+
end
344+
end
345+
rec.call(model)
346+
end
347+
end
348+
316349
# @api public
317350
#
318351
# Returns the raw value associated with the given key, if found. Otherwise, nil is
@@ -349,6 +382,14 @@ def to_h = @data
349382

350383
alias_method :to_hash, :to_h
351384

385+
# @api public
386+
#
387+
# In addition to the behaviour of `#to_h`, this method will recursively call
388+
# `#to_h` on nested models.
389+
#
390+
# @return [Hash{Symbol=>Object}]
391+
def deep_to_h = self.class.recursively_to_h(@data, convert: false)
392+
352393
# @param keys [Array<Symbol>, nil]
353394
#
354395
# @return [Hash{Symbol=>Object}]
@@ -364,29 +405,6 @@ def deconstruct_keys(keys)
364405
.to_h
365406
end
366407

367-
class << self
368-
# @api private
369-
#
370-
# @param model [FinchAPI::Internal::Type::BaseModel]
371-
#
372-
# @return [Hash{Symbol=>Object}]
373-
def walk(model)
374-
walk = ->(x) do
375-
case x
376-
in FinchAPI::Internal::Type::BaseModel
377-
walk.call(x.to_h)
378-
in Hash
379-
x.transform_values(&walk)
380-
in Array
381-
x.map(&walk)
382-
else
383-
x
384-
end
385-
end
386-
walk.call(model)
387-
end
388-
end
389-
390408
# @api public
391409
#
392410
# @param a [Object]
@@ -432,12 +450,15 @@ def inspect(depth: 0)
432450
# @api public
433451
#
434452
# @return [String]
435-
def to_s = self.class.walk(@data).to_s
453+
def to_s = deep_to_h.to_s
436454

437455
# @api private
438456
#
439457
# @return [String]
440-
def inspect = "#<#{self.class}:0x#{object_id.to_s(16)} #{self}>"
458+
def inspect
459+
converted = self.class.recursively_to_h(self, convert: true)
460+
"#<#{self.class}:0x#{object_id.to_s(16)} #{converted}>"
461+
end
441462

442463
define_sorbet_constant!(:KnownField) do
443464
T.type_alias { {mode: T.nilable(Symbol), required: T::Boolean, nilable: T::Boolean} }

rbi/finch_api/internal/type/base_model.rbi

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,18 @@ module FinchAPI
199199
end
200200
end
201201

202+
class << self
203+
# @api private
204+
sig do
205+
params(
206+
model: FinchAPI::Internal::Type::BaseModel,
207+
convert: T::Boolean
208+
).returns(FinchAPI::Internal::AnyHash)
209+
end
210+
def recursively_to_h(model, convert:)
211+
end
212+
end
213+
202214
# Returns the raw value associated with the given key, if found. Otherwise, nil is
203215
# returned.
204216
#
@@ -233,6 +245,12 @@ module FinchAPI
233245
def to_hash
234246
end
235247

248+
# In addition to the behaviour of `#to_h`, this method will recursively call
249+
# `#to_h` on nested models.
250+
sig { overridable.returns(FinchAPI::Internal::AnyHash) }
251+
def deep_to_h
252+
end
253+
236254
sig do
237255
params(keys: T.nilable(T::Array[Symbol])).returns(
238256
FinchAPI::Internal::AnyHash
@@ -241,17 +259,6 @@ module FinchAPI
241259
def deconstruct_keys(keys)
242260
end
243261

244-
class << self
245-
# @api private
246-
sig do
247-
params(model: FinchAPI::Internal::Type::BaseModel).returns(
248-
FinchAPI::Internal::AnyHash
249-
)
250-
end
251-
def walk(model)
252-
end
253-
end
254-
255262
sig { params(a: T.anything).returns(String) }
256263
def to_json(*a)
257264
end

sig/finch_api/internal/type/base_model.rbs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,20 @@ module FinchAPI
6868
state: FinchAPI::Internal::Type::Converter::dump_state
6969
) -> (::Hash[top, top] | top)
7070

71+
def self.recursively_to_h: (
72+
FinchAPI::Internal::Type::BaseModel model,
73+
convert: bool
74+
) -> ::Hash[Symbol, top]
75+
7176
def []: (Symbol key) -> top?
7277

7378
def to_h: -> ::Hash[Symbol, top]
7479

7580
alias to_hash to_h
7681

77-
def deconstruct_keys: (::Array[Symbol]? keys) -> ::Hash[Symbol, top]
82+
def deep_to_h: -> ::Hash[Symbol, top]
7883

79-
def self.walk: (
80-
FinchAPI::Internal::Type::BaseModel model
81-
) -> ::Hash[Symbol, top]
84+
def deconstruct_keys: (::Array[Symbol]? keys) -> ::Hash[Symbol, top]
8285

8386
def to_json: (*top a) -> String
8487

0 commit comments

Comments
 (0)