Skip to content

Instantly share code, notes, and snippets.

@reneeb
Last active December 27, 2015 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reneeb/7336866 to your computer and use it in GitHub Desktop.
Save reneeb/7336866 to your computer and use it in GitHub Desktop.
=head2 File::HashCache
Bei Webanwendungen gibt es immer wieder das Problem, dass an JavaScript- oder CSS-Dateien etwas
angepasst wurde, diese Änderungen aber nicht sofort beim Benutzer ankommen, weil der
Browser die Datei cached. Hier hilft es, nach der Änderung den Namen der Datei anzupassen.
Um nicht hunderte Vorkommen der Einbindung des Skripts anzupassen - wobei man dabei garantiert
das eine oder andere Vorkommen vergisst -, kann man das Generieren der Datei automatisieren.
Hier hilft C<File::HashCache>. Auf Basis des Dateiinhalts wird der Dateiname erweitert und
in einem "Cache"-Verzeichnis gespeichert.
use File::HashCache;
my $hc = File::HashCache->new(
cache_dir => '/var/www/js/cache',
);
my $hashed_path = $hc->hash(
'/var/www/js/test.js'
);
Der Aufruf der C<hash>-Methode muss in jedem Request stattfinden, denn dann überprüft das Modul
ob sich die Datei geändert hat und generiert gegebenenfalls eine neue Datei.
Die Integration in Template::Toolkit könnte so aussehen:
$template->process('template.tt2', {
script => sub {
my $path = $hc->hash($_[0]);
"<script src=\"js/$path\" type=\"text/javascript\"></script>\n";
} } ) || die $template->error();
# And in your template.tt2 file:
# [% script("myscript.js") %]
# which will get replaced with something like:
# <script src="js/myscript-708b88f899939c4adedc271d9ab9ee66.js"
# type="text/javascript"></script>
Das Modul bietet aber noch mehr Möglichkeiten. Man kann das Modul auch so verwenden, dass
beim Erzeugen der gecachten Dateien das JavaScript bzw. das CSS komprimiert wird:
use JavaScript::Minifier::XS qw(minify);
my $hc = File::HashCache->new(
cache_dir => 'js',
process_js => \&minify,
process_css =>
\&CSS::Minifier::XS::minify,
);
=head2 Git::Repository::Log
I<git> ist ein verteiltes Versionskontrollsystem (I<VCS>), das auch bei der Perl-Kernentwicklung verwendet wird. Der Vorteil gegenüber älteren - zentralen - Systemen wie I<svn> oder I<CVS> ist, dass man auch unterwegs Änderungen I<committen> kann, egal ob man eine Internetverbindung hat oder nicht. Sobald man wieder online ist, kann man die gesammelten Änderungen an Remote-Repositories I<pushen>.
Auch wenn bei I<git> jede Kopie des Repositories als "Hauptrepository" dienen kann, wird es bei den meisten Projekten ein zentrales Repository geben, in dem alle Änderungen gesammelt werden.
In manchen Fällen muss man aus einem Perl-Programm heraus mit einem Git-Repository arbeiten - z.B. das Anlegen neuer Repositories, Logs abfragen etc. Entweder man nutzt direkt die git-Befehle und greift sich die Daten mittels C<qx//> oder ähnlichen ab, oder man nimmt ein Modul. Eines der Module ist C<Git::Repository>.
# neues git repo erzeugen
Git::Repository->run(
init => $dir,
);
$r = Git::Repository->new(
work_tree => $dir,
);
# mit bestehendem git repo arbeiten
$repo = Git::Repository->new(
work_tree => '/local/git-repo/',
);
# mit bestehendem git repo arbeiten
$repo = Git::Repository->new(
git_dir => '/local/git-repo/.git',
);
chdir $git_dir;
my $add_output = Git::Repository->run(
add => $file,
);
my $commit_output = Git::Repository->run(
commit =>
'-m' => $file,
'--author' => $author,
$file
);
C<$dir> ist ein beliebiger Pfad. C<Git::Repository> selbst ist so ausgelegt, dass es theoretisch auf allen Plattformen funktioniert. Aber das Modul benutzt zum Absetzen der git-Befehle das Modul C<System::Command> und das hat Probleme mit Windows. Philippe Bruhat, der Autor beider Module, ist für Hilfe dankbar.
Man hat auch die Möglichkeit, C<run> als Objekt-Methode und nicht als Klassenmethode aufzurufen. Dann ist das C<chdir> in das Verzeichnis des Repositories nicht notwendig:
my $r = Git::Repository->new(
work_tree => $git_dir,
);
my $add_output = $r->run(
add => $file,
);
Wenn man C<run> als Klassenmethode aufruft und sie I<nicht> im Verzeichnis des Repositories aufruft, bekommt man die Fehlermeldung I<fatal: Not a git repository (or any of the parent directories)>
Diejenigen, die sich mit I<git> auskennen, sehen, dass C<Git::Repository> die C<git>-Befehle 1:1 benötigt.
my $commit_output = Git::Repository->run(
commit =>
'-m' => 'fixed annoying bug',
'-a',
);
entspricht dem git-Befehl C<git commit -m 'fixed annoying bug' -a>. Das Modul ist also nicht wirklich eine Abstraktion. Warum also das Modul nutzen? Zum einen bietet es die Möglichkeit, Plugins zu schreiben. Zum anderen existiert die Methode C<command>. Diese wird so benutzt wie die C<run>-Methode, allerdings liefert es nicht einfach den Ausgabestring von C<git> zurück, sondern ein Command-Objekt. Das holt nicht die komplette Ausgabe auf einmal. Das ist vorteilhaft wenn man Befehle nutzen möchte, die große Ausgaben produzieren (z.B. C<git log>) und somit viel Speicher benötigen würden.
my $cmd = $r->command(
log => '--pretty=oneline',
'--all',
);
my $log = $cmd->stdout;
while (<$log>) {
...;
}
$cmd->close;
Und hier kommt dann auch das Modul zum Tragen, das hier eigentlich vorgestellt werden soll: C<Git::Repository::Log>. Das ist ein solches Plugin, das man für C<Git::Repository> schreiben kann. Das Modul bietet einen Iterator und erstellt aus den einzelnen Log-Meldungen Objekte, so dass man bequem auf die Informationen der Log-Meldung zugreifen kann.
# load the Log plugin
use Git::Repository 'Log';
# get the log for last commit
my ($log) = Git::Repository->log( '-1' );
# get the author's email
print my $email = $log->author_email;
Möchte man einen Stream von Logmeldungen haben und auswerten, sollte mit dem Iterator gearbeitet werden:
use Git::Repository::Log::Iterator;
# use a default Git::Repository context
my $iter = Git::Repository::Log::Iterator->new('HEAD~10..');
# or provide an existing instance
my $iter = Git::Repository::Log::Iterator->new( $r, 'HEAD~10..' );
# get the next log record
while ( my $log = $iter->next ) {
print $log->author_email,"\n";
}
=head2 Data::Section
Manchmal ist es sehr praktisch, feste Textteile in den C<__DATA__>-Bereich zu schreiben. Gerade wenn es kleine
Textteile sind lohnt es sich nicht, diese in Dateien oder gar eine Datenbank zu schreiben. Nur oft genug hat man
das Problem, dass man gerne mehrere Textteile in den Bereich schreiben möchte. Hier hilft dann
C<Data::Section>.
package MyConfig;
use Data::Section -setup;
# get_config('prod');
# get_config('dev');
sub get_config {
my ($class, $type) = @_;
my $data = $self->section_data( $type || 'dev' );
my %config = map{ split /\s*=\s*/ }split /\n/, $data;
return %config;
}
__DATA__
__[ dev ]__
host = localhost
db = test
__[ prod ]__
host = test.de
db = prod
=head2 App::MojoSlides
Perl-Konferenzen. Perl-Themen. Warum dann nicht eine Präsentationssoftware, die in Perl geschrieben ist.
Joel Berger nutzt bei C<App::MojoSlides> - wie der Name schon ahnen lässt - Mojolicious. Aus Mojolicious-Templates
werden die Folien generiert, wobei für die Templates eigene Hilfsfunktionen existieren, um das Verhalten
an LaTeX-Beamer anzunähern.
Für Syntaxhighlighting wird C<PPI> genutzt und für das Basislayout wird Bootstrap eingesetzt (wobei man
das natürlich anpassen kann).
Das Konfigurationsfile (hier: I<test_slides.pl>) muss zu einem Hash evaluieren. Die Slides kann man als Templates
direkt in den C<__DATA__>-Bereich packen. In der Konfiguration muss man dann noch angeben, welche Slides es
gibt. Mit C<mojo_slides test_slides.pl daemon> kann man dann die Anwendung starten und im Browser ist
die Präsentation unter I<http://localhost:3000> erreichbar.
use Mojo::Base -strict;
my $config = {
slides => [qw/start seite2/],
bootstrap_theme => 1,
};
__DATA__
@@ start.html.ep
% title '$foo - Test';
%= column 6 => begin
%= overlay "1-" => begin
Test 1
% end
%= overlay "2-" => begin
Erst beim zweiten Klick sichtbar
% end
% end
%= column 6 => begin
%= overlay 1 => begin
Spalte 2
% end
% end
@@ seite2.html.ep
% title 'Seite2';
%= p 'test'
=head2 Regexp::VerbalExpressions
Wer schon immer lesbare Reguläre Ausdrück haben wollte, kann sich mal C<Regexp::VerbalExpressions>
anschauen. Dort sind für die Elemente von Regulären Ausdrücken entsprechende Methoden vorhanden.
Das ist Modul ist ganz nett um Einsteigern Regexe näherzubringen und zu zeigen wie man Regexe aufbauen
kann. Ein Ersatz für die puristischen Reguläre Ausdrücke ist es aber nicht, da auch nicht alle Features der
Regex-Engine umgesetzt wurden.
use Regexp::VerbalExpressions;
# Regex for URLs
my $re = verex
->start_of_line
->then('http')
->maybe('s')
->then('://')
->maybe('www.')
->anything_but(' ')
->end_of_line;
if ('https://www.google.com/' =~ $re) {
print 'We have a correct URL';
}
# ^(?:http)(?:s)?(?:\:\/\/)(?:www\.)?(?:[^\ ]*)$
print $re;
=head2 Pod::Markdown
Markdown ist aktuell die Markup-Sprache schlechthin. Viele Wikis und Github "verstehen" Markdown und
auch sonstige Programme (z.B. pandoc), die das Format verarbeiten können, gibt es genug. Liegt die Dokumentation
für ein Modul in I<Pod> vor und wird die Dokumentation in Markdown benötigt, dann hilft C<Pod::Markdown>.
Dieses Modul ist von C<Pod::Parser> abgeleitet, kennt also die gleichen Methoden und Einstellungen. Die wichtigste
Methode ist C<as_markdown>.
#!/usr/bin/perl
use strict;
use warnings;
use Pod::Markdown;
my $parser = Pod::Markdown->new;
$parser->parse_from_file( $0 );
print $parser->as_markdown;
=head1 $foo - Perl--Magazin
=head2 CPAN-News
In den CPAN-News werden neue Module
vorgestellt.
=cut
__END__
$ perl pod_markdown.pl
# $foo - Perl--Magazin
## CPAN-News
In den CPAN-News werden neue Module vorgestellt.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment