Perthon

Va ką šiandien užtikau:

Posted today on PerlMonks was an interesting tool. Eventually, I
hope you Python monkeys will come to your senses and turn to Perl
for sanity. To ease such transition, see the Perthon project:


/http://perthon.sourceforge.net

Now, your Python code can be reborn as the Perl it always should
have been.

Komentarų turbūt nereikia ;-) Šiaip įdomus projektukas (bet kaip
ir dauguma kalbų vertėjų turbūt nelabai pritaikomas praktikoje)

Perlo objektai: antra dalis

Pagalvojimai apie ateitį: geresni konstruktoriai

Nors šiuo metu dar gal ir nežinote kas yra paveldimumas, bet kažkada
ateityje matyt teks su tuo susidurti. Tam, kad

paveldimumas veiktų kaip turėtų, reikia naudoti bless() su
dviem argumentais. Antruoju argumentu yra

perduodama klasė, į kurią bus „palaiminama“.

Tuo pačiu padarysime konstruktorių lankstesnį, kad būtų jį galima
iškviesti tiek kaip klasės, tiek kaip ir objekto

metodą. T.y. kad būtų galima rašyti:

$as = Asmuo->naujas();
$ji = $as->naujas();

Viskas ką mums reikia padaryti, tai patikrinti ar į konstruktorių
buvo perduota nuoroda (reference) ar ne.

Funkcija buvo iškviesta kaip objekto metodas jeigu buvo
perduota nuoroda – tokiu atveju reikia

sužinoti kas tai per klasė naudojantis funkcija ref(). Jei
perduota ne nuoroda, o paprasčiausias klasės

pavadinimas, tai juo ir naudojamės (tokiu atveju funkcija iškviesta kaip
klasės metodas).

    sub naujas {
        my $perduota = shift;
        my $klase = ref($perduota) || $perduota;
        my $mano  = {};
        $mano->{VARDAS}   = undef;
        $mano->{AMZIUS}   = undef;
        $mano->{KOLEGOS}  = [];
        bless ($mano, $klase);
        return $mano;
    } 

Štai ir viskas ką reikia žinoti apie konstruktorius. Jie suteikia
objektams gyvenimą grąžindami nuorodas į supakuotus

nepermatomus daiktus vadinamus objektais. Po to šiuos objektus galima
naudoti iškviečiant jų metodus.

Destruktoriai

viskas kas turi pradžią, turi ir pabaigą. Objekto pradžia yra
konstruktoriaus metodas, o pabaiga –

destruktorius. Destruktorius yra metodas, kuris automatiškai
iškviečiamas tada kai objektas nustoja egzistuoti.

Destruktoriai Perle turi būti pavadinti funkcijos vardu
DESTROY ir naudojami atlikti švarinimo darbus

(uždaryti atidarytas bylas, soketus, ir panašiai)

Kodėl konstruktoriai gali vadintis kaip nori, o detruktoriai ne? Tai
yra būtina todėl, kad konstruktorius iškviečia

pats programuotojas, o destruktoriai yra iškviečiami automatiškai paties
interpretatoriaus (pe rgarbage

collection mechanizmą). Todėl reikia destruktorių vadinti vardu
DESTROY tam kad Perlas žinotų ką

iškviesti. Perlas neduoda garantijų kad DESTROY bus
iškviestas tuoj po objekto sunaikinimo – jis

iškviečiamas kada patogiau pačiam Perlui, todėl destruktoriuje į tai
reikia atsižvelgti.

Kodėl DESTROY rašomas visomis didžiosiomis raidėmis?
Perlas turi tradiciją vadinti visas funkcijas,

kurios bus iškviečiamos pačio interpretatoriaus, o ne programuotojo
vadinti didžiosiomis raidėmis. Panašiai yra su

BEGIN, END, AUTOLOAD bei visais
metodais priklausančiais tie

mechanizmui (žr. perltie dokumentaciją)

Objektinėse kalbose dažniausiai visai nereikia sukti galvos kada bus
iškviestas destruktorius. Jis iškviečiamas tada

kada reikia. Žemo lygio programavimo kalbose, kuriose nėra automatinio
atminties valdymo niekaip neįmanoma padaryti taip,

kad destruktorius būtų iškviestas automatiškai jį sunaikinus – tam
programuotojas pats turi iškviesti desktruktorių

ir atlaisvinti atmintį ir kitus resursus. Perle, ne taip kaip C++,
objektų destruktoriai retai reikalingi, o jei jie ir

reikalingi tai jie iškviečiami automatiškai. Mūsų klasėje
Asmuo mums nereikia destruktoriaus, nes Perlas

pats pasirūpina tokiais paprastais dalykais kaip atminties
atlaisvinimas.

Vienintelė situacija, kai Perlo magija gali nesuveikti gali būti
tokia, kai naudojama duomanų struktūra, rodanti į

pati save:

$sitas-gt;{BETKAS} = $sitas;

Tokiu atveju reikia ištrinti tokią nuorodą į save pačiam, jei
nenorite kad programa naudotų vis daugiau atminties

(memory leak). Tiesa, kai programa baigia darbą, visa atmintis
grąžinama, tad kažkada ji bus

atlaisvinta, išskyrus atvejus kai ji niekada nebaigia darbo.

Perlo objektų pradžiamokslis: pirmoji dalis

Objekto vaizdavimas

Dažniausiai Perle Paskalio įrašas arba C struktūra, arba C+ klasė yra
saugoma anoniminio asociatyvaus masyvo (hešo) pavidalu. Taip
saugoti yra patogu, nes heše galima saugoti neribotą kiekį
elementų, kuriuos galima pasiekti per unikalų hešo raktą.

Jeigu tik norite kažko panašaus į C struktūrą, tai galima daryti
taip:

$irasas = {
    vardas   => "Petras",
    amzius   => 21,
    kolegos  => [ "Juozas", "Nikolajus", "Vaidas"],
};

Jeigu norite lengviau perskaitomo kodo, galite hešo raktus
rašyti didžiosiomis raidėmis:

$irasas = {
    VARDAS   => "Petras",
    AMZIUS   => 21,
    KOLEGOS  => [ "Juozas", "Nikolajus", "Vaidas"],
};

Norėdami prieiti prie vardo „Petras“ galite rašyti
$irasas->{VARDAS}, o norėdami gauti kolegų masyvą galite
rašyti @{ $irasas->{KOLEGOS} }.

Labai panaši idėja yra naudojama ir objektams, tik nereikėtų prieiti
prie objekto sudėtinių dalių prieiti tiesiogiai – tam dažniausiai
yra naudojamos specialiai tam parašytos funkcijos. Galima sakyti kad
objektas turėtų būti tiesiog daiktas, prie kurio duomenų reiktų prieiti
tik per specialias jo funkcijas.

Klasės sąsaja

Tarkim, kad turim klasę Asmuo. Štai kaip būtų galima ja
naudotis:

    use Asmuo;

    $jo = Asmuo->naujas();
    $jo->vardas("Petras");
    $jo->amzius(21);
    $jo->kolegos( "Juozas", "Nikolajus", "Vaidas" );

    push @Visi_asmenys, $jo;  # išsaugom objektą vėlesniam naudojimui

    printf "%s turi %d metus.\n", $jo->vardas, $jo->amzius;
    print "Jo kolegos yra: ", join(", ", $jo->kolegos), "\n";

    printf "Paskutinis asmuo yra %s\n", $Visi_asmenys[-1]->vardas; 

Kaip matote, klasės Asmuo vartotojas nežino (ir neturi
žinoti) kaip yra saugomi duomenys klasėje Asmuo. Visus
duomenis vartotojas pasiekia tik per metodus (t.y. funkcijas, kurios
priklauso klasei)

Konstruktoriai ir objekto metodai

Tačiau kažkas turi žinoti, kaip duomenys saugomi klasėje, ir
tas kažkas yra pati klasė. Klasė aprašo metodus, kuriais
naudojanti galima prieiti prie prie objekto duomenų. Štai kaip galima
aprašyti klasę Asmuo naudojantis standartiniu duomenų
saugojimo hešo nuorodoje būdu. Aprašysime klasės metoda
naujas(), kuris bus objekto konstruktorius, bei tris
objekto metodus vardas(), amzius() ir
kolegos() per kuriuos bus galima prieiti prie objekte
saugomų duomenų.

    package Asmuo;
    use strict;

    ####################################################
    ## objekto konstruktorius (supaprastinta versija) ##
    ####################################################
    sub naujas {
        my $mano  = {};
        $mano->{VARDAS}   = undef;
        $mano->{AMZIUS}    = undef;
        $mano->{KOLEGOS}  = [];
        bless($mano);           # bet zr. zemiau
        return $mano;
    }

    ##############################################
    ## metodai objektu duomenis pasiekti        ##
    ##                                          ##
    ## Metodai nustato reikšmę, jei perduodamas ##
    ## argumentas, ir tik grąžina reikšmę jei   ##
    ## argumentai neperduodami                  ##
    ##############################################

    sub vardas {
        my $mano = shift;
        if (@_) { $mano->{VARDAS} = shift }
        return $mano->{VARDAS};
    }

    sub amzius {
        my $mano = shift;
        if (@_) { $mano->{AMZIUS} = shift }
        return $mano->{AMZIUS};
    }

    sub kolegos {
        my $mano = shift;
        if (@_) { @{ $mano->{KOLEGOS} } = @_ }
        return @{ $mano->{KOLEGOS} };
    }

    1;  # Tam kad 'use' arba 'require' nesikeiktų

Sukūrėme tris metodus, per kuriuos galima prieiti prie objekto duomenų:
vardas(), amzius() ir kolegos().
Jie labai panašūs. Jei nustato reikšmę jeigu iškviečiami su argumentu,
ir grąžina reikšmę jeigu iškviečiami be argumentų.

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į

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).

Kas svarbiausia šablonų varikliams

Nuskaičiau šiandien PHP forume įdomią diskusiją apie tai kas svarbiausia PHP šablonų varikliuose (ačiū scooox už nuorodą). Labiausiai prieštaringų minčių man sukėlė citata O jei template nera svarbiausia greitis... tai kas tada svarbu? Navarotai? Jei taip – tada tu grybas. Tiesą sakant „navarotai“ yra labai svarbu. Ir turbūt svarbiausia (na, jei greitis nėra visiškai šliaužiantis). Gyvename tokiais laikais kai kompiuterio laikas yra pigus, o programuotojų laikas kainuoja brangiai, tad aš geriau rinkčiausi lėtesnę šablonų sistemą (na, ne tris kart lėtesnę, bet tarkim iki 50% lėtesnę) jei su ja man būtų žymiai lengviau programuoti. Šablonų kodas vis tiek neužima labai daug laiko, tad geriausiu atveju bus sutaupoma keletas dešimčių tūkstantųjų sekundės kiekvienai užklausai. Sakoma, kad lašas po lašo ir akmenį pratašo, o centą pridėjus prie cento susidaro milijonai, bet abejoju ar šie palyginimai čia tinka. Na, jei svetainė gauna po 10 užklausų per sekundę, gal tada ir bus pastebėtas šioks toks skirtumas kokį šablonų variklį naudosime, bet kiek yra svetainių, kur užklausos ateina po 10 per sekundę? Juk tai beveik milijonas užklausų per dieną (heh, aš esu laimingas kai gaunu kokį tūkstantį ;)

Tad manau, jog šablonų „benchmarkinimas“ yra per daug sureikšminamas. IMHO aišku ;)

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ų.

Apache::DBI

Hmm.. aišku bėdos su MySQL nesibaigia. to $dbh ||= triuko nepakako, teko skripto gale nutraukinėt ryšį su MySQL naudojant $dbh->disconnect; — tai veikia gerai, bet niekas nebekešuojama.

Ir čia į pagalbą atėjo Apache::DBI. Pasirodo užtenka jį užkrauti httpd.conf failiuke ir magiškai visos jungtys su MySQL tampa ‘persistant‘. Smagu ;)