Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00534 008661 10441568 na godz. na dobę w sumie
Ruby. Receptury - książka
Ruby. Receptury - książka
Autor: , Liczba stron: 888
Wydawca: Helion Język publikacji: polski
ISBN: 83-246-0768-4 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> ruby - programowanie
Porównaj ceny (książka, ebook, audiobook).

Zbiór gotowych rozwiązań dla programistów używających języka Ruby

Korzystasz w pracy z języka Ruby i zastanawiasz się, czy niektóre zadania programistyczne można wykonać szybciej? Chcesz poznać zasady programowania obiektowego w Ruby? A może interesuje Cię framework Ruby on Rails? Język Ruby zdobywa coraz większą popularność, jest wykorzystywany do tworzenia aplikacji sieciowych i stał się podstawą środowiska Ruby on Rails. Jednak nawet najlepszy język programowania nie uwalnia programistów od żmudnego realizowania zadań, które nie mają zbyt wiele wspólnego z tworzeniem aplikacji, czyli usuwania błędów, implementowania typowych algorytmów, poszukiwania rozwiązań mniej lub bardziej typowych problemów i wielu innych.

Książka 'Ruby. Receptury' znacznie przyspieszy Twoją pracę. Znajdziesz tu kilkaset praktycznych rozwiązań problemów wraz z przejrzystym komentarzem oraz tysiące wierszy proponowanego kodu, który będziesz mógł wykorzystać w swoich projektach. Przeczytasz o strukturach danych, algorytmach, przetwarzaniu plików XML i HTML, tworzeniu interfejsów użytkownika dla aplikacji i połączeniach z bazami danych. Nauczysz się generować i obrabiać pliki graficzne, korzystać z usług sieciowych, wyszukiwać i usuwać błędy w aplikacjach, a także pisać skrypty niezwykle pomocne w administrowaniu systemem operacyjnym Linux.

Jeśli chcesz rozwiązać problem, skorzystaj z gotowej receptury
-- koło już wynaleziono.

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Ruby. Receptury Autorzy: Lucas Carlson, Leonard Richardson T³umaczenie: Andrzej Gra¿yñski, Rados³aw Meryk ISBN: 83-246-0768-4 Tytu³ orygina³u: Ruby Cookbook Format: B5, stron: 888 Zbiór gotowych rozwi¹zañ dla programistów u¿ywaj¹cych jêzyka Ruby (cid:129) Jak przetwarzaæ pliki XML i HTML? (cid:129) Jak wykorzystywaæ œrodowisko Ruby on Rails? (cid:129) W jaki sposób ³¹czyæ Ruby z technologi¹ AJAX? Korzystasz w pracy z jêzyka Ruby i zastanawiasz siê, czy niektóre zadania programistyczne mo¿na wykonaæ szybciej? Chcesz poznaæ zasady programowania obiektowego w Ruby? A mo¿e interesuje Ciê framework Ruby on Rails? Jêzyk Ruby zdobywa coraz wiêksz¹ popularnoœæ, jest wykorzystywany do tworzenia aplikacji sieciowych i sta³ siê podstaw¹ œrodowiska Ruby on Rails. Jednak nawet najlepszy jêzyk programowania nie uwalnia programistów od ¿mudnego realizowania zadañ, które nie maj¹ zbyt wiele wspólnego z tworzeniem aplikacji, czyli usuwania b³êdów, implementowania typowych algorytmów, poszukiwania rozwi¹zañ mniej lub bardziej typowych problemów i wielu innych. Ksi¹¿ka „Ruby. Receptury” znacznie przyspieszy Twoj¹ pracê. Znajdziesz tu kilkaset praktycznych rozwi¹zañ problemów wraz z przejrzystym komentarzem oraz tysi¹ce wierszy proponowanego kodu, który bêdziesz móg³ wykorzystaæ w swoich projektach. Przeczytasz o strukturach danych, algorytmach, przetwarzaniu plików XML i HTML, tworzeniu interfejsów u¿ytkownika dla aplikacji i po³¹czeniach z bazami danych. Nauczysz siê generowaæ i obrabiaæ pliki graficzne, korzystaæ z us³ug sieciowych, wyszukiwaæ i usuwaæ b³êdy w aplikacjach, a tak¿e pisaæ skrypty niezwykle pomocne w administrowaniu systemem operacyjnym Linux. (cid:129) Przetwarzanie danych tekstowych i liczbowych (cid:129) Operacje na tablicach (cid:129) Praca z systemem plików (cid:129) Programowanie obiektowe (cid:129) Przetwarzanie dokumentów XML i HTML oraz plików graficznych (cid:129) Generowanie plików PDF (cid:129) Po³¹czenie z bazami danych (cid:129) Korzystanie z poczty elektronicznej, protoko³u telnet i po³¹czeñ Torrent (cid:129) Projektowanie aplikacji internetowych za pomoc¹ Ruby on Rails (cid:129) Stosowanie us³ug sieciowych (cid:129) Optymalizacja aplikacji (cid:129) Tworzenie wersji dystrybucyjnych (cid:129) Automatyzacja zadañ z wykorzystaniem jêzyka Rake (cid:129) Budowanie interfejsów u¿ytkownika Jeœli chcesz rozwi¹zaæ problem, skorzystaj z gotowej receptury — ko³o ju¿ wynaleziono Wydawnictwo Helion ul. Koœciuszki 1c 44-100 Gliwice tel. 032 230 98 63 e-mail: helion@helion.pl Spis treści Wprowadzenie .............................................................................................................. 17 1. Łańcuchy ........................................................................................................................29 32 34 35 37 39 41 42 43 45 47 48 49 51 52 53 55 58 60 61 64 1.1. Budowanie łańcucha z części 1.2. Zastępowanie zmiennych w tworzonym łańcuchu 1.3. Zastępowanie zmiennych w istniejącym łańcuchu 1.4. Odwracanie kolejności słów lub znaków w łańcuchu 1.5. Reprezentowanie znaków niedrukowalnych 1.6. Konwersja między znakami a kodami 1.7. Konwersja między łańcuchami a symbolami 1.8. Przetwarzanie kolejnych znaków łańcucha 1.9. Przetwarzanie poszczególnych słów łańcucha 1.10. Zmiana wielkości liter w łańcuchu 1.11. Zarządzanie białymi znakami 1.12. Czy można potraktować dany obiekt jak łańcuch? 1.13. Wyodrębnianie części łańcucha 1.14. Obsługa międzynarodowego kodowania 1.15. Zawijanie wierszy tekstu 1.16. Generowanie następnika łańcucha 1.17. Dopasowywanie łańcuchów za pomocą wyrażeń regularnych 1.18. Zastępowanie wielu wzorców w pojedynczym przebiegu 1.19. Weryfikacja poprawności adresów e-mailowych 1.20. Klasyfikacja tekstu za pomocą analizatora bayesowskiego 2. Liczby .............................................................................................................................67 68 70 73 2.1. Przekształcanie łańcucha w liczbę 2.2. Porównywanie liczb zmiennopozycyjnych 2.3. Reprezentowanie liczb z dowolną dokładnością 5 2.4. Reprezentowanie liczb wymiernych 2.5. Generowanie liczb pseudolosowych 2.6. Konwersje między różnymi podstawami liczenia 2.7. Logarytmy 2.8. Średnia, mediana i moda 2.9. Konwersja stopni na radiany i odwrotnie 2.10. Mnożenie macierzy 2.11. Rozwiązywanie układu równań liniowych 2.12. Liczby zespolone 2.13. Symulowanie subklasingu klasy Fixnum 2.14. Arytmetyka liczb w zapisie rzymskim 2.15. Generowanie sekwencji liczb 2.16. Generowanie liczb pierwszych 2.17. Weryfikacja sumy kontrolnej w numerze karty kredytowej 76 77 79 80 83 85 87 91 94 96 100 105 107 111 3. Data i czas .....................................................................................................................113 115 119 122 126 127 129 131 134 135 138 139 140 142 145 3.1. Odczyt dzisiejszej daty 3.2. Dekodowanie daty, dokładne i przybliżone 3.3. Drukowanie dat 3.4. Iterowanie po datach 3.5. Arytmetyka dat 3.6. Obliczanie dystansu między datami 3.7. Konwersja czasu między strefami czasowymi 3.8. Czas letni 3.9. Konwersje między obiektami Time i DateTime 3.10. Jaki to dzień tygodnia? 3.11. Obsługa dat biznesowych 3.12. Periodyczne wykonywanie bloku kodu 3.13. Oczekiwanie przez zadany odcinek czasu 3.14. Przeterminowanie wykonania 4. Tablice .......................................................................................................................... 147 149 152 154 155 156 158 159 4.1. Iterowanie po elementach tablicy 4.2. Wymiana zawartości bez używania zmiennych pomocniczych 4.3. Eliminowanie zdublowanych wartości 4.4. Odwracanie kolejności elementów w tablicy 4.5. Sortowanie tablicy 4.6. Sortowanie łańcuchów bez rozróżniania wielkości liter 4.7. Zabezpieczanie tablic przed utratą posortowania 6 | Spis treści 4.8. Sumowanie elementów tablicy 4.9. Sortowanie elementów tablicy według częstości występowania 4.10. Tasowanie tablicy 4.11. Znajdowanie N najmniejszych elementów tablicy 4.12. Tworzenie hasza za pomocą iteratora inject 4.13. Ekstrahowanie wybranych elementów z tablicy 4.14. Operacje teoriomnogościowe na tablicach 4.15. Partycjonowanie i klasyfikacja elementów zbioru 164 165 167 168 170 172 175 177 5. Hasze ...........................................................................................................................183 186 187 189 191 193 195 196 200 201 203 204 207 209 210 211 5.1. Wykorzystywanie symboli jako kluczy 5.2. Wartości domyślne w haszach 5.3. Dodawanie elementów do hasza 5.4. Usuwanie elementów z hasza 5.5. Tablice i inne modyfikowalne obiekty w roli kluczy 5.6. Kojarzenie wielu wartości z tym samym kluczem 5.7. Iterowanie po zawartości hasza 5.8. Iterowanie po elementach hasza w kolejności ich wstawiania 5.9. Drukowanie hasza 5.10. Inwersja elementów hasza 5.11. Losowy wybór z listy zdarzeń o różnych prawdopodobieństwach 5.12. Tworzenie histogramu 5.13. Odwzorowanie zawartości dwóch haszów 5.14. Ekstrakcja fragmentów zawartości haszów 5.15. Przeszukiwanie hasza przy użyciu wyrażeń regularnych 6. Pliki i katalogi .............................................................................................................. 213 216 218 220 223 224 227 230 232 233 234 6.1. Czy taki plik istnieje? 6.2. Sprawdzanie uprawnień dostępu do plików 6.3. Zmiana uprawnień dostępu do plików 6.4. Sprawdzanie, kiedy plik był ostatnio używany 6.5. Przetwarzanie zawartości katalogu 6.6. Odczytywanie zawartości pliku 6.7. Zapis do pliku 6.8. Zapis do pliku tymczasowego 6.9. Losowy wybór wiersza z pliku 6.10. Porównywanie dwóch plików 6.11. Swobodne nawigowanie po „jednokrotnie odczytywalnych” strumieniach wejściowych 238 Spis treści | 7 6.12. Wędrówka po drzewie katalogów 6.13. Szeregowanie dostępu do pliku 6.14. Tworzenie wersjonowanych kopii pliku 6.15. Łańcuchy udające pliki 6.16. Przekierowywanie standardowego wejścia i standardowego wyjścia 6.17. Przetwarzanie plików binarnych 6.18. Usuwanie pliku 6.19. Obcinanie pliku 6.20. Znajdowanie plików o określonej własności 6.21. Odczytywanie i zmiana bieżącego katalogu roboczego 240 242 245 248 250 252 255 257 258 260 7. Bloki kodowe i iteracje ...............................................................................................263 265 267 269 7.1. Tworzenie i wywoływanie bloku kodowego 7.2. Tworzenie metod wykorzystujących bloki kodowe 7.3. Przypisywanie bloku kodowego do zmiennej 7.4. Bloki kodowe jako domknięcia: odwołania do zmiennych zewnętrznych w treści bloku kodowego 7.5. Definiowanie iteratora dla struktury danych 7.6. Zmiana sposobu iterowania po strukturze danych 7.7. Nietypowe metody klasyfikujące i kolekcjonujące 7.8. Zatrzymywanie iteracji 7.9. Iterowanie równoległe 7.10. Kod inicjujący i kończący dla bloku kodowego 7.11. Tworzenie systemów luźno powiązanych przy użyciu odwołań zwrotnych 272 273 276 278 279 281 285 287 8. Obiekty i klasy ............................................................................................................. 291 294 296 299 301 303 305 307 308 311 315 317 319 321 8.1. Zarządzanie danymi instancyjnymi 8.2. Zarządzanie danymi klasowymi 8.3. Weryfikacja funkcjonalności obiektu 8.4. Tworzenie klasy pochodnej 8.5. Przeciążanie metod 8.6. Weryfikacja i modyfikowanie wartości atrybutów 8.7. Definiowanie wirtualnych atrybutów 8.8. Delegowanie wywołań metod do innego obiektu 8.9. Konwersja i koercja typów obiektów 8.10. Prezentowanie obiektu w postaci czytelnej dla człowieka 8.11. Metody wywoływane ze zmienną liczbą argumentów 8.12. Symulowanie argumentów zawierających słowa kluczowe 8.13. Wywoływanie metod superklasy 8 | Spis treści 8.14. Definiowanie metod abstrakcyjnych 8.15. Zamrażanie obiektów w celu ich ochrony przed modyfikacją 8.16. Tworzenie kopii obiektu 8.17. Deklarowanie stałych 8.18. Implementowanie metod klasowych i metod-singletonów 8.19. Kontrolowanie dostępu — metody prywatne, publiczne i chronione 323 325 327 330 332 334 9. Moduły i przestrzenie nazw .......................................................................................339 339 343 345 346 348 350 352 353 354 9.1. Symulowanie wielokrotnego dziedziczenia za pomocą modułów-domieszek 9.2. Rozszerzanie wybranych obiektów za pomocą modułów 9.3. Rozszerzanie repertuaru metod klasowych za pomocą modułów 9.4. Moduł Enumerable — zaimplementuj jedną metodę, dostaniesz 22 za darmo 9.5. Unikanie kolizji nazw dzięki ich kwalifikowaniu 9.6. Automatyczne ładowanie bibliotek na żądanie 9.7. Importowanie przestrzeni nazw 9.8. Inicjowanie zmiennych instancyjnych dołączanego modułu 9.9. Automatyczne inicjowanie modułów-domieszek 10. Odzwierciedlenia i metaprogramowanie .................................................................357 358 359 363 364 366 368 370 372 375 377 380 382 383 386 389 391 10.1. Identyfikacja klasy obiektu i jej superklasy 10.2. Zestaw metod obiektu 10.3. Lista metod unikalnych dla obiektu 10.4. Uzyskiwanie referencji do metody 10.5. Poprawianie błędów w „obcych” klasach 10.6. Śledzenie zmian dokonywanych w danej klasie 10.7. Weryfikacja atrybutów obiektu 10.8. Reagowanie na wywołania niezdefiniowanych metod 10.9. Automatyczne inicjowanie zmiennych instancyjnych 10.10. Oszczędne kodowanie dzięki metaprogramowaniu 10.11. Metaprogramowanie z użyciem ewaluacji łańcuchów 10.12. Ewaluacja kodu we wcześniejszym kontekście 10.13. Anulowanie definicji metody 10.14. Aliasowanie metod 10.15. Programowanie zorientowane aspektowo 10.16. Wywołania kontraktowane 11. XML i HTML .................................................................................................................395 396 398 11.1. Sprawdzanie poprawności dokumentu XML 11.2. Ekstrakcja informacji z drzewa dokumentu Spis treści | 9 11.3. Ekstrakcja informacji w trakcie analizy dokumentu XML 11.4. Nawigowanie po dokumencie za pomocą XPath 11.5. Parsowanie błędnych dokumentów 11.6. Konwertowanie dokumentu XML na hasz 11.7. Walidacja dokumentu XML 11.8. Zastępowanie encji XML 11.9. Tworzenie i modyfikowanie dokumentów XML 11.10. Kompresowanie białych znaków w dokumencie XML 11.11. Autodetekcja standardu kodowania znaków w dokumencie 11.12. Konwersja dokumentu między różnymi standardami kodowania 11.13. Ekstrakcja wszystkich adresów URL z dokumentu HTML 11.14. Transformacja tekstu otwartego na format HTML 11.15. Konwertowanie ściągniętego z internetu dokumentu HTML na tekst 11.16. Prosty czytnik kanałów 400 401 404 406 409 411 414 417 418 419 420 423 425 428 12. Formaty plików graficznych i innych ........................................................................ 433 433 436 439 441 444 447 449 451 453 455 458 460 461 465 12.1. Tworzenie miniaturek 12.2. Dodawanie tekstu do grafiki 12.3. Konwersja formatów plików graficznych 12.4. Tworzenie wykresów 12.5. Wprowadzanie graficznego kontekstu za pomocą wykresów typu Sparkline 12.6. Silne algorytmy szyfrowania danych 12.7. Przetwarzanie danych rozdzielonych przecinkami 12.8. Przetwarzanie plików tekstowych nie w pełni zgodnych z formatem CSV 12.9. Generowanie i przetwarzanie arkuszy Excela 12.10. Kompresowanie i archiwizowanie plików za pomocą narzędzi Gzip i Tar 12.11. Czytanie i zapisywanie plików ZIP 12.12. Czytanie i zapisywanie plików konfiguracyjnych 12.13. Generowanie plików PDF 12.14. Reprezentowanie danych za pomocą plików muzycznych MIDI 13. Bazy danych i trwałość obiektów ............................................................................. 469 472 475 476 13.1. Serializacja danych za pomocą biblioteki YAML 13.2. Serializacja danych z wykorzystaniem modułu Marshal 13.3. Utrwalanie obiektów z wykorzystaniem biblioteki Madeleine 13.4. Indeksowanie niestrukturalnego tekstu z wykorzystaniem biblioteki SimpleSearch 13.5. Indeksowanie tekstu o określonej strukturze z wykorzystaniem biblioteki Ferret 10 | Spis treści 479 481 13.6. Wykorzystywanie baz danych Berkeley DB 13.7. Zarządzanie bazą danych MySQL w systemie Unix 13.8. Zliczanie wierszy zwracanych przez zapytanie 13.9. Bezpośrednia komunikacja z bazą danych MySQL 13.10. Bezpośrednia komunikacja z bazą danych PostgreSQL 13.11. Mapowanie obiektowo-relacyjne z wykorzystaniem biblioteki ActiveRecord 13.12. Mapowanie obiektowo-relacyjne z wykorzystaniem biblioteki Og 13.13. Programowe tworzenie zapytań 13.14. Sprawdzanie poprawności danych z wykorzystaniem biblioteki ActiveRecord 13.15. Zapobieganie atakom typu SQL Injection 13.16. Obsługa transakcji z wykorzystaniem biblioteki ActiveRecord 13.17. Definiowanie haków dotyczących zdarzeń związanych z tabelami 13.18. Oznaczanie tabel bazy danych z wykorzystaniem modułów-domieszek 484 486 487 489 491 493 497 501 504 507 510 511 514 14. Usługi internetowe .....................................................................................................519 520 522 524 526 528 531 535 538 540 543 546 547 549 550 552 555 557 559 562 567 14.1. Pobieranie zawartości strony WWW 14.2. Obsługa żądań HTTPS 14.3. Dostosowywanie nagłówków żądań HTTP 14.4. Wykonywanie zapytań DNS 14.5. Wysyłanie poczty elektronicznej 14.6. Czytanie poczty z serwera IMAP 14.7. Czytanie poczty z wykorzystaniem protokołu POP3 14.8. Implementacja klienta FTP 14.9. Implementacja klienta telnet 14.10. Implementacja klienta SSH 14.11. Kopiowanie plików do innego komputera 14.12. Implementacja klienta BitTorrent 14.13. Wysyłanie sygnału ping do zdalnego komputera 14.14. Implementacja własnego serwera internetowego 14.15. Przetwarzanie adresów URL 14.16. Pisanie skryptów CGI 14.17. Ustawianie plików cookie i innych nagłówków odpowiedzi HTTP 14.18. Obsługa przesyłania plików na serwer z wykorzystaniem CGI 14.19. Uruchamianie serwletów WEBrick 14.20. Własny klient HTTP Spis treści | 11 15. Projektowanie aplikacji internetowych: Ruby on Rails ............................................ 571 573 576 578 581 582 585 588 590 594 595 596 599 601 602 15.1. Prosta aplikacja Rails wyświetlająca informacje o systemie 15.2. Przekazywanie danych ze sterownika do widoku 15.3. Tworzenie układu nagłówka i stopki 15.4. Przekierowania do innych lokalizacji 15.5. Wyświetlanie szablonów za pomocą metody render 15.6. Integracja baz danych z aplikacjami Rails 15.7. Reguły pluralizacji 15.8. Tworzenie systemu logowania 15.9. Zapisywanie haseł użytkowników w bazie danych w postaci skrótów 15.10. Unieszkodliwianie kodu HTML i JavaScript przed wyświetlaniem 15.11. Ustawianie i odczytywanie informacji o sesji 15.12. Ustawianie i odczytywanie plików cookie 15.13. Wyodrębnianie kodu do modułów pomocniczych 15.14. Rozdzielenie widoku na kilka części 15.15. Dodawanie efektów DHTML z wykorzystaniem biblioteki script.aculo.us 15.16. Generowanie formularzy do modyfikowania obiektów modelu 15.17. Tworzenie formularzy Ajax 15.18. Udostępnianie usług sieciowych w witrynie WWW 15.19. Przesyłanie wiadomości pocztowych za pomocą aplikacji Rails 15.20. Automatyczne wysyłanie komunikatów o błędach pocztą elektroniczną 15.21. Tworzenie dokumentacji witryny WWW 15.22. Testy modułowe witryny WWW 15.23. Wykorzystywanie pułapek w aplikacjach internetowych 605 607 611 614 616 618 620 621 624 638 640 642 644 645 649 16. Usługi sieciowe i programowanie rozproszone .......................................................627 628 631 634 636 637 16.1. Wyszukiwanie książek w serwisie Amazon 16.2. Wyszukiwanie zdjęć w serwisie Flickr 16.3. Jak napisać klienta XML-RPC? 16.4. Jak napisać klienta SOAP? 16.5. Jak napisać serwer SOAP? 16.6. Wyszukiwanie w internecie z wykorzystaniem usługi sieciowej serwisu Google 16.7. Wykorzystanie pliku WSDL w celu ułatwienia wywołań SOAP 16.8. Płatności kartami kredytowymi 16.9. Odczytywanie kosztów przesyłki w serwisie UPS lub FedEx 16.10. Współdzielenie haszów przez dowolną liczbę komputerów 16.11. Implementacja rozproszonej kolejki 12 | Spis treści 16.12. Tworzenie współdzielonej „tablicy ogłoszeń” 16.13. Zabezpieczanie usług DRb za pomocą list kontroli dostępu 16.14. Automatyczne wykrywanie usług DRb z wykorzystaniem biblioteki Rinda 16.15. Wykorzystanie obiektów pośredniczących 16.16. Zapisywanie danych w rozproszonej pamięci RAM z wykorzystaniem systemu MemCached 16.17. Buforowanie kosztownych obliczeniowo wyników za pomocą systemu MemCached 16.18. Zdalnie sterowana „szafa grająca” 650 653 654 656 659 661 664 17. Testowanie, debugowanie, optymalizacja i tworzenie dokumentacji ...................669 670 672 673 676 677 679 681 684 686 690 692 696 699 701 702 17.1. Uruchamianie kodu wyłącznie w trybie debugowania 17.2. Generowanie wyjątków 17.3. Obsługa wyjątków 17.4. Ponawianie próby wykonania kodu po wystąpieniu wyjątku 17.5. Mechanizmy rejestrowania zdarzeń w aplikacji 17.6. Tworzenie i interpretowanie stosu wywołań 17.7. Jak pisać testy modułowe? 17.8. Uruchamianie testów modułowych 17.9. Testowanie kodu korzystającego z zewnętrznych zasobów 17.10. Wykorzystanie pułapek do kontroli i modyfikacji stanu aplikacji 17.11. Tworzenie dokumentacji aplikacji 17.12. Profilowanie aplikacji 17.13. Pomiar wydajności alternatywnych rozwiązań 17.14. Wykorzystywanie wielu narzędzi analitycznych jednocześnie 17.15. Co wywołuje tę metodę? Graficzny analizator wywołań 18. Tworzenie pakietów oprogramowania i ich dystrybucja ........................................705 18.1. Wyszukiwanie bibliotek poprzez kierowanie zapytań do repozytoriów gemów 18.2. Instalacja i korzystanie z gemów 18.3. Wymaganie określonej wersji gemu 18.4. Odinstalowywanie gemów 18.5. Czytanie dokumentacji zainstalowanych gemów 18.6. Tworzenie pakietów kodu w formacie gemów 18.7. Dystrybucja gemów 18.8. Instalacja i tworzenie samodzielnych pakietów z wykorzystaniem skryptu setup.rb 706 709 711 714 715 717 719 722 Spis treści | 13 19. Automatyzacja zadań z wykorzystaniem języka Rake ............................................725 727 729 731 733 734 737 738 740 19.1. Automatyczne uruchamianie testów modułowych 19.2. Automatyczne generowanie dokumentacji 19.3. Porządkowanie wygenerowanych plików 19.4. Automatyczne tworzenie gemów 19.5. Pobieranie informacji statystycznych dotyczących kodu 19.6. Publikowanie dokumentacji 19.7. Równoległe uruchamianie wielu zadań 19.8. Uniwersalny plik Rakefile 20. Wielozadaniowość i wielowątkowość ......................................................................747 748 751 754 756 758 760 763 766 20.1. Uruchamianie procesu-demona w systemie Unix 20.2. Tworzenie usług systemu Windows 20.3. Wykonywanie dwóch operacji jednocześnie z wykorzystaniem wątków 20.4. Synchronizacja dostępu do obiektu 20.5. Niszczenie wątków 20.6. Równoległe uruchamianie bloku kodu dla wielu obiektów 20.7. Ograniczanie liczby wątków z wykorzystaniem ich puli 20.8. Sterowanie zewnętrznym procesem za pomocą metody popen 20.9. Przechwytywanie strumienia wyjściowego i informacji o błędach z polecenia powłoki w systemie Unix 20.10. Zarządzanie procesami w innym komputerze 20.11. Unikanie zakleszczeń 21. Interfejs użytkownika .................................................................................................773 774 21.1. Pobieranie danych wejściowych wiersz po wierszu 21.2. Pobieranie danych wejściowych znak po znaku 776 778 21.3. Przetwarzanie argumentów wiersza polecenia 21.4. Sprawdzenie, czy program działa w trybie interaktywnym 781 21.5. Konfiguracja i porządkowanie po programie wykorzystującym 767 768 770 782 784 785 787 790 791 792 795 798 bibliotekę Curses 21.6. Czyszczenie ekranu 21.7. Określenie rozmiaru terminala 21.8. Zmiana koloru tekstu 21.9. Odczytywanie haseł 21.10. Edycja danych wejściowych z wykorzystaniem biblioteki Readline 21.11. Sterowanie migotaniem diod na klawiaturze 21.12. Tworzenie aplikacji GUI z wykorzystaniem biblioteki Tk 21.13. Tworzenie aplikacji GUI z wykorzystaniem biblioteki wxRuby 14 | Spis treści 21.14. Tworzenie aplikacji GUI z wykorzystaniem biblioteki Ruby/GTK 21.15. Tworzenie aplikacji Mac OS X z wykorzystaniem biblioteki RubyCocoa 21.16. Wykorzystanie AppleScript do pobierania danych wejściowych od użytkownika 802 805 812 22. Rozszerzenia języka Ruby z wykorzystaniem innych języków ...............................815 816 819 822 825 827 22.1. Pisanie rozszerzeń w języku C dla języka Ruby 22.2. Korzystanie z bibliotek języka C z poziomu kodu Ruby 22.3. Wywoływanie bibliotek języka C za pomocą narzędzia SWIG 22.4. Kod w języku C wstawiany w kodzie Ruby 22.5. Korzystanie z bibliotek Javy za pośrednictwem interpretera JRuby 23. Administrowanie systemem ......................................................................................831 832 833 835 836 23.1. Pisanie skryptów zarządzających zewnętrznymi programami 23.2. Zarządzanie usługami systemu Windows 23.3. Uruchamianie kodu w imieniu innego użytkownika 23.4. Okresowe uruchamianie zadań bez używania mechanizmu cron lub at 23.5. Usuwanie plików, których nazwy spełniają kryteria określone przez wyrażenie regularne 23.6. Zmiana nazw grupy plików 23.7. Wyszukiwanie plików zdublowanych 23.8. Automatyczne wykonywanie kopii zapasowych 23.9. Ujednolicanie własności i uprawnień w katalogach użytkowników 23.10. Niszczenie wszystkich procesów wybranego użytkownika 838 840 842 845 846 849 Skorowidz ................................................................................................................... 853 Spis treści | 15 ROZDZIAŁ 1. Łańcuchy Ruby jest językiem przyjaznym programiście. Przed programistami hołdującymi filozofii pro- gramowania zorientowanego obiektowo odkryje on drugą jego naturę; programiści stroniący od obiektów nie powinni mieć natomiast większych trudności, bowiem — w odróżnieniu od wielu innych języków — w języku Ruby stosuje się zwięzłe i konsekwentne nazewnictwo me- tod, które generalnie zachowują się tak, jak (intuicyjnie) można by tego oczekiwać. Łańcuchy znakomicie nadają się na obszar „pierwszego kontaktu” z językiem Ruby: są uży- teczne, łatwo się je tworzy i wykorzystuje, występują w większości języków, a więc służyć mogą zarówno jako materiał porównawczy, jak i okazja do przedstawienia koncepcyjnych nowości języka Ruby w rodzaju duck typing (receptura 1.12), otwartych klas (receptura 1.10), symboli (receptura 1.7), a nawet gemów (receptura 1.20). Omawiane koncepcje ilustrujemy konsekwentnie interaktywnymi sesjami języka Ruby. W śro- dowisku Uniksa i Mac OS X służy do tego program irb, uruchamiany z wiersza poleceń. Użyt- kownicy Windows mogą także wykorzystywać w tym celu program fxri, dostępny za pomo- cą menu Start (po zainstalowaniu środowiska Ruby za pomocą pakietu „one-click installer”, który pobrać można spod adresu http:/rubyforge.org/projects/rubyinstaller). Program irb jest rów- nież dostępny w Windows. Wspomniane programy tworzą po uruchomieniu interaktywną po- włokę języka Ruby, pod kontrolą której wykonywać można fragmenty przykładowego kodu. Łańcuchy języka Ruby podobne są do łańcuchów w innych „dynamicznych” językach — Perlu, Pythonie czy PHP. Nie różnią się zbytnio od łańcuchów znanych z języków C i Java. Są dyna- miczne, elastyczne i modyfikowalne. Rozpocznijmy więc naszą sesję, wpisując do wiersza poleceń powłoki następujący tekst: string = To jest napis Spowoduje to wyświetlenie rezultatu wykonania polecenia: = To jest napis Polecenie to powoduje utworzenie łańcucha To jest napis i przypisanie go zmiennej o na- zwie string. Łańcuch ten staje się więc wartością zmiennej i jednocześnie wartością całego wy- rażenia, co uwidocznione zostaje w postaci wyniku wypisywanego (po strzałce = ) w ramach interaktywnej sesji. W treści książki zapisywać będziemy ten rodzaj interakcji w postaci string To jest napis = To jest napis W języku Ruby wszystko, co można przypisać zmiennej, jest obiektem. W powyższym przy- kładzie zmienna string wskazuje na obiekt klasy String. Klasa ta definiuje ponad sto metod 29 — nazwanych fragmentów kodu służących do wykonywania rozmaitych operacji na łańcu- chach. Wiele z tych metod wykorzystywać będziemy w naszej książce, także w niniejszym rozdziale. Jedna z tych metod — String#length — zwraca rozmiar łańcucha, czyli liczbę skła- dających się na niego bajtów: string.length = 13 W wielu językach programowania wymagana (lub dopuszczalna) jest para nawiasów po na- zwie wywoływanej metody: string.length() = 13 W języku Ruby nawiasy te są niemal zawsze nieobowiązkowe, szczególnie w sytuacji, gdy do wywoływanej metody nie są przekazywane żadne parametry (jak w powyższym przykła- dzie). Gdy parametry takie są przekazywane, użycie nawiasów może uczynić całą konstruk- cję bardziej czytelną: string.count s = 2 # s występuje dwukrotnie string.count( s ) = 2 Wartość zwracana przez metodę sama z siebie jest obiektem. W przypadku metody String# length, wywoływanej w powyższym przykładzie, obiekt ten jest liczbą 20, czyli egzempla- rzem (instancją) klasy Fixnum. Ponieważ jest obiektem, można na jego rzecz także wywoły- wać metody: string.length.next = 14 Weźmy teraz pod uwagę bardziej ciekawy przypadek — łańcuch zawierający znaki spoza kodu ASCII. Poniższy łańcuch reprezentuje francuskie zdanie „il était une fois” zakodowane według UTF-81: french_string = il xc3xa9tait une fois # = il 303251tait une fois Wiele języków programowania, między innymi Java, traktuje łańcuchy jako ciągi znaków. W języku Ruby łańcuch postrzegany jest jako ciąg bajtów. Ponieważ powyższy łańcuch za- wiera 14 liter i 3 spacje, można by domniemywać, że jego długość wynosi 17; ponieważ jedna z liter jest znakiem dwubajtowym, łańcuch składa się z 18, nie 17 bajtów: french_string.length # = 18 Do różnorodnego kodowania znaków powrócimy w recepturach 1.14 i 11.12; specyfiką łań- cuchów zawierających znaki wielobajtowe zajmiemy się także w recepturze 1.8. Znaki specjalne (tak jak binarne dane w łańcuchu french_string) mogą być reprezentowane za pomocą tzw. sekwencji unikowych (escaping). Ruby udostępnia kilka rodzajów takich se- kwencji w zależności od tego, w jaki sposób tworzony jest dany łańcuch. Jeżeli mianowicie łańcuch ujęty jest w cudzysłów ( ... ), można w nim kodować zarówno znaki binarne (jak w przykładowym łańcuchu francuskim), jak i znak nowego wiersza znany z wielu innych języków: puts Ten łańcuch zawiera znak nowego wiersza # Ten łańcuch # zawiera znak nowego wiersza W łańcuchu zamkniętym znakami apostrofu ( ... ) jedynym dopuszczalnym znakiem specjalnym jest odwrotny ukośnik (backslash), umożliwiający reprezentowanie pojedyncze- go znaku specjalnego; para \ reprezentuje pojedynczy backslash. 1 xc3xa9 jest zapisem w języku Ruby unikodowego znaku é w reprezentacji UTF-8. 30 | Rozdział 1. Łańcuchy puts Ten łańcuch wbrew pozorom niezawiera znaku nowego wiersza # Ten łańcuch wbrew pozorom niezawiera znaku nowego wiersza puts To jest odwrotny ukośnik: \ # To jest odwrotny ukośnik: Do kwestii tej powrócimy w recepturze 1.5, a w recepturach 1.2 i 1.3 zajmiemy się bardziej spektakularnymi możliwościami łańcuchów ograniczonych apostrofami. Oto inna użyteczna możliwość inicjowania łańcucha, nazywana w języku Ruby here documents: long_string = EOF To jest długi łańcuch Składający się z kilku akapitów EOF # = To jest długi łańcuch Składający się z kilku akapitów puts long_string # To jest długi łańcuch # Składający się z kilku akapitów Podobnie jak w przypadku większości wbudowanych klas języka Ruby, także w przypadku łańcuchów można kodować tę samą funkcjonalność na wiele różnych sposobów („idiomów”) i programista może dokonać wyboru tego, który odpowiada mu najbardziej. Weźmy jako przy- kład ekstrakcję podłańcucha z długiego łańcucha: programiści preferujący podejście obiekto- we zapewne użyliby do tego celu metody String#slice: string # To jest napis string.slice(3,4) # jest Programiści wywodzący swe nawyki z języka C skłonni są jednak do traktowania łańcuchów jako tablic bajtów — im także Ruby wychodzi naprzeciw, umożliwiając ekstrakcję poszczegól- nych bajtów łańcucha: string[3].chr + string[4].chr + string[5].chr + string[6].chr # = jest Podobnie proste zadanie mają programiści przywykli do Pythona: string[3, 4] # = jest W przeciwieństwie do wielu innych języków programowania, łańcuchy Ruby są modyfiko- walne (mutable) — można je zmieniać już po zadeklarowaniu. Oto wynik działania dwóch me- tod: String#upcase i String#upcase! — zwróć uwagę na istotną różnicę między nimi: string.upcase # = TO JEST NAPIS string # = To jest napis string.upcase! # = TO JEST NAPIS string # = TO JEST NAPIS Przy okazji widoczna staje się jedna z konwencji składniowych języka Ruby: metody „nie- bezpieczne” — czyli głównie te modyfikujące obiekty „w miejscu” — opatrywane są nazwami kończącymi się wykrzyknikiem. Inna konwencja syntaktyczna związana jest z predykatami, czyli metodami zwracającymi wartość true albo false — ich nazwy kończą się znakiem za- pytania. string.empty? # = false string.include? To # = true Użycie znaków przestankowych charakterystycznych dla języka potocznego, w celu uczynie- nia kodu bardziej czytelnym dla programisty, jest odzwierciedleniem filozofii twórcy języka Ruby, Yukihiro „Matza” Matsumoto, zgodnie z którą to filozofią Ruby powinien być czytelny 1.1. Budowanie łańcucha z części | 31 przede wszystkim dla ludzi, zaś możliwość wykonywania zapisanych w nim programów przez interpreter jest kwestią wtórną. Interaktywne sesje języka Ruby są niezastąpionym narzędziem umożliwiającym poznawanie metod języka i praktyczne eksperymentowanie z nimi. Ponownie zachęcamy do osobistego sprawdzania prezentowanego kodu w ramach sesji programu irb lub fxri, a z biegiem cza- su tworzenia i testowania także własnych przykładów. Dodatkowe informacje na temat łańcuchów Ruby można uzyskać z następujących źródeł: • Informację o dowolnej wbudowanej metodzie języka można otrzymać wprost w oknie programu fxri, wybierając odnośną pozycję w lewym panelu. W programie irb można użyć w tym celu polecenia ri — na przykład informację o metodzie String#upcase! uzy- skamy za pomocą polecenia ri String#upcase! • why the lucky stiff napisał wspaniałe wprowadzenie do instalacji języka Ruby oraz wyko- rzystywania poleceń ir i irb. Jest ono dostępne pod adresem http://poignantguide.net/ruby/ expansion-pak-1.html. • Filozofię projektową języka Ruby przedstawia jego autor, Yukihiro „Matz” Matsumoto, w wywiadzie dostępnym pod adresem http://www.artima.com/intv/ruby.html. 1.1. Budowanie łańcucha z części Problem Iterując po strukturze danych, należy zbudować łańcuch reprezentujący kolejne kroki tej iteracji. Rozwiązanie Istnieją dwa efektywne rozwiązania tego problemu. W najprostszym przypadku rozpoczy- namy od łańcucha pustego, sukcesywnie dołączając do niego podłańcuchy za pomocą ope- ratora : hash = { key1 = val1 , key2 = val2 } string = hash.each { |k,v| string #{k} is #{v} } puts string # key1 is val1 # key2 is val2 Poniższa odmiana tego prostego rozwiązania jest nieco efektywniejsza, chociaż mniej czytelna: string = hash.each { |k,v| string k is v } Jeśli wspomnianą strukturą danych jest tablica, bądź też struktura ta daje się łatwo przetrans- formować na tablicę, zwykle bardziej efektywne rozwiązanie można uzyskać za pomocą me- tody Array#join: puts hash.keys.join( ) + # key1 # key2 32 | Rozdział 1. Łańcuchy Dyskusja W językach takich jak Pyton czy Java sukcesywne dołączanie podłańcuchów do pustego po- czątkowo łańcucha jest rozwiązaniem bardzo nieefektywnym. Łańcuchy w tych językach są niemodyfikowalne (immutable), a więc każdorazowe dołączenie podłańcucha wiąże się ze stworzeniem nowego obiektu. Dołączanie serii podłańcuchów oznacza więc tworzenie dużej liczby obiektów pośrednich, z których każdy stanowi jedynie „pomost” do następnego etapu. W praktyce przekłada się to na marnotrawstwo czasu i pamięci. W tych warunkach rozwiązaniem najbardziej efektywnym byłoby zapisanie poszczególnych podłańcuchów w tablicy (lub innej modyfikowalnej strukturze) zdolnej do dynamicznego roz- szerzania się. Gdy wszystkie podłańcuchy zostaną już zmagazynowane we wspomnianej ta- blicy, można połączyć je w pojedynczy łańcuch za pomocą operatora stanowiącego odpowied- nik metody Array#join języka Ruby. W języku Java zadanie to spełnia klasa StringBuffer. Unikamy w ten sposób tworzenia wspomnianych obiektów pośrednich. W języku Ruby sprawa ma się zgoła inaczej, bo łańcuchy są tu modyfikowalne, podobnie jak tablice. Mogą więc być rozszerzane w miarę potrzeby, bez zbytniego obciążania pamięci lub procesora. W najszybszym wariancie rozwiązania możemy więc w ogóle zapomnieć o tabli- cy pośredniczącej i umieszczać poszczególne podłańcuchy bezpośrednio wewnątrz łańcucha docelowego. Niekiedy skorzystanie z Array#join okazuje się szybsze, lecz zwykle niewiele szybsze, ponadto konstrukcja oparta na jest generalnie łatwiejsza do zrozumienia. W sytuacji, gdy efektywność jest czynnikiem krytycznym, nie należy tworzyć nowych łańcu- chów, jeżeli możliwe jest dołączanie podłańcuchów do łańcucha istniejącego. Konstrukcje w rodzaju str a + b czy str #{var1} #{var2} powodują tworzenie nowych łańcuchów, które natychmiast „podłączane” są do większego łańcucha — a tego właśnie chcielibyśmy unikać. Umożliwia nam to konstrukcja str var1 var2 Z drugiej jednak strony, nie powinno się modyfikować łańcuchów nietworzonych przez sie- bie i względy bezpieczeństwa przemawiają za tworzeniem nowego łańcucha. Gdy definiujesz metodę otrzymującą łańcuch jako parametr, metoda ta nie powinna modyfikować owego łań- cucha przez dołączanie podłańcuchów na jego końcu — chyba że właśnie to jest celem meto- dy (której nazwa powinna tym samym kończyć się wykrzyknikiem, dla zwrócenia szczegól- nej uwagi osoby studiującej kod programu). Przy okazji ważna uwaga: działanie metody Array#join nie jest dokładnie równoważne do- łączaniu kolejnych podłańcuchów do łańcucha. Array#join akceptuje separator, który wsta- wiany jest między każde dwa sąsiednie elementy tablicy; w przeciwieństwie do sukcesywne- go dołączania podłańcuchów, separator ten nie jest umieszczany po ostatnim elemencie. Różnicę tę ilustruje poniższy przykład: data = [ 1 , 2 , 3 ] s = data.each { |x| s x oraz } s # = 1 oraz 2 oraz 3 oraz data.join( oraz ) # = 1 oraz 2 oraz 3 1.1. Budowanie łańcucha z części | 33 Aby zasymulować działanie Array#join za pomocą iteracji, można wykorzystać metodę Enumerable#each_with_index, opuszczając separator dla ostatniego indeksu. Da się to jed- nak zrobić tylko wówczas, gdy liczba elementów objętych enumeracją znana jest a priori: s = data.each_with_index { |x, i| s x; s | if i data.length-1 } s # = 1|2|3 1.2. Zastępowanie zmiennych w tworzonym łańcuchu Problem Należy stworzyć łańcuch zawierający reprezentację zmiennej lub wyrażenia języka Ruby. Rozwiązanie Należy wewnątrz łańcucha zamknąć zmienną lub wyrażenie w nawiasy klamrowe i poprze- dzić tę konstrukcję znakiem # (hash). liczba = 5 Liczba jest równa #{liczba}. # = Liczba jest równa 5. Liczba jest równa #{5}. # = Liczba jest równa 5. Liczba następna po #{liczba} równa jest #{liczba.next}. # = Liczba następna po 5 równa jest 6. Liczba poprzedzająca #{liczba} równa jest #{liczba-1}. # = Liczba poprzedzająca 5 równa jest 4. To jest ##{number}! # = To jest #5! Dyskusja Łańcuch ujęty w cudzysłów ( ... ) jest przez interpreter skanowany pod kątem obecności specjalnych kodów substytucyjnych. Jednym z najbardziej elementarnych i najczęściej używa- nych kodów tego typu jest znak , zastępowany znakiem nowego wiersza. Oczywiście istnieją bardziej skomplikowane kody substytucyjne. W szczególności dowolny tekst zamknięty w nawiasy klamrowe poprzedzone znakiem # (czyli konstrukcja #{tekst}) interpretowany jest jako wyrażenie języka Ruby, a cała konstrukcja zastępowana jest w łań- cuchu wartością tego wyrażenia. Jeżeli wartość ta nie jest łańcuchem, Ruby dokonuje jej kon- wersji na łańcuch za pomocą metody to_s. Proces ten nosi nazwę interpolacji. Tak powstały łańcuch staje się nieodróżnialny od łańcucha, w którym interpolacji nie zasto- sowano: #{liczba} == 5 # = true Za pomocą interpolacji można umieszczać w łańcuchu nawet spore porcje tekstu. Przypad- kiem ekstremalnym jest definiowanie klasy wewnątrz łańcucha i wykorzystanie podłańcucha stanowiącego wynik wykonania określonej metody tej klasy. Mimo ograniczonej raczej uży- teczności tego mechanizmu, warto go zapamiętać jako dowód wspaniałych możliwości języ- ka Ruby. {Tutaj jest #{class InstantClass def bar pewien tekst end end 34 | Rozdział 1. Łańcuchy InstantClass.new.bar }.} # = Tutaj jest pewien tekst. Kod wykonywany w ramach interpolacji funkcjonuje dokładnie tak samo, jak każdy inny kod Ruby w tej samej lokalizacji. Definiowana w powyższym przykładzie klasa InstantClass nie różni się od innych klas i może być używana także na zewnątrz łańcucha. Gdy w ramach interpolacji wywoływana jest metoda powodująca efekty uboczne, efekty te widoczne są na zewnątrz łańcucha. W szczególności, jeżeli efektem ubocznym jest nadanie war- tości jakiejś zmiennej, zmienna ta zachowuje tę wartość na zewnątrz łańcucha. Mimo iż nie po- lecamy celowego polegania na tej własności, należy koniecznie mieć świadomość jej istnienia. Zmiennej x nadano wartość #{x = 5; x += 1}. # = Zmiennej x nadano wartość 6. x # = 6 Jeżeli chcielibyśmy potraktować występującą w łańcuchu sekwencję #{tekst} w sposób lite- ralny, nie jako polecenie interpolacji, wystarczy poprzedzić ją znakiem odwrotnego ukośnika () albo zamknąć łańcuch znakami apostrofu zamiast cudzysłowu: #{foo} # = #{foo} #{foo} # = #{foo} Alternatywnym dla {} kodem substytucyjnym jest konstrukcja here document. Pozwala ona na zdefiniowanie wielowierszowego łańcucha, którego ogranicznikiem jest wiersz o wyróż- nionej postaci. name = Mr. Lorum email = END Szanowny #{name}, Niestety, nie możemy pozytywnie rozpatrzyć Pańskiej reklamacji w związku z oszacowaniem szkody, gdyż jesteśmy piekarnią, nie firmą ubezpieczeniową. Podpisano, Buła, Rogal i Precel Piekarze Jej Królewskiej Wysokości END Język Ruby pozostawia programiście dużą swobodę w zakresie wyboru postaci wiersza ogra- niczającego: koniec_wiersza Pewien poeta z Afryki Pisał dwuwierszowe limeryki koniec_wiersza # = Pewien poeta z Afryki Pisał dwuwierszowe limeryki Patrz także • Za pomocą techniki opisanej w recepturze 1.3 można definiować łańcuchy i obiekty sza- blonowe, umożliwiające „odroczoną” interpolację. 1.3. Zastępowanie zmiennych w istniejącym łańcuchu Problem Należy utworzyć łańcuch umożliwiający interpolację wyrażenia języka Ruby, jednakże bez wykonywania tej interpolacji — ta wykonana zostanie później, prawdopodobnie wtedy, gdy będą znane wartości zastępowanych wyrażeń. 1.3. Zastępowanie zmiennych w istniejącym łańcuchu | 35 Rozwiązanie Problem można rozwiązać za pomocą dwojakiego rodzaju środków: łańcuchów typu printf oraz szablonów ERB. Ruby zapewnia wsparcie dla znanych z C i Pythona łańcuchów formatujących typu printf. Kody substytucyjne w ramach tych łańcuchów mają postać dyrektyw rozpoczynających się od znaku (modulo): template = Oceania zawsze była w stanie wojny z s. template Eurazją # = Oceania zawsze była w stanie wojny z Eurazją. template Antarktydą # = Oceania zawsze była w stanie wojny z Antarktydą. Z dwoma miejscami dziesiętnymi: .2f Math::PI # = Z dwoma miejscami dziesiętnymi: 3.14 Dopełnione zerami: .5d Math::PI # = Dopełnione zerami: 00003 Szablony ERB przypominają swą postacią kod w języku JSP lub PHP. Zasadniczo szablon ERB traktowany jest jako „normalny” łańcuch, jednak pewne sekwencje sterujące traktowane są jako kod w języku Ruby lub aktualne wartości wyrażeń: template = ERB.new q{Pyszne = food !} food = kiełbaski template.result(binding) # = Pyszne kiełbaski! food = masło orzechowe template.result(binding) # = Pyszne masło orzechowe! Poza sesją irb można pominąć wywołania metody Kernel#binding: puts template.result # Pyszne masło orzechowe! Szablony ERB wykorzystywane są wewnętrznie przez widoki Rails i łatwo można rozpoznać je w plikach .rhtml. Dyskusja W szablonach ERB można odwoływać się do zmiennych (jak food w powyższym przykła- dzie), zanim zmienne te zostaną zdefiniowane. Wskutek wywołania metody ERB#result lub ERB#run szablon jest wartościowany zgodnie z bieżącymi wartościami tych zmiennych. Podobnie jak kod w języku JSP i PHP, szablony ERB mogą zawierać pętle i rozgałęzienia wa- runkowe. Oto przykład rozbudowanego szablonu ERB: template = q{ if problems.empty? Wygląda na to, że w kodzie nie ma błędów! else W kodzie kryją się nastepujące potencjalne problemy: problems.each do |problem, line| * = problem w wierszu = line end end }.gsub(/^s+/, ) template = ERB.new(template, nil, ) problems = [[ Użyj is_a? zamiast duck typing , 23], [ eval() jest potencjalnie niebezpieczne , 44]] template.run(binding) 36 | Rozdział 1. Łańcuchy # W kodzie kryją się nastepujące potencjalne problemy: # * Użyj is_a? zamiast duck typing w wierszu 23 # * eval() jest potencjalnie niebezpieczne w wierszu 44 problems = [] template.run(binding) # Wygląda na to, że w kodzie nie ma błędów! ERB jest wyrafinowanym mechanizmem, jednak ani szablony ERB, ani łańcuchy typu printf nie przypominają w niczym prostych podstawień prezentowanych w recepturze 1.2. Podsta- wienia te nie są aktywowane, jeśli łańcuch ujęty jest w apostrofy ( ... ) zamiast w cudzy- słów ( ... ). Można wykorzystać ten fakt do zbudowania szablonu zawierającego meto- dę eval: class String def substitute(binding=TOPLEVEL_BINDING) eval( { #{self} }, binding) end end template = q{Pyszne #{food}!} # = Pyszne #{food}! food = kiełbaski template.substitute(binding) # = Pyszne kiełbaski! food = masło orzechowe template.substitute(binding) # = Pyszne masło orzechowe! Należy zachować szczególną ostrożność, używając metody eval, bowiem potencjalnie stwarza ona możliwość wykonania dowolnego kodu, z czego skwapliwie skorzystać może ewentual- ny włamywacz. Nie zdarzy się to jednak w poniższym przykładzie, jako że dowolna wartość zmiennej food wstawiona zostaje do łańcucha jeszcze przed jego interpolacją: food = #{system( dir )} puts template.substitute(binding) # Pyszne #{system( dir )}! Patrz także • Powyżej prezentowaliśmy proste przykłady szablonów ERB; przykłady bardziej skom- plikowane znaleźć można w dokumentacji klas ERB pod adresem http://www.ruby-doc.org/ stdlib/libdoc/erb/rdoc/classes/ERB.html. • Receptura 1.2, „Zastępowanie zmiennych w tworzonym łańcuchu”. • Receptura 10.12, „Ewaluacja kodu we wcześniejszym kontekście”, zawiera informacje na temat obiektów Binding. 1.4. Odwracanie kolejności słów lub znaków w łańcuchu Problem Znaki lub słowa występują w łańcuchu w niewłaściwej kolejności. 1.4. Odwracanie kolejności słów lub znaków w łańcuchu | 37 Rozwiązanie Do stworzenia nowego łańcucha, zawierającego znaki łańcucha oryginalnego w odwrotnej kolejności, można posłużyć się metodą reverse: s = .kapo an sipan tsej oT s.reverse # = To jest napis na opak. s # = .kapo an sipan tsej oT s.reverse! # = To jest napis na opak. s # = To jest napis na opak. W celu odwrócenia kolejności słów w łańcuchu, należy podzielić go najpierw na podłańcuchy oddzielone „białymi” znakami2 (czyli poszczególne słowa), po czym włączyć listę tych słów z powrotem do łańcucha, w odwrotnej kolejności. s = kolei. po nie Wyrazy s.split(/(s+)/).reverse!.join( ) # = Wyrazy nie po kolei. s.split(//).reverse!.join( ) # = Wyrazy nie po. kolei Dyskusja Metoda String#split wykorzystuje wyrażenie regularne w roli separatora. Każdorazowo gdy element łańcucha udaje się dopasować do tego wyrażenia, poprzedzająca go część łańcu- cha włączona zostaje do listy, a metoda split przechodzi do skanowania dalszej części łań- cucha. Efektem przeskalowania całego łańcucha jest lista podłańcuchów znajdujących się mię- dzy wystąpieniami separatora. Użyte w naszym przykładzie wyrażenie regularne /(s+)/ reprezentuje dowolny ciąg „białych” znaków, zatem metoda split dokonuje podziału łańcu- cha na poszczególne słowa (w potocznym rozumieniu). Wyrażenie regularne /b reprezentuje granicę słowa; to nie to samo co „biały” znak, bowiem granicę słowa może także wyznaczać znak interpunkcyjny. Zwróć uwagę na konsekwencje tej różnicy w powyższym przykładzie. Ponieważ wyrażenie regularne /(s+)/ zawiera parę nawiasów, separatory także są włącza- ne do listy wynikowej. Jeżeli zatem zestawimy elementy tej listy w kolejności odwrotnej, se- paratory oddzielające słowa będą już obecne na swych miejscach. Poniższy przykład ilustruje różnicę między zachowywaniem a ignorowaniem separatorów: Trzy banalne wyrazy .split(/s+/) # = [ Trzy , banalne , wyrazy ] Trzy banalne wyrazy .split(/(s+)/) # = [ Trzy , , banalne , , wyrazy ] Patrz także • Receptura 1.9, „Przetwarzanie poszczególnych słów łańcucha”, ilustruje kilka wyrażeń regularnych wyznaczających alternatywną definicję „słowa”. • Receptura 1.11, „Zarządzanie białymi znakami”. • Receptura 1.17, „Dopasowywanie łańcuchów za pomocą wyrażeń regularnych”. 2 Pojęcie „białego znaku” wyjaśnione jest w recepturze 1.11 — przyp. tłum. 38 | Rozdział 1. Łańcuchy 1.5. Reprezentowanie znaków niedrukowalnych Problem Należy stworzyć łańcuch zawierający znaki sterujące, znaki w kodzie UTF-8 lub dowolne znaki niedostępne z klawiatury. Rozwiązanie Ruby udostępnia kilka mechanizmów unikowych (escape) w celu reprezentowania znaków niedrukowalnych. W łańcuchach ujętych w cudzysłowy mechanizmy te umożliwiają repre- zentowanie dowolnych znaków. Dowolny znak można zakodować w łańcuchu, podając jego kod ósemkowy (octal) w formie ooo lub kod szesnastkowy (hexadecimal) w formie xhh. octal = 00011020 octal.each_byte { |x| puts x } # 0 # 1 # 8 # 16 hexadecimal = x00x01x10x20 hexadecimal.each_byte { |x| puts x } # 0 # 1 # 16 # 32 W ten sposób umieszczać można w łańcuchach znaki, których nie można wprowadzić bez- pośrednio z klawiatury czy nawet wyświetlić na ekranie terminala. Uruchom poniższy pro- gram, po czym otwórz wygenerowany plik smiley.html w przeglądarce WWW. open( smiley.html , wb ) do |f| f meta http-equiv= Content-Type content= text/html;charset=UTF-8 f xe2x98xBA end Niektóre z niedrukowalnych znaków — te wykorzystywane najczęściej — posiadają specjal- ne, skrócone kody unikowe: a == x07 # = true #ASCII 0x07 = BEL (Dźwięk systemowy)  == x08 # = true #ASCII 0x08 = BS (Cofanie) e == x1b # = true #ASCII 0x1B = ESC (Escape) f == x0c # = true #ASCII 0x0C = FF (Nowa strona) == x0a # = true #ASCII 0x0A = LF (Nowy wiersz) == x0d # = true #ASCII 0x0D = CR (Początek wiersza) == x09 # = true #ASCII 0x09 = HT (Tabulacja pozioma) v == x0b # = true #ASCII 0x0B = VT (Tabulacja pionowa) Dyskusja W języku Ruby łańcuchy są ciągami bajtów. Nie ma znaczenia, czy bajty te są drukowalny- mi znakami ASCII, niedrukowalnymi znakami binarnymi, czy też mieszanką obydwu tych kategorii. 1.5. Reprezentowanie znaków niedrukowalnych | 39 Znaki niedrukowalne wyświetlane są w języku Ruby w czytelnej dla człowieka reprezentacji ooo, gdzie ooo jest kodem znaku w reprezentacji ósemkowej; znaki posiadające reprezenta- cję mnemoniczną w postaci znak wyświetlane są jednak w tej właśnie postaci. Znaki dru- kowalne wyświetlane są zawsze w swej naturalnej postaci, nawet jeżeli w tworzonym łańcu- chu zakodowane zostały w inny sposób. x10x11xfexff # = 2021376377 x48145x6cx6c157x0a # = Hello Znak odwrotnego ukośnika () reprezentowany jest przez parę takich ukośników (\) — jest to konieczne dla odróżnienia literalnego użycia znaku od mnemonicznej sekwencji uniko- wej rozpoczynającej się od takiego znaku. Przykładowo, łańcuch \n składa się z dwóch znaków: odwrotnego ukośnika i litery n. \ .size # = 1 \ == x5c # = true \n [0] == ?\ # = true \n [1] == ?n # = true \n =~ / / # = nil Ruby udostępnia także kilka wygodnych skrótów dla reprezentowania kombinacji klawiszy w rodzaju Ctrl+C. Sekwencja C- znak oznacza rezultat naciśnięcia klawisza znak z jed- noczesnym przytrzymaniem klawisza Ctrl; analogicznie sekwencja M- znak oznacza rezul- tat naciśnięcia klawisza znak z jednoczesnym przytrzymaniem klawisza Alt (lub Meta): C-aC-bC-c # = 010203 # Ctrl+A Ctrl+B Ctrl+C M-aM-bM-c # = 341342343 # Alt+A Alt+B Alt+C Dowolna z opisywanych sekwencji może pojawić się wszędzie tam, gdzie Ruby spodziewa się znaku. W szczególności możliwe jest wyświetlenie kodu znaku w postaci dziesiętnej — na- leży w tym celu poprzedzić ów znak znakiem zapytania (?). ?C-a # = 1 ?M-z # = 250 W podobny sposób można używać rozmaitych reprezentacji znaków do specyfikowania za- kresu znaków w wyrażeniach regularnych: contains_control_chars = /[C-a-C-^]/ Foobar =~ contains_control_chars # = nil FooC-zbar =~ contains_control_chars # = 3 contains_upper_chars = /[x80-xff]/ Foobar =~ contains_upper_chars # = nil Foo212bar =~ contains_upper_chars # = 3 Poniższa aplikacja śledzi („szpieguje”) naciśnięcia klawiszy, reagując na niektóre kombinacje specjalne: def snoop_on_keylog(input) input.each_byte do |b| case b when ?C-c; puts Ctrl+C: zatrzymać proces? when ?C-z; puts Ctrl+Z: zawiesić proces? when ? ; puts Nowy wiersz. when ?M-x; puts Alt+X: uruchomić Emacs? end end end snoop_on_keylog( ls -ltR03emacsHello12370rot13-other-window1232 ) # Ctrl+C: zatrzymać proces? 40 | Rozdział 1. Łańcuchy # Nowy wiersz. # Alt+X: uruchomić Emacs? # Nowy wiersz. # Ctrl+Z: zawiesić proces? Sekwencje reprezentujące znaki specjalne interpretowane są tylko w łańcuchach ujętych w cudzysłów oraz łańcuchach tworzonych za pomocą konstrukcji {} lub Q{}. Nie są one interpretowane w łańcuchach zamkniętych znakami apostrofu oraz łańcuchach tworzonych za pomocą konstrukcji q{}. Fakt ten można wykorzystać w przypadku potrzeby literalnego wyświetlenia sekwencji reprezentujących znaki specjalne oraz w przypadku tworzenia łańcu- chów zawierających dużą liczbę odwrotnych ukośników. puts foo bar # foo bar puts {foo bar} # foo bar puts Q{foo bar} # foo bar puts foo bar # foo bar puts q{foo bar} # foo bar Nieinterpretowanie sekwencji reprezentujących znaki specjalne w łańcuchach zamkniętych znakami apostrofu może wydać się dziwne — i niekiedy nieco kłopotliwe — programistom przyzwyczajonym do języka Python. Jeżeli łańcuch ujęty w cudzysłów sam zawiera znaki cudzysłowu ( ), jedynym sposobem reprezentowania tychże jest użycie sekwencji unikowej , 42 lub x22. W przypadku łańcuchów obfitujących w znaki cudzysłowu może się to wydać kłopotliwe i najwygodniejszym rozwiązaniem jest zamknięcie łańcucha apostrofami — znaków cudzysłowu można wówczas używać literalnie, tracimy jednak możliwość inter- pretowania znaków specjalnych. Na szczęście istnieje złoty środek pozwalający na pogodze- nie tych sprzecznych racji: jeśli chcesz zachować możliwość interpretowania znaków specjal- nych w łańcuchach najeżonych znakami cudzysłowu, użyj konstrukcji {}. 1.6. Konwersja między znakami a kodami Problem Chcemy otrzymać kod ASCII danego znaku lub przetransformować kod ASCII znaku w sam znak. Rozwiązanie Kod ASCII znaku możemy poznać za pomocą operatora ?: ?a # = 97 ?! # = 33 ? # = 10 W podobny sposób możemy poznać kod ASCII znaku wchodzącego w skład łańcucha — na- leży wówczas wyłuskać ów znak z łańcucha za pomocą indeksu: a [0] # = 97 kakofonia [1] # = 97 1.6. Konwersja między znakami a kodami | 41 Konwersję odwrotną — kodu ASCII na znak o tym kodzie — realizuje metoda chr, zwracają- ca jednoznakowy łańcuch: 97.chr # = a 33.chr # = ! 10.chr # = 0.chr # = 00 256.chr # RangeError: 256 out of char range Dyskusja Mimo iż łańcuch jako taki nie jest tablicą, może być utożsamiany z tablicą obiektów Fixnum — po jednym obiekcie dla każdego bajta. Za pomocą odpowiedniego indeksu można wyłu- skać obiekt Fixnum reprezentujący konkretny bajt łańcucha, czyli kod ASCII tego bajta. Za po- mocą metody String#each_byte można iterować po wszystkich obiektach Fixnum tworzących dany łańcuch. Patrz także • Receptura 1.8, „Przetwarzanie kolejnych znaków łańcucha”. 1.7. Konwersja między łańcuchami a symbolami Problem Mając symbol języka Ruby, należy uzyskać reprezentujący go łańcuch, lub vice versa — ziden- tyfikować symbol odpowiadający danemu łańcuchowi. Rozwiązanie Konwersję symbolu na odpowiadający mu łańcuch realizuje metoda Symbol#to_s lub metoda Symbol#id2name, dla której to_s jest aliasem. :a_symbol.to_s # = a_symbol :InnySymbol.id2name # = InnySymbol : Jeszcze jeden symbol! .to_s # = Jeszcze jeden symbol! Odwołanie do symbolu następuje zwykle przez jego nazwę. Aby uzyskać symbol reprezento- wany przez łańcuch w kodzie programu, należy posłużyć się metodą String.intern: :dodecahedron.object_id # = 4565262 symbol_name = dodecahedron symbol_name.intern # = :dodecahedron symbol_name.intern.object_id # = 4565262 Dyskusja Symbol jest najbardziej podstawowym obiektem języka Ruby. Każdy symbol posiada nazwę i wewnętrzny identyfikator (internal ID). Użyteczność symboli wynika z faktu, że wielokrot- ne wystąpienie tej samej nazwy w kodzie programu oznacza każdorazowo odwołanie do te- go samego symbolu. 42 | Rozdział 1. Łańcuchy Symbole są często bardziej użyteczne niż łańcuchy. Dwa łańcuchy o tej samej zawartości są dwoma różnymi obiektami — można jeden z nich zmodyfikować bez wpływu na drugi. Dwie identyczne nazwy odnoszą się do tego samego symbolu, co oczywiście przekłada się na oszczędność czasu i pamięci. string .object_id # = 1503030 string .object_id # = 1500330 :symbol.object_id # = 4569358 :symbol.object_id # = 4569358 Tak więc n wystąpień tej samej nazwy odnosi się do tego samego symbolu, przechowywanego w pamięci w jednym egzemplarzu. n identycznych łańcuchów to n różnych obiektów o iden- tycznej zawartości. Także porównywanie symboli jest szybsze niż porównywanie łańcuchów, bowiem sprowadza się jedynie do porównywania identyfikatorów. string1 == string2 # = false :symbol1 == :symbol2 # = false Na koniec zacytujmy hakera od języka Ruby, Jima Wericha: • Użyj łańcucha, jeśli istotna jest zawartość obiektu (sekwencja tworzących go znaków). • Użyj symbolu, jeśli istotna jest tożsamość obiektu. Patrz także • Receptura 5.1, „Wykorzystywanie symboli jako kluczy”. • Receptura 8.12, „Symulowanie argumentów zawierających słowa kluczowe”. • Rozdział 10., a szczególnie receptura 10.4, „Uzyskiwanie referencji do metody”, i receptu- ra 10.10, „Oszczędne kodowanie dzięki metaprogramowaniu”. • http://glu.ttono.us/articles/2005/08/19/understanding-ruby-symbols — interesujący artykuł o sym- bolach języka Ruby. 1.8. Przetwarzanie kolejnych znaków łańcucha Problem Należy wykonać pewną czynność w stosunku do każdego znaku łańcucha z osobna. Rozwiązanie W dokumencie złożonym wyłącznie ze znaków ASCII każdy bajt łańcucha odpowiada jedne- mu znakowi. Za pomocą metody String#each_byte można wyodrębnić poszczególne bajty jako liczby, które następnie mogą być skonwertowane na znaki. foobar .each_byte { |x| puts #{x} = #{x.chr} } # 102 = f # 111 = o # 111 = o # 98 = b # 97 = a # 114 = r 1.8. Przetwarzanie kolejnych znaków łańcucha | 43 Za pomocą metody String#scan można wyodrębnić poszczególne znaki łańcucha jako jedno- znakowe łańcuchy: foobar .scan( /./ ) { |c| puts c } # f # o # o # b # a # r Dyskusja Ponieważ łańcuch jest sekwencją bajtów, można by oczekiwać, że metoda String#each umoż- liwia iterowanie po tej sekwencji, podobnie jak metoda Array#each. Jest jednak inaczej — me- toda String#each dokonuje podziału łańcucha na podłańcuchy względem pewnego separa- tora (którym domyślnie jest znak nowego wiersza): foo bar .each { |x| puts x } # foo # bar Odpowiednikiem metody Array#each w odniesieniu do łańcuchów jest metoda each_byte. Każdy element łańcucha może być traktowany jako obiekt Fixnum, a metoda each_byte umoż- liwia iterowanie po sekwencji tych obiektów. Metoda String#each_byte jest szybsza niż String#scan i jako taka zalecana jest w przypad- ku przetwarzania plików ASCII — każdy wyodrębniony obiekt Fixnum może być łatwo prze- kształcony w znak (jak pokazano w Rozwiązaniu). Metoda String#scan dokonuje sukcesywnego dopasowywania podanego wyrażenia regu- larnego do kolejnych porcji łańcucha i wyodrębnia każdą z tych opcji. Jeżeli wyrażeniem tym jest /./, wyodrębniane są poszczególne znaki łańcucha. Jeśli zmienna $KCODE jest odpowiednio ustawiona, metoda scan może być stosowana także do łańcuchów zawierających znaki w kodzie UTF-8. Jest to najprostsza metoda przeniesienia koncepcji „znaku” na grunt łańcuchów języka Ruby, które z definicji są ciągami bajtów, nie znaków. Poniższy łańcuch zawiera zakodowaną w UTF-8 francuską frazę „ça va”: french = xc3xa7a va Nawet jeżeli znaku ç nie sposób poprawnie wyświetlić na terminalu, poniższy przykład ilu- struje zmianę zachowania metody String#scan w sytuacji, gdy określi się wyrażenie regu- larne stosownie do standardów Unicode lub ustawi zmienną $KCODE tak, by Ruby traktował wszystkie łańcuchy jako kodowane według UTF-8: french.scan(/./) { |c| puts c } # Ă # § # a # # v # a french.scan(/./u) { |c| puts c } # ç # a # 44 | Rozdział 1. Łańcuchy # v # a $KCODE = u french.scan(/./) { |c| puts c } # ç # a # # v # a Gdy Ruby traktuje łańcuchy jako sekwencje znaków UTF-8, a nie ASCII, dwa bajty reprezen- tujące znak ç traktowane są łącznie, jako pojedynczy znak. Nawet jeśli niektórych znaków UTF-8 nie można wyświetlić na ekranie terminala, można stworzyć programy, które zajmą się ich obsługą. Patrz także • Receptura 11.12, „Konwersja dokumentu między różnymi standardami kodowania”. 1.9. Przetwarzanie poszczególnych słów łańcucha Problem Należy wydzielić z łańcucha jego kolejne słowa i dla każdego z tych słów wykonać pewną czynność. Rozwiązanie Najpierw należy zastanowić się nad tym, co rozumiemy pod pojęciem „słowa” w łańcuchu. Co oddziela od siebie sąsiednie słowa? Tylko białe znaki, czy może także znaki interpunkcyj- ne? Czy „taki-to-a-taki” to pojedyncze słowo, czy może cztery słowa? Te i inne kwestie roz- strzyga się jednoznacznie, definiując wyrażenie regularne reprezentujące pojedyncze słowo (kilka przykładów takich wyrażeń podajemy poniżej w Dyskusji). Wspomniane wyrażenie regularne należy przekazać jako parametr metody String#scan, któ- ra tym samym dokona podzielenia łańcucha na poszczególne słowa. Prezentowana poniżej metoda word_count zlicza wystąpienia poszczególnych słów w analizowanym tekście; zgod- nie z użytym wyrażeniem regularnym „słowo” ma składnię identyczną z identyfikatorem ję- zyka Ruby, jest więc ciągiem liter, cyfr i znaków podkreślenia: class String def word_count frequencies = Hash.new(0) downcase.scan(/w+/) { |word| frequencies[word] += 1 } return frequencies end end {Dogs dogs dog dog dogs.}.word_count # = { dogs = 3, dog = 2} { I have no shame, I said.}.word_count
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Ruby. Receptury
Autor:
,

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: