package WWW::Wikipedia::TemplateFiller::Source; use warnings; use strict; # Plus: +Field means show field only if extended-fields is enabled # Minus: -Field means always show, regardless of extended-fields status # Other: Field means show only if filled use Date::Calc; use XML::Writer; use HTML::Entities; use Tie::IxHash; use Carp; =head1 NAME WWW::Wikipedia::TemplateFiller::Source - Base class for data sources =head1 DESCRIPTION This is an internal base class from which data source classes inherit. From an end-user perspective, there is unlikely any reason to know anything about this module. That said, feel free to poke around. :-) =head1 METHODS =head2 new my $source = new WWW::Wikipedia::TemplateFiller::Source( filler => $filler, %attrs ); Create a new source object with the given filler and attributes C<%attrs>. =cut sub new { my( $pkg, %attrs ) = @_; croak "no TemplateFiller object provided as 'filler' attr" unless $attrs{filler}; if( my $class = $pkg->search_class ) { $attrs{__search} = new WWW::Search($class); } my $self = bless \%attrs, $pkg; return $self; } sub __result_from_cache { } sub __result_to_cache { } sub __cache_key { my( $self, $id ) = @_; return $self->type.'-'.$id; } =head2 _search_obj my $search = $source->_search_obj; (Internal method.) Returns the L object used by this source class. Only useful for source subclasses that define a C class method, which defines the L module to be used for backend searches. =cut sub _search_obj { shift->{__search} } =head2 _search my $result = $source->_search($id); (Internal method.) Performs a basic L search. Only useful for source subclasses that define a C class method. Essentially the same as: $source->_search->native_query($id); return $source->_search->next_result; except that a cache may be used internally to speed things up. =cut sub _search { my( $self, $id ) = @_; my $result = $self->__result_from_cache( $id ); if( not $result ) { $self->_search_obj->native_query($id); $result = $self->_search_obj->next_result; $self->__result_to_cache( $id => $result ); } return $result; } =head2 template_name Class method only; used by source classes to define the title of the template they will be populating. Example for PubmedId source: sub template_name { 'cite journal' } =cut sub template_name { croak "no 'template_name' class method specified in this source" } =head2 filler Returns the filler associated with this source. =cut sub filler { shift->{filler} } =head2 source_url Returns the url associated with this source data. =cut sub source_url { shift->{__source_url} } sub __source_obj { my( $self, $attrs ) = @_; while( my($k,$v) = each %$attrs ) { ( my $plain_k = $k ) =~ s/^\W//; $self->{$k} = $v; $self->{$plain_k} = $v; } return $self; } =head2 fill my $template = $source->fill; Fills the appopriate template with data from this source. =cut sub fill { my( $self, %args ) = @_; my $raw_basic_fields = $self->template_basic_fields(%args); my %field_status; tie( my %basic_fields, 'Tie::IxHash' ); foreach my $raw_param ( keys %$raw_basic_fields ) { next if $raw_param =~ /^__/; # Plus: +Field means show field only if extended-fields is enabled # Minus: -Field means always show, regardless of extended-fields status # Other: Field means show only if filled ( my $param = $raw_param ) =~ s/^([\-\+])//; my $lead = $1 || ''; my $show = $lead eq '-' ? 'always_show' : $lead eq '+' ? 'show_if_extended' : 'show_if_filled'; $field_status{$param} = $show; $basic_fields{$param} = $raw_basic_fields->{$raw_param}; } $self->{field_status} = \%field_status; $self->{basic_fields} = \%basic_fields; return $self; } =head2 output my $markup = $source->output( %args ); Returns the filled template output. This is where the magic is. =cut sub output { my( $self, %args ) = @_; $self->fill(%args) unless $self->{basic_fields}; my $ref_name = $self->get_ref_name; my $add_ref_tag = $args{add_ref_tag}; my $vertical = $args{vertical}; my $format = $args{format} ? $args{format} : 'text'; my $add_param_space = $args{add_param_space}; my $show_extended = $args{extended}; tie( my %all_fields, 'Tie::IxHash' ); %all_fields = ( %{ $self->{basic_fields} }, %{ $self->template_output_fields(%args) } ); tie( my %params, 'Tie::IxHash' ); foreach my $param ( keys %all_fields ) { next if $param =~ /^__/; $params{$param} = { value => $all_fields{$param}, show => $self->{field_status}->{$param} }; } my @pairs = ( ); while( my( $param, $info ) = each %params ) { $info->{show} ||= ''; next if $info->{show} eq 'show_if_filled' and !defined($info->{value}); next if $info->{show} eq 'show_if_extended' and !$show_extended; my $pair = sprintf ( ($add_param_space ? "%s = %s" : "%s=%s"), $param, $info->{value} || ''); push @pairs, $pair; } my $citation; $citation = "{{".$self->template_name; $citation .= $vertical ? "\n" : ' '; foreach my $pair ( @pairs ) { $citation .= ' ' unless $vertical; $citation .= !$vertical && $citation =~ s/\s*$// ? ' ' : ''; $citation .= $add_param_space ? "| $pair" : "|$pair"; $citation .= "\n" if $vertical; } $citation .= "}}"; if( $add_ref_tag ) { $citation = $ref_name ? sprintf( '%s', $ref_name, $citation ) : sprintf( '%s', $citation ); } if( $format eq 'xml' ) { my $output = ''; my $writer = new XML::Writer( OUTPUT => \$output ); $writer->startTag( 'wikitemplate', application => 'cite' ); $writer->startTag( 'content' ); $writer->characters( $citation ); $writer->endTag(); $writer->startTag('paramlist'); while( my( $param, $info ) = each %params ) { $writer->startTag( 'param', name => $param ); $writer->characters($info->{value}); $writer->endTag(); } $writer->endTag(); $writer->endTag; $writer->end; $writer->close; return $output; } $citation = encode_entities( $citation ) if $args{encode_entities}; return $citation; } =head2 template_basic_fields Used in subclasses. Static class method that returns an ordered hash of fields to be populated only during the call to C. =cut sub template_basic_fields { croak "no 'template_basic_fields' provided by this source" } =head2 template_output_fields Used in subclasses. Static class method that returns an ordered hash of fields to be populated only during the call to C. =cut sub template_output_fields { {} } =head2 get_ref_name my $id = $source->get_ref_name; Returns the ID to be used in the CrefE> tag. Wraps around the C method to provide wiki escaping. =cut sub get_ref_name { my $self = shift; my $ref_name = $self->template_ref_name; # Arcadian asks that quotation marks are removed from ref_name # so that MediaWiki renders the ref properly $ref_name =~ s/[\"\']//g; return $ref_name; } =head2 template_ref_name Returns the ID to be used in the CrefE> tag. You should be using C instead, probably. =cut sub template_ref_name { my $pkg = shift; croak ref($pkg).' does not define a template_ref_name() method' } =head2 type my $type = $source->type; Returns the type of source this is. =cut sub type { my $self = shift; ( my $type = ref $self || $self ) =~ s/.*::(.*)//; return lc $type; } sub __today_and_now { my @ymd = map { $_ < 10 ? "0$_" : $_ } Date::Calc::Today(); return sprintf '%s-%s-%s', @ymd; } =head1 AUTHOR David J. Iberri, C<< >> =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 SUPPORT You can find documentation for this module with the perldoc command. perldoc WWW::Wikipedia::TemplateFiller::Source You can also look for information at: =over 4 =item * AnnoCPAN: Annotated CPAN documentation L =item * CPAN Ratings L =item * RT: CPAN's request tracker L =item * Search CPAN L =back =head1 ACKNOWLEDGEMENTS =head1 COPYRIGHT & LICENSE Copyright (c) David J. Iberri, all rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1;