This repository has been archived by the owner on Oct 15, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #480 from wilkox/chinese_zodiac
Add Chinese Zodiac goodie
- Loading branch information
Showing
4 changed files
with
212 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
|