Any-Renderer

 view release on metacpan or  search on metacpan

lib/Any/Renderer.pm  view on Meta::CPAN

	my @possible_locations = grep { -d $_ } map { File::Spec->catdir ( $_, split ( /::/, __PACKAGE__ ) ) } @INC;

	my %found;
	my $collector = sub
	{
		return unless $_ =~ /\.pm$/;

		my $file = $File::Find::name;
		$file =~ s/\Q$File::Find::topdir\E//;
		$file =~ s/\.pm$//;

		my @dirs = File::Spec->splitdir ( $file );
		shift @dirs;
		$file = join ( "::", @dirs );

		$found{ $file }=1;
	};

	File::Find::find ( $collector, @possible_locations );

	#Ensure that modules adapting other multi-format modules have lower precedence 
	#than native Any::Renderer backends in the event of both offering the same format
	my @backends = ();
	foreach (@LowPriProviders) {
		push @backends, $_ if delete $found{$_}; #ensure these are at the front of the list
	}
	push @backends, keys %found; #Higher precendence modules go later in the list

	%Formats = (); #Clear and rebuild
	foreach my $file ( @backends )
	{
		# load the module and discover which formats it presents us with,
		# including whether the formats need a template
		TRACE ( "Testing $file" );
		
		my ($module, $func);
		eval {
			$module = _load_module($file);     
			$func = $module->can( "available_formats" );
		};
		warn($@) if($@); #Warn if there are compilation problems with backend modules
		
		next unless $func;
		
		my $formats_offered = &$func;

		DUMP ( "${module}::available_formats", $formats_offered );

		foreach ( @$formats_offered )
		{
			$Formats { $_ } = $file;
		}
	}

	return [ sort keys %Formats ];
}

#Loads an Any::Renderer backend (safely)
sub _load_module {
	my $file = shift; 
	die ("Backend module name $file looks dodgy - will not load") unless($file =~ /^[\w:]+$/); #Protect against code injection

	my $module = "Any::Renderer::" . $file;  
	unless($INC{"Any/Renderer/$file.pm"}) {
		TRACE ( "Loading renderer backend '" . $module . "'" );
		eval "require " . $module;
		die ("Any::Renderer - problem loading backend module: ". $@ ) if ( $@ );
	}
	return $module;
}

sub TRACE {}
sub DUMP {}

1;

=head1 NAME

Any::Renderer - Common API for modules that convert data structures into strings

=head1 SYNOPSIS

	$renderer = new Any::Renderer ( $format, \%options );
	$string = $renderer->render ( $structure );
	$bool = Any::Renderer::requires_template ( $format );
	$list_ref = Any::Renderer::available_formats ();

=head1 DESCRIPTION

A renderer in this context is something that turns a data structure into a
string.  This includes templating engines, serialisers etc.

This module provides a consistent API to these services so that your
application can generate output in an extensible variety of formats.
Formats currently supported include:

	- XML (via XML::Simple)
	- XML+XSLT
	- Data::Dumper
	- Javascript, Javascript::Anon & JSON
	- UrlEncoded
	- The formats supported by Data::Serializer (e.g. Config::General and Config::Wrest)
	- Any templating language supported by Any::Template

The module will discover any backend modules and offer up their formats.
Once loaded, Any::Renderer will look for a module to handle any new formats it doesn't know about, so adding new formats in a persistent environment won't require the module to be reloaded.
However if you CHANGE which module provides a format you will need to reload Any::Renderer (e.g. send a SIGHUP to modperl).

=head1 METHODS

=over 4

=item $r = new Any::Renderer($format,\%options)

Create a new instance of an Any::Render object using a rendering format of
$format and the options listed in the hash %options (see individual rendering
module documentation for details of which options various modules accept).

=item $string = $r->render($data_structure)

Render the data structure $data_structure with the Any::Renderer object $r.



( run in 2.529 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )