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

Commit

Permalink
Merge pull request #480 from wilkox/chinese_zodiac
Browse files Browse the repository at this point in the history
Add Chinese Zodiac goodie
  • Loading branch information
Jag Talon committed Jun 30, 2014
2 parents b4d1c58 + 769f3ca commit 82ec048
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 0 deletions.
2 changes: 2 additions & 0 deletions dist.ini
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ Locale::Currency::Format = 1.30
Net::IP = 0
Math::BaseConvert = 0
Telephony::CountryDialingCodes = 1.04
DateTime::Calendar::Chinese = 1.00
DateTime::Event::Chinese = 1.00

[Prereqs / TestRequires]
Test::More = 0.98
Expand Down
113 changes: 113 additions & 0 deletions lib/DDG/Goodie/ChineseZodiac.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package DDG::Goodie::ChineseZodiac;
# ABSTRACT: Return the Chinese zodiac animal for a given year.

use DDG::Goodie;
use DateTime::Calendar::Chinese;
use DateTime::Event::Chinese qw(chinese_new_year_before chinese_new_year_after);
use utf8;
use feature 'state';

triggers any => 'chinese zodiac', 'shēngxiào', 'shengxiao', 'shēng xiào', 'sheng xiao';
zci is_cached => 1;

name 'Chinese Zodiac';
description 'Return the Chinese zodiac animal for a given year';
primary_example_queries 'chinese zodiac for 1969';
secondary_example_queries '2004 chinese zodiac animal', 'what was the chinese zodiac animal in 1992', 'what will the chinese zodiac animal be for 2056', 'last year\'s chinese zodiac';
category 'dates';
topics 'special_interest';
code_url 'https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DDG/Goodie/ChineseZodiac.pm';
attribution github => ['http://github.com/wilkox', 'wilkox'];

my %animal_to_language = (
'hare' => { en => 'Rabbit', zh => '' },
'dragon' => { en => 'Dragon', zh => '' },
'snake' => { en => 'Snake', zh => '' },
'horse' => { en => 'Horse', zh => '' },
'sheep' => { en => 'Goat', zh => '' },
'monkey' => { en => 'Monkey', zh => '' },
'fowl' => { en => 'Rooster', zh => '' },
'dog' => { en => 'Dog', zh => '' },
'pig' => { en => 'Pig', zh => '' },
'rat' => { en => 'Rat', zh => '' },
'ox' => { en => 'Ox', zh => '' },
'tiger' => { en => 'Tiger', zh => '' }
);

handle remainder => sub {

#Figure out what year the user is interested in
my $year_gregorian;

#Return if more than one number has been included;
# this IA only supports years (for now)
return if /\d+[^\d]+\d+/;

#Parse out a relative year expression if it was supplied
if (/this\syear('s)?/) {
$year_gregorian = DateTime->now(time_zone => 'Asia/Shanghai') or return;
} elsif (/next\syear('s)?/) {
$year_gregorian = DateTime->now(time_zone => 'Asia/Shanghai')->add(years => 1) or return;
} elsif (/last\syear('s)?/) {
$year_gregorian = DateTime->now(time_zone => 'Asia/Shanghai')->subtract(years => 1) or return;

#If no relative year was supplied, look for an explicit year
# DateTime::Event::SolarTerm only supports 1900--2069, so
# return nothing if the user provides a year outside this range
} elsif (/\b(\d+)\b/) {
return unless $1 >= 1900 && $1 <= 2069;
$year_gregorian = DateTime->new(year => $1, month => 6, time_zone => 'Asia/Shanghai');

#Otherwise, default to now if it seems like the user is
# asking a question about the current zodiac animal
} elsif (/(what|which|year|animal|current|now|today|this)/) {
$year_gregorian = DateTime->now(time_zone => 'Asia/Shanghai') or return;

#Don't want to show instant answer if user is just looking for
# general information on the chinese zodiac
} else {
return;
}

#Find the Chinese year that aligns
# with the query (presumed Gregorian) year
my $year_chinese = DateTime::Calendar::Chinese->from_object(object => $year_gregorian);

#Get the inclusive Gregorian date range for the Chinese year
#Note that returned dates will be for the 'Asia/Shanghai'
# time zone (China Standard Time/CST) as this is where
# Chinese New Year is calculated
my $year_start = chinese_new_year_before($year_gregorian)->set_time_zone('Asia/Shanghai');
my $year_end = chinese_new_year_after($year_gregorian)->subtract(days => 1)->set_time_zone('Asia/Shanghai');

my $animal = $year_chinese->zodiac_animal;
my $english = $animal_to_language{$animal}{'en'};
my $character = $animal_to_language{$animal}{'zh'};

my $statement = 'Chinese zodiac animal for ' . format_datetime($year_start) . "\x{2013}" . format_datetime($year_end);

return answer => $english, html => wrap_html($character, $english, $statement);
};

sub format_datetime {
my $dt = shift;
my $formatted = $dt->strftime('%b %e, %Y');
$formatted =~ s/\s\s/ /g;
return $formatted;
}

# This function adds some HTML and styling to our output
# so that we can make it prettier (copied from the Conversions
# goodie)
sub append_css {
my $html = shift;
state $css = share("style.css")->slurp;
return "<style type='text/css'>$css</style>$html";
}

sub wrap_html {
my ($character, $english, $statement) = @_;
return append_css("<div class='zci--chinesezodiac'><div class='zodiaccharacter'>$character ($english)</div><span class='statement'>$statement</span></div>");
}

1;
12 changes: 12 additions & 0 deletions share/goodie/chinese_zodiac/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.zci--answer .zci--chinesezodiac {
padding-top: .25em;
padding-bottom: .25em;
}

.zci--answer .zci--chinesezodiac .zodiaccharacter {
font-size: 1.7em;
}

.zci--answer .zci--chinesezodiac .statement {
color: #747474;
}
85 changes: 85 additions & 0 deletions t/ChineseZodiac.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env perl

use strict;
use warnings;
use Test::More;
use DDG::Test::Goodie;
use utf8;

zci answer_type => 'chinesezodiac';
zci is_cached => 1;

ddg_goodie_test(
[qw(
DDG::Goodie::ChineseZodiac
)],

#Primary example
'chinese zodiac for 1969' => test_zci('Rooster', html => qr/Rooster/),

#Secondary examples
'2004 chinese zodiac animal' => test_zci('Monkey', html => qr/Monkey/),
'what was the chinese zodiac animal in 1992' => test_zci('Monkey', html => qr/Monkey/),
'what will the chinese zodiac animal be for 2056' => test_zci('Rat', html => qr/Rat/),
'last year\'s chinese zodiac' => test_zci(qr/./, html => qr/./),

#Primary example with different query formats
'1969 chinese zodiac animal' => test_zci('Rooster', html => qr/Rooster/),
'what was the chinese zodiac animal for 1969' => test_zci('Rooster', html => qr/Rooster/),
'what will the chinese zodiac animal be for people born in the year 1969' => test_zci('Rooster', html => qr/Rooster/),
'chinese zodiac for a person born in 1969' => test_zci('Rooster', html => qr/Rooster/),
'chinese zodiac of 1969' => test_zci('Rooster', html => qr/Rooster/),

#Alternative triggers
'1969 shēngxiào' => test_zci('Rooster', html => qr/Rooster/),
'shengxiao animal 1969' => test_zci('Rooster', html => qr/Rooster/),
'shēng xiào for 1969' => test_zci('Rooster', html => qr/Rooster/),
'i was born in 1969 what is my sheng xiao' => test_zci('Rooster', html => qr/Rooster/),

#Test some different years
# Taken from http://www.chinesezodiac.com/calculator.php
'chinese zodiac animal for 1924' => test_zci('Rat', html => qr/Rat/),
'chinese zodiac animal for 1929' => test_zci('Snake', html => qr/Snake/),
'chinese zodiac animal for 1934' => test_zci('Dog', html => qr/Dog/),
'chinese zodiac animal for 1939' => test_zci('Rabbit', html => qr/Rabbit/),
'chinese zodiac animal for 1944' => test_zci('Monkey', html => qr/Monkey/),
'chinese zodiac animal for 1949' => test_zci('Ox', html => qr/Ox/),
'chinese zodiac animal for 1954' => test_zci('Horse', html => qr/Horse/),
'chinese zodiac animal for 1959' => test_zci('Pig', html => qr/Pig/),
'chinese zodiac animal for 1964' => test_zci('Dragon', html => qr/Dragon/),
'chinese zodiac animal for 1969' => test_zci('Rooster', html => qr/Rooster/),
'chinese zodiac animal for 1974' => test_zci('Tiger', html => qr/Tiger/),
'chinese zodiac animal for 2027' => test_zci('Goat', html => qr/Goat/),
'chinese zodiac animal for 2040' => test_zci('Monkey', html => qr/Monkey/),

#Test for correct date ranges
# Taken from http://www.chinesezodiac.com/calculator.php
'chinese zodiac animal for 1925' => test_zci('Ox', html => qr/Jan\s24,\s1925.Feb\s12,\s1926/),
'chinese zodiac animal for 1937' => test_zci('Ox', html => qr/Feb\s11,\s1937.Jan\s30,\s1938/),
'chinese zodiac animal for 1953' => test_zci('Snake', html => qr/Feb\s14,\s1953.Feb\s2,\s1954/),
'chinese zodiac animal for 1973' => test_zci('Ox', html => qr/Feb\s3,\s1973.Jan\s22,\s1974/),
'chinese zodiac animal for 1997' => test_zci('Ox', html => qr/Feb\s7,\s1997.Jan\s27,\s1998/),
'chinese zodiac animal for 2013' => test_zci('Snake', html => qr/Feb\s10,\s2013.Jan\s30,\s2014/),
'chinese zodiac animal for 2017' => test_zci('Rooster', html => qr/Jan\s28,\s2017.Feb\s15,\s2018/),
'chinese zodiac animal for 2041' => test_zci('Rooster', html => qr/Feb\s1,\s2041.Jan\s21,\s2042/),

#Should not trigger
'wikipedia chinese zodiac' => undef,
'what is my zodiac sign' => undef,
'what is the chinese word for duck' => undef,
'buy an inflatable zodiac chinese online store' => undef,
'chinese zodiac 20 march 1997' => undef,
'chinese zodiac 1997-03-20' => undef,
'what was the chinese zodiac animal on the 3rd of april 1945' => undef,

#No support currently for years outside 1900--2069
'chinese zodiac 1899' => undef,
'chinese zodiac 1900' => test_zci('Rat', html => qr/Rat/),
'chinese zodiac 2069' => test_zci('Ox', html => qr/Ox/),
'chinese zodiac 2070' => undef,
'chinese zodiac 2000000000000' => undef,

);

done_testing;

0 comments on commit 82ec048

Please sign in to comment.