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į

ActivePerl build 807

Pasirodė populiaros Perlo distribucijos Windows platformai ActivePerl
versija. Ši versija yra kurta 5.8.1 Perlo versijos pagrindu ir turi
nemažai atnaujintų modulių. Patys didžiausi atnaujinti moduliai yra
XML::Parser ir Archive::Tar. Visi ActivePerl
vartotojai turbūt turėtų atsinaujinti Perlo versijas į šią naują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.

Num2LTWord Perlu

Kai kam prireikė funkcijos, kuri
verstų skaičius į lietuvių kalbą. Tad parašiau Perlinį moduliuką –
gal bus dar kam nors naudingas. (Parsiųsti kaip normalų modulį galima iš
čia)

#!/usr/bin/perl -w
package Num2LTWord;

=head1 Num2LTWord -- skaičiai lietuviškai

Modulis verčiantis (sveikus) skaičius į lietuvių kalbą

=head2 NAUDOJIMAS

    use Num2LTWord;
    num2ltword(2003);

=head2 FUNKCIJOS

=head3 num2ltword ( skaičius )

Ši funkcija grąžina suformuotą lietuvišką skaičiaus pavadinimą.

=head2 RIKTAI IR APRIBOJIMAI

Funkcija C<num2ltword> supranta tik sveikus skaičius intervale
(- 1 000 000 000; 1 000 000 000)

=head2 AUTORIUS

Petras Kudaras aka moxliukas (moxliukas@delfi.lt)

=cut

use strict;
use warnings;
use Exporter;
our @ISA = qw/Exporter/;
our @EXPORT = qw/num2ltword/;
our $VERSION = 0.02;

sub num2ltword {
    my $ka = shift;
    my $result = '';

    return "Nežinau kaip čia paverst" unless $ka eq int($ka);
    return "nulis" if $ka == 0;
    my $kam = abs $ka;
    $result .= "minus " if $ka < 0;
    if($kam >= 1_000_000_000) {
        return "Per didelis man čia skaičius";
    } else {
        $result .= __iki1e9($kam);
        $result =~ s/\s+$//;
        $result =~ s/\s+/ /g;
        return $result;
    }
}

sub __iki10 {
    my $ka = shift;
    my @skaitmenys =     ("", "vienas", "du",
                 "trys", "keturi", "penki",
                 "šeši", "septyni", "aštuoni",
                 "devyni", "dešimt");
    return $skaitmenys[$ka];
}

sub __iki20 {
    my $ka = shift;
    my @lika =     ("vienuolika", "dvylika", "trylika",
             "keturiolika", "penkiolika", "šešiolika",
             "septyniolika", "aštuoniolika", "devyniolika");
    if ($ka <= 10) {
        return __iki10($ka);
    } else {
        return $lika[$ka % 10 - 1];
    }
}

sub __iki100 {
    my $ka = shift;
    my @desimt = ("", "", "dvi", "tris", "keturias", "penkias",
            "šešias", "septynias", "aštuonias", "devynias");
    if ($ka < 20) {
        return __iki20($ka);
    } else {
        if($ka % 10 == 0) {
            return $desimt[int($ka/10)] . "dešimt";
        } else {
            return $desimt[int($ka/10)] . "dešimt " . __iki10($ka % 10);
        }
    }
}

sub __iki1000 {
    my $ka = shift;
    return __iki100($ka) if ($ka < 100);
    if(int($ka / 100) == 1) {
        return __iki10(int($ka/100)) . " šimtas " . __iki100($ka % 100);
    } else {
        return __iki10(int($ka/100)) . " šimtai " . __iki100($ka % 100);
    }
}

sub __iki1e6 {
    my $ka = shift;
    return __iki1000($ka) if ($ka < 1000);
    my $t = __iki1000(int($ka/1000));
    if ($t =~ /vienas$/) {
        return "$t tūkstantis " . __iki1000($ka % 1000);
    } elsif ($t =~ /(?:lika|šimtai|imt)\s*$/) {
        return "$t tūkstančių " . __iki1000($ka % 1000);
    } else {
                return "$t tūkstančiai " . __iki1000($ka % 1000);
    }
}

sub __iki1e9 {
    my $ka = shift;
        return __iki1e6($ka) if ($ka < 1_000_000);
        my $t = __iki1e6(int($ka/1_000_000));
        if ($t =~ /vienas$/) {
                return "$t milijonas " . __iki1e6($ka % 1_000_000);
        } elsif ($t =~ /(?:šimtai|lika|imt)\s*$/) {
                return "$t milijonų " . __iki1e6($ka % 1_000_000);
        } else {
                return "$t milijonai " . __iki1e6($ka % 1_000_000);
        }
}                                                   
1;

IE įdomybės ir bluejackinimas

Labai įdomus dalykas, kurį šiandien aptikau benaršydamas internetą
buvo Internet Explorerio featuras, kurio pagalba galima
išsikviesti Notepad. Tereikia parašyti kažką panašaus į:

<img 
src="view-source:file:///C:/WINNT/system32/shell32.dll">

Ir jei jūsų Windows sėdi kataloge C:WINNT, greit pajausite kaip
Notepad pradeda prakaituoti stengdamasis parodyti bylą
shell32.dll. O juk galima įdėti ir kelias tokia nuorodas ir
staiga swape gali atsirasti kokia pora gigabaitų duomenų. Įdomu
dar ir tai, kad tokių dalykų nepagauna jokios Popup blokavimo
programos. Tiesiog tai vienas iš Internet Explorer featurų. :-) (Plačiau
http://computerbytesman.com/security/notepadpopups.htm)

Šiandien pietaudamas nubluejackinau antrą žmogų. Vėlgi Nokijos
turėtojas, tačiau šį kartą ne jaunutė mergina, o gana pagyvenęs
kostiumuotas verslininkas. Labai buvo įdomi jo reakcija: viską jis
priėmė labai natūraliai (na, aš jam tik pasiunčiau „you have been
bluejacked“) ir ramiai. Parodė savo partneriui savo telefoną ir
pasakė „tos reklamos visur jau lenda“. Matyt žmogus nulipęs
nuo Internet Explorerio su šokinėjančiais langais.

Testai perl-dev

Pridėjau šiandien į perl-dev CVS kodo testus. Šiaip atrodo Lietuvoje niekas lyg ir
nedaro web aplikacijų kartu su testais (test based programming), nors
Perlmonksuose teko girdėti apie tai nemažai. Esmė yra tame, kad pakeitus
kažkokį failą automatiškai prasitestuojama ar viskas veikia kaip ir
turėtų, ar tie pakeitimai nesugriovė kokio nors kodo kuris seniau jau
veikė. Šiek tiek gal ir su eXtreme Programming susiję (ten pradžioj
parašomas testas kuris neveikia, o paskui stengiamasi padaryt kad jis
veiktų). Na, žiūrėsim kaip čia bus ir ar bus iš to naudos. Pagrindinis
šių testų tikslas (bent jau man atrodytų) būtų automatiškas patikrinimas
ar visa svetainė validuojasi su W3C validatoriais (tam parašiau labai
paprastą funkciją, kurią galima rasti perl-dev/src/lib/W3Validate.pm)

Visi testai sėdi direktorijoje src/t/* – pirmasis
tik patikrina ar yra visos bylos savo vietose ir ar jas įmanoma
nuskaityti (o jei jos baigiasi .pl arba .t
– ar galima jas vykdyti), kitas patestuoja dhandler, o
trečias – autohandler (tiksliau index.html).
Testus galima paleisti arba iš src/t/ direktorijos po
vieną, arba visus iš karto skriptu ./runtests.pl (arba per
Makefilemake test)

Visus šiuos pakeitimus galima atsisiųsti per CVS arba čia
(tiesa, kol kas extractina į ‘.’ o ne į ‘perl-dev’ — jei bus
skundų tai pakeisiu

Perlinis alarm()

Turėjau šiokių problemų su perlific, mat jeigu jis kurį
laiką nevykdydavo jokios MySQL užklausos, MySQL uždarydavo ryšį su perlu
ir duomenų bazė tapdavo nebepasiekiama. Norint išlaikyti atvirą jungtį
su MySQL reikia kas kažkiek laiko papinginti duombazę
iškviečiant $dbh->ping();. Tai galima padaryti keleta
būdu (juk čia Perlas): fork()‘int ir atskirame procese
daryti while(1) { sleep(60); $dbh->ping(); }, galima
naudotis gijomis (jei Perlas kompiliuotas su jomis) – use
threads;
, galima apsirašyti funkciją on_ping (nes juk
tai IRC botas). Padariau dar kitaip. Štai tas kodas:

$SIG{ALRM} = \&on_alarm;
alarm(60);
sub on_alarm {
        $dbh->ping;
        $SIG{ALRM} = \&on_alarm;
        alarm(60);
}

Šis kodo gabaliukas aprašo funkciją, kuri turi būti iškviečiama kai
gaunamas sisteminis signalas SIGALARM. Paskui su alarm(60)
nurodoma operacinei sistemai kad ji praneštų kai praeis 60 sekundžių.
Pačioje funkcijoje reikia iš naujo nurodyti SIGALARM funkciją ir laiko
tarpą. Gaunasi poor man’s multithreading.