Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A presentation about Ruby for beginners (PL only).

A presentation about Ruby for beginners (PL only).

Workshops on Łódź University of Technology as part of ATP.

Avatar for Michał Dulat

Michał Dulat

April 19, 2016

Other Decks in Education

Transcript

  1. Krótka historia • powstał w 1995 r. • autor Yukihiro

    Matsumoto “Matz” • zyskał popularność dzięki web framework’owi Ruby on Rails
  2. Krótka historia • powstał w 1995 r. • autor Yukihiro

    Matsumoto “Matz” • zyskał popularność dzięki web framework’owi Ruby on Rails • doczekał się różnych implementacji, tj. JRuby, RubyMotion, MRuby.
  3. • interpretowany • imperatywny • obiektowy • dynamicznie typowany (duck

    typing) • posiada automatyczne odśmiecanie pamięci Główne cechy języka
  4. Główne cechy języka • interpretowany • imperatywny • obiektowy •

    dynamicznie typowany (duck typing) • posiada automatyczne odśmiecanie pamięci • otwarte klasy
  5. Plan warsztatów • wszystko zwraca wartość • wszystko jest obiektem

    • kontenery i enumeratory • getter i setter
  6. Plan warsztatów • wszystko zwraca wartość • wszystko jest obiektem

    • kontenery i enumeratory • getter i setter • otwarte klasy i operacje na czasie
  7. Plan warsztatów • wszystko zwraca wartość • wszystko jest obiektem

    • kontenery i enumeratory • getter i setter • otwarte klasy i operacje na czasie • dziedziczenie i moduły
  8. Plan warsztatów • wszystko zwraca wartość • wszystko jest obiektem

    • kontenery i enumeratory • getter i setter • otwarte klasy i operacje na czasie • dziedziczenie i moduły • dynamiczne tworzenie metod
  9. Plan warsztatów • wszystko zwraca wartość • wszystko jest obiektem

    • kontenery i enumeratory • getter i setter • otwarte klasy i operacje na czasie • dziedziczenie i moduły • dynamiczne tworzenie metod • bloki, lambdy i proc’ki.
  10. Definiowanie metody def method_name # Wartość na końcu metody jest

    końcową wartością # zwróconą przez metodę. end
  11. Definiowanie metody def method_name(argument_1, …) # Wartość na końcu metody

    jest końcową wartością # zwróconą przez metodę. end
  12. Quiz met = def method_5 5 if 1 == 1

    end > met #=> :method_5
  13. Wszystko jest obiektem • definicja klasy • instancje klasy zwane

    są obiektami • na każdym obiekcie można wykonać szereg metod class Car def fuel_limit "60 liters" end end Car.new.fuel_limit # => "60 liters"
  14. Wszystko jest obiektem • definicja klasy • instancje klasy zwane

    są obiektami • na każdym obiekcie można wykonać szereg metod • podstawowe typy tj. liczba, tablica są obiektami 2.even? # => true
  15. Podstawowe typy kontenerów • tablice [1, ":)", [1, 2, 3]]

    ["car", "plane", "ship"] == %w(car plane ship)
  16. Podstawowe typy kontenerów • tablice [1, ":)", [1, 2, 3]]

    ["car", "plane", "ship"] == %w(car plane ship) [:car, :plane, :ship]
  17. Podstawowe typy kontenerów • tablice [1, ":)", [1, 2, 3]]

    ["car", "plane", "ship"] == %w(car plane ship) [:car, :plane, :ship] == %i(car plane ship)
  18. Podstawowe typy kontenerów • tablice [1, ":)", [1, 2, 3]]

    ["car", "plane", "ship"] == %w(car plane ship) [:car, :plane, :ship] == %i(car plane ship) [1, 2, 3].size
  19. Podstawowe typy kontenerów • tablice [1, ":)", [1, 2, 3]]

    ["car", "plane", "ship"] == %w(car plane ship) [:car, :plane, :ship] == %i(car plane ship) [1, 2, 3].size #=> 3
  20. Podstawowe typy kontenerów • tablice [1, ":)", [1, 2, 3]]

    ["car", "plane", "ship"] == %w(car plane ship) [:car, :plane, :ship] == %i(car plane ship) [1, 2, 3].size #=> 3 [1] + [2, 3]
  21. Podstawowe typy kontenerów • tablice [1, ":)", [1, 2, 3]]

    ["car", "plane", "ship"] == %w(car plane ship) [:car, :plane, :ship] == %i(car plane ship) [1, 2, 3].size #=> 3 [1] + [2, 3] #=> [1, 2, 3]
  22. Podstawowe typy kontenerów • tablice [1, ":)", [1, 2, 3]]

    ["car", "plane", "ship"] == %w(car plane ship) [:car, :plane, :ship] == %i(car plane ship) [1, 2, 3].size #=> 3 [1].+([2, 3]) #=> [1, 2, 3]
  23. Podstawowe typy kontenerów • tablice [1, ":)", [1, 2, 3]]

    ["car", "plane", "ship"] == %w(car plane ship) [:car, :plane, :ship] == %i(car plane ship) [1, 2, 3].size #=> 3 [1] + [2, 3] #=> [1, 2, 3] %w(plane car ship).sort
  24. Podstawowe typy kontenerów • tablice [1, ":)", [1, 2, 3]]

    ["car", "plane", "ship"] == %w(car plane ship) [:car, :plane, :ship] == %i(car plane ship) [1, 2, 3].size #=> 3 [1] + [2, 3] #=> [1, 2, 3] %w(plane car ship).sort #=> ["car", "plane", "ship"]
  25. Podstawowe typy kontenerów • tablice [1, ":)", [1, 2, 3]]

    ["car", "plane", "ship"] == %w(car plane ship) [:car, :plane, :ship] == %i(car plane ship) [1, 2, 3].size #=> 3 [1] + [2, 3] #=> [1, 2, 3] %w(plane car ship).sort #=> ["car", "plane", "ship"] [1, 2, 3].select { |number| (number % 2).zero? }
  26. Podstawowe typy kontenerów • tablice [1, ":)", [1, 2, 3]]

    ["car", "plane", "ship"] == %w(car plane ship) [:car, :plane, :ship] == %i(car plane ship) [1, 2, 3].size #=> 3 [1] + [2, 3] #=> [1, 2, 3] %w(plane car ship).sort #=> ["car", "plane", "ship"] [1, 2, 3].select { |number| (number % 2).zero? } #=> [2]
  27. Podstawowe typy kontenerów • tablice • tablice asocjacyjne (hashe) –

    znane również jako “mapa” i “słownik” { key_1: :value_1, key_2: :value_2 }
  28. Podstawowe typy kontenerów • tablice • tablice asocjacyjne (hashe) –

    znane również jako “mapa” i “słownik” { key_1: :value_1, key_2: :value_2 } { "key 1" => "value 2", "key 2" => "value 2" }
  29. Podstawowe typy kontenerów • tablice • tablice asocjacyjne (hashe) –

    znane również jako “mapa” i “słownik” { key_1: :value_1, key_2: :value_2 } { "key 1" => "value 2", "key 2" => "value 2" } { 0 => false, 1 => true }.invert
  30. Podstawowe typy kontenerów • tablice • tablice asocjacyjne (hashe) –

    znane również jako “mapa” i “słownik” { key_1: :value_1, key_2: :value_2 } { "key 1" => "value 2", "key 2" => "value 2" } { 0 => false, 1 => true }.invert #=> { false => 0, true => 1 }
  31. Podstawowe typy kontenerów • tablice • tablice asocjacyjne (hashe) –

    znane również jako “mapa” i “słownik” { key_1: :value_1, key_2: :value_2 } { "key 1" => "value 2", "key 2" => "value 2" } { 0 => false, 1 => true }.invert #=> { false => 0, true => 1 } hash = { true => ":)", false => ":(" } hash[true]
  32. Podstawowe typy kontenerów • tablice • tablice asocjacyjne (hashe) –

    znane również jako “mapa” i “słownik” { key_1: :value_1, key_2: :value_2 } { "key 1" => "value 2", "key 2" => "value 2" } { 0 => false, 1 => true }.invert #=> { false => 0, true => 1 } hash = { true => ":)", false => ":(" } hash[true] #=> ":)"
  33. Podstawowe typy kontenerów • tablice • tablice asocjacyjne (hashe) –

    znane również jako “mapa” i “słownik” { key_1: :value_1, key_2: :value_2 } { "key 1" => "value 2", "key 2" => "value 2" } { 0 => false, 1 => true }.invert #=> { false => 0, true => 1 } hash = { true => ":)", false => ":(" } hash[true] #=> ":)" { 0 => false, 1 => true }.values_at(0, 1)
  34. Podstawowe typy kontenerów • tablice • tablice asocjacyjne (hashe) –

    znane również jako “mapa” i “słownik” { key_1: :value_1, key_2: :value_2 } { "key 1" => "value 2", "key 2" => "value 2" } { 0 => false, 1 => true }.invert #=> { false => 0, true => 1 } hash = { true => ":)", false => ":(" } hash[true] #=> ":)" { 0 => false, 1 => true }.values_at(0, 1) #=> [false, true]
  35. Podstawowe typy kontenerów • tablice • tablice asocjacyjne (hashe) –

    znane również jako “mapa” i “słownik” { key_1: :value_1, key_2: :value_2 } { "key 1" => "value 2", "key 2" => "value 2" } { 0 => false, 1 => true }.invert #=> { false => 0, true => 1 } hash = { true => ":)", false => ":(" } hash[true] #=> ":)" { 0 => false, 1 => true }.values_at(0, 1) #=> [false, true] { 1 => { 2 => 3 } }.dig(1, 2)
  36. Podstawowe typy kontenerów • tablice • tablice asocjacyjne (hashe) –

    znane również jako “mapa” i “słownik” { key_1: :value_1, key_2: :value_2 } { "key 1" => "value 2", "key 2" => "value 2" } { 0 => false, 1 => true }.invert #=> { false => 0, true => 1 } hash = { true => ":)", false => ":(" } hash[true] #=> ":)" { 0 => false, 1 => true }.values_at(0, 1) #=> [false, true] { 1 => { 2 => 3 } }.dig(1, 2) #=> 3
  37. Enumeratory tablic [1, 2, 3].each { |number| p number *

    2 } [1, 2, 3].each.with_index { |number, index| p number + index }
  38. Enumeratory tablic [1, 2, 3].each { |number| p number *

    2 } [1, 2, 3].each.with_index { |number, index| p number + index } #=> 1 3 5
  39. [1, 2, 3].each { |number| p number * 2 }

    [1, 2, 3].each.with_index { |number, index| p number + index } [1, 2, 3].map { |number| number * 2 } Enumeratory tablic
  40. [1, 2, 3].each { |number| p number * 2 }

    [1, 2, 3].each.with_index { |number, index| p number + index } [1, 2, 3].map { |number| number * 2 } #=> [2, 4, 6] Enumeratory tablic
  41. Enumeratory tablic [1, 2, 3].each { |number| p number *

    2 } [1, 2, 3].each.with_index { |number, index| p number + index } [1, 2, 3].map { |number| number * 2 } [1, 2, 3].map.with_index { |number, index| number + index }
  42. Enumeratory tablic [1, 2, 3].each { |number| p number *

    2 } [1, 2, 3].each.with_index { |number, index| p number + index } [1, 2, 3].map { |number| number * 2 } [1, 2, 3].map.with_index { |number, index| number + index } #=> [1, 3, 5]
  43. Enumeratory hashy { [1, 2] => [3, 4], "hello "

    => "world!!!" }.each do |key, value| p key + value end
  44. Enumeratory hashy { [1, 2] => [3, 4], "hello "

    => "world!!!" }.each do |key, value| p key + value end #=> [1, 2, 3, 4] "hello world!!!"
  45. Enumeratory hashy { [1, 2] => [3, 4], "hello "

    => "world!!!" }.each do |key, value| p key + value end #=> [1, 2, 3, 4] "hello world!!!" { "hello" => 1, "world" => 1, "!" => 3 }.map { |key, value| key * value }.join(" ")
  46. Enumeratory hashy { [1, 2] => [3, 4], "hello "

    => "world!!!" }.each do |key, value| p key + value end #=> [1, 2, 3, 4] "hello world!!!" { "hello" => 1, "world" => 1, "!" => 3 }.map { |key, value| key * value }.join(" ") #=> "hello world !!!"
  47. Input: (1..10).to_a Output: [4, 16, 36, 64, 100] Solution: (1..10).select

    { |num| num % 2 == 0 }.map { |num| num * num } Zadanie 1
  48. Input: [ "mów dała dwóm, "brzoza", "sedes", "Do geese see

    God", "Was it a cat I saw", "orkom mokro", "ruby on rails" ] Zadanie 2 Output: [ "mów dała dwóm, "sedes", "Do geese see God", "Was it a cat I saw", "orkom mokro" ]
  49. Input: [ "mów dała dwóm, "brzoza", "sedes", "Do geese see

    God", "Was it a cat I saw", "orkom mokro", "ruby on rails" ] Zadanie 2 Output: [ "mów dała dwóm, "sedes", "Do geese see God", "Was it a cat I saw", "orkom mokro" ] Solution: input.select do |el| compressed = el.downcase.gsub(" ", "") compressed.reverse == compressed end
  50. Zadanie Input: class User end Output: user = User.new user.first_name

    = "Joe" user.last_name = "Doe" user.age = 30 user.gender = "male" puts user.first_name #=> Joe puts user.last_name #=> Doe puts user.age #=> 30 puts user.gender #=> male
  51. class User def first_name=(value) @first_name = value end def first_name

    @first_name end # … end Zadanie – rozwiązanie 1
  52. class User %w(first_name last_name age gender).each do |attribute_name| define_method "#{attribute_name}="

    do |value| instance_variable_set("@#{attribute_name}", value) end define_method "#{attribute_name}" do instance_variable_get("@#{attribute_name}") end end end Zadanie – rozwiązanie 2
  53. class User %w(first_name last_name age gender).each do |attribute_name| define_method "#{attribute_name}="

    do |value| instance_variable_set("@#{attribute_name}", value) end define_method "#{attribute_name}" do instance_variable_get("@#{attribute_name}") end end end Zadanie – rozwiązanie 2
  54. Zadanie – rozwiązanie 3 class User attr_reader :first_name, :last_name, :age,

    :gender attr_writer :first_name, :last_name, :age, :gender end
  55. Zadanie – rozwiązanie 4 class User ATTRIBUTE_NAMES = %i(first_name last_name

    age gender) attr_reader *ATTRIBUTE_NAMES attr_writer *ATTRIBUTE_NAMES end
  56. Modyfikacja klas wbudowanych typów • nadpisanie metody klasy podstawowej class

    String def to_i Integer(self) * 2 end end > "1".to_i #=> 2
  57. Modyfikacja klas wbudowanych typów • nadpisanie metody klasy podstawowej •

    dopisanie nowej metody do klasy podstawowej class String def count_words self.split(" ").count end end
  58. Modyfikacja klas wbudowanych typów • nadpisanie metody klasy podstawowej •

    dopisanie nowej metody do klasy podstawowej class String def count_words split(" ").count end end
  59. Modyfikacja klas wbudowanych typów • nadpisanie metody klasy podstawowej •

    dopisanie nowej metody do klasy podstawowej class String def count_words split(" ").count end end > "Ala ma kota".count_words #=> 3
  60. Zadanie Input: class Integer end Operacje na czasie: Time.now #=>

    aktualny czas systemowy Time.now + 1 #=> aktualny czas + 1 sekunda Output: puts 1.second.ago puts 1.minute.ago puts 1.hour.ago puts 1.day.ago puts 1.second.since puts 1.minute.since puts 1.hour.since puts 1.day.since
  61. Zadanie Input: class Integer end Operacje na czasie: Time.now #=>

    aktualny czas systemowy Time.now + 1 #=> aktualny czas + 1 sekunda Output: puts 1.second.ago puts 2.5.minutes.ago puts 1.minute.ago puts 1.hour.ago puts 1.day.ago puts 1.second.since puts 1.minute.since puts 1.hour.since puts 1.day.since
  62. Rozwiązanie class Numeric def ago Time.now - self end def

    since Time.now + self end def second self end alias :seconds :second def minute 60 * seconds end alias :minutes :minute # … end
  63. Dziedziczenie • mechanizm jednokrotnego dziedziczenia class Message attr_accessor :content end

    class Sms < Message end sms = Sms.new sms.content = "Hello World!" puts sms.content #=> "Hello World!"
  64. Dziedziczenie • mechanizm jednokrotnego dziedziczenia • w przypadku braku podania

    klasy, dziedziczymy po klasie Object • dziedziczyć możemy po klasach wbudowanych
  65. Dziedziczenie • mechanizm jednokrotnego dziedziczenia • w przypadku braku podania

    klasy, dziedziczymy po klasie Object • dziedziczyć możemy po klasach wbudowanych class Message < String end message = Message.new("Hello World!") puts message #=> "Hello World!"
  66. Dziedziczenie • mechanizm jednokrotnego dziedziczenia • w przypadku braku podania

    klasy, dziedziczymy po klasie Object • dziedziczyć możemy po klasach wbudowanych class Message < String end message = Message.new("Hello World!") puts message #=> "Hello World!" puts Message.new("Hello World!") == String.new("Hello World!") #=> true
  67. Dziedziczenie • mechanizm jednokrotnego dziedziczenia • w przypadku braku podania

    klasy, dziedziczymy po klasie Object • dziedziczyć możemy po klasach wbudowanych class Message < String end message = Message.new("Hello World!") puts message #=> "Hello World!" puts Message.new("Hello World!") == String.new("Hello World!") #=> true puts "Hello World!" == String.new("Hello World!") #=> true
  68. Moduły • pozwalają rozszerzyć klasę o nowe metody module Message

    attr_accessor :subject, :body, :recipient, :sender def send # Jakaś magia "Message was sent." end end class Email include Message end email = Email.new email.subject = "Subject" email.body = "Body" email.recipient = "[email protected]" email.sender = "[email protected]" puts email.send #=> "Message was sent."
  69. Moduły • pozwalają rozszerzyć klasę o nowe metody module Message

    def is_sendable? true end end class Email extend Message end puts Email.is_sendable? #=> true
  70. Moduły • pozwalają rozszerzyć klasę o nowe metody • można

    je wykorzystywać w wielu klasach • istnieją moduły wbudowane w język
  71. Moduły • pozwalają rozszerzyć klasę o nowe metody • można

    je wykorzystywać w wielu klasach • istnieją moduły wbudowane w język class Player include Comparable attr_reader :score def initialize(value) @score = value end def <=>(player) score <=> player.score end end player1 = Player.new(10) player2 = Player.new(20) puts player1 < player2 #=> true
  72. Zadanie Input: class Player end class Cheater end Wymagania: •

    wykorzystać dziedziczenie i/lub moduły. • nie wolno używać modułu Comparable. player1 = Player.new(10) player2 = Player.new(20) cheater = Cheater.new(20) puts player1 == player2 #=> false puts player1 < player2 #=> true puts cheater > player2 #=> true
  73. Zadanie – rozwiązanie 1 module ComparableScores def ==(obj) score ==

    obj.score end def <(obj) score < obj.score end def >(obj) score > obj.score end end class Player include ComparableScores attr_reader :score def initialize(value) @score = value end end class Cheater include ComparableScores attr_reader :score def initialize(value) @score = value * 2 end end player1 = Player.new(10) player2 = Player.new(20) cheater = Cheater.new(20) puts player1 == player2 #=> false puts player1 < player2 #=> true puts cheater > player2 #=> true
  74. Zadanie – rozwiązanie 2 module ComparableScores def ==(obj) score ==

    obj.score end def <(obj) score < obj.score end def >(obj) score > obj.score end end class Player include ComparableScores attr_reader :score def initialize(value) @score = value end end class Cheater < Player def initialize(value) @score = value * 2 end end player1 = Player.new(10) player2 = Player.new(20) cheater = Cheater.new(20) puts player1 == player2 #=> false puts player1 < player2 #=> true puts cheater > player2 #=> true
  75. Dynamiczne tworzenie metod • define_method define_method :sum do |n1, n2|

    n1 + n2 end sum(1, 2) #=> 3 sum("a", "b") #=> "ab" sum([1], [2, 3]) #=> [1, 2, 3]
  76. Dynamiczne tworzenie metod • define_method • method_missing class Integer private

    def method_missing(name, *args, &block) "Are you kidding me? #{name} does not exist!" end end 1.foobar #=>"Are you kidding me? foobar does not exist!"
  77. Zadanie Output: puts "a".a? #=> true puts "a".b? #=> false

    puts "c".c? #=> true … puts "y".z? #=> false Wymagania: • obsłużyć co najmniej wszystkie litery alfabetu • obsłużyć tylko metody ze znakiem zapytania na końcu • napisać jak najkrótszy kod
  78. Block • składnia jednoliniowa • składnia wielowierszowa • blok nie

    jest obiektem, jest częścią składni wywoływanej metody { puts "Hello World" } #=> syntax error
  79. Block – przykłady • [1, 2, 3].map { |number| number

    * 2 } • %w(string text integer).sort_by { |element| element.length }
  80. Block – przykłady • [1, 2, 3].map { |number| number

    * 2 } • %w(string text integer).sort_by { |element| element.length } • [1, 2, 3].select do |number| (number % 2).zero? end
  81. Block – przykłady • [1, 2, 3].map { |number| number

    * 2 } • %w(string text integer).sort_by { |element| element.length } • [1, 2, 3].select do |number| (number % 2).zero? end • def say_hello_to say_hello_to { "Michał" } "Hello #{yield}" #=> "Hello Michał" end
  82. Lambda • składnie lambda { … } lambda { |x1,

    …| … } -> { … } ->(x1, …) { … }
  83. Lambda • składnie • jest obiektem klasy Proc • wymaga

    zdefiniowania ilości argumentów lam = ->(x1, x2, x3) { puts x1 + x2 } puts lam.call(1, 2) #=> ArgumentError: wrong number of arguments
  84. Lambda • składnie • jest obiektem klasy Proc • wymaga

    zdefiniowania ilości argumentów lam = ->(x1, x2) { puts x1 + x2 } puts lam.call(1, 2) #=> 3
  85. Lambda – przykład lam = ->(x1, x2) { x1 <=>

    x2 } [3, 2, 1].sort(&lam) #=> [1, 2, 3]
  86. Lambda – przykład lam = ->(x1, x2) { x1 <=>

    x2 } [3, 2, 1].sort(&lam) == [3, 2, 1].sort { |x1, x2| x1 <=> x2 } #=> true
  87. • składnie • jest obiektem klasy Proc • NIE wymaga

    zdefiniowania ilości argumentów Proc
  88. • składnie • jest obiektem klasy Proc • NIE wymaga

    zdefiniowania ilości argumentów prok = proc { |x1, x2, x3| x1 + x2 } puts prok.call(1, 2) #=> 3 Proc
  89. Proc – przykład prok = proc { |x1, x2, x3|

    x1 <=> x2 } [3, 2, 1].sort(&prok)
  90. Proc – przykład prok = proc { |x1, x2, x3|

    x1 <=> x2 } [3, 2, 1].sort(&prok) #=> [1, 2, 3]
  91. Zadanie Input: [1, "a", 2, 3, "b", "z", 7, "g"]

    Wymagania: • wykorzystaj blok(i) • wykorzystaj lambde lub proc Output: ["a", "b", "g", "z", 7, 3, 2, 1]
  92. Rozwiązanie 1 array = [1, "a", 2, 3, "b", "z",

    7, "g"] strings, integers = array.partition { |x| x.is_a?(String) } strings.sort! integers.sort! { |x, y| y <=> x } strings + integers #=> ["a", "b", "g", "z", 7, 3, 2, 1]
  93. Rozwiązanie 2 lam = ->(x, y) do return 1 if

    x.is_a?(Fixnum) && y.is_a?(String) return -1 if x.is_a?(String) && y.is_a?(Fixnum) return x <=> y if x.is_a?(String) && y.is_a?(String) y <=> x end [1, "a", 2, 3, "b", "z", 7, "g"].sort(&lam) #=> ["a", "b", "g", "z", 7, 3, 2, 1]
  94. Zachęcamy do odwiedzenia lokalnych grup Ruby! • ŁRUG – Łódź

    Ruby User Group • SRUG – Silesia Ruby User Group • WRUG – Warsaw Ruby User Group • DRUG – Dolnośląska Ruby User Group • i wiele innych