CGI-Application-Plugin-ViewCode
view release on metacpan or search on metacpan
lib/CGI/Application/Plugin/ViewCode.pm view on Meta::CPAN
The name of the module to view. By default it is the module currently being run. Also,
since colons (':') aren't simply typed into URL's, you can just substitute '-' for '::'.
?rm=view_code?module=My-Base-Class
=item highlight
Boolean indicates whether syntax highlighting (using L<Syntax::Highlight::Perl::Improved>)
is C<on> or C<off>. By default it is C<on>.
=item line_no
Boolean indicates whether the viewing of line numbers is C<on> or C<off>. By default it is C<on>.
It C<line_no> is on, you can also specify which line number you want to see by adding an anchor
to the link:
?rm=view_code#215
This will take you immediately to line 215 of the current application module.
=item pod
Boolean indicates whether POD is seen or not. By default it is seen>.
=back
=head2 view_pod
This extra run mode will accept the following arguments in the query string:
=over
=item module
The name of the module to view. By default it is the module currently being run. Also,
since colons (':') aren't simply typed into URL's, you can just substitute '-' for '::'.
?rm=view_pod?module=My-Base-Class
=back
=head1 AS A POPUP WINDOW
This plugin can be used in conjunction with L<CGI::Application::Plugin::DevPopup>. If we detect
that L<CGI::Application::Plugin::DevPopup> is running and turned on, we will create a sub-report
that includes the highlighted source code.
So you can simply do the following:
BEGIN { $ENV{CAP_DEVPOPUP_EXEC} = 1; } # turn it on for real
use CGI::Application::Plugin::DevPopup;
use CGI::Application::Plugin::ViewCode;
Befault, this report will be the same thing produced by C<view_code>. If you want this
report to include the C<view_pod> report, simply set the the C<$ENV{CAP_VIEWCODE_POPUP_POD}>
to true. You can also turn off the C<view_code> report but setting
C<$ENV{CAP_VIEWCODE_POPUP_CODE}> to false.
# have the POD report, but not the code in the dev popup window
BEGIN {
$ENV{CAP_DEVPOPUP_EXEC} = 1; # turn it on for real
$ENV{CAP_VIEWCODE_POPUP_POD} = 1; # turn on POD report
$ENV{CAP_VIEWCODE_POPUP_CODE} = 0; # turn off code report
}
use CGI::Application::Plugin::DevPopup;
use CGI::Application::Plugin::ViewCode;
=cut
sub import {
my $caller = scalar(caller);
$caller->add_callback( init => \&_add_runmode );
# if we are running under CGI::Application::Plugin::DevPopup
if( $ENV{CAP_DEVPOPUP_EXEC} ) {
# if we wan't to add the POD report
if( exists $ENV{CAP_VIEWCODE_POPUP_POD} && $ENV{CAP_VIEWCODE_POPUP_POD} ) {
$caller->add_callback( devpopup_report => \&_view_pod );
}
# include the view_code report by default unless it's turned off
if(! (exists $ENV{CAP_VIEWCODE_POPUP_CODE} && !$ENV{CAP_VIEWCODE_POPUP_CODE}) ) {
$caller->add_callback( devpopup_report => \&_view_code );
}
}
}
sub _add_runmode {
my $self = shift;
$self->run_modes(
view_code => \&_view_code,
view_pod => \&_view_pod
);
}
sub _view_code {
my $self = shift;
my $query = $self->query;
my %options;
foreach my $opt qw(highlight line_no pod) {
if( defined $query->param($opt) ) {
$options{$opt} = $query->param($opt);
} else {
$options{$opt} = 1;
}
}
# get the file to be viewed
my $module = _module_name($query->param('module') || ref($self));
# change into file name
my $file = _module_file_name($module);
# make sure the file exists
if( $file && -e $file ) {
my $IN;
open($IN, $file)
or return _error("Could not open $file for reading! $!");
my @lines= <$IN>;
# if we aren't going to highlight then turn all colors/styles
# into simple black
my %styles = %DEFAULT_STYLES;
my $style_sec = '';
foreach my $style (keys %styles) {
$styles{$style} = 'color:#000000;'
if( !$options{highlight} );
$style_sec .= ".$style { $styles{$style} }\n";
}
# now use Syntax::Highlight::Perl::Improved to do the work
require Syntax::Highlight::Perl::Improved;
my $formatter = Syntax::Highlight::Perl::Improved->new();
$formatter->define_substitution(%SUBSTITUTIONS);
foreach my $style (keys %styles) {
$formatter->set_format($style, [qq(<span class="$style">), qq(</span>)]);
}
@lines = $formatter->format_string(@lines);
# if we want line numbers
if( $options{line_no} ) {
my $i = 1;
@lines = map {
(qq(<span class="LineNumber"><a name="$i">) . $i++ . qq(:</a></span> ). $_)
} @lines;
}
# apply any other transformations necessary
if( $options{highlight} || !$options{pod} ) {
foreach my $line (@lines) {
# if they don't want the pod
if( !$options{pod} ) {
if( $line =~ /<span class="Comment_POD"/ ) {
$line = '';
next;
}
}
# if they are highlighting
if( $options{highlight} ) {
if( $line =~ /<span class="Package">([^<]*)<\/span>/ ) {
my $package = $1;
my $link = $package;
$link =~ s/::/-/g;
my $rm = $self->mode_param();
$rm = ref $rm ? 'rm' : $rm; # not really anything we can do if their mode_param returns a sub ref
$link = "?$rm=view_code&module=$package;view_code_no_popup=1";
$line =~ s/<span class="Package">[^<]*<\/span>/<a class="Package" href="$link">$package<\/a>/;
}
}
}
}
my $code = join('', @lines);
# if we are under CGI::Application::Plugin::DevPopup then let's create this as a report instead
if( $ENV{CAP_DEVPOPUP_EXEC} && !$query->param('view_code_no_popup') ) {
$self->devpopup->add_report(
title => 'View Code',
summary => "View code of $module",
report => "<style>$style_sec</style><pre>$code</pre>",
);
} else {
return qq(
<html>
<head>
<title>$module - View Source</title>
<style>$style_sec</style>
</head>
<body>
<pre>$code</pre>
</body>
</html>
);
}
} else {
return _error( ($file ? "File $file " : "Module $module ") . "does not exist!");
}
}
sub _view_pod {
my $self = shift;
my $query = $self->query;
# get the file to be viewed
my $module = _module_name($query->param('module') || ref($self));
# change into file name
my $file = _module_file_name($module);
# make sure the file exists
if( $file && -e $file ) {
require Pod::Xhtml;
my $pod_parser = new Pod::Xhtml(
StringMode => 1,
MakeIndex => 0,
FragmentOnly => 1,
TopLinks => 0,
MakeMeta => 0,
);
$pod_parser->parse_from_file($file);
my $pod = $pod_parser->asString;
# if we are under CGI::Application::Plugin::DevPopup then let's create this as a report instead
if( $ENV{CAP_DEVPOPUP_EXEC} && !$query->param('view_code_no_popup') ) {
$self->devpopup->add_report(
title => 'View POD',
summary => "View POD of $module",
report => "<pre>$pod</pre>",
);
} else {
return qq(
<html>
<head>
<title>$module - View POD</title>
</head>
<body>
<pre>$pod</pre>
</body>
</html>
);
}
} else {
return _error( ($file ? "File $file " : "Module $module ") . "does not exist!");
}
}
sub _module_name {
my $name = shift;
$name =~ s/-/::/g;
return $name;
}
sub _module_file_name {
my $module = shift;
# change into file name
$module =~ s/::/\//g;
$module .= '.pm';
return $INC{$module};
}
sub _error {
my $message = shift;
return qq(
<html>
<head>
<title>View Source Error!</title>
</head>
<body>
<h1 style="color: red">Error!</h1>
<strong>Sorry, but there was an error in your
request to view the source:
<blockquote><em>$message</em></blockquote>
</body>
</html>
);
}
1;
__END__
=head1 SECURITY
( run in 2.570 seconds using v1.01-cache-2.11-cpan-364913b4093 )