# frozen_string_literal: true module Redd module Utilities # Unmarshals hashes into objects. class Unmarshaller # Contains the mapping from 'kind' strings to classes. # TODO: UserList type! MAPPING = { 't1' => Models::Comment, 't2' => Models::User, 't3' => Models::Submission, 't4' => Models::PrivateMessage, 't5' => Models::Subreddit, 'more' => Models::MoreComments, 'wikipage' => Models::WikiPage, 'modaction' => Models::Subreddit::ModAction, 'LabeledMulti' => Models::Multireddit, 'LiveUpdate' => Models::LiveThread::LiveUpdate }.freeze def initialize(client) @client = client end def unmarshal(res) # I'm loving the hell out of this pattern. model = js_listing(res) || js_model(res) || api_listing(res) || api_model(res) raise "cannot unmarshal: #{res.inspect}" if model.nil? model end private # Unmarshal frontent API-style listings def js_listing(res) # One day I'll get to deprecate Ruby 2.2 and jump into the world of Hash#dig. return nil unless res[:json] && res[:json][:data] && res[:json][:data][:things] Models::Listing.new(@client, children: res[:json][:data][:things].map { |t| unmarshal(t) }) end # Unmarshal frontend API-style models. def js_model(res) # FIXME: deprecate this? this shouldn't be happening in the API, so this is better handled # in the respective classes. Models::BasicModel.new(@client, res[:json][:data]) if res[:json] && res[:json][:data] end # Unmarshal API-provided listings. def api_listing(res) return nil unless res[:kind] == 'Listing' attributes = res[:data] attributes[:children].map! { |child| unmarshal(child) } Models::Listing.new(@client, attributes) end # Unmarshal API-provided model. def api_model(res) return nil unless MAPPING[res[:kind]] MAPPING[res[:kind]].new(@client, res[:data]) end end end end