lib/redd/utilities/unmarshaller.rb in redd-0.8.4 vs lib/redd/utilities/unmarshaller.rb in redd-0.8.5

- old
+ new

@@ -12,31 +12,53 @@ 't3' => Models::Submission, 't4' => Models::PrivateMessage, 't5' => Models::Subreddit, 'more' => Models::MoreComments, 'wikipage' => Models::WikiPage, - 'Listing' => Models::Listing, 'modaction' => Models::Subreddit::ModAction, 'LabeledMulti' => Models::Multireddit, 'LiveUpdate' => Models::LiveThread::LiveUpdate }.freeze def initialize(client) @client = client end - def unmarshal(response) - if response[:json] && response[:json][:data] - if response[:json][:data][:things] - Models::Listing.new(@client, children: response[:json][:data][:things]) - else - Models::BasicModel.new(@client, response[:json][:data]) - end - elsif MAPPING.key?(response[:kind]) - MAPPING[response[:kind]].new(@client, response[:data]) - else - raise "unknown type to unmarshal: #{response[:kind].inspect}" - 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