package Text::AutoLink; use strict; use warnings; use 5.006; use vars qw($VERSION); use HTML::TreeBuilder; use Module::Pluggable require => 0, search_path => 'Text::AutoLink::Plugin', sub_name => 'available_plugins', ; BEGIN { $VERSION = '0.04000' } sub new { my $class = shift; my %args = @_; my $self = bless { plugins => [], }, $class; $args{plugins} ||= [$class->available_plugins]; foreach my $p (@{$args{plugins}}) { if (! ref $p) { eval "require $p"; die if $@; $p = $p->new; } push @{$self->{plugins}}, $p; } return $self; } sub plugins { my $self = shift; wantarray ? @{$self->{plugins}} : $self->{plugins}; } sub _parse { my $self = shift; my $x = shift; if ($x->attr('_tag') eq 'a') { return; } my @list = $x->content_list; for(my $i = 0; $i < @list; $i++) { my $c = $list[$i]; if (ref $c) { $self->_parse($c); } else { foreach my $p ($self->plugins) { next unless $c; next unless $p->process(\$c); my $subtree = HTML::TreeBuilder->new_from_content($c); $self->_parse($subtree); $x->splice_content($i, 1, $subtree); } } } } sub parse_file { my $self = shift; my $file = shift; open my $fh, "<", $file or die "Failed to open file $file: $!"; $self->parse_fh($fh); } sub parse_fh { my $self = shift; my $fh = shift; my $text = join '', <$fh>; return $self->parse_string($text); } sub parse_string { my $self = shift; my $string = shift; my $ret; my $tree = HTML::TreeBuilder->new_from_content($string); $self->_parse($tree); foreach my $i ($tree->look_down(_implicit => 1)) { $i->replace_with_content if $i->parent; } if ($tree->implicit) { $ret = join('', map { ref $_ ? $_->as_HTML : $_ } $tree->content_list ); } else { $ret = $tree->as_HTML; } $tree->delete; return $ret; } 1; __END__ =head1 NAME Text::AutoLink - Automatically Linkfy =head1 SYNOPSIS use Text::AutoLink; my $auto = Text::AutoLink->new; my $text = $auto->parse_string('http://search.cpan.org'); # 'http://search.cpan.org' my $auto = Text::AutoLink->new( plugins => [ 'Text::AutoLink::Plugin::HTTP' Text::AutoLink::Plugin::FTP->new(%args) ] ); =head1 DESCRIPTION Text::AutoLink is a module inspired by Text::Hatena. I just wanted to automatically make HTML links in arbitrary text that is not in Text::Hatena format, so here it is. Text::AutoLink is designed such that it can handle plain text or HTML text, with the focus on allowing arbitrary plugins to handle the transformation. =head1 METHODS =head2 new(%args) Creates a new Text::AutoLink object. =over 4 =item plugins ARRAYREF You may specify the list of plugins that you want to apply on a text. If you don't specify this parameter, Text::AutoLink will include all the plugins that are available under Text::AutoLink::Plugin namespace. =back =head2 plugins Returns the list of plugins that are associated with this instance. =head2 parse_string SCALAR Parses the given string and auto-links strings that are not already linked. Returns the modified string. =head2 parse_file SCALAR Parses the given file. =head2 parse_fh FILEHANDLE Parses the given file handle. =head1 CAVEATS Text::AutoLink internally uses HTML::TreeBuilder, so the resulting text may slightly be different from the input. In my experience this is usually not a problem, but if you are being strict it may bite you. =head1 AUTHOR Copyright (c) 2006-2007 Daisuke Maki Edaisuke@endeworks.jp. =head1 LICENSE This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See http://www.perl.com/perl/misc/Artistic.html =cut