emq/quakelive_api

View on GitHub
lib/quakelive_api/parser/summary.rb

Summary

Maintainability
A
3 hrs
Test Coverage
module QuakeliveApi
  module Parser
    class Summary < Base

      def country
        document.at(selector(:country))['title']
      end

      def nick
        document.at(selector(:nick)).xpath('text()').text.strip
      end

      def clan
        clan_tag = document.at(selector(:clan))
        clan_tag.text if clan_tag
      end

      def model
        div = document.at(selector(:model))
        name  = div['title']
        image = decode_background(div['style'])
        Items::Model.new(name, image)
      end

      def member_since
        Date.parse vitals.at(selector(:member)).next.text.match(/([\w.\s,]+)/)[1]
      end

      def last_game
        node = vitals.at selector(:last)
        decode_time(node['title']) if node
      end

      def time_played
        node = vitals.at selector(:played)
        GameTime.new(node['title']) if node
      end

      def wins
        to_integer vitals.at(selector(:wins)).next.text
      end

      def accuracy
        vitals.at(selector(:accuracy)).next.text.match(/([\d.]+)%/)[1].to_f
      end

      def losses_quits
        parse_slashed vitals.at(selector(:losses))
      end

      def frags_deaths
        parse_slashed vitals.at(selector(:frags))
      end

      def hits_shots
        parse_slashed vitals.at(selector(:hits))
      end

      def favourites
        Items::Favourite.new(*document.css(selector(:favs))
          .map { |n| n.next.text.strip }
          .map { |n| n == "None" ? nil : n })
      end

      def awards
        awards = document.css(selector(:awards)).map do |node|
          title = node.at('.vcenter_data b')

          next if title.text =~ /No recent award/

          info        = node['title']
          icon        = node.at('img')['src']
          awarded     = title.next.next
          description = awarded.next.next

          Items::Award.new(icon, info, title.text.strip, awarded.text.strip, description.text.strip.gsub("\n",""))
        end.compact

        awards.any? ? awards : nil
      end

      def recent_games
        games = document.css(selector(:games)).map do |node|
          gametype = decode_gametype node.at('img.gametype')['src']
          finish   = node.at('span.finish').text.strip.match(/Finish:\s+(\w+)/i)[1]
          played   = node.at('span.played').text.strip.match(/Played:\s+([\w ]+)/i)[1]
          image    = node.at('img.levelshot')['src']

          Items::RecentGame.new(gametype, finish, played, image)
        end.compact

        games if games.any?
      end

      def recent_competitors
        competitors = document.css(selector(:competitors)).map do |node|
          next if node.at('.rcmp_none')

          icon   = decode_background node.at('.usericon_standard_lg')['style']
          nick   = node.at('a.player_nick_dark').xpath('child::text()').to_s
          played = decode_time(node.at('span.text_tooltip')['title'])

          Items::Competitor.new(icon, nick, played )
        end.compact

        competitors if competitors.any?
      end

      private

      def selectors
        {
          country:     "img.playerflag",
          nick:        ".profile_title",
          clan:        ".profile_title a.clan",
          model:       ".prf_imagery div",
          vitals:      ".prf_vitals p",
          member:      "b:contains('Member Since')",
          last:        "b:contains('Last Game') + span",
          played:      "b:contains('Time Played') + span",
          wins:        "b:contains('Wins')",
          losses:      "b:contains('Losses')",
          frags:       "b:contains('Frags')",
          hits:        "b:contains('Hits')",
          accuracy:    "b:contains('Accuracy')",
          favs:        ".prf_faves b",
          awards:      ".prf_awards .awd_details",
          games:       ".recent_match",
          competitors: "#qlv_profileBottomInset .rcmp_block"
        }
      end

      def decode_time(string)
        Time.strptime(string, '%m/%d/%Y %H:%M %p')
      end

      # FIXME: not really fully implemented
      def decode_gametype(string)
        if string =~ /ca_/
          'CA'
        elsif string =~ /tdm_/
          'TDM'
        elsif string =~ /ctf_/
          'CTF'
        elsif string =~ /duel_/
          'Duel'
        elsif string =~ /ad_/
          'Attack&Defend'
        elsif string =~ /ffa_/
          'FFA'
        elsif string =~ /ft_/
          'FreezeTag'
        elsif string =~ /race_/
          'Race'
        elsif string =~ /rr_/
          'Red Rover'
        end
      end

      def decode_background(string)
        string.strip.match(/background(?:-image)?: url\(([\w:\/.]+)/)[1]
      end

      def vitals
        document.at(selector(:vitals))
      end

      def parse_slashed(node)
        match = node.next.text.match(/([\d,]+) \/ ([\d,]+)/)
        [match[1], match[2]].map { |r| to_integer(r) }
      end

    end
  end
end