# typed: true # frozen_string_literal: true require "json" module DearInventory class Model extend T::Sig extend T::Helpers abstract! extend DearInventory::IsASubclass sig do params( fields: T::Hash[ Symbol, T::Hash[Symbol, T.any(Symbol, T.class_of(DearInventory::Model))] ] ).void end def self.fields(fields) if ancestors[1].const_defined?(:FIELDS) fields = ancestors[1]::FIELDS.merge(fields) end const_set(:FIELDS, fields.freeze) enumerate_fields do |_, specifications| __send__(:attr_reader, specifications[:name]) end end sig { void } def self.enumerate_fields const_get(:FIELDS).each do |response_name, specifications| yield(response_name, specifications) end end alias initialize_abstract initialize sig do params(values: T.nilable(T::Hash[T.any(String, Symbol), T.untyped])).void end def initialize(values = nil) initialize_abstract return if values.nil? self.class.enumerate_fields do |response_name, specifications| value = field_value(response_name, T.must(values), specifications) instance_variable_set(:"@#{specifications[:name]}", value) end end private # rubocop:disable Metrics/AbcSize # rubocop:disable Metrics/CyclomaticComplexity # rubocop:disable Metrics/MethodLength sig do params( response_name: Symbol, values: T::Hash[T.any(String, Symbol), T.untyped], specifications: T::Hash[Symbol, T.any(Symbol, T.class_of(DearInventory::Model))] ).returns(T.untyped) end def field_value(response_name, values, specifications) model = T.cast( specifications[:model], T.nilable(T.class_of(DearInventory::Model)) ) value = values[response_name.to_s] case specifications[:type] when :BigDecimal value.to_d when :Date ::Date.parse(value) unless value.nil? when :DateTime ::DateTime.parse(value) unless value.nil? when :Array initialize_array_values_in_models(value, T.must(model)) when :Hash T.must(model).new(value) else value end end # rubocop:enable Metrics/AbcSize # rubocop:enable Metrics/CyclomaticComplexity # rubocop:enable Metrics/MethodLength sig do params( array: T.nilable(T::Array[T::Hash[T.any(String, Symbol), T.untyped]]), model: T.class_of(DearInventory::Model) ).returns(T.nilable(T::Array[DearInventory::Model])) end def initialize_array_values_in_models(array, model) return if array.nil? array.each_with_object([]) do |values, records| records << model.new(values) end end end end