package Scrabble::Dict; use base qw/Exporter/; use LWP::UserAgent; use strict; our @EXPORT_OK = qw/scrabble_define/; our $VERSION = '0.01'; my %defaults = ( host => 'www.hasbro.com', uri_home => '/games/adult-games/scrabble/home.cfm', uri_dict => '/games/adult-games/scrabble/home.cfm?page=Dictionary/dict', undefined_as => '' ); sub new { my $this = shift; my $class = ref($this) || $this; my %init = @_ & 1 ? die "argument hash expected" : @_; my $self = { _host => delete $init{host} || $defaults{host}, _uri_home => delete $init{uri_home} || $defaults{uri_home}, _uri_dict => delete $init{uri_dict} || $defaults{uri_dict}, _undefined_as => delete $init{undefined_as} || $defaults{undefined_as}, }; $self->{_ua} = LWP::UserAgent->new(%init, cookie_jar => {}); return bless $self => $class; } sub define { my ($self, $word) = (shift, lc shift); my $ua = $self->{_ua}; my %param = ( type => 'dictionary', exact => 'on', Word => $word ); # hasbro site forces us to eat ColdFusion cookies the first time my $url_home = "http://$self->{_host}$self->{_uri_home}"; my $cookie_scan = sub { $_[1] eq 'CFID' && $_[4] eq $self->{_host} }; $ua->get($url_home) if not $ua->cookie_jar->scan($cookie_scan); my $url_dict = "http://$self->{_host}$self->{_uri_dict}"; my $html = ''; $ua->post($url_dict, \%param, ':content_cb' => sub { $html .= shift }); return $self->scrape_definition($html, $word); } sub scrape_definition { my ($self, $html, $word) = (shift, shift, shift); return $1 if $html =~ m{
.*? \Q$word\E .*? \\ \s+ (.*?) .*?
}xsm; return $self->{_undefined_as}; } sub scrabble_define { my $word = shift; return __PACKAGE__->new(@_)->define($word); } 1; __END__ =head1 NAME Scrabble::Dict - look up words in the official Scrabble dictionary =head1 SYNOPSIS # procedural interface use Scrabble::Dict qw/scrabble_define/; print scrabble_define('quixotry')."\n"; # OO interface use Scrabble::Dict; my $dict = Scrabble::Dict->new(env_proxy => 1); # example: look up all the two letter words for my $c0 ('a' .. 'z') { for my $c1 ('a' .. 'z') { my $def = $dict->define($c0.$c1); print "${c0}${c1} $def\n" if $def; } } =head1 DESCRIPTION I is a screen-scraper interface to the Official Scrabble Player's Dictionary (OSPD) available online at http://www.hasbro.com/scrabble. =head1 METHODS =over 4 =item $dict = Scrabble::Dict->new(%options, %lwp_options); Construct a new Scrabble dictionary object. Recognized options are: host hostname of Scrabble site uri_home path of home page where we get cookies uri_dict path + query of word lookup page undefined_as return this when no definition is found These default to values which work currently, but may stop working at any given moment--this is screen-scraping after all. Any other key-value options are passed on to the constructor of I, giving you some finer-grained control over the connection. Refer to I for more. Before the actual word lookup is performed, cookies must be obtained from the Hasbro home page. The first call to define() on a I will take care of this. Subsequent calls on that object will be faster. =item $dict->define($word) Lookup the definition for a word. If no match is found, return the value of the 'undefined_as' option. =item $dict->scrape_definition($html, $word) Internal: finds the needle in the haystack. You could subclass and override if the page layout changes. =back =head1 FUNCTIONS =over 4 =item scrabble_define($word, %options, %lwp_options) Look up a word using a new I object. See new() for a description of available options. Note that the OO interface will be faster for multiple lookups. =back =head1 AUTHOR Alan Grow =head1 COPYRIGHT AND LICENSE This module is not endorsed by Hasbro Inc. The name Scrabble is a registered trademark of Hasbro Inc. Copyright (C) 2007 by Alan Grow This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.3 or, at your option, any later version of Perl 5 you may have available.