Module: XeroKiwi::Accounting::Hydrator
- Defined in:
- lib/xero_kiwi/accounting/hydrator.rb
Overview
Hydrates a raw JSON value into a typed Ruby attribute, driven by the metadata declared via the Resource DSL (see resource.rb).
Supported types:
:string / :enum / :guid / :bool / :decimal - pass-through
:date - parsed to a UTC Time
:object - Klass.new(raw[, reference: true])
:collection - Array of Klass.new(item[, reference: true])
A custom ‘hydrate: ->(raw) { … }` lambda short-circuits dispatch and runs before the nil guard, so it can return a value for nil/empty raw input (e.g. PaymentTerms’s nil-and-empty-hash handling).
Class Method Summary collapse
- .build_object(raw, spec) ⇒ Object
-
.call(raw, spec) ⇒ Object
rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity.
-
.parse_time(value) ⇒ Object
Xero uses two timestamp formats depending on the endpoint:.
-
.resolve_class(name) ⇒ Object
‘of:` accepts a String/Symbol to defer constant lookup — useful when a resource references another that hasn’t been loaded yet (forward refs).
Class Method Details
.build_object(raw, spec) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/xero_kiwi/accounting/hydrator.rb', line 64 def build_object(raw, spec) target = spec[:of] or raise ArgumentError, "#{spec[:type].inspect} attribute requires `of:`" klass = target.is_a?(Class) ? target : resolve_class(target) if spec[:reference] klass.new(raw, reference: true) else klass.new(raw) end end |
.call(raw, spec) ⇒ Object
rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/xero_kiwi/accounting/hydrator.rb', line 23 def call(raw, spec) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity return spec[:hydrate].call(raw) if spec[:hydrate] return [] if spec[:type] == :collection && raw.nil? return nil if raw.nil? case spec[:type] when :string, :enum, :guid, :bool, :decimal raw when :date parse_time(raw) when :object build_object(raw, spec) when :collection raw.map { |item| build_object(item, spec) } else raise ArgumentError, "unknown attribute type: #{spec[:type].inspect}" end end |
.parse_time(value) ⇒ Object
Xero uses two timestamp formats depending on the endpoint:
ISO 8601: "2019-07-09T23:40:30.1833130" (connections API)
.NET JSON: "/Date(1574275974000)/" (accounting API)
Both parse to UTC Time. Unparseable input returns nil.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/xero_kiwi/accounting/hydrator.rb', line 48 def parse_time(value) return nil if value.nil? str = value.to_s.strip return nil if str.empty? if (match = str.match(%r{\A/Date\((\d+)([+-]\d{4})?\)/\z})) Time.at(match[1].to_i / 1000.0).utc else str = "#{str}Z" unless str.match?(/[Zz]\z|[+-]\d{2}:?\d{2}\z/) Time.iso8601(str) end rescue ArgumentError nil end |
.resolve_class(name) ⇒ Object
‘of:` accepts a String/Symbol to defer constant lookup — useful when a resource references another that hasn’t been loaded yet (forward refs).
78 79 80 81 82 |
# File 'lib/xero_kiwi/accounting/hydrator.rb', line 78 def resolve_class(name) name.to_s.split("::").reduce(XeroKiwi::Accounting) do |namespace, part| namespace.const_get(part) end end |