DuckDuckGo: make the structure easier to maintain.

- Group up data in more human-friendly ways.
- Allow for generation of text and html responses from a base format, in
  most cases
- Move (almost) all processing outside the handler.

This also alphabetizes the keyword list which may have been a mistake.
The keywords don't reflect everything (given aliases) and maybe the old
structure made it easier for people to know where to put things
by looking for similar subjects.

Includes some improvements suggested by @crazedpsyc and @moollaza on
previous revisions.
master
Matt Miller 2014-05-02 09:22:22 +08:00
parent 2dd1faf40e
commit e0c590f23b
2 changed files with 243 additions and 175 deletions

View File

@ -11,180 +11,240 @@ code_url 'https://github.com/duckduckgo/zeroclickinfo-goodies/blob/master/lib/DD
category 'cheat_sheets';
topics 'everyday';
attribution twitter => 'crazedpsyc',
cpan => 'CRZEDPSYC' ;
cpan => 'CRZEDPSYC';
triggers startend => "duckduckgo", "ddg", "zeroclickinfo";
zci is_cached => 1;
# TODO: Merge these into just one hash. It's easier to work with it that way.
# This contains all of the responses in plain text.
my %data = (
goodies => "DuckDuckGo's Goodie repository: https://github.com/duckduckgo/zeroclickinfo-goodies",
spice => "DuckDuckGo's Spice repository: https://github.com/duckduckgo/zeroclickinfo-spice",
longtail => "DuckDuckGo's Longtail repository: https://github.com/duckduckgo/zeroclickinfo-longtail",
fathead => "DuckDuckGo's Fathead repository: https://github.com/duckduckgo/zeroclickinfo-fathead",
help => "Need help? Visit our help page: http://dukgo.com/help/",
roboduck => "DuckDuckGo's official IRC bot: https://github.com/Getty/duckduckgo-roboduck",
privacy => "DuckDuckGo's privacy policy: https://duckduckgo.com/privacy",
xmpp => "DuckDuckGo's XMPP service: https://duck.co/blog/using-pidgin-with-xmpp-jabber",
tor => "DuckDuckGo's Tor hidden service: https://3g2upl4pq6kufc4m.onion",
hiddenservice => \"tor",
torhiddenservice => \"tor",
contributing => "Contributing to DuckDuckGo: https://duck.co/help/community/contributing",
opensource => "DuckDuckGo's open source projects: https://duck.co/help/open-source/opensource-overview",
ads => "Advertising and Affiliates on DuckDuckGo: https://duck.co/help/company/advertising-and-affiliates",
businessmodel => \"ads",
advertisements => \"ads",
press => "DuckDuckGo's press page: https://duck.co/help/company/press",
traffic => "DuckDuckGo's traffic page: https://duckduckgo.com/traffic.html",
firefox => "DuckDuckGo's Firefox help page: https://duck.co/help/desktop/firefox",
chrome => "DuckDuckGo's Chrome help page: https://duck.co/help/desktop/chrome",
safari => "DuckDuckGo's Safari help page: https://duck.co/help/desktop/safari",
ie => "DuckDuckGo's Internet Explorer help page: https://duck.co/help/desktop/internet-explorer",
internetexplorer => \"ie",
opera => "DuckDuckGo's Opera help page: https://duck.co/help/desktop/opera",
spread => "DuckDuckGo's Spread page: https://duckduckgo.com/supportus.html",
syntax => "DuckDuckGo's available search syntax: https://duck.co/help/results/syntax",
app => "DuckDuckGo's mobile app: https://duckduckgo.com/app/",
ios => \"app",
android => \"app",
mobile => \"app",
blog => "DuckDuckGo's official blog: https://duck.co/blog",
translation => "Help translate DuckDuckGo (https://duck.co/translate) or adjust your language in the settings menu (https://duckduckgo.com/settings).",
translations => \"translation",
language => \"translation",
languages => \"translation",
settings => "DuckDuckGo's settings: https://duckduckgo.com/settings",
partnership => "Partnering with DuckDuckGo: https://duck.co/help/company/partnerships",
api => "DuckDuckGo's API: https://duckduckgo.com/api",
about => "DuckDuckGo's about page: https://duckduckgo.com/about",
short => "DuckDuckGo's short URL: http://ddg.gg/",
shorturl => \"short",
shortdomain => \"short",
ia => "DuckDuckGo's instant answers display helpful information at the top of the search page (like this box).\nSuggest or develop them on http://duckduckhack.com and see all the current instant answers on the Goodies page (https://duckduckgo.com/goodies).",
instantanswers => \"ia",
hiring => "Check out the DuckDuckGo hiring article: https://duck.co/help/company/hiring",
job => \"hiring",
jobs => \"hiring",
twitter => 'Follow us on @duckduckgo',
facebook => "Like us on https://www.facebook.com/duckduckgo",
community => "Join our growing community: https://duck.co/",
doodle => "Take a look at our holiday logos! https://duck.co/help/settings/holiday-logos",
swag => "Thanks for the support! Check out the DuckDuckGo store for t-shirts, stickers, and other items. https://duck.co/help/community/swag",
merch => \"swag",
merchandise => \"swag",
shirt => \"swag",
sticker => \"swag",
stickers => \"swag",
irc => "DuckDuckGo's official IRC channel is #duckduckgo on irc.freenode.net.",
remove => "To remove DuckDuckGo from your browser, take a look at https://duck.co/help/desktop. Please let us know why you are leaving at https://duckduckgo.com/feedback!",
removing => \"remove",
removal => \"remove",
duck => "I am the duck. Dax the duck.",
dax => \"duck",
whosdax => \"duck",
whoisdax => \"duck",
whostheduck => \"duck",
whoistheduck => \"duck",
mirrormirroronthewallwhosthefairestofthemall => \"duck",
(map {
$_ => "Zero Click Info is the term DuckDuckGo uses for these boxes, which often provide useful instant answers above traditional results.",
} "zeroclickinfo", "zeroclick", "0click", "0clickinfo", "zero 0", "zero click info", "zero-click info")
# If the text and HTML versions can be reasonably generated from the same format
# use base_format. If info_url is included, the words surrounded with [] will be linked
# in the HTML version. The url will be appended to the text version.
#
# Otherwise, include both text and html keys.
#
# If more than one keyword applies, add an aliases key with an array ref of string aliases.
my %responses = (
about => {
base_format => "DuckDuckGo's [about page]",
info_url => 'https://duckduckgo.com/about',
},
ads => {
base_format => "[Advertising and Affiliates on DuckDuckGo]",
info_url => 'https://duck.co/help/company/advertising-and-affiliates',
aliases => [qw( businessmodel advertisements )],
},
api => {
base_format => "DuckDuckGo's [API]",
info_url => 'https://duckduckgo.com/api',
},
app => {
base_format => "DuckDuckGo's [mobile app]",
info_url => 'https://duckduckgo.com/app/',
aliases => [qw( ios android mobile )],
},
blog => {
base_format => "DuckDuckGo's [official blog]",
info_url => 'https://duck.co/blog',
},
chrome => {
base_format => "DuckDuckGo's [Chrome help page]",
info_url => 'https://duck.co/help/desktop/chrome',
},
contributing => {
base_format => '[Contributing to DuckDuckGo]',
info_url => 'https://duck.co/help/community/contributing',
},
community => {
base_format => 'Join our [growing community]',
info_url => 'https://duck.co/',
},
doodle => {
base_format => "Take a look at our [holiday logos]",
info_url => 'https://duck.co/help/settings/holiday-logos',
},
duck => {
text => "I am the duck. Dax the duck.",
html => "<img src='https://duckduckgo.com/assets/logo_header.v101.png' alt='Dax' /><br/>I am the duck. Dax the duck.",
aliases => [qw( dax whosdax whoisdax whostheduck whoistheduck mirrormirroronthewallwhosthefairestofthemall )],
},
facebook => {
base_format => "Like us on [Facebook]",
info_url => 'https://www.facebook.com/duckduckgo'
},
fathead => {
base_format => "DuckDuckGo's [Fathead repository]",
info_url => 'https://github.com/duckduckgo/zeroclickinfo-fathead',
},
firefox => {
base_format => "DuckDuckGo's [Firefox help page]",
info_url => 'https://duck.co/help/desktop/firefox',
},
goodies => {
base_format => "DuckDuckGo's [Goodie repository]",
info_url => 'https://github.com/duckduckgo/zeroclickinfo-goodies',
},
help => {
base_format => "Need help? Visit our [help page]",
info_url => 'http://dukgo.com/help/',
},
hiring => {
base_format => "Check out the DuckDuckGo [hiring article]",
info_url => 'https://duck.co/help/company/hiring',
aliases => [qw( job jobs )],
},
ia => {
text =>
"DuckDuckGo's instant answers display helpful information at the top of the search page (like this box).\nSuggest or develop them on http://duckduckhack.com and see all the current instant answers on the Goodies page (https://duckduckgo.com/goodies).",
html =>
"DuckDuckGo's instant answers display helpful information at the top of the search page (like this box).<br>Suggest or develop them on <a href='http://duckduckhack.com/'>DuckDuckHack</a> and see all the current instant answers on the <a href='https://duckduckgo.com/goodies'>Goodies page</a>.",
aliases => [qw( instantanswer instantanswers )],
},
ie => {
base_format => "DuckDuckGo's [Internet Explorer help page]",
info_url => 'https://duck.co/help/desktop/internet-explorer',
aliases => [qw( internetexplorer )],
},
irc => {
text => "DuckDuckGo's official IRC channel is #duckduckgo on irc.freenode.net.",
html =>
"DuckDuckGo's official IRC channel is <a href='http://webchat.freenode.net/?channels=duckduckgo'>#duckduckgo</a> on <a href='http://freenode.net/'>irc.freenode.net</a>",
},
longtail => {
base_format => "DuckDuckGo's [Longtail repository]",
info_url => 'https://github.com/duckduckgo/zeroclickinfo-longtail',
},
opensource => {
base_format => "DuckDuckGo's [open source projects]",
info_url => 'https://duck.co/help/open-source/opensource-overview',
},
opera => {
base_format => "DuckDuckGo's [Opera help page]",
info_url => 'https://duck.co/help/desktop/opera',
},
partnership => {
base_format => "[Partnering with DuckDuckGo]",
info_url => 'https://duck.co/help/company/partnerships',
},
press => {
base_format => "DuckDuckGo's [press page]",
info_url => 'https://duck.co/help/company/press',
},
privacy => {
base_format => "DuckDuckGo's [privacy policy]",
info_url => 'https://duckduckgo.com/privacy',
},
remove => {
text =>
"To remove DuckDuckGo from your browser, take a look at https://duck.co/help/desktop. Please let us know why you are leaving at https://duckduckgo.com/feedback!",
html =>
"To remove DuckDuckGo from your browser, take a look <a href='https://duck.co/help/desktop'>here</a>. Please <a href='https://duckduckgo.com/feedback'>let us know</a> why you are leaving!",
aliases => [qw( removing removal )],
},
roboduck => {
base_format => "DuckDuckGo's official [IRC bot]",
info_url => 'https://github.com/Getty/duckduckgo-roboduck',
},
safari => {
base_format => "DuckDuckGo's [Safari help page]",
info_url => 'https://duck.co/help/desktop/safari',
},
settings => {
base_format => "DuckDuckGo [settings]",
info_url => 'https://duckduckgo.com/settings',
},
short => {
text => "DuckDuckGo's short URL: http://ddg.gg/",
html => "DuckDuckGo's short URL: <a href='http://ddg.gg/'>http://ddg.gg/</a>.",
aliases => [qw( shorturl shortdomain )],
},
spice => {
base_format => "DuckDuckGo's [Spice repository]",
info_url => 'https://github.com/duckduckgo/zeroclickinfo-spice',
},
spread => {
base_format => "DuckDuckGo's [Spread page]",
info_url => 'https://duckduckgo.com/supportus.html',
},
swag => {
base_format => "Thanks for the support! Check out the [DuckDuckGo store] for t-shirts, stickers, and other items",
info_url => 'https://duck.co/help/community/swag',
aliases => [qw( merch merchandise shirt shirts sticker stickers )],
},
syntax => {
base_format => "DuckDuckGo's [available search syntax]",
info_url => 'https://duck.co/help/results/syntax',
},
tor => {
base_format => "DuckDuckGo's [Tor hidden service]",
info_url => 'https://3g2upl4pq6kufc4m.onion',
aliases => [qw( hiddenservice torhiddenservice )],
},
traffic => {
base_format => "DuckDuckGo's [traffic page]",
info_url => 'https://duckduckgo.com/traffic.html',
},
translation => {
text =>
"Help translate DuckDuckGo (https://duck.co/translate) or adjust your language in the settings menu (https://duckduckgo.com/settings).",
html =>
"Help <a href='https://duck.co/translate'>translate DuckDuckGo</a> or adjust your language in the <a href='https://duckduckgo.com/settings'>settings menu</a>.",
aliases => [qw( translations language languages )],
},
twitter => {
base_format => 'Follow us on [@duckduckgo]',
info_url => 'https://twitter.com/duckduckgo',
},
xmpp => {
base_format => "DuckDuckGo's [XMPP service]",
info_url => 'https://duck.co/blog/using-pidgin-with-xmpp-jabber',
},
zci => {
base_format => "Zero Click Info is the term DuckDuckGo uses for these boxes, which often provide useful instant answers above traditional results.",
aliases => ["zeroclickinfo", "zeroclick", "0click", "0clickinfo", "zero 0", "zero click info", "zero-click info"],
},
);
# This contains all of the responses in HTML format.
my %data_html = (
goodies => "DuckDuckGo's <a href='https://github.com/duckduckgo/zeroclickinfo-goodies'>Goodie repository</a>",
spice => "DuckDuckGo's <a href='https://github.com/duckduckgo/zeroclickinfo-spice'>Spice repository</a>",
longtail => "DuckDuckGo's <a href='https://github.com/duckduckgo/zeroclickinfo-longtail'>Longtail repository</a>",
fathead => "DuckDuckGo's <a href='https://github.com/duckduckgo/zeroclickinfo-fathead'>Fathead repository</a>",
help => "Need help? Visit our <a href='http://dukgo.com/help/'>help page</a>.",
roboduck => "DuckDuckGo's official <a href='https://github.com/Getty/duckduckgo-roboduck'>IRC bot</a>.",
privacy => "DuckDuckGo's <a href='https://duckduckgo.com/privacy'>privacy policy</a>..",
xmpp => "DuckDuckGo's <a href='https://duck.co/blog/using-pidgin-with-xmpp-jabber'>XMPP service</a>.",
tor => "DuckDuckGo's <a href='https://3g2upl4pq6kufc4m.onion'>Tor hidden service</a>.",
hiddenservice => \"tor",
torhiddenservice => \"tor",
contributing => "<a href='https://duck.co/help/community/contributing'>Contributing to DuckDuckGo</a>",
opensource => "DuckDuckGo's <a href='https://duck.co/help/open-source/opensource-overview'>open source projects</a>.",
ads => "<a href='https://duck.co/help/company/advertising-and-affiliates'>Advertising and Affiliates on DuckDuckGo</a>.",
businessmodel => \"ads",
advertisements => \"ads",
press => "DuckDuckGo's <a href='https://duck.co/help/company/press'>press page</a>.",
traffic => "DuckDuckGo's <a href='https://duckduckgo.com/traffic.html'>traffic page</a>.",
firefox => "DuckDuckGo's <a href='https://duck.co/help/desktop/firefox'>Firefox help page</a>.",
chrome => "DuckDuckGo's <a href='https://duck.co/help/desktop/chrome'>Chrome help page</a>.",
safari => "DuckDuckGo's <a href='https://duck.co/help/desktop/safari'>Safari help page</a>.",
ie => "DuckDuckGo's <a href='https://duck.co/help/desktop/internet-explorer'>Internet Explorer help page</a>.",
internetexplorer => \"ie",
opera => "DuckDuckGo's <a href='https://duck.co/help/desktop/opera'>Opera help page</a>.",
spread => "DuckDuckGo's <a href='https://duckduckgo.com/supportus.html'>Spread page</a>.",
syntax => "DuckDuckGo's <a href='https://duck.co/help/results/syntax'>available search syntax</a>.",
app => "DuckDuckGo's <a href='https://duckduckgo.com/app/'>mobile app</a>.",
ios => \"app",
android => \"app",
mobile => \"app",
blog => "DuckDuckGo's <a href='https://duck.co/blog'>official blog</a>.",
translation => "Help <a href='https://duck.co/translate'>translate DuckDuckGo</a> or adjust your language in the <a href='https://duckduckgo.com/settings'>settings menu</a>.",
translations => \"translations",
language => \"translations",
languages => \"translations",
settings => "DuckDuckGo's <a href='https://duckduckgo.com/settings'>settings</a>.",
partnership => "<a href='https://duckduckgo.com/settings'>Partnering with DuckDuckGo</a>.",
api => "DuckDuckGo's <a href='https://duckduckgo.com/api'>API</a>.",
about => "DuckDuckGo's <a href='https://duckduckgo.com/about'>about page</a>.",
short => "DuckDuckGo's short URL: <a href='http://ddg.gg/'>http://ddg.gg/</a>.",
shorturl => \"short",
shortdomain => \"short",
ia => "DuckDuckGo's instant answers display helpful information at the top of the search page (like this box).<br>Suggest or develop them on <a href='http://duckduckhack.com/'>DuckDuckHack</a> and see all the current instant answers on the <a href='https://duckduckgo.com/goodies'>Goodies page</a>.",
instantanswers => \"ia",
hiring => "Check out the <a href='https://duck.co/help/company/hiring'>DuckDuckGo hiring article</a>.",
job => \"hiring",
jobs => \"hiring",
twitter => "Follow us on <a href='https://twitter.com/duckduckgo'>\@duckduckgo</a>.",
facebook => "Like us on <a href='https://www.facebook.com/duckduckgo'>Facebook</a>.",
community => "Join our <a href='https://duck.co/'>growing community</a>!",
doodle => "Take a look at our <a href='https://duck.co/help/settings/holiday-logos'>holiday logos</a>!",
swag => "Thanks for the support! Check out the <a href='https://duck.co/help/community/swag'>DuckDuckGo store</a> for t-shirts, stickers, and other items.",
merch => \"swag",
merchandise => \"swag",
shirt => \"swag",
sticker => \"swag",
stickers => \"swag",
irc => "DuckDuckGo's official IRC channel is <a href='http://webchat.freenode.net/?channels=duckduckgo'>#duckduckgo</a> on <a href='http://freenode.net/'>irc.freenode.net</a>",
remove => "To remove DuckDuckGo from your browser, take a look <a href='https://duck.co/help/desktop'>here</a>. Please <a href='https://duckduckgo.com/feedback'>let us know</a> why you are leaving!",
removing => \"remove",
removal => \"remove",
duck => "<img src='https://duckduckgo.com/assets/logo_header.v101.png' alt='Dax' /><br/>I am the duck. Dax the duck.",
dax => \"duck",
whosdax => \"duck",
whoisdax => \"duck",
whostheduck => \"duck",
whoistheduck => \"duck",
mirrormirroronthewallwhosthefairestofthemall => \"duck",
(map {
$_ => "Zero Click Info is the term DuckDuckGo uses for these boxes, which often provide useful instant answers above traditional results.",
} "zeroclickinfo", "zeroclick", "0click", "0clickinfo", "zero 0", "zero click info", "zero-click info")
);
# Above is intended to be human-friendly.
# Now we make it computer-friendly.
foreach my $keyword (keys %responses) {
my $response = $responses{$keyword};
if (my $base_format = $response->{base_format}) {
# We need to produce the output for each version.
if (my $info_url = $response->{info_url}) {
$response->{text} = $base_format;
$response->{text} =~ s/[\[\]]//g; # No internal linking.
$response->{text} .= ': ' . $response->{info_url}; # Stick the link on the end.
$response->{html} = $base_format;
$response->{html} =~ s#\[#<a href='$info_url'>#; # Insert link.
$response->{html} =~ s#\]#</a>#;
$response->{html} .= '.';
} else {
# No link to insert, so it must be ready for both.
$response->{text} = $response->{html} = $response->{base_format};
}
}
if (ref($response->{aliases}) eq 'ARRAY') {
foreach my $alias (@{$response->{aliases}}) {
# Assume we didn't add an alias for an existing keyword.
$responses{$alias} = $response;
}
}
foreach my $key (keys %$response) {
# No matter what they added above, we only use the following keys for the actual response.
delete $response->{$key} unless (grep { $key eq $_ } (qw(text html)));
}
}
handle remainder => sub {
s/\W+//g;
my $key = lc;
# Make sure that it exists in both hashes.
if(defined $data_html{$key} && defined $data{$key}) {
my $response = $responses{$key};
# Both of them should be references.
if(ref($data_html{$key}) && ref($data{$key})) {
$key = ${$data{$key}};
return $data{$key}, html => $data_html{$key};
}
return $data{$key}, html => $data_html{$key};
}
return;
return unless ($response);
return $response->{text}, html => $response->{html};
};
1;

View File

@ -6,31 +6,39 @@ use Test::More;
use DDG::Test::Goodie;
zci answer_type => 'duckduckgo';
zci is_cached => 1;
zci is_cached => 1;
ddg_goodie_test(
[qw(
DDG::Goodie::DuckDuckGo
)],
ddg_goodie_test([qw(
DDG::Goodie::DuckDuckGo
)
],
'duckduckgo Zero-Click Info' => test_zci(
"Zero Click Info is the term DuckDuckGo uses for these boxes, which often provide useful instant answers above traditional results.",
html => "Zero Click Info is the term DuckDuckGo uses for these boxes, which often provide useful instant answers above traditional results."
"Zero Click Info is the term DuckDuckGo uses for these boxes, which often provide useful instant answers above traditional results.",
html => "Zero Click Info is the term DuckDuckGo uses for these boxes, which often provide useful instant answers above traditional results."
),
'ddg zeroclick' => test_zci(
"Zero Click Info is the term DuckDuckGo uses for these boxes, which often provide useful instant answers above traditional results.",
html => "Zero Click Info is the term DuckDuckGo uses for these boxes, which often provide useful instant answers above traditional results."
"Zero Click Info is the term DuckDuckGo uses for these boxes, which often provide useful instant answers above traditional results.",
html => "Zero Click Info is the term DuckDuckGo uses for these boxes, which often provide useful instant answers above traditional results."
),
'duckduckgo help' => test_zci(
"Need help? Visit our help page: http://dukgo.com/help/",
html => "Need help? Visit our <a href='http://dukgo.com/help/'>help page</a>."
"Need help? Visit our help page: http://dukgo.com/help/",
html => "Need help? Visit our <a href='http://dukgo.com/help/'>help page</a>."
),
'duckduckgo about' => test_zci(
"DuckDuckGo's about page: https://duckduckgo.com/about", html => "DuckDuckGo's <a href='https://duckduckgo.com/about'>about page</a>."
),
'ddg merch' => test_zci(
"Thanks for the support! Check out the DuckDuckGo store for t-shirts, stickers, and other items: https://duck.co/help/community/swag",
html =>
"Thanks for the support! Check out the <a href='https://duck.co/help/community/swag'>DuckDuckGo store</a> for t-shirts, stickers, and other items."
),
'duckduckgo irc' => test_zci(
"DuckDuckGo's official IRC channel is #duckduckgo on irc.freenode.net.",
html => "DuckDuckGo's official IRC channel is <a href='http://webchat.freenode.net/?channels=duckduckgo'>#duckduckgo</a> on <a href='http://freenode.net/'>irc.freenode.net</a>"
"DuckDuckGo's official IRC channel is #duckduckgo on irc.freenode.net.",
html =>
"DuckDuckGo's official IRC channel is <a href='http://webchat.freenode.net/?channels=duckduckgo'>#duckduckgo</a> on <a href='http://freenode.net/'>irc.freenode.net</a>"
),
irc => undef,
);
done_testing;