Perlinio modulio pavyzdys

Vakar IRC buvau paklaustas, kaip yra daromi objektiniai Perlo moduliai. Parašiau ir paprastą moduliuką, kuris parodo kaip veikia visas Perlo objektiškumas. Štai modulis Modulis.pm:

package Modulis;
use strict;
use warnings;

sub naujas {
    bless {};
}

sub vardas {
    my $self = shift;
    $_[0]     ? $self->{'vardas'} = $_[0]
        : $self->{'vardas'};
}
1;

Modulis prasideda paketo apibrėžimu (package Modulis;) bei aprašo dvi funkcijas (tiksliau vieną funkciją ir vieną metodą). Funkcija naujas sukuria ir grąžina naują objektą Modulis. Tam paprasčiausiai užtenka palaiminti su bless nuorodą į tuščią asociatyvų masyvą (hešą). Metodas vardas gali būti kartu naudojamas tiek reikšmės nustatymui, tiek gavimui. Jei jį iškviesime be jokių parametrų, jis grąžins objekto kintamojo ‘vardas’ (kuris tėra tik įrašas asociatyviajame masyve) reikšmę. Jei šį metodą iškviesime su argumentu, jis priskirs šio argumento reikšmę objekto kintamajam ‘vardas’ (būtent
tai ir atlieka antra metodo eilutė su trinariu ?: operatoriumi – pasižiūri ar perduotas argumentas, ir jeigu taip, tai pakeičia ‘vardas’ reikšmę) Metodas nuo paprastos funkcijos skiriasi tik tuo, kad jam pirmu argumentu yra perduodamas pats objektas. Todėl pirmoji metodo eilutė yra my $self = shift; – ja mes kintamajam $self priskiriam „savo paties objekto“ reikšmę. Toliau $self veikia panašiai kaip $this PHP kalboje.

O štai paprastas pavyzdys kaip naudotis šiuo objektiniu moduliu:

#!/usr/bin/perl -wl
use strict;
use Modulis;

my $a = naujas Modulis; # sukuriam objektą

$a->vardas('Petras'); # užsetinam per metodą
print $a->vardas;     # gettinam per metodą

$a->{'vardas'} = "Vytas"; # užsetinam per kintamąjį
print $a->{'vardas'};     # gettinam per kintamąjį

Acme::Apache::Werewolf

Acme::Apache::Werewolf yra naujas ir labai naudingas Perlo modulis, kuris leidžia apsaugoti Apache serverio direktorijas nuo vilkolakių. io modulio pagalba galima uždrausti priėjimą prie Apache direktorijų mėnulio pilnaties metu, tereikia į httpd.conf įrašyti:

<Directory /fullmoon>    PerlAccessHandler Acme::Apache::Werewolf

    PerlSetVar MoonLength 4

</Directory>

Tris kart valio CPAN, nes dabar mano Apachei nebaisūs jokie vilkolakiai.

Perl 5.6.2

Šeštadienį buvo išleista 5.6.2 Perlo versija. Perlo 5.6.x šaka nėra mirusi, ji vis dar palaikoma. Pagrindinis šios versijos tikslas buvo galimybė sukompiliuoti Perlą su naujais įrankiais (kaip kad gcc 3.3) ir operacinėmis sistemomis, kurios atsirado jau po Perl 5.6.1 išleidimo (AIX 5 ir Mac OS X). Tuo pačiu buvo atnaujinti ir kai kurie moduliai. Parsisiųsti 5.6.2 galima iš čia.

Moblogas

Vakar naktį pasidariau moblogą. Tai turbūt vienas iš tų projektų kur dariau nes galiu padaryt, o ne todėl kad reikia. Faktiškai Perlo kodo rašymas visada malonus, net jei ir nepildysiu to moblogo ateityje – iš manęs fotografas tai kaip iš mano bobulės perlininkė.

Visam šitam daiktui tiesiog persikopijavau savo svetainės kodą į kitą direktoriją, šiek tiek pataisiau šablonus (bet ne iki galo, nes vakar jau labai norėjosi miego), sukūriau porą SQL lentelių, pataisiau kodą, kad dirbtų su tomis naujomis lentelėmis ir parašiau el. pašto apdorojimo programėlę. Pakeitimų ne tiek daug kaip atrodo ;)

Štai kodas, kuris apdoroja gautą el. paštą, surašo kur reikia attachmentu atėjusias JPG bylas ir įterpia reikiamus duomenų bazės įrašus:

#!/usr/bin/perl -w

use strict;use MIME::Parser;

use FileHandle;

use File::Path;

use DBI;

$|++; # Autoflush on

# Prisijungiam prie MySQL

my $dbh = DBI->connect("DBI:mysql:database=moxliukas;dbhost=localhost",

        'moxliukas', 'passwordas');

# katalogų keliai - laikinas ir output

my $tmp_dir = '/home/moxliukas/tmp';

my $output_dir = '/home/moxliukas/public_html/moblog/images';

my $parser = MIME::Parser->new;

$parser->output_dir($tmp_dir);

# Skaitom viską iš STDIN

my $entry = $parser->parse(*STDIN);

# Kiekvienai MIME daliai...

for my $part ($entry->parts) {

       # Žiūrim koks duomenų tipas

        my $mime = $part->mime_type;

        if($mime =~ /jpeg/) {  # jei tai JPG...

             # sukuriam bylos pavadinimą pagal unix timestamp

                my $url = time() . '.jpg';

                my $fh = FileHandle->new($output_dir . '/' . $url, 'w');

                binmode($fh);

                my $ifh = $part->open('r');

             # perkopijuojam bylas kur reikia

                $fh->print($ifh->getlines);

                $_->close for($fh, $ifh);

             # įterpiam į duombazę

                my $sql = "INSERT INTO moblogs SET kada=NOW(), url='$url'";

                $dbh->do($sql);

        } else {

          # Jei tai ne JPG, praleidžiam šią dalį

                next;

        }

}

$dbh->disconnect;

Įdomūs lingvistiniai pastebėjimai

Pastarosiomis dienomis internete sklando šis tekstas:

Aoccdrnig to a rscheearch at an Elingsh uinervtisy, it deosn’t mttaer in waht oredr the ltteers in a wrod are, the olny iprmoetnt tihng is taht frist and lsat ltteer is at the rghit pclae. The rset can be a toatl mses and you can sitll raed it wouthit a porbelm. Tihs is bcuseae we do not raed ervey lteter by it slef but the wrod as a wlohe.

Komentarų kaip ir nereikia ;-) Tiesa, lietuvių kalboje suprasti sudarkytus žodžius yra žymiai sunkiau (nes turim mes galūnes, be to mūsų žodžiai ilgesni). Štai parašiai perlinį skriptuką kuris išdarko žodžius:

#!/usr/bin/perl -w
use strict;

while (<>) {
        s/([^[:punct:][:space:][:digit:]]+)/keichiam($1)/ge;
        print;
}

sub keichiam {
        my @w = split //, $_[0];
        my $p = shift @w;
        my $l = pop @w;
        my %h;
        $h{$_} = rand for @w;
        @w = sort { $h{$a} <=> $h{$b} } @w;
        $p .= $_ for @w;
        $p.$l;
}

PHP fanams internete yra ir PHP versija (pradinis kodas).

HTML::Mason ir Perl.lt

Jau keletą kartų esu minėjęs Perlo modulį HTML::Mason, kurio dėka galima rašyti web skriptus PHP stiliumi. HTML::Mason geriausiai veikia ant mod_perl, bet tik ant pirmos Apache versijos. Nežinau ar tai gerai, bet stengiuosi po truputį pereiti prie Apache2, o ten pasirodo HTML::Mason dar nėra palaikomas per mod_perl. Bet visgi sprendimas yra – naudotis CGI sąsaja.

Beje, Oreilly knyga apie HTML::Mason kabo nemokamai internete adresu masonbook.com. Tai šiandieną turbūt paskirsiu jos skaitymui (nors ir gimtadienis mano ;). Persiskaitęs šią knygą turėsiu geresnį supratimą apie tai kaip ten viskas veikia, o tada jau bus galima planuotis perl.lt griaučius. Na bent jau mano tokie planai.

Perlo „range“ operatorius

EnC manęs PHP forume paprašė paaiškint, kaip veikia Perlo „range“ operatorius. Nesinori PHP forumą teršti perliniais
dalykais, tad bandysiu tai paaiškinti čia. Beje, visa tai ką čia rašau galima rasti Perlo dokumentacijoje (konsolėje tereikia surinkt perldoc perlop).

Perlo „range“ operatorius žymimas dviem taškais, ir reiškia faktiškai du dalykus. Pirmoji reikšmė yra labai paprasta –
parašius 1..10 gausime reikšmių nuo 1 iki 10 sąrašą (list). Būtent ši operatoriaus reikšmė naudojama masyvų kontekste
(list context – kai reikia jog išraiška grąžintų masyvą, o ne skaliarą). Šitaip labai lengvai galima formuoti masyvus:

my @masyvas = 1..10;
# tas pats kaip @masyvas = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Tačiau pats populiariausias šio dalyko panaudojimo būdas yra cikluose, nes vietoj sunkiai įskaitomo

for($i = 1; $i <= 10; $i++) {
# ... kažką darom 10 kartų
}

galima parašyti trumpai ir aiškiai:

for(1..10) {
# ... kažką darom 10 kartų
}

Kitas dažnas šio operatoriaus panaudojimas tame pačiame kontekste yra masyvų dalijimas (slice):

my @foo = (1, 2, 3, 4, 5, 6);
my @bar = @foo[3..5];
# @bar dabar yra (4, 5, 6);
my @baz = @foo[3..$#foo];
# @bar dabar irgi yra (4, 5, 6);

„Range“ operatoriui galima perduot ne vien skaitmenis, bet ir simbolių eilutes (pagal tam tikrą algoritmą bus didinami simbolių eilutės ASCII kodai), tad šis Perlo sakinys atspausdins visą anglišką abėcėlę:

print for 'a'..'z';

Arba tiesiog:

print 'a'..'z';

Vienas geriausių šio operatoriaus pliusų yra tas, kad jis neužsigrobia daug atminties yra intervalo „neišplečia“ atmintyje jei to būtinai nereikia, tad for(1..1000000) {...} nesukuria laikinojo masyvo su milijonu įrašų.

Jei intervalų sudarymas iš simbolių eilučių atrodo ganėtinai magiškai, tai patys didžiausi stebuklai prasideda tada, kai
„range“ operatorius naudojamas skaliariniame kontekste (kai išraiška turi grąžinti skaliarą, o ne masyvą). Dažniausiai taip šis operatorius naudojamas if sąlygoje. Šis operatorius grąžina 0 (false) iki tol kol kairė šio operatoriaus pusė pradeda
grąžint true, tada grąžina true iki tol kol dešinė pusė pradeda grąžint true. Lengviausia turbūt suprast pavyzdžiu:

while(<>) {
print if /PRADZIA/../PABAIGA/;
}

Šis kodas skaito iš bylos eilutes, ir spausdina tik tas, kurios yra tarp eilučių, atitinkančių įpraiškas /PRADZIA/ ir
/PABAIGA/. Tarkime jei byla bus:

foo
bar
PRADZIA
kazkas
dar
PABAIGA
nu
gi

bus atspausdinama tik kazkas ir dar (nespausdina kol neatitinka įpraiškos /PRADZIA/, o tada spausdina iki tol kol atitinka įpraišką /PABAIGA/) Magija čia nesibaigia. Jei vietoj įpraiškos įrašysim skaičių, jis bus magiškai lyginamas su $., kuris reiškia eilutės numerį. Tad kodas

print if 101..200;

atspausdins antrąjį šimtą eilučių.

Trumpas tipas apie Perlinį PHP mysql_fetch_assoc() atitikmenį

Vienam žmogui iš PerlMonks kilo panaši problemą kaip ir man, darant šią svetainę – jis, uždavęs MySQL užklausą SELECT * FROM users WHERE id=100 norėjo naudotis rezultatais pateiktais hešais (t.y. $user{username}, $user{email} ir panašiai). PHP tai būtų padaroma su mysql_fetch_assoc() funkcija. Perle pasirodo tai nėra nei kiek sudėtingiau (net šiek tiek gėda pačiam pasidarė, kad pats nesugalvojau) – my %user = %{ $sth->fetchrow_hashref } padaro tai ko reikia.

Visiems gi pasitaiko tokių proto nušvitimo akimirkų ;)