Last active
December 27, 2015 13:59
-
-
Save reneeb/7336866 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
=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