{ "metadata": { "language": "ruby", "name": "", "signature": "sha256:23f9633c9931b45ff0bbb11f4f1b402bc484219b8ae917b4e08887e0a58686c9" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Funkcje oraz instrukcje warunkowe" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Definiowanie funkcji" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Definiowane funkcji w Ruby odbywa si\u0119 za pomoc\u0105 s\u0142\u00f3w kluczowych `def` i `end`. Najprostsza funkcj mo\u017ce wygl\u0105da\u0107 nast\u0119puj\u0105co:\n", "```ruby\n", "def pozdrowienie\n", " puts \"Witaj epi\"\n", "end\n", "```\n", "\n", "Wywo\u0142ujemy j\u0105 podaj\u0105c jej nazw\u0119, np.\n", "```ruby\n", "pozdrowienie\n", "pozdrowienie\n", "pozdrowienie\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nawiasy w wywo\u0142aniu s\u0105 opcjonalne, w szczeg\u00f3lno\u015bci, je\u015bli funkcja nie przyjmuje parametr\u00f3w. Ale mo\u017cna r\u00f3wnie\u017c j\u0105 wywo\u0142a\u0107 z nawiasami - w szczeg\u00f3lno\u015bci je\u015bli mamy zagnie\u017cd\u017cone wywo\u0142ania funkcji:\n", "```ruby\n", "pozdrowienie()\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Uwaga**: IRuby zapami\u0119tuje zdefiniowane funkcje, ale tylko w ramach jednej sesji uruchomieniowej. Dlatego je\u015bli chcemy wykorzysta\u0107 wcze\u015bniej zdefiniowan\u0105 funkcj\u0119 w innej kom\u00f3rce, musimy si\u0119 upewni\u0107, czy zosta\u0142a zdefiniowana w tej samej sesji." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Funkcje mog\u0105 przyjmowa\u0107 parametry. Poniewa\u017c Ruby jest j\u0119zykiem dynamicznie typizowanym, nie okre\u015blamy ich typ\u00f3w, a jedynie nazwy:\n", "```ruby\n", "def pozdrowienie(imie)\n", " puts \"Witaj #{imie}\"\n", "end\n", "\n", "pozdrowienie(\"Anno\")\n", "pozdrowienie(\"B\u0142a\u017ceju\")\n", "pozdrowienie(\"Zosiu\")\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Parametry mog\u0105 by\u0107 opcjonalne - je\u015bli nie przeka\u017cemy warto\u015bci, to zostanie u\u017cyta warto\u015b\u0107 domy\u015blna, np.\n", "```ruby\n", "def pozdrowienie(imie=\"cz\u0142owieku\")\n", " puts \"Witaj #{imie}\"\n", "end\n", "\n", "pozdrowienie(\"Anno\")\n", "pozdrowienie\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Jako sw\u00f3j wynik, funkcje zwracaj\u0105 warto\u015b\u0107 ostatniego ewaluowanego (obliczanego) wyra\u017cenia, np.\n", "```ruby\n", "def razy_dwa(wartosc)\n", " 2 * wartosc\n", "end\n", "\n", "razy_dwa(2)\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Warto zwr\u00f3ci\u0107 uwag\u0119, \u017ce funkcja nie zawsze wypisuje co\u015b na ekran (por\u00f3wnaj funkcje `pozdrowienie` oraz `razy_dwa`)! Dlatego je\u015bli wywo\u0142ujemy funkcje, kt\u00f3re tylko zwracaj\u0105 warto\u015b\u0107, musimy sami wy\u015bwietli\u0107 ich wynik. W przeciwnym razie zostanie wy\u015bwietlona warto\u015b\u0107 tylko ostatniego wywo\u0142ania. Pr\u00f3wnaj:\n", "```ruby\n", "razy_dwa(3)\n", "razy_dwa(4)\n", "```\n", "oraz\n", "```ruby\n", "puts razy_dwa(3)\n", "puts razy_dwa(4)\n", "```" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Zadanie 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Zdefiniuj funkcj\u0119 `pierwiastek_szescienny`, kt\u00f3ra oblicza pierwiastek szcze\u015bcienny z przekazanego parametru. Je\u015bli u\u017cytkownik nie przeka\u017ce \u017cadnego parametru, to funkcja powinna zwraca\u0107 warto\u015b\u0107 0. Sprawd\u017a dzia\u0142anie funkcj dla nast\u0119puj\u0105cych przypadk\u00f3w:\n", "* 8\n", "* 27\n", "* brak parametru\n", "\n", "Dlaczego warto\u015b\u0107 otrzymana dla 27 jest niedok\u0142adna?" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 12 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Instrukcja warunkowa `if`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Podstawow\u0105 instrukcj\u0105 warunkow\u0105 w Ruby jest `if`. \n", "\n", "Jest ona podobna do instrukcji z j\u0119zycka C:\n", "```ruby\n", "def parzystosc(liczba)\n", " if liczba % 2 == 0\n", " \"Liczba #{liczba} jest parzysta\"\n", " else\n", " \"Liczba #{liczba} jest nieparzysta\"\n", " end\n", "end\n", "\n", "puts parzystosc(11)\n", "puts parzystosc(12)\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 16 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instrukcja `if` nie wymaga u\u017cycia nawias\u00f3w wok\u00f3\u0142 warunku. Ponadto zamiast nawias\u00f3w klamrowych wykorzystywane s\u0105 wy\u0142\u0105cznie s\u0142owa kluczowe: opcjonalne `else` oraz wymagane `end`. Je\u015bli w instrukcji wyst\u0119puje po\u0142\u0105czenie instrukcji `else` z `if` to u\u017cywa si\u0119 innego s\u0142owa kluczowego `elsif`:\n", "```ruby\n", "def jezyk(plik)\n", " print \"#{plik} -> \"\n", " if plik =~ /\\.rb\\z/\n", " puts \"J\u0119zyk Ruby\"\n", " elsif plik =~ /\\.c\\z/\n", " puts \"J\u0119zyk C\"\n", " elsif plik =~ /\\.java\\z/\n", " puts \"J\u0119zyk Java\"\n", " else\n", " puts \"Nieznany j\u0119zyk programowania\"\n", " end\n", "end\n", "jezyk(\"program.c\")\n", "jezyk(\"inny_program.rb\")\n", "jezyk(\"prosty_program.scala\")\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 20 }, { "cell_type": "markdown", "metadata": {}, "source": [ "W j\u0119zyku Ruby wyst\u0119puj\u0105 tylko dwie warto\u015bci, kt\u00f3re oznaczaj\u0105 fa\u0142sz: warto\u015b\u0107 `nil` oraz warto\u015b\u0107 `false`. Wszystkie pozosta\u0142e warto\u015bci traktowane s\u0105 jako prawda. Dlatego np. w poprzednim przyk\u0142adzie, nawet gdyby dopasowanie da\u0142o wynik `0`, tzn. zaczyna\u0142o si\u0119 na pocz\u0105tku \u0142a\u0144cucha, kod zadzia\u0142a\u0142by poprawnie:\n", "```ruby\n", "if 0 \n", " \"Zero jest prawd\u0105\"\n", "else\n", " \"Zero jest fa\u0142szem\"\n", "end\n", "``` " ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Z\u0142o\u017cone wyra\u017cenia logiczne konstruowane s\u0105 za pomoc\u0105 operator\u00f3w logicznych: `||` (lub), `&&` (i) oraz `!` (nie). Przy z\u0142o\u017conych warunkach warto u\u017cy\u0107 nawias\u00f3w:\n", "```ruby\n", "def dobry_wybor?(plik)\n", " print \"#{plik} -> \"\n", " if !(plik =~ /\\.rb\\z/) && !(plik =~ /\\.py\\z/)\n", " puts \"to kiepski wyb\u00f3r\"\n", " else\n", " puts \"to dobry wyb\u00f3r\"\n", " end\n", "end\n", "\n", "dobry_wybor?(\"rails.rb\")\n", "dobry_wybor?(\"django.py\")\n", "dobry_wybor?(\"yoomla.php\")\n", "\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Uwaga!** W powy\u017cszym przyk\u0142adzie nawiasy s\u0105 wymagane. Isotna jest tutaj kolejno\u015b\u0107 dzia\u0142a\u0144. Mo\u017ca to sprawdzi\u0107 na nast\u0119puj\u0105cych przyk\u0142adach:\n", "```ruby\n", "puts !\"aaa\" =~ /b/\n", "puts !(\"aaa\" =~ /b/)\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 17 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dlatego je\u015bli chcemy zanegowa\u0107 dopasowanie do wzorca lepiej u\u017cy\u0107 specjalnego operatora !~:\n", "```ruby\n", "\"aaa\" !~ /b/\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 16 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Istniej\u0105 r\u00f3wnie\u017c operatory `or`, `and` oraz `not`, ale nie powinno si\u0119 ich stosowa\u0107 w instrukcji warunkowej, gdy\u017c s\u0105 to instrukcje steruj\u0105ce." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Zadanie 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Zdefiniuj funkcje `przytnij`, kt\u00f3ra akceptuje jeden parametr - napis. Funkcja powinna zwarca\u0107 ten sam napis, je\u015bli jest kr\u00f3tszy ni\u017c 30 znak\u00f3w. W przeciwnym razie przycina\u0107 napis oraz dodawa\u0107 3 kropki na ko\u0144cu, wskazuj\u0105ce, \u017ce napis zost\u0142 uci\u0119ty. \u0141\u0105cznie z kropkami napis nie mo\u017ce by\u0107 d\u0142u\u017cszy ni\u017c 15 znak\u00f3w. Ostatni wyraz w napisie powinie by\u0107 wy\u015bwietlony zawsze w ca\u0142o\u015bci.\n", "Przyk\u0142adowo:\n", "```ruby\n", "puts przytnij(\"Ala ma kota.\") # Ala ma kota.\n", "puts przytnij(\"Ala ma kota, papug\u0119 i psa.\") # Ala ma kota,...\n", "puts przytnij(\"Ala ma psa, papug\u0119 i kota.\") # Ala ma psa,...\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 43 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Instrukcja warunkowa `unless`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "W j\u0119zyku Ruby istnieje r\u00f3wnie\u017c polecenie `unless`, kt\u00f3re dzia\u0142a jak \"odwr\u00f3cony\" `if`, tzn. warunek jest zanegowany. Poprzedni przyk\u0142ad mo\u017cemy wyrazi\u0107 nast\u0119puj\u0105co:\n", "```ruby\n", "def dobry_wybor?(plik)\n", " unless plik =~ /\\.rb\\z/\n", " puts \"To kiepski wyb\u00f3r\"\n", " end\n", "end\n", "dobry_wybor?(\"program.c\")\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [ "\n" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 45 }, { "cell_type": "markdown", "metadata": {}, "source": [ "`if` oraz `unless` mog\u0105 r\u00f3wnie\u017c dzia\u0142a\u0107 jako tzw. modyfikatory, stoj\u0105ce po instrukcji. Pozwalaj\u0105 zwi\u0119\u017alej zapisa\u0107 warunkowe wykonanie pojedynczej instrukcji:\n", "```ruby\n", "def dobry_wybor?(plik)\n", " puts \"To kiepski wyb\u00f3r\" unless plik =~ /\\.rb\\z/\n", "end\n", "dobry_wybor?(\"program.c\")\n", "```\n", "Tego rodzaju kod czyta si\u0119 bardzo naturalnie i cz\u0119sto spotykany jest w programach napisanych w Ruby." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 47 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Rodzaje r\u00f3wno\u015bci" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "W instrukcjach warunkowych cz\u0119sto por\u00f3wnujemy warto\u015bci, np. dw\u00f3ch zmiennych. Nale\u017cy zwr\u00f3ci\u0107 uwag\u0119, \u017ce istnieje wiele rodzaj\u00f3w r\u00f3wno\u015bci, kt\u00f3re maj\u0105 zastosowanie w r\u00f3\u017cnych okoliczno\u015bciach:\n", "* `==` - naturalna r\u00f3wno\u015b\u0107\n", "* `eql?` - dodatkowy wym\u00f3g - identyczny typ warto\u015bci\n", "* `equal?` - identyczne obiekty\n", "* `=~` - dopasowanie wyra\u017ce\u0144 regularnych\n", "* `===` - por\u00f3wnywanie w instrukcji selekcji" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Naturalne r\u00f3wno\u015b\u0107 jest najcz\u0119\u015bciej wykorzystywana i pozwala por\u00f3wnywa\u0107 proste oraz z\u0142o\u017cone warto\u015bci:\n", "```ruby\n", "p 0 == 0.0\n", "p \"ala\" == \"ala\"\n", "p [1,2,3] == [1,2,3]\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "`eql?` dodaje wym\u00f3g, aby warto\u015bci posiada\u0142y identyczny typ. Np. liczby ca\u0142kowite i rzeczywiste maj\u0105 inny typ, dlatego ta instrukcja mo\u017ce s\u0142u\u017cy\u0107 do ich odr\u00f3\u017cnienia:\n", "```ruby\n", "p 0.eql?(0.0)\n", "p \"ala\".eql?(\"ala\")\n", "p [1,2,3].eql?([1,2,3])\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Operator `eql?` jest stosowany w po\u0142\u0105czeniu z tablicami asocjacyjnymi - to ten rodzaj r\u00f3wno\u015bci wykorzystywany jest do zast\u0119powania zawarto\u015bci tablicy:\n", "```ruby\n", "tablica = {}\n", "tablica[1] = \"jeden\"\n", "tablica[1.0] = \"jeden\"\n", "p tablica\n", "\n", "tablica = {}\n", "tablica[\"1\"] = \"jeden\"\n", "tablica[\"1\"] = \"jeden\"\n", "p tablica\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`equal?` jest jeszcze bardziej restrykcyjne. Wymagana jest _identyczno\u015b\u0107_ obiekt\u00f3w. Zasadniczo dwa r\u00f3\u017cne obiekty cho\u0107 mog\u0105 mie\u0107 identyczn\u0105 warto\u015b\u0107, nie b\u0119d\u0105 r\u00f3wne wzgl\u0119dem tej r\u00f3wno\u015bci, je\u015bli nie s\u0105 dok\u0142adnie tym samym obiektem:\n", "```ruby\n", "a = \"ala\"\n", "p a.equal?(a)\n", "b = a\n", "p a.equal?(b)\n", "c = \"ala\"\n", "p a.equal?(c)\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Istniej\u0105 jednak pewne warto\u015bci, kt\u00f3re zawsze posiadaj\u0105 dok\u0142adnie jedn\u0105 instancj\u0119 - s\u0105 to symbole oraz \"ma\u0142e\" liczby ca\u0142kowite:\n", "```ruby\n", "a = :ala\n", "b = :ala\n", "p a.equal?(b)\n", "a = 10\n", "b = 10\n", "p a.equal?(b)\n", "a = 10.0\n", "b = 10.0\n", "p a.equal?(b)\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Operator `=~` wykorzystywany jest do dopasowywania wyra\u017ce\u0144 regularnych. Podobnie dzia\u0142a r\u00f3wnie\u017c operator `===`, ale ma on szersze zastosowanie, przede wszystkim dlatego, \u017ce wykorzystywany jest w instrukcji selekcji (patrz ni\u017cej). Wiele typ\u00f3w posiada metod\u0119 pozwalaj\u0105c\u0105 na wykorzystanie tego operatora, np. \n", "```ruby\n", "p (1..5) === 3\n", "p (1..5) === 5\n", "p (1...5) === 5\n", "p Fixnum === 1\n", "p /^a/ === \"ala\"\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Uwaga**: operator `===` nie jest symetryczny!\n", "```ruby\n", "p (1..5) === 3\n", "p 3 === (1..5)\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 48 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Zadanie 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Zdefiniuj funkcj\u0119 `rowne_tablice?(a,b)`, kt\u00f3ra zwraca prawd\u0119, je\u015bli tablice s\u0105 r\u00f3wne, bez wzgl\u0119du na kolejno\u015b\u0107 element\u00f3w. Np.\n", "```ruby\n", "puts rowne_tablice?([1,2,3],[1,2,3]) # true\n", "puts rowne_tablice?([1,2,3],[3,2,1]) # true \n", "puts rowne_tablice?([1,2,3],[1,2]) # false\n", "puts rowne_tablice?([1,2,3],[1,2,3,4]) # false\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 52 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Instrukcja selekcji - `case`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instrukcja `case` to instrukcja selekcji. Najprostsze jej zastosowanie polega na por\u00f3wnaniu zmiennej ze sta\u0142\u0105, np.\n", "```ruby\n", "case liczba\n", "when 1\n", " puts \"jeden\"\n", "when 2\n", " puts \"dwa\"\n", "when 3 \n", " puts \"trzy\"\n", "else\n", " puts \"bardzo du\u017ca liczba\"\n", "end\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [ "liczba = 5\n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dzi\u0119ki wykorzystaniu operatora `===` zastosowanie instrukcji `case` jest znacznie szersze. Mo\u017cna np. por\u00f3wna\u0107 warto\u015b\u0107 zmiennej z szeregiem wyra\u017ce\u0144 regularnych:\n", "```ruby\n", "case plik\n", "when /\\.rb\\z/\n", " \"Ruby\"\n", "when /\\.pl\\z/\n", " \"Perl\"\n", "when /\\.php\\z/\n", " \"PHP\"\n", "when /\\.c\\z/\n", " \"J\u0119zyk C\"\n", "else\n", " \"Nieznany j\u0119zyk\"\n", "end\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [ "plik = \"moj_program.php\"\n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Mo\u017cliwe jest r\u00f3wnie\u017c zastosowanie zakres\u00f3w:\n", "```ruby\n", "case rok\n", "when 1901..2000\n", " \"XX\"\n", "when 2001..2100\n", " \"XXI\"\n", "when 2101..2200\n", " \"XXII\"\n", "else\n", " \"ciemne wieki\"\n", "end\n", "```" ] }, { "cell_type": "code", "collapsed": false, "input": [ "rok = 1994\n" ], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }