Skip to content
This repository has been archived by the owner on Oct 15, 2022. It is now read-only.

[Instant Answer] Pokemon info #1536

Merged
merged 19 commits into from
Mar 20, 2015
31 changes: 31 additions & 0 deletions lib/DDG/Spice/Pokemon/Data.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package DDG::Spice::Pokemon::Data;
# ABSTRACT: Returns pokemon data from the pokeapi API

use DDG::Spice;

spice is_cached => 1;
spice proxy_cache_valid => "200 30d";

name "Pokemon";
source "Pokéapi";
icon_url "/i/www.pokeapi.co.ico";
description "Fetches details of a given Pokemon";
primary_example_queries "pokemon pikachu", "bulbasaur pokemon";
category "entertainment";
topics "entertainment", "geek";
code_url "https://github.com/duckduckgo/zeroclickinfo-spice/blob/master/lib/DDG/Spice/Pokemon.pm";
attribution github => ["AkA84"];

# Triggers
triggers startend => "pokemon";

spice to => 'http://pokeapi.co/api/v1/pokemon/$1/';
spice wrap_jsonp_callback => 1;

# Handle statement
handle remainder => sub {
return lc $_ if $_;
return;
};

1;
20 changes: 20 additions & 0 deletions lib/DDG/Spice/Pokemon/Description.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package DDG::Spice::Pokemon::Description;
# ABSTRACT: Returns pokemon description from the pokeapi API

use DDG::Spice;

spice is_cached => 1;
spice proxy_cache_valid => "200 30d";

attribution github => ["AkA84"];

triggers any => "///***never_trigger***///";

spice to => 'http://pokeapi.co/api/v1/description/$1/';

handle remainder => sub {
return $_ if $_;
return;
};

1;
1 change: 1 addition & 0 deletions share/spice/pokemon/data/content.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div class="pokemon__description"></div>
8 changes: 8 additions & 0 deletions share/spice/pokemon/data/pokemon_data.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.zci--pokemon .pokemon__description {
margin-bottom: 10px;
}

.zci--pokemon .zci__header__sub {
display: block;
padding-left: 0;
}
136 changes: 136 additions & 0 deletions share/spice/pokemon/data/pokemon_data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
(function (env) {
"use strict";

var ID = 'pokemon',
INFOBOX_PROPS = ['hp', 'attack', 'defense', 'height', 'weight', 'speed'],
DESCRIPTION_ENDPOINT = '/js/spice/pokemon/description/{id}',
POKEAPI_SPRITE_URL = 'http://pokeapi.co/media/img/{id}.png';
/**
* [ Pokemon::Data ]
*/
env.ddg_spice_pokemon_data = function(api_result){
if( !api_result ) {
return Spice.failed('pokemon');
}

Spice.add({
id: ID,
name: 'Pokedex',
data: api_result,
meta: {
sourceName: 'pokeapi.co',
sourceUrl: 'http://pokeapi.co/',
sourceIconUrl: 'http://pokeapi.co/static/favicon.ico'
},
normalize: function(item) {
return {
title: item.name,
image: getSprite.call(item),
imageIsLogo: true,
infoboxData: getInfoboxData.call(item),
subtitle: (function(evolutions) {
if( evolutions.length > 0 ) {
var html = 'Evolves into: <a href="?q={name}+pokemon">{name}</a>';

return new Handlebars.SafeString(html.replace(/{name}/g, evolutions[0].to));
}
}(item.evolutions))
};
},
onShow: function() {
fetchDescription(api_result.descriptions).done(function(api_result) {
var description = api_result ? api_result.description : 'Description not available';

Spice.getDOM(ID).find('.pokemon__description').html(description);
});
},
templates: {
group: 'info',
options: {
content: Spice.pokemon_data.content,
moreAt: true
}
}
});
};

/**
* Chooses a random pokemon's description from the available sets
* and then calls the Pokemon::Description endpoint to fetch its full text
*
* @param {Array} descriptions
* @return {jqXHR} the Promise object
*/
function fetchDescription(descriptions) {
if( descriptions.length > 0 ) {
var randIndex = Math.floor(Math.random() * descriptions.length),
id = descriptions[randIndex].resource_uri.match(/(\d+)\/$/)[1];

return $.getJSON(DESCRIPTION_ENDPOINT.replace('{id}', id));
} else {
return new jQuery.Deferred().resolve(null).promise();
}
}

/**
* Returns the list of capitalized names from a collection
*
* @context {item}
* @param {Array} collection
* @return {Array}
*/
function getCollectionNames(collection) {
return $.map(this[collection], function(element) {
return DDG.capitalize(element.name);
});
}

/**
* Returns the list of label/value pairs to display in the Info Box
*
* @context {item}
* @return {Array}
*/
function getInfoboxData() {
var infoboxData = [{ heading: 'Info' }];

if( this.types.length > 0 ) {
infoboxData.push({
label: 'Type',
value: getCollectionNames.call(this, 'types').join(', ')
});
}

if( this.egg_groups.length > 0 ) {
infoboxData.push({
label: 'Egg groups',
value: getCollectionNames.call(this, 'egg_groups').join(', ')
});
}

for( var prop in this ) {
if( INFOBOX_PROPS.indexOf(prop) !== -1 && parseInt(this[prop], 10) ) {
infoboxData.push({
label: DDG.capitalize(prop),
value: this[prop]
});
}
}

return infoboxData;
}

/**
* Returns the url of the pokemon's sprite or null if the API doesn't provide any
*
* @context {item}
* @return {String / null}
*/
function getSprite() {
if( this.sprites.length !== 0 ) {
return POKEAPI_SPRITE_URL.replace('{id}', this.national_id);
} else {
return null;
}
}
}(this));
26 changes: 26 additions & 0 deletions t/Pokemon.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env perl

use strict;
use warnings;
use Test::More;
use DDG::Test::Spice;

spice is_cached => 1;

ddg_spice_test(
[qw( DDG::Spice::Pokemon::Data)],
'pikachu pokemon' => test_spice(
'/js/spice/pokemon/data/pikachu',
call_type => 'include',
caller => 'DDG::Spice::Pokemon::Data'
),
'pokemon Charizard' => test_spice(
'/js/spice/pokemon/data/charizard',
call_type => 'include',
caller => 'DDG::Spice::Pokemon::Data'
),
'bulbasaur pokemon stats' => undef,
);

done_testing;