Hatena-Keyword
view release on metacpan or search on metacpan
lib/Hatena/Keyword.pm view on Meta::CPAN
package Hatena::Keyword;
use strict;
use warnings;
use base qw(Class::Data::Inheritable Class::Accessor::Fast Class::ErrorHandler);
use overload '""' => \&as_string, fallback => 1;
use Carp;
use URI;
use RPC::XML;
use RPC::XML::Client;
our $VERSION = 0.05;
my @Fields = qw(refcount word score cname);
__PACKAGE__->mk_accessors(@Fields);
__PACKAGE__->mk_classdata(rpc_client => RPC::XML::Client->new(
URI->new_abs('/xmlrpc', 'http://d.hatena.ne.jp/'),
useragent => [ agent => join('/', __PACKAGE__, __PACKAGE__->VERSION) ],
));
sub extract {
my $class = shift;
my $body = shift or croak sprintf 'usage %s->extract($text)', $class;
my $args = shift || {};
$args->{mode} = 'lite';
my $res = $class->_call_rpc_with_cache($body, $args)
or $class->error($class->errstr);
my @keywords = map { $class->_instance_from_rpcdata($_) }@{$res->{wordlist}};
return wantarray ? @keywords : \@keywords;
}
sub markup_as_html {
my $class = shift;
my $body = shift or croak sprintf 'usage %s->markup_as_html($text)', $class;
my $args = shift || {};
$args->{mode} = '';
my $res = $class->_call_rpc_with_cache($body, $args)
or $class->error($class->errstr);
return $res->value;
}
sub _call_rpc_with_cache {
my $class = shift;
my ($body, $args) = @_;
$body = pack('C0A*', $body); # hacking for utf-8 flag
my $cache = delete $args->{cache};
return $class->_call_rpc($body, $args) unless ref($cache);
croak "cache object must have get and set method."
if not $cache->can('get') or not $cache->can('set');
require Digest::MD5;
require Storable;
my $key = sprintf(
'%s-%s-%s',
$args->{mode} || '',
Digest::MD5::md5_hex($body),
Digest::MD5::md5_hex(Storable::freeze($args)),
);
my $res = Storable::thaw($cache->get($key));
unless (defined $res) {
$res = $class->_call_rpc($body, $args)
or return $class->error($class->errstr);
$cache->set($key =>Storable::freeze($res));
}
$res;
}
sub _call_rpc {
my ($class, $body, $args) = @_;
my $params = {
body => RPC::XML::string->new($body),
score => RPC::XML::int->new($args->{score} || 0),
mode => RPC::XML::string->new($args->{mode} || ''),
cname => defined $args->{cname} ? RPC::XML::array->new(
map { RPC::XML::string->new($_) } @{$args->{cname}}
) : undef,
a_target => RPC::XML::string->new($args->{a_target} || ''),
a_class => RPC::XML::string->new($args->{a_class} || ''),
};
# For all categories, It doesn't need an undefined cname value.
delete $params->{cname} unless defined $params->{cname};
my $res = $class->rpc_client->send_request(
RPC::XML::request->new('hatena.setkeywordlink', $params),
);
return ref $res ? $res : $class->error(qq/RPC Error: "$res"/);
}
sub _instance_from_rpcdata {
my ($class, $data) = @_;
return $class->new({
map {$_ => $data->{$_}->value } @Fields,
});
}
sub jcode {
my $self = shift;
$self->{_jcode} and return $self->{_jcode};
require Jcode;
return $self->{_jcode} = Jcode->new($self->as_string, 'utf8');
}
sub as_string { $_[0]->word }
1;
__END__
=head1 NAME
Hatena::Keyword - Extract Hatena Keywords in a string
=head1 VERSION
Version 0.03
=head1 SYNOPSIS
use Hatena::Keyword;
@keywords = Hatena::Keyword->extract("Perl and Ruby and Python.");
print $_->score, "\t", $_ for @keywords;
$keywords = Hatena::Keyword->extract("Hello, Perl!", {
score => 20,
cname => [qw(hatena web book)],
});
print $_->refcount, "\t", $_->jcode->euc for @$keywords;
my $cache = Cache::File->new(
cache_root => '/path/to/cache',
default_expires => '3600 sec',
);
$keywords = Hatena::Keyword->extract("Hello, Hatena!", {
cache => $cache,
});
$html = Hatena::Keyword->markup_as_html("Perl and Ruby");
$html = Hatena::Keyword->markup_as_html("Hello, Perl!", {
score => 20,
cname => [qw(hatena web book)],
a_class => 'keyword',
a_target => '_blank',
});
=head1 DESCRIPTION
This module allows you to extract Hatena keywords used in an
arbitrary text and also allows you to mark up a text as HTML with
( run in 1.324 second using v1.01-cache-2.11-cpan-6aa56a78535 )