plik


ÿþIDZ DO IDZ DO PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ 100 sposobów na Perl SPIS TRESCI SPIS TRESCI Autorzy: Damian Conway, Curtis  Ovid Poe T³umaczenie: S³awomir Dzieniszewski KATALOG KSI¥¯EK KATALOG KSI¥¯EK ISBN: 83-246-0634-3 Tytu³ orygina³u: Perl Hacks: Tips & Tools KATALOG ONLINE KATALOG ONLINE for Programming, Debugging, and Surviving Format: B5, stron: 320 ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG TWÓJ KOSZYK TWÓJ KOSZYK Zbiór skutecznych rozwi¹zañ dla programistów aplikacji internetowych DODAJ DO KOSZYKA DODAJ DO KOSZYKA " Zwiêkszanie produktywnoSci pracy " Tworzenie interfejsów u¿ytkownika " Wyszukiwanie i usuwanie b³êdów CENNIK I INFORMACJE CENNIK I INFORMACJE Perl, od swojego zaistnienia na rynku, wyewoluowa³ od prostego narzêdzia do przetwarzania tekstów i budowania raportów do formy zaawansowanego jêzyka ZAMÓW INFORMACJE ZAMÓW INFORMACJE programowania pozwalaj¹cego na tworzenie praktycznie ka¿dej aplikacji dzia³aj¹cej O NOWOSCIACH O NOWOSCIACH w sieci. Mimo doSæ zaawansowanego  wieku , nie traci nic na popularnoSci. W sieci pojawiaj¹ siê coraz nowsze wersje, a grono programistów korzystaj¹cych z Perla ZAMÓW CENNIK ZAMÓW CENNIK stale roSnie. Spo³ecznoSæ u¿ytkowników tego jêzyka skupiona wokó³ portalu CPAN udostêpnia napisane przez siebie skrypty, wskutek czego z wieloma problemami programistycznymi mo¿na sobie poradziæ, korzystaj¹c z gotowych rozwi¹zañ lub CZYTELNIA siêgaj¹c do innych xróde³. CZYTELNIA Dziêki ksi¹¿ce  100 sposobów na Perl odkryjesz ma³o znane i mniej typowe FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE zastosowania tego jêzyka. Czytaj¹c j¹, dowiesz siê, w jaki sposób wykorzystaæ Perl do ró¿nych zadañ. Nauczysz siê zwiêkszaæ efektywnoSæ swojej pracy, tworzyæ elementy interaktywne i przetwarzaæ pliki tekstowe w nietypowy sposób. Zapoznasz siê z odczytywaniem danych z baz i arkuszy kalkulacyjnych, prac¹ z modu³ami oraz programowaniem obiektowym. Znajdziesz tu tak¿e informacje o testowaniu kodu, usuwaniu b³êdów i optymalizowaniu wydajnoSci programów napisanych w Perlu. " Korzystanie z biblioteki CPAN " Automatyczne formatowanie kodu w edytorze Emacs " Generowanie elementów graficznych " Przetwarzanie arkuszy kalkulacyjnych " Praca z bazami danych Wydawnictwo Helion " Tworzenie zestawu narzêdziowego modu³ów ul. KoSciuszki 1c " Korzystanie z obiektów 44-100 Gliwice " Testowanie kodu tel. 032 230 98 63 " Sledzenie wykonywania programu e-mail: helion@helion.pl O autorach ..................................................................................................................................... 7 Przedmowa ................................................................................................................................... 13 RozdziaB 1. Sposoby zwikszajce produktywno[ .................................................................. 19 1. Dodawanie skrótów biblioteki CPAN do przegldarki Firefox .............................. 19 2. Zaprzganie do pracy narzdzia Perldoc .................................................................... 22 3. Przegldanie dokumentacji Perla w internecie .......................................................... 25 4. Zastpowanie poleceD powBoki aliasami ..................................................................... 27 5. AutouzupeBnianie identyfikatorów Perla w edytorze Vim ...................................... 30 6. Dobieranie najlepszego dla Perla trybu edytora Emacs ........................................... 33 7. Wymuszanie lokalnego stylu ........................................................................................ 35 8. Unikanie zachowywania zBego kodu Perla ................................................................. 38 9. Automatyzowanie przegldów kodu .......................................................................... 42 10. Uruchamianie testów z edytora Vim ........................................................................... 44 11. Uruchamianie kodu Perla spod edytora Emacs ......................................................... 46 RozdziaB 2. Interakcja z u|ytkownikiem ...................................................................................... 49 12. Wykorzystywanie edytora ze zmiennej $EDITOR jako interfejsu u|ytkownika .... 49 13. PrawidBowa wspóBpraca w wierszu poleceD .............................................................. 51 14. Upraszczanie interakcji z terminalem .......................................................................... 53 15. Ostrzeganie naszego Maca ............................................................................................. 58 16. Interaktywne aplikacje graficzne .................................................................................. 61 17. Zbieranie informacji na temat konfiguracji programu .............................................. 66 18. Przepisywanie na nowo stron WWW .......................................................................... 69 RozdziaB 3. ObsBuga danych ........................................................................................................ 73 19. Traktowanie pliku jak tablicy ........................................................................................ 73 20. Odczytywanie plików wstecz ........................................................................................ 75 21. Wykorzystywanie jako zródBa danych dowolnego arkusza kalkulacyjnego ........ 76 22. Porzdkowanie kodu wspóBpracujcego z baz danych .......................................... 81 23. Budowanie biblioteki kodu SQL ................................................................................... 84 24. Dynamiczne przepytywanie baz danych bez pomocy kodu SQL ............................... 86 Spis tre[ci | 3 25. Wizanie kolumn bazy danych ..................................................................................... 87 26. Wykorzystywanie iteracji i technik generowania kosztownych danych ............... 89 27. Pobieranie z iteratora wicej ni| jednej warto[ci ....................................................... 91 RozdziaB 4. Praca z moduBami ..................................................................................................... 95 28. Skracanie dBugich nazw klas ......................................................................................... 95 29. Zarzdzanie [cie|kami do moduBów ........................................................................... 96 30. Ponowne Badowanie zmodyfikowanych moduBów ................................................... 99 31. Przygotowywanie osobistych zestawów moduBów ................................................ 100 32. Zarzdzanie instalowaniem moduBów ...................................................................... 103 33. Zachowywanie [cie|ek do moduBów ......................................................................... 105 34. Tworzenie standardowego zestawu narzdziowego moduBów ............................ 107 35. Pisanie przykBadowych kodów do przewodników dla u|ytkowników .............. 110 36. Zastpowanie wadliwego kodu pochodzcego z zewntrz ................................... 112 37. Wznie[ toast za CPAN .................................................................................................. 114 38. Poprawianie warunków uruchamiajcych wyjtki ................................................. 115 39. Lokalne odszukiwanie moduBów CPAN ................................................................... 118 40. PrzeksztaBcanie samodzielnych aplikacji Perla w pakiety ...................................... 122 41. Tworzenie wBasnych leksykalnych komunikatów ostrzegawczych ..................... 126 42. Odszukiwanie i raportowanie bBdów w moduBach ............................................... 127 RozdziaB 5. Sposoby na obiekty ................................................................................................ 133 43. Tworzenie zamknitych obiektów .............................................................................. 133 44. Darmowe (prawie) serializowanie obiektów ............................................................ 136 45. Umieszczanie dodatkowych informacji w atrybutach ............................................ 138 46. Upewnianie si, |e metody s prywatne dla obiektów .......................................... 140 47. Autodeklarowanie argumentów metod .................................................................... 144 48. Kontrola dostpu do zdalnych obiektów .................................................................. 147 49. Przygotowywanie naprawd polimorficznych obiektów ....................................... 150 50. Automatyczne generowanie metod dostpu ............................................................ 152 RozdziaB 6. Wykrywanie i usuwanie bBdów .............................................................................. 157 51. Szybkie wyszukiwanie bBdów kompilacji ............................................................... 157 52. Uwidacznianie niewidocznych warto[ci ................................................................... 159 53. Wyszukiwanie bBdów za pomoc testów ................................................................ 161 54. Wykrywanie bBdów za pomoc komentarzy .......................................................... 163 55. Wy[wietlanie kodu zródBowego zwizanego z bBdem ......................................... 167 56. Analiza funkcji anonimowych ..................................................................................... 170 57. Nadawanie nazw procedurom anonimowym .......................................................... 172 58. Wyszukiwanie zródBa pochodzenia procedury ........................................................ 174 59. Dopasowywanie debugera do naszych potrzeb ...................................................... 175 4 | Spis tre[ci RozdziaB 7. Triki dla twórców programów ................................................................................ 179 60. Przebudowywanie dystrybucji kodu ......................................................................... 179 61. Testowanie z u|yciem specyfikacji ............................................................................. 181 62. Oddzielanie testów programisty od testów u|ytkownika ..................................... 185 63. Automatyczne uruchamianie testów ......................................................................... 188 64. Ogldanie informacji o niepowodzeniach  w kolorze! ........................................ 189 65. Testy na |ywym kodzie ................................................................................................ 192 66. Poprawianie rekordów szybko[ci ............................................................................... 195 67. Budowanie wBasnej wersji Perla .................................................................................. 196 68. Uruchamianie zestawów testów z trwaBym Badowaniem potrzebnego kodu .... 199 69. Symulowanie w testach nieprzyjaznego [rodowiska .............................................. 204 RozdziaB 8. Poznaj swój kod ...................................................................................................... 209 70. Kolejno[ wykonywania kodu .................................................................................... 209 71. Badanie naszych struktur danych ............................................................................... 213 72. Bezpieczne wyszukiwanie funkcji .............................................................................. 215 73. Sprawdzanie, jakie moduBy tworz rdzeD Perla ...................................................... 218 74. Zledzenie wszystkich wykorzystywanych moduBów .............................................. 219 75. Wyszukiwanie wszystkich symboli u|ywanych w pakiecie ................................. 223 76. Zagldanie za zamknite drzwi .................................................................................. 225 77. Wyszukiwanie wszystkich zmiennych globalnych ................................................. 228 78. Dokonywanie introspekcji procedur .......................................................................... 231 79. Odnajdywanie importowanych funkcji ..................................................................... 234 80. Profilowanie rozmiaru programu ............................................................................... 236 81. Ponowne wykorzystywanie procesów Perla ............................................................ 239 82. Zledzenie operatorów ................................................................................................... 241 83. Pisanie wBasnych ostrze|eD ......................................................................................... 243 RozdziaB 9. Poszerz swoje zrozumienie Perla .......................................................................... 247 84. Podwajanie danych za pomoc funkcji dualvar() .................................................... 247 85. Zastpowanie mikkich odwoBaD prawdziwymi odwoBaniami ............................ 249 86. Optymalizowanie kBopotliwych elementów ............................................................. 252 87. Blokowanie tablic asocjacyjnych ................................................................................. 253 88. Sprztanie po sobie przy wychodzeniu z zakresu ................................................... 255 89. Dziwne sposoby wywoBywania funkcji ..................................................................... 257 90. U|ycie funkcji glob w cigach ..................................................................................... 263 91. Jak zaoszczdzi sobie pracy przy kodzie sprawdzajcym bBdy ........................ 266 92. Przygotowywanie lepszych warto[ci zwracanych przez procedury .................... 268 93. Zwracanie warto[ci aktywnych .................................................................................. 272 94. Tworzenie wBasnej skBadni Perla ................................................................................ 275 Spis tre[ci | 5 95. Modyfikowanie semantyki kodu za pomoc filtrów kodu zródBowego ............. 277 96. Korzystanie ze wspólnych bibliotek bez pomocy kodu XS ................................... 281 97. Uruchamianie dwóch usBug na pojedynczym porcie TCP ..................................... 283 98. Poprawianie naszych tablic dyspozycji ..................................................................... 287 99. Zledzenie przybli|eD w obliczeniach ......................................................................... 290 100. Przeci|anie operatorów .............................................................................................. 293 101. Po|ytki z zabaw z kodem ............................................................................................ 298 Skorowidz ................................................................................................................................. 301 6 | Spis tre[ci SPOSÓB Tworzenie zamknitych obiektów 43. R O Z D Z I A A P I  T Y Sposoby 43.  50. Jak Batwo zgadn, Perl te| posiada obiekty. Oprócz dziwacznej na pierwszy rzut oka funkcji bless oraz odpowiedniego przekwalifikowania procedur, pakietów i odwoBaD obiektowy jzyk Perl oferuje programi[cie wiele nowych opcji i rozszerza znacznie mo|- liwo[ci jzyka. Cz[ z Czytelników zapewne korzysta z funkcji bless, by tworzy (potocznie  bBogosBawi ) obiekty tylko dlatego, |e potrzebuj rekordów obiektów. Warto jednak zastanowi si nad korzy[ciami, które mo|e przynie[ lepsza enkapsulacja (obu- dowywanie) danych, automatyczna serializacja danych czy wymuszanie kontroli dostpu do danych. Im wicej programista wie na temat Perla, tym wicej bdzie miaB dostpnych opcji, umo|- liwiajcych tworzenie i korzystanie z wy|szych poziomów abstrakcji. Nastpnym razem, gdy jego wspóBpracownicy natrafi znowu na zBo|ony problem, którego nie potrafi roz- wiza, bdzie mógB zajrze do swej magicznej sakwy z trikami obiektowymi i u[mie- chajc si, uspokoi ich:  Bez obaw, za pomoc Perla mo|na rozwiza ka|dy problem . SPOSÓB Tworzenie zamknitych obiektów 43. Zadbaj o dobre obudowanie atrybutów obiektu W Perlu 5 obsBuga obiektów sprowadzona jest do minimum. Perl daje programi[cie wy- starczajce narzdzia, by umo|liwi programowanie obiektowe, nie chroni go jednak przed robieniem z obiektami rzeczy nieodpowiedzialnych. Oczywi[cie, domy[lne podej[cie do programowania obiektowego jest z reguBy najprostsze (oraz najmniej odpowiedzialne), cho niestety nie najporzdniejsze ani te| nieuBatwiajce pózniejszej obsBugi kodu. W wikszo[ci przypadków obiektami bd po prostu bBogosBawione (tj. przemienione w obiekty za pomoc funkcji bless) tablice asocjacyjne, poniewa| pocztkujcym pro- gramistom najBatwiej zrozumie ich dziaBanie i najBatwiej te| z nich skorzysta. Niestety, czasem trudno znalez w nich ewentualne bBdy i tak naprawd nie oferuj |adnego obudowania (enkapsulacji) dla danych. Dlatego te| warto sign po specjalne, czysto obiektowe rozwizania1. 1 Wicej na ten temat mo|na znalez w artykule  Seven Sins of Perl OO Programing ( Siedem grzechów gBównych programowania obiektowego w Perlu ), w przegldzie The Perl Review 2.1, zima 2005. Sposoby na obiekty | 133 SPOSÓB Tworzenie zamknitych obiektów 43. Na szcz[cie mo|na to Batwo naprawi. Sposób Obiekt przygotowany w Perlu potrzebuje dwóch rzeczy: miejsca, w którym bdzie prze- chowywa dane instancji, oraz klasy, w której mo|na bdzie znalez jego metody. BBogo- sBawiona tablica asocjacyjna (lub tablica, skalar, procedura, typeglob, etc.) przechowuje swoje dane wewntrz obiektu, który bdziemy przesyBa. Je[li dokonamy dereferencji odwoBania, to niestety bdzie mo|na odczytywa dane obiektu z dowolnego miejsca, nawet spoza klasy. PrawidBowo przygotowany, zamknity (ang. inside out) obiekt powinien przechowywa dane w innym miejscu, najcz[ciej w zmiennej leksykalnej, której zakres odpowiada zakre- sowi klasy. W przypadku u|ycia zmiennych leksykalnych nie bdzie mo|na (tzn. zazwy- czaj nie bdzie mo|na  patrz  Zagldanie za zamknite drzwi [SposOb 76.]) siga do danych bez u|ycia specjalnych metod dostpu obiektu. Pierwsza ksi|ka Damiana Conwaya, Object Oriented Perl (wydawnictwo Manning, 2000), pokazywaBa ró|ne sposoby przygotowywania obudowywania danych. Jego ostatnia ksi|ka, Perl. Najlepsze rozwizania (wydawnictwo Helion 2006), zaleca stosowanie si do nich wszystkim programistom, którym zale|y na jako[ci kodu. Jedna z do[wiadczonych weteranek Perla, Abigail, badaBa mo|liwo[ci wBa[ciwie zbudowanych obiektów przez kilka lat. Wiele z jej spostrze|eD i porad mo|na znalez w dokumentacji moduBu Class::Std. Uruchamianie sposobu Prosta i niezbyt wyszukana implementacja obiektu, przeznaczona dla klasy rekordu prze- chowujcego dane, mo|e wyglda tak: # tworzymy nowy zakres dla zmiennych leksykalnych { package InsideOut::User; use Scalar::Util 'refaddr'; # zmienne leksykalne sBu|ce do przechowywania danych instancji my %names; my %addresses; sub new { my ($class, $data) = @_; # bBogosBawimy nowy skalar, by zdoby jego identyfikator obiektu bless \(my $self), $class; # zachowujemy dane instancji my $id = refaddr( $self ); $names{ $id } = $data->{name}; $addresses{ $id } = $data->{address}; return $self; 134 | Sposoby na obiekty SPOSÓB Tworzenie zamknitych obiektów 43. } # metody dostpu takie jak $self->{name}, czy $self->{address} nie dziaBaj sub get_name { my $self = shift; return $names{ refaddr( $self ) }; } sub get_address { my $self = shift; return $addresses{ refaddr( $self ) }; } # wielu ludzi zapomina o tej cz[ci sub DESTROY { my $self = shift; my $id = refaddr( $self ); delete $names{ $id }; delete $addresses{ $id }; } } 1; Jak wida, zdefiniowanie zamknitego obiektu wymaga troch wicej pisania, niemniej kod jest teraz znacznie czystszy. Teraz mo|emy podklasowa lub zaimplementowa na nowo klas InsideOut::User bez konieczno[ci korzystania z bBogosBawionej tablicy asocjacyjnej  wystarczy dostosowa si do interfejsu definiowanego przez t klas i kod powinien zadziaBa. Eksplorowanie sposobu W sieci CPAN dostpne s trzy moduBy Class:Std, Class::InsideOut i Object: :InsideOut, które uBatwiaj programistom pisanie prawidBowych, zamknitych obiektów. Ka|dy z nich oferuje ró|ne triki i u|yteczne mo|liwo[ci. W module Class::Std miBe jest to, |e automatycznie tworzy metody umo|liwiajce dostp do danych obiektu (ang. accessors  metody dostpu) i modyfikowanie (ang. mutators  metody modyfikujce) tych danych. Ponadto przywoBuje lepsze konstruktory i destruktory obiektu oraz  umo|liwia definiowanie dodatkowych informacji w atrybutach zmiennych i procedur [SposOb 45]. Korzystajc z moduBu Class::Std, przedstawion wcze[niej klas mo|na by napisa w na- stpujcy sposób: { package InsideOut::User; use Class::Std; my %names :ATTR( :get<name> :init_arg<name> ); my %addresses :ATTR( :get<address> :init_arg<address> ); } Sposoby na obiekty | 135 SPOSÓB Darmowe (prawie) serializowanie obiektów 44. Kod ten automatycznie wygeneruje metody dostpu get_name() i get_address() oraz konstruktor, który pobierze pocztkowe warto[ci obiektów z odwoBania do tablicy asocjacyjnej wedBug odpowiednich kluczy tej|e tablicy. SkBadnia tu zaprezentowana nie jest tak elegancka, jak skBadnia Perla 6, niemniej jest znacznie krótsza ni| zaprezentowana wcze[niej wersja napisana od podstaw w Perlu 5  i co wa|niejsze, oferuje dokBadnie te same funkcje. SPOSÓB Darmowe (prawie) serializowanie obiektów 44. Przechowuj dane, unikajc baBaganu, nieporozumieD oraz wielkich obiektów danych binarnych Niektóre programy bezwzgldnie potrzebuj trwaBego zapisywania danych i czasami okazuje si, |e wykonywanie mapowania midzy obiektami a ró|nymi tabelami w peBni relacyjnej bazy danych jest zbyt pracochBonne. Szczególnie w tych przypadkach, gdy liczy si szybko[ i Batwo[ edytowania danych  w takich sytuacjach trudno o lepszy inter- fejs do ich edytowania ni|  nasz ulubiony edytor [SposOb 12.]. Zamiast rcznego konfigurowania wszystkiego w programie i tracenia naszej cennej mBodo[ci na tworzenie idealnego schematu bazy danych lub wiczenia si w korzystaniu z jzyka XML czemu po prostu nie serializowa (zapisywa na trwaBe) danych z obiektów w plikach YAML? Sposób Je[li korzystamy z obiektów zbudowanych na tablicach asocjacyjnych, to serializowanie danych jest bardzo proste  wystarczy utworzy kopi tablicy asocjacyjnej i serializo- wa j np. w pliku: use YAML 'DumpFile'; sub serialize { my ($object, $file) = @_; my %data = %$object; DumpFile( $file, \%data ); } ZakBadamy tutaj oczywi[cie, |e warto[ przechowywana w zmiennej $object jest obiektem, który chcemy serializowa, a zmienna $file okre[la [cie|k do pliku, w którym obiekt ma zosta zachowany. Je[li natomiast korzystamy  z prawidBowo zamknitych obiektów [SposOb 43.], to czeka nas troch wicej pracy: package Graphics::Drawable; { use Class::Std; my %coords_of :ATTR( :get<coords> :init_arg<coords> ); my %velocities_of :ATTR( :get<velocity> :init_arg<velocity> ); my %shapes_of :ATTR( :get<shape> :init_arg<shape> ); 136 | Sposoby na obiekty SPOSÓB Darmowe (prawie) serializowanie obiektów 44. sub get_serializable_data { my $self = shift; my %data; for my $attribute (qw( coords velocity shape )) { my $method = 'get_' . $attribute; $data{ $attribute } = $self->$method( ); } return \%data; } } Teraz nasza funkcja serialize() bdzie mogBa unikn naruszenia obudowania da- nych i przywoBa procedur get_serializable_data(). Obiekt znajdujcy si w po- cztku ukBadu wspóBrzdnych  wspóBrzdne (0, 0, 0)  poruszajcy si wzdBu| osi X z prdko[ci (velocity) jednej jednostki na jednostk odlegBo[ci  ruch (1, 0, 0)  oraz ksztaBt okrgu Circle zostan zserializowane w nastpujcy sposób: --- coords: - 0 - 0 - 0 shape: Circle velocity: - 1 - 0 - 0 Je[li potrzebna bdzie wiksza liczba obiektów, wystarczy skopiowa plik do nowej lo- kalizacji i odpowiednio go zmodyfikowa. Nale|y tylko pamita, aby zachowa prawi- dBow skBadni jzyka YAML2. Przywracanie takich obiektów jest proste. Wystarczy u|y metody LoadFile() moduBu YAML(): use YAML 'LoadFile'; sub deserialize { my ($class, $file) = @_; my $data = LoadFile( $file ); return $class->new( $data ); } Je[li nasz konstruktor klasy pobiera jako atrybut odwoBanie do tablicy asocjacyjnej, której klucze odpowiadaj nazwom atrybutów (tak jak to jest w klasie Class::Std), to w zasa- dzie mamy ju| wszystkie potrzebne elementy serializacji. Oczywi[cie wszystko to wy- maga przygotowania pewnej fabryki obiektów, która bdzie zarzdzaBa instancjami, 2 Co jednak jest prostsze ni| rczne pisanie prawidBowego kodu XML& Sposoby na obiekty | 137 SPOSÓB Umieszczanie dodatkowych informacji w atrybutach 45. mapowaBa pliki i [cie|ki na klasy oraz zachowywaBa i pobieraBa obiekty, |e nie wspomn o zarzdzaniu bBdami. Wszystkim tym mo|e zaj si moduB Class::Storage- Factory, dostpny w sieci CPAN. Je[li ju| mamy te wszystkie narzdzia  i aby móc odtworzy obiekt, potrzebujemy tyl- ko danych z publicznego interfejsu obiektu (atrybutów konstruktora i danych dostp- nych za pomoc metod dostpu)  to serializowanie do pliku YAML lub innego czysto tekstowego formatu (mo|e np. JSON?) jest szybkie, wygodne i prawie nic nie kosztuje. SPOSÓB Umieszczanie dodatkowych informacji w atrybutach 45. Opatrz swoje zmienne i procedury paroma dodatkowymi informacjami Procedury i zmienne s do[ oczywiste. Owszem, mo|na przesyBa odwoBania do nich lub zmieni je w procedury i zmienne anonimowe, a nastpnie robi z nimi ró|ne dziwne rzeczy, niemniej tak czy siak mamy niewielki wpByw na to, co Perl bdzie z nimi robi. Najlepszym rozwizaniem jest przydanie im atrybutów. Wspomniane atrybuty s to maBe fragmenty danych podczepiane do zmiennych lub procedur. Z ich pomoc mo|na skBoni Perla, by uruchomiB dowolny kod, jaki bdzie nam potrzebny. Daje to naprawd nieograniczone mo|liwo[ci. Sposób ZaBó|my, |e przygotowali[my klas i chcieliby[my udokumentowa przeznaczenie ka|- dej z jej metod. Niektóre jzyki dostarczaj w tym celu krótkich BaDcuchów dokumentujcych (ang. docstrings)  komentarzy, które mo|na oglda, przywoBujc metody klasy. Ko- mentarze Perla s raczej nudne, niemniej mo|na osign prawie taki sam efekt, opatrujc metody odpowiednimi atrybutami procedur. Rozwa|my klas Counter, której celem jest dostarczenie domy[lnego konstruktora zlicza- jcego liczb utworzonych obiektów. Korzystajc z atrybutu Doc oferowanego przez moduB Attribute::Docstring, mo|na przygotowa nastpujc klas: package Counter; use strict; use warnings; use Attribute::Docstring; our $counter :Doc( 'licznik wszystkich nowych obiektów Foo' ); sub new :Doc( 'konstruktor obiektu Foo' ) { $counter++; bless { }, shift; } 138 | Sposoby na obiekty SPOSÓB Umieszczanie dodatkowych informacji w atrybutach 45. sub get_count :Doc( 'zwraca licznik dla wszystkich obiektów foo' ) { return $counter; } 1; Prototyp pojawia si zaraz po nazwie procedury i jest poprzedzony dwukropkiem. W prze- ciwnym razie wygldaBby zupeBnie jak wywoBanie funkcji. Argumentem (jedynym) tak definiowanego atrybutu jest BaDcuch dokumentujcy. Uruchamianie sposobu Najprostszym sposobem tworzenia atrybutów i korzystania z nich jest u|ycie pomocy moduBu Attribute::Handlers. Umo|liwia on pisanie procedur nazywanych od atrybutów, które chcemy zadeklarowa. Implementacja pakietu Attribute::Docstring jest nastpujca: package Attribute::Docstring; use strict; use warnings; use Scalar::Util 'blessed'; use Attribute::Handlers; my %doc; sub UNIVERSAL::Doc :ATTR { my ($package, $symbol, $referent, $attr, $data, $phase) = @_; return if $symbol eq 'LEXICAL'; my $name = *{$symbol}{NAME}; $doc{ $package }{ $name } = $data; } sub UNIVERSAL::doc { my ($self, $name) = @_; my $package = blessed( $self ) || $self; return unless exists $doc{ $package }{ $name }; return $doc{ $package }{ $name }; } 1; Aby atrybut Doc dostpny byB wszdzie, moduB definiuje procedur UNIVERSAL::Doc. Procedura ta sama w sobie równie| posiada atrybut :ATTR, który opisuje j jako proce- dur obsBugujc atrybuty. W przypadku ka|dej procedury lub zmiennej deklarujcej atrybut Doc, procedura UNIVERSAL::Doc otrzymywa bdzie kilka informacji. Tutaj najwa|niejsze s pakiet zawierajcy procedur, symbol  za pomoc którego, wykorzystujc dostp typeglob, Sposoby na obiekty | 139 SPOSÓB Upewnianie si, |e metody s prywatne dla obiektów 46. bdzie mo|na pobra nazw  i dane przypisane atrybutowi. W klasie Counter proce- dura obsBugujca atrybuty otrzyma nazw pakietu, czyli Counter, oraz typeglob z na- zw symbolu new, gdy tylko Perl skoDczy kompilowanie metody new(). Nastpnie za- chowa dane atrybutu (sam BaDcuch dokumentujcy) w tablicy asocjacyjnej, której kluczami s najpierw nazwa pakietu, a nastpnie nazwa symbolu. Z uwagi na ró|nice w sposobie, w jaki Perl traktuje zmienne leksykalne i zmienne glo- balne, procedura nie bdzie w stanie wiele zrobi, je[li otrzyma symbol leksykalny (tzn. gdy zmienna $symbol bdzie LEXICAL). Tego rodzaju zmienne i procedury s prywat- nymi zmiennymi i procedurami pakietu, wic i tak nie warto ich w ten sposób doku- mentowa. Podobna metoda doc() dziaBa na ka|dej klasie i obiekcie, tak wic wywoBanie Coun- ter->doc( 'new' ), jak równie| $counter->doc( 'get_count' ), zwróci BaDcuch dokumentujcy dla odpowiedniej metody podanej jako argument. Po prostu odszuka BaD- cuch dokumentujcy metod w odpowiednim pakiecie i zwróci go. Eksplorowanie sposobu Jednym z potencjalnych usprawnieD opisanego sposobu jest dodanie do nazwy odpo- wiedniej  pieczci (ang. sigil), aby zapobiec wzajemnemu zapisywaniu BaDcuchów do- kumentujcych zmienn o nazwie $count i metod count(). Wymaga to bdzie wpro- wadzenia zmian w procedurze UNIVERSAL::doc(), by zmienna $name zawieraBa odpowiedni piecz (lub nie, je[li pieczci identyfikujc opatrzona ma by metoda). Kolejna mo|liwo[ polega na pobraniu procedury UNIVERSAL::Doc()z moduBu UNIVERSAL i doBczeniu jej do kodu klasy  zamiast importowania jej do pakietu (klasy), który korzysta z tego moduBu. W ten sposób zdejmujemy obci|enia z moduBu UNIVER- SAL kosztem jednak za[miecania kodu przywoBujcych go klas. Czasem taka wymiana jest opBacalna, czasem nie. Atrybuty mog mie dBugo[ kilku wierszy, niemniej trzeba niestety korzysta w tym celu ze skBadni heredocs. SPOSÓB Upewnianie si, |e metody s prywatne dla obiektów 46. Dowiedz si, jak niewielkim wysiBkiem wymusza enkapsulacj metod Perl oferuje bardzo wszechstronne narzdzia programowania obiektowego, umo|liwia- jce tworzenie i emulacj praktycznie dowolnych rodzajów obiektów lub systemów klas. Mechanizm programowania obiektowego w Perlu jest równie| bardzo permisywny i nie oferuje bazowo |adnej kontroli dostpu do danych obiektu. Dowolny zewntrzny kod mo|e w ka|dej chwili wykorzysta lub podprowadzi metody obiektu i ich metody nad- rzdne, u|ywajc ich w innej klasie. Mo|e równie| przywoBywa rzekomo prywatne metody obiektu wbrew intencjom programisty, który pisaB jego kod. 140 | Sposoby na obiekty SPOSÓB Upewnianie si, |e metody s prywatne dla obiektów 46. Zgodnie z powszechnie przyjt w spoBeczno[ci programistów Perla konwencj metody, których nazwy zaczynaj si od znaku podkre[lenia, nale|y traktowa jako metody prywatne i nie próbowa ich pokrywa, przywoBywa spoza klasy ani te| u|ywa in- nych trików i sztuczek programistycznych, które umo|liwiByby obej[cie ich prywatno[ci. Jest to rozsdna zasada, niemniej nale|y pamita, |e jest to tylko konwencja, niewymu- szana w |aden sposób przez konstrukcj jzyka. Nadal wiec mo|na przywoBywa pry- watne obiekty w niewBa[ciwy sposób, obojtnie, czy przez przypadek, czy te| celowo. Na szcz[cie istniej lepsze (lub przynajmniej niefrasobliwe) sposoby ukrywania metod. Sposób Najprostszy sposób, gwarantujcy, |e procedury bd w momencie kompilowania trakto- wane jak metody, to skorzystanie z  atrybutów procedur [SposOb 45.]. ModuB Class:: HideMethods dodaje do metod atrybut Hide, który czyni je niedostpnymi i prawie niemo|liwymi do wywoBania spoza programu: package Class::HideMethods; use strict; use warnings; use Attribute::Handlers; my %prefixes; sub import { my ($self, $ref) = @_; my $package = caller( ); $prefixes{ $package } = $ref; } sub gen_prefix { my $invalid_chars = "\0\r\n\f\b"; my $prefix; for ( 1 .. 5 ) { my $char_pos = int( rand( length( $invalid_chars ) ) ); $prefix .= substr( $invalid_chars, $char_pos, 1 ); } return $prefix; } package UNIVERSAL; sub Private :ATTR { my ($package, $symbol, $referent, $attr, $data, $phase) = @_; my $name = *{ $symbol }{NAME}; my $newname = Class::HideMethods::gen_prefix( $package ) . $name; my @refs = map { *$symbol{ $_ } } qw( HASH SCALAR ARRAY GLOB ); *$symbol = do { local *symbol }; Sposoby na obiekty | 141 SPOSÓB Upewnianie si, |e metody s prywatne dla obiektów 46. no strict 'refs'; *{ $package . '::' . $newname } = $referent; *{ $package . '::' . $name } = $_ for @refs; $prefixes{ $package }{ $name } = $newname; } 1; Aby ukry metod, kod ten zastpuje symbol metody nowym pustym typem globalnym typeglob. Zabieg ten usuwa jednak wszystkie zmienne o tej samej nazwie, wic odpowiedni kod kopiuje je najpierw z symbolu i zapisuje w nowym, pustym symbolu. Wida tutaj, jak mo|na  usuwa dane z typu globalnego typeglob. Uruchamianie sposobu Korzystanie z tego moduBu nie jest trudne. Wewntrz naszej klasy wystarczy zadekla- rowa leksykaln tablic asocjacyjn, która przechowywa bdzie sekretne nowe nazwy metod. Nale|y przesBa j do wiersza instrukcji use Class::HideMethods u|ywajcej pomocniczego moduBu: package SecretClass; my %methods; use Class::HideMethods \%methods; sub new { bless { }, shift } sub hello :Private { return 'hello' } sub goodbye { return 'goodbye' } sub public_hello { my $self = shift; my $hello = $methods{hello}; $self->$hello( ); } 1; Nale|y pamita, aby przywoBywa wszystkie prywatne metody, u|ywajc skBadni $przywoBujcy->$nazwa_metody i odpowiedniej ukrytej nazwy metody. Aby upewni si, czy to zabezpieczenie dziaBa, wykonajmy kilka testów próbujcych przywoBa metody z zewntrznego kodu: use Test::More tests => 6; my $sc = SecretClass->new( ); isa_ok( $sc, 'SecretClass' ); ok( ! $sc->can( 'hello' ), 'hello( ) powinna by ukryta' ); ok( $sc->can( 'public_hello' ), 'public_hello( ) powinna by dostpna' ); is($sc->public_hello( ), 'hello', '... i powinna móc przywoBywa hello( )' ); ok( $sc->can( 'goodbye' ), 'goodbye( ) powinna by dostpna ' ); is($sc->goodbye( ), 'goodbye', '... i powinna da si przywoBywa' ); 142 | Sposoby na obiekty SPOSÓB Upewnianie si, |e metody s prywatne dla obiektów 46. Nawet podklasy zdefiniowanej klasy nie s w stanie przywoBa jej metod bezpo[rednio. Jak wida, udaBo si uzyska caBkiem dobry poziom prywatno[ci! Jak ten sposób dziaBa Wewntrznie Perl wykorzystuje tzw. tablice symboli (ang. symbol tables) do przechowy- wania wszystkiego, co opatrzone jest nazw  zmiennych, procedur, metod, klas i pa- kietów. Robi tak dla wygody ludzi programistów. Teoretycznie nie powinno Perla inte- resowa, jak metoda ma nazw, mo|e przywoBywa j zarówno za pomoc nazwy, jak i poprzez odwoBanie czy te| luzny opis. Po cz[ci jest to prawda, a po cz[ci nie. Tylko dla parsera Perla wa|ne s nazwy. Akcepto- walne identyfikatory powinny zaczyna si od litery alfabetu albo znaku podkre[lenia i za- wiera jeden lub wicej znaków alfanumerycznych lub znaków podkre[lenia. Gdy ju| parser Perla dokona analizy programu, sprawdzi, jakimi symbolami dysponuje, w spo- sób podobny do tego, w jaki przeglda warto[ci przechowywane w tablicy asocjacyjnej. Je[li uda nam si przekona Perla, aby odszukaB symbol zawierajcy teoretycznie nie- prawidBowe znaki, z ochot to zrobi. Na szcz[cie istnieje wicej ni| jeden sposób przywoBywania metod. Je[li mamy skalar za- wierajcy nazw metody (który mo|na zdefiniowa jako BaDcuch zawierajcy praktycz- nie dowolne znaki, niekoniecznie poprawny identyfikator) lub odwoBanie do samej me- tody, to Perl przywoBa metod dla elementu wywoBujcego. To poBowa caBego triku. Druga z wykorzystywanych magicznych sztuczek polega na usuniciu symbolu z tablicy symboli, obecnego tam pod swoj niesekretn nazw. Bez tego u|ytkownicy mogliby omi- n sekretn nazw i przywoBywa teoretycznie ukryt metod wprost. Jednak skoro prawdziwa nazwa jest niewidoczna, to sama klasa musi w jaki[ sposób odnajdywa swoje prywatne metody, by móc je przywoBywa. WBa[nie temu sBu|y lek- sykalna tablica asocjacyjna %methods, która nie jest normalnie widoczna spoza samej klasy (lub przynajmniej spoza zawierajcego j pliku). Eksplorowanie sposobu Sprytniejsza wersja tego kodu mogBaby nawet oby si bez wykorzystywania tablicy asocja- cyjnej %methods w klasie, której metody s ukrywane. By mo|e wykorzystujc klau- zul constant, by przechowywa nazwy metod w sposób bardziej odpowiedni. Podej[cie to nie jest kompletnym rozwizaniem problemu kontroli dostpu do wewntrz- nych metod i zmiennych obiektu, przynajmniej w tym sensie, |e dostp do nich mógBby by blokowany przez sam jzyk. Nadal bowiem mo|na znalez obej[cie przedstawione- go tu zabezpieczenia. Na przykBad mo|na by byBo przejrze tablic symboli pakietu, szu- kajc zdefiniowanego kodu. Jednym ze sposobów zapobie|enia takim sprytnym sztuczkom jest zrezygnowanie z zapisywania metod z powrotem w tablicy symboli pod zmienionymi nazwami. Zamiast tego nale|y zupeBnie usun metody z tabeli symboli i przechowywa odpowiednie odwoBania w leksykalnej pamici podrcznej (ang. cache) dla metod. Sposoby na obiekty | 143 SPOSÓB Autodeklarowanie argumentów metod 47. W ten sposób uda si nam powstrzyma wikszo[ zdeterminowanych ludzi. Jednak lu- dzie naprawd zdeterminowani wiedz, |e moduB PadWalker z sieci CPAN umo|liwia im  wykorzystywanie zmiennych leksykalnych poza ich normalnym zakresem [SposOb 76.]& Niemniej ka|dy, kto zada sobie a| tyle wysiBku, mógBby równie| bez wikszego wysiBku sprawi, by zamiast Badowania moduBu Class::HideMethods nasz pakiet Ba- dowaB co[ innego, co nie usunie symboli ukrytych metod. Mimo to nadal jednak trudno bdzie przywoBa metody obiektu przez przypadek lub nawet celowo bez odrobiny po- rzdnego gBówkowania. Prawdopodobnie jest to równie| najlepsze zabezpieczenie, jakie mo|na przygotowa w Perlu 5. SPOSÓB Autodeklarowanie argumentów metod 47. Wiesz kim jeste[, wic nie ma powodu, by si powtarza Oferowane przez Perl narzdzia programowania obiektowego s bardzo wszechstronne, gBównie z uwagi na swoj prostot i minimalizm. Czasami jest to korzystne: umo|liwia programistom tworzenie skomplikowanych systemów obiektowych nawet na bazie bardzo skromnego zestawu narzdzi. Kiedy indziej jednak nawet najprostsze rzeczy programuje si w bólach. Mimo i| programista nie musi zawsze przywoBywa w metodach kod je wywoBujcy za pomoc zmiennej $self, to jednak bardzo czsto stawa bdzie przed konieczno[ci deklarowania argumentu okre[lajcego kod wywoBujcy i zarzdzania nim oraz innymi argumentami. Jest to do[ kBopotliwe  niemniej mo|na temu zaradzi. Oczywi[cie, mo|na by skorzysta z  profesjonalnego filtru kodu zródBowego [SposOb 94.], aby z jego pomoc odBo|y na bok argument $self i przetwarza tylko pozostaBe argumenty z listy. To jednak raczej zbyt rozbudowane narzdzie, by u|ywa go do usuwania takiej drobnej niewygody. Istnieje inny, lepszy sposób. Sposób Rozwizanie tego problemu bez wykorzystywania filtrów kodu zródBowego wymaga roz- wizania trzech problemów. Po pierwsze potrzebny nam bdzie jaki[ sposób oznaczania procedury jako metody, poniewa| nie wszystkie procedury s metodami. Po drugie, aby zachowane zostaBy reguBy dobrego programowania, rozwizanie to powinno by kom- patybilne z deklaracj strict. Po trzecie wreszcie, powinien istnie jaki[ sposób umo|- liwiajcy dodawanie wBa[ciwych operacji, by mo|na byBo definiowa warto[ci zmiennej $self i innych argumentów. Rozwizanie pierwszego problemu jest proste: wystarczy skorzysta z  atrybutu procedury [SposOb 45.] o nazwie Method. Rozwizanie trzeciego równie| nie jest trudne z pomoc moduBu  B::Deparse [SposOb 56.] oraz instrukcji eval. Natomiast drugi wymaga pewnego zachodu& Na szcz[cie jednak wszystkie problemy mo|na rozwiza w jednym, do[ krótkim module: 144 | Sposoby na obiekty SPOSÓB Autodeklarowanie argumentów metod 47. package Attribute::Method; use strict; use warnings; use B::Deparse; use Attribute::Handlers; my $deparse = B::Deparse->new( ); sub import { my ( $class, @vars ) = @_; my $package = caller( ); my %references = ( '$' => \undef, '@' => [ ], '%' => { }, ); push @vars, '$self'; for my $var (@vars) { my $reftype = substr( $var, 0, 1, '' ); no strict 'refs'; *{ $package . '::' . $var } = $references{$reftype}; } } sub UNIVERSAL::Method :ATTR(RAWDATA) { my ($package, $symbol, $referent, undef, $arglist) = @_; my $code = $deparse->coderef2text( $referent ); $code =~ s/{/sub {\nmy (\$self, $arglist) = \@_;\n/; no warnings 'redefine'; *$symbol = eval "package $package; $code"; } 1; Wszystkie zmienne, wBczajc w to zmienn $self, powinny by zmiennymi leksykal- nymi w obrbie swoich metod, bowiem w przeciwnym razie mog si zdarzy nieprzy- jemne rzeczy, gdy spróbujemy przywoBywa jedn metod spod drugiej. Na przykBad mo|emy niechccy zapisa nowymi warto[ciami jak[ zmienn globaln. Procedura ob- sBugujca atrybut Method pobiera skompilowany kod, dokonuje jego analizy i wstawia sBowo kluczowe sub oraz wiersz zajmujcy si obsBug argumentów przed reszt kodu. Wszystkie argumenty dla atrybutu musz by nazwami zmiennych leksykalnych o za- kresie ograniczonym do danej metody. Skompilowanie tego kodu z instrukcj eval przygotuje now, anonimow procedur, któr kod wstawia nastpnie do tablicy symboli zaraz po wyBczeniu ostrze|eD Subro- utine %s redefined (procedura %s zostaBa przedefiniowana). Sposoby na obiekty | 145 SPOSÓB Autodeklarowanie argumentów metod 47. Uruchamianie sposobu W kodzie ka|dej klasy, dla której nie chce nam si na okrgBo deklarowa i pobiera wci| tych samych argumentów, mo|na napisa: package Easy::Class; use strict; use warnings; use Attribute::Method qw( $status ); sub new :Method { bless { @_ }, $self; } sub set_status :Method( $status ) { $self->{status} = $status; } sub get_status :Method { return $self->{status}; } 1; Dla ka|dej metody oznaczonej atrybutem :Method argument okre[lajcy kod przywo- Bujcy $self mamy teraz zadeklarowany niejako za darmo. Ponadto dla ka|dej metody opatrzonej tym atrybutem, parametryzowanej przez list nazw zmiennych, otrzymamy równie| te zmienne. Warto równie| zwróci uwag na magiczne sztuczki zastosowane w procedurze import(), jak równie| na list przesyBanych jej argumentów. W ten wBa[nie sposób omijany jest test badajcy poprawno[ kodu wBczany przez deklaracj strict. Gdyby[my zamiast tego u|yli tylko struktur refs i subs, to nie musieliby[my nawet przesyBa moduBowi Attribute::Method listy interesujcych nas zmiennych. Eksplorowanie sposobu Czy to rozwizanie jest lepsze ni| zastosowanie filtrów kodu zródBowego? Oczywi[cie, jego skBadnia nie jest tak czysta. Z drugiej strony, rozwizania oparte na atrybutach przewa|nie s mniej wra|liwe ni| filtrowanie kodu zródBowego. Przede wszystkim nie uniemo|liwiaj korzystania z innych filtrów kodu zródBowego lub innych atrybutów. Ponadto praktycznie nigdy nie zawodz  je[li nawet nasze procedury bd zawiera bBdy, to Perl zaraportuje je w czasie kompilacji, z punktu widzenia oryginalnego kodu, zanim jeszcze przywoBa procedur obsBugujc atrybuty. Technika ta sprawdza si naj- lepiej w klasach posiadajcych kilka lub wicej metod, z których ka|da wymaga prze- sBania jej takich samych argumentów. 146 | Sposoby na obiekty SPOSÓB Kontrola dostpu do zdalnych obiektów 48. Kolejnym mo|liwym rozwizaniem tego problemu jest przepisanie na nowo drzewa ope- racji (ang. optree) dla odwoBaD do kodu (co wymaga moduBu B::Generate i wiele cier- pliwo[ci), by doda operacje przypisujce argumenty do odpowiednich zmiennych. Oczywi[cie, trzeba bdzie wstawi zmienne leksykalne do PAD-a powizanego z CV, jednak Czytelnicy, którzy wiedz, co to znaczy, bd równie| zapewne wiedzieli, jak to zrobi. Wyszukiwanie i rezerwowanie wszystkich zmiennych leksykalnych, które nasze metody zamykaj, nie wypada tak zle w porównaniu z innymi metodami. Patrz  Zagldanie za zamknite drzwi [SposOb 76.]. Alternatywny sposób rozwizania tego problemu mo|na znalez w module Sub::MicroSig, napisanym przez Richarda Signesa. SPOSÓB Kontrola dostpu do zdalnych obiektów 48. Wymuszaj kontrol dostpu w swoich obiektach Je[li chodzi o podej[cie do kontroli dostpu i prywatno[ci, jzyk Perl jest bardzo uprzejmy i maBo restrykcyjny. Czasami jest to zalet  nie musimy na przykBad dBugo zastana- wia si, co i jak nale|y ukry. Jest to równie| korzystne, gdy musimy szybko przejrze kod przygotowany przez kogo[ innego. Innym razem z kolei wa|niejsze podczas programowania mog si okaza wzgldy bez- pieczeDstwa  szczególnie wtedy, kiedy nasz program bdzie musiaB stawi czoBa dzi- kiemu, groznemu [wiatu zewntrznemu. Nawet wtedy, kiedy musimy wystawi nasz kod na niebezpieczeDstwa internetu, nie chcieliby[my przecie|, by ka|dy mógB z nim robi, co mu si |ywnie podoba. Liczne moduBy i narzdzia programistyczne, takie jak SOAP::Lite, uBatwiaj usBugom WWW siganie do prostych, starych obiektów Perla. Tutaj poka|, jak zabezpieczy odrobin kod programów. Sposób Po pierwsze, nale|y zdecydowa, jakiego rodzaju operacje dany obiekt powinien obsBu- giwa. Wezmy standardowy przykBad skBadnicy danych obsBugiwanej przez internet. Potrzebna nam bdzie mo|liwo[ pobierania elementu, wstawiania elementu, aktuali- zowania elementu oraz usuwania go. Nastpnie nale|y zidentyfikowa typy dostpu: dla potrzeb tworzenia, odczytywania, zapisywania i usuwania. Mo|na by oczywi[cie przechowywa w kodzie lub w pliku konfiguracyjnym list ma- pujc wszystkie wymienione sposoby dostpu na odpowiednie metody obiektów wy- korzystywanych w naszym programie (systemie zarzdzania skBadnic). To jednak byBoby idiotycznie skomplikowane  w koDcu pracujemy w Perlu! Zamiast tego lepiej skorzy- sta z  atrybutów procedur [SposOb 45.]. Sposoby na obiekty | 147 SPOSÓB Kontrola dostpu do zdalnych obiektów 48. package Proxy::AccessControl; use strict; use warnings; use Attribute::Handlers; my %perms; sub UNIVERSAL::perms { my ($package, $symbol, $referent, $attr, $data) = @_; my $method = *{ $symbol }{NAME}; for my $permission (split(/\s+/, $data)) { push @{ $perms{ $package }{ $method } }, $permission; } } sub dispatch { my ($user, $class, $method, @args) = @_; return unless $perms{ $class }{ $method } and $class->can( $method ); for my $perm (@{ $perms{ $class }{ $method } }) { die "Potrzebne uprawnienia '$perm\n'" unless $user->has_permission( $perm ); } $class->$method( @args ); } 1; Deklarowanie uprawnieD jest proste: package Inventory; use Proxy::AccessControl; sub insert :perms( 'create' ) { my ($self, $attributes) = @_; # ... } sub delete :perms( 'delete' ) { my ($self, $id) = @_; # ... } sub update :perms( 'write' ) { my ($self, $id, $attributes) = @_; # ... } 148 | Sposoby na obiekty SPOSÓB Kontrola dostpu do zdalnych obiektów 48. sub fetch :perms( 'read' ) { my ($self, $id) = @_; # ... } Mo|na tak|e Bczy uprawnienia i w ten sposób dopasowywa je do naszych potrzeb: sub clone :perms( 'read create' ) { my ($self, $id, $attributes) = @_; # ... } Pakiet Proxy::AccessControl dostarcza procedury obsBugujcej atrybuty perms, która rejestruje dzielon spacjami list uprawnieD dla ka|dej zaznaczonej metody. Do- starcza równie| metody dispatch()  peBnicej funkcj bariery chronicej system po- midzy nadchodzcymi |daniami przesyBanymi przez kontroler (ang. controller) a obiekta- mi Perla, które bd obsBugiwa |dania. Jedyn rzecz, która pozostaBa do zrobienia (poza napisaniem kodu tworzcego logik biznesow programu), jest sprawienie, aby nasz kontroler przesyBaB wszystkie dane za po[rednictwem metody Proxy::AccessControl::dispatch(). Funkcja ta wymaga przesBania jej trzech parametrów. Pierwszy parametr $user reprezentuje w pewnym sensie mo|liwo[ci dostpu, które ma zewntrzny u|ytkownik. (Nasz kod powinien umo|- liwia tworzenie i uwierzytelnianie tego obiektu). Parametry $class i $method identy- fikuj odpowiednio klas i wywoBywan metod, je[li u|ytkownik ma uprawnienia do jej wywoBania. Eksplorowanie sposobu Metoda dispatch() jest do[ prost metod po[redniczc. By mo|e warto byBoby przygotowa odpowiednich specjalnych po[redników (proxy), dopasowanych do kon- kretnych usBug WWW lub protokoBów u|ywanych przez zdalne obiekty. Za kulisami mogByby one pobiera tylko jeden dodatkowy parametr (obiekt u|ytkownika) i dla ka|- dej metody po[redniczcej dostarczaByby wBasnej implementacji proxy wykonujcej od- powiednie testy dostpu, a nastpnie odpowiednio przekazujcej dalej lub odrzucajcej |dania. Ponadto mo|na by równie| rozszerzy kontrol dostpu, by nie ograniczaBa si tylko do sprawdzania uprawnieD. Mo|na na przykBad kontrolowa dostp do obiektów w zale|- no[ci od liczby równolegle wykonywanych prób sigania do nich, fazy ksi|yca, rodzaju zdalnego systemu operacyjnego, pory dnia czy jakiegokolwiek innego parametru. Ka|de dane, które mo|na umie[ci w atrybucie, bd akceptowalne. Sposoby na obiekty | 149 SPOSÓB Przygotowywanie naprawd polimorficznych obiektów 49. SPOSÓB Przygotowywanie naprawd polimorficznych obiektów 49. Buduj klasy, opierajc si na tym, co bd robi, a nie na tym, skd dziedzicz Wiele przewodników i ksi|ek po[wiconych programowaniu stara si przekona Czy- telnika, |e centralnym elementem programowania obiektowego jest dziedziczenie. Co nie jest prawd. Znacznie wa|niejszy jest polimorfizm. Oznacza to, |e gdy przywoBujemy procedur log() na obiekcie, który potrafi zapisywa w dzienniku swój wewntrzny status, obiekt zapisze ten status, a nie to, |e dziedziczy ze znajdujcej si gdzie[ jakiej[ abstrakcyjnej klasy Logger czy te| wylicza dla nas jaki[ abstrakcyjny dziennik. Perl 6 uBatwia ten ro- dzaj programowania, udostpniajc role. W Perlu 5 natomiast mo|na albo zbudowa polimorfizm samemu, albo skorzysta z moduBu Class::Trait, by rozbi zBo|one opera- cje na bardziej naturalne, nazwane grupami metod. Brzmi to okropnie abstrakcyjnie  niemniej, je[li mamy zBo|ony problem, który jeste[my w stanie odpowiednio rozBo|y na czynniki, to mo|emy bez trudu napisa odpowiedni kod i uzyska efekt polimorfizmu. Sposób Wyobrazmy sobie, |e budujemy aplikacj zaopatrzon w odpowiedni, dokonujcy abs- trakcji model obiektów, perspektyw (ang. view) i kontroler. Przygotowali[my wiele ty- pów sBu|cych do zwracania danych  standardowy obiekt dla jzyka XHTML, odpo- wiednio przykrojony dla jzyka XHTML u|ywanego przez urzdzenia przeno[ne i obiekty zwracajce dane w formacie Ajax lub JSON dla usBug WWW opartych na REST, jak rów- nie| przyjazne dla oprogramowania opiekujcego si interfejsem u|ytkownika. Ka|da mo|liwa perspektywa posiada odpowiadajc jej klas perspektywy. Jak do tej pory, caBy projekt ma sens. Teraz pojawia si jednak pytanie, w jaki sposób ustala, z której perspektywy nale|y korzysta, gdy kod aplikacji bdzie otrzymywaB i rozpatrywaB ko- lejne |dania? Co gorsza, je[li mamy wiele perspektyw, to w jaki sposób zbudowa od- powiednie klasy bez popadania w szaleDstwo, próbujc rozwa|a wszystkie mo|liwe kombinacje? Je[li zdecydujemy si na drobne oszustwo i zadeklarujemy perspektywy jako cechy (ang. traits), to mo|liwe bdzie zastosowanie ich na obiektach tworzcych model i, co za tym idzie, odpowiednie zarzdzanie danymi. Oto przykBad modelu, z którego dziedzicz dwie konkretne klasy wuja Uncle i bratanka Nephew: package Model; sub new { my ($class, %args) = @_; bless \%args, $class; 150 | Sposoby na obiekty SPOSÓB Przygotowywanie naprawd polimorficznych obiektów 49. } sub get_data { my $self = shift; my %data = map { $_ => $self->{$_} } qw( imie profesja wiek ); return \%data; } 1; Perspektywy s równie| bardzo proste: package View; use Class::Trait 'base'; package TextView; use base 'View'; sub render { my $self = shift; printf( "Nazywam si %s. Moja profesja to %s i mam %d lat.\n", @{ $self->get_data( ) }{qw( imie profesja wiek )} ); } package YAMLView; use YAML; use base 'View'; sub render { my $self = shift; print Dump $self->get_data( ); } 1; Tekstowa perspektywa wy[wietla Badnie sformatowany BaDcuch tekstu, podczas gdy perspektywa YAML zwraca serializowan wersj struktury danych. Teraz klasa kontro- lera musi tylko utworzy odpowiedni model obiektowy i zanim przywoBa procedur render(), zastosowa go na odpowiedniej perspektywie: # wykorzystujemy model i ogldamy klasy # tworzymy odpowiednie obiekty modelu my $uncle = Uncle->new( imie => 'Robert', profesja => 'Wuj', wiek => 50 ); my $nephew = Nephew->new( imie => 'Jakub', profesja => 'Agent Chaosu', wiek => 3 ); # stosujemy odpowiednie perspektywy Class::Trait->apply( $uncle, 'TextView' ); Class::Trait->apply( $nephew, 'YAMLView' ); Sposoby na obiekty | 151 SPOSÓB Automatyczne generowanie metod dostpu 50. # wy[wietlamy wyniki $uncle->render( ); $nephew->render( ); Uruchamianie sposobu Kod ten wy[wietla nastpujce informacje: Nazywam si Robert. Pracuj jako Wuj i mam 50 lat. --- imie: Jakub profesja: Agent Chaosu wiek: 3 Eksplorowanie sposobu Je[li nawet za pomoc ról i cech (ang. traits) mo|na byBoby osign tylko tyle, to i tak byByby one ju| niezmiernie u|yteczne. Oferuj nam jednak znacznie wicej! ModuB Class::Traits dostarcza metod does(), któr mo|na wykorzysta, by sprawdzi mo|liwo[ci obiektu. ZakBadajc, |e mo|emy otrzyma obiekt, który ma ju| wbudowan perspektyw (na przykBad model debugowania), nale|y przywoBa metod does, aby upewni si, czy naprawd posiada on ju| perspektyw: Class::Trait->apply( $uncle, $view_type ) unless $uncle->does( 'View' ); Ponadto cechy wcale nie musz dziedziczy z bazowej cechy. Je[li caBy kod korzystajcy z obiektów i klas za pomoc cech bdzie wykonywaB testy za pomoc metody does(), a nie za pomoc metody isa() Perla, to bdziemy mogli korzysta z cech, które bd robi to, co trzeba, niepowizanych |adnymi relacjami ani stosunkiem dziedziczenia z |adn inn cech. Przydaje si to szczególnie w przypadku modeli i perspektyw, które korzystaj z po- [redników (proxies) lub wykonuj zapisywanie w dziennikach. SPOSÓB Automatyczne generowanie metod dostpu 50. Nie pisz dBu|ej metod dostpu rcznie Jedn z zalet Perla jest oszczdzanie programistom pracy. Nie oznacza to oczywi[cie, |e nie trzeba w ogóle pracowa, ale |e mo|na swoj prac wykona przy minimum wBo|o- nego wysiBku. W koDcu nikt nie ma ochoty po raz kolejny wpisywa tego samego kodu. Niech komputer si tym zajmie. Metody dostpu (ang. accessors) i metody modyfikujce (ang. mutators), lub inaczej, me- tody pobierajce (ang. getters) i ustawiajce (ang. setters) dane, s wBa[nie przykBadem takiego kodu. Oto prosty obiektowy moduB: package My::Customer; use strict; use warnings; 152 | Sposoby na obiekty SPOSÓB Automatyczne generowanie metod dostpu 50. sub new { bless { }, shift } sub first_name { my $self = shift; return $self->{first_name} unless @_; $self->{first_name} = shift; return $self; } sub last_name { my $self = shift; return $self->{last_name} unless @_; $self->{last_name} = shift; return $self; } sub full_name { my $self = shift; return join ' ', $self->first_name( ), $self->last_name( ); } 1; Oraz prosty program, który z niego korzysta: my $cust = My::Customer->new( ); $cust->first_name( 'Jan' ); $cust->last_name( 'Publiczny' ); print $cust->full_name( ); I wy[wietla tekst Jan Publiczny. Oczywi[cie, gdyby to naprawd byB obiekt reprezentujcy klienta, musiaBby robi co[ wicej. Na przykBad mo|na by byBo okre[la wypBacalno[ kredytow klienta, to|samo[ gBównego sprzedawcy, który go obsBuguje, itd. Jak wida, metody pobierajce imi first_name i nazwisko last_name s prawie iden- tyczne. Nowe metody dostpu równie| zapewne bd bardzo podobne. Czy nie daBoby si tego jako[ zautomatyzowa? Sposób W sieci CPAN dostpnych jest wiele moduBów, które potrafi sobie poradzi z tym za- daniem, ka|dy w odrobin inny sposób. Tutaj przedstawi dwa przykBady takich mo- duBów  jeden najbardziej wszechstronny, a drugi narzucajcy programi[cie najmniej- sze ograniczenia. Class::MethodMaker Jednym z najstarszych takich moduBów jest Class::MethodMaker, po raz pierwszy opublikowany w 1996 roku. Posiada bardzo bogaty zestaw funkcji i cho jego doku- mentacja pozostawia troch do |yczenia, z samego moduBu korzysta si z Batwo[ci. Aby przekonwertowa kod wcze[niejszego pakietu My::Customer, nale|y napisa: Sposoby na obiekty | 153 SPOSÓB Automatyczne generowanie metod dostpu 50. package My::Customer; use strict; use warnings; use Class::MethodMaker[ new => [qw( new )], scalar => [qw( first_name last_name )],]; sub full_name { my $self = shift; return join ' ', $self->first_name( ), $self->last_name( ); } Konstruktor, jak wida, jest bardzo prosty, ale co staBo si z metodami first_name i last_name? Argumenty przesBane moduBowi Class::MethodMaker polecaj mu utwo- rzy dwa komplety metody dostpu i metody modyfikujcej dla dwóch warto[ci skalarnych. Niemniej, mimo i| kod ten wyglda prawie identycznie, ma jednak znacznie wiksze mo|liwo[ci. ZaBó|my, |e chcemy sprawdzi, czy kto[ ju| definiowaB warto[ zmiennej first_name, czy te| ma przypisan warto[ undef: print $cust->first_name_isset( ) ? 'true' : 'false'; Nawet je[li zmienna imienia first_name ma warto[ undef, metoda first_name() zwróci warto[ true(). Oczywi[cie, czasami wygodniej byBoby, aby zmienna miaBa status zmiennej jeszcze nieokre[lonej, nawet je[li wcze[niej przypisana byBa ju| jej jaka[ warto[. To równie| da si zrobi: $cust->first_name( 'Ozymandias' ); print $cust->first_name_isset( ) ? 'true' : 'false'; # prawda - true $cust->first_name_reset( ); print $cust->first_name_isset( ) ? 'true' : 'false'; # faBsz - false Class::BuildMethods ModuB Class::MethodMaker obsBuguje równie| tablice, tablice asocjacyjne i wiele in- nych u|ytecznych funkcji. Niemniej wymaga, aby w obiektach korzysta z bBogosBawio- nych (za pomoc funkcji bless) tablic asocjacyjnych. Prawd powiedziawszy, wik- szo[ moduBów z sieci CPAN, które tworz metody dostpu, przyjmuje jakie[ zaBo|enia na temat wewntrznej struktury naszych obiektów. Jednym z nielicznych wyjtków jest moduB Class::BuildMethods. ModuB Class::BuildMethods umo|liwia programi[cie budowanie metod dostpu dla tworzonej klasy niezale|nie od tego, czy oparta jest ona na bBogosBawionej tablicy asocjacyjnej, odwoBaniu do tablicy, wyra|eniu regularnym, czy jeszcze czym[ innym. Osiga to,  sigajc po trik wykorzystywany przy tworzeniu prawidBowo zamknitych obiek- tów [SposOb 43.]. Typowy kod tworzcy z jego pomoc klas bdzie wygldaB mniej wicej tak: 154 | Sposoby na obiekty SPOSÓB Automatyczne generowanie metod dostpu 50. package My::Customer; use strict; use warnings; use Class::BuildMethods qw( first_name last_name ); # Warto zauwa|y, |e je[li wolimy, mo|emy u|y odwoBania do tablicy sub new { bless [ ], shift } sub full_name { my $self = shift; return join ' ', $self->first_name( ), $self->last_name( ); } 1; Z klasy tej korzysta si taka samo jak z ka|dej innej. Wewntrznie indeksuje ona warto- [ci metod dostpu wedBug adresu obiektu. Standardowo automatycznie zajmuje si niszczeniem obiektu, niemniej pozwala te| programi[cie zrobi to rcznie, je[li potrze- bowa bdzie jakiego[ specjalnego zachowania w metodzie DESTROY (takiego jak na przy- kBad zdjcie wcze[niej zaBo|onych blokad). Konstrukcja moduBu Class::BuildMethods jest bardzo prosta. Podobnie jak wik- szo[ innych moduBów zajmujcych si generowaniem metod dostpu dla obiektów, do- starcza programi[cie kilku wygodnych funkcji, jednak tylko wtedy, gdy chodzi o domy[lne warto[ci i sprawdzanie danych: use Class::BuildMethods 'imie', gender => { default => 'mezczyzna' }, age => { validate => sub { my ($self, $age) = @_; carp 'Nie mo|esz studiowa, je[li jeste[ istot ni|sz' if ( $age < 18 && ! $self->is_emancipated( ) ); }}; W tym kodzie zwizana z pBci metoda gender() zwróci warto[ male (m|czyzna), chyba |e ustawimy w zmiennej jak[ inn warto[. Zwizana z wiekiem metoda age() demonstruje natomiast, jak przygotowa elastyczny mechanizm sprawdzania warto[ci. Poniewa| metoda validate() wskazuje do odwoBania do procedury, a nie dostarcza specjalnych procedur sprawdzajcych warto[ci, przyjte przez autora zaBo|enia co do sposobu sprawdzania kodu nie bd nas w |adnym stopniu ogranicza. ModuB Class::BuildMethods zawsze zakBada, |e metody ustawiajce warto[ci (meto- dy modyfikujce) zawsze bd wymagaBy tylko jednego argumentu, programista musi wic pamita, aby w razie czego przesyBa im odwoBania do tablic i tablic asocjacyjnych. Sposoby na obiekty | 155 SPOSÓB Automatyczne generowanie metod dostpu 50. Ponadto moduB ten nie obsBuguje tworzenia metod klasy (tj. metod statycznych). Ograni- czenia te oznaczaj, |e zaprezentowany tu kod nie w ka|dej sytuacji bdzie speBniaB po- trzeby programisty, ale nasz przykBadowy moduB miaB z zaBo|enia by bardzo porosty. Dokumentacj moduBu mo|na przeczyta i zrozumie za jednym posiedzeniem. Uruchamianie sposobu Automatyczne generowanie metod dostpu stanowi dla programisty mas pracy. Wy- zwala jego umysB z monotonii powtarzalnej pracy. Do[wiadczony programista Perla wie bowiem, |e w programowaniu inteligentne lenistwo polega na tym, |e ka|da zaoszcz- dzona minuta, której nie stracimy, zajmujc si nudnymi szczegóBami, mo|e zosta po- [wicona na rozwizywanie naprawd powa|nych problemów. 156 | Sposoby na obiekty

Wyszukiwarka

Podobne podstrony:
100 sposobow na PHP0php
100 sposobow na zglebienie tajemnic umyslu0taj
100 sposobow na tworzenie robotow sieciowych
100 sposobów na Linux
100 sposobów na BSD
100 sposobow na serwery Windows0ser

więcej podobnych podstron