Menu
CoddyTech

טיפוס ברווז

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Ruby של Coddy. שיעור 33 מתוך 57.

Ruby לא בודקת את המחלקה של אובייקט לפני קריאה למתודה; היא רק דורשת שלאובייקט תהיה המתודה. "אם הוא הולך כמו ברווז ומגעגע כמו ברווז, הוא ברווז." זהו טיפוס ברווז: אפשר להשתמש באותה דרך במחלקות שאין להן מחלקת־על משותפת:

class Duck
  def speak
    "Quack"
  end
end

class Robot
  def speak
    "Beep"
  end
end

class Radio
  def speak
    "...news..."
  end
end

[Duck.new, Robot.new, Radio.new].each { |thing| puts thing.speak }

פלט:

Quack
Beep
...news...

גם מחלקות מובנות משתתפות. שיטה שמשתמשת רק ב־<< עובדת עם מערך, מחרוזת או כל אובייקט שלך שמגדיר את <<:

class Tally
  attr_reader :count

  def initialize
    @count = 0
  end

  def <<(_item)
    @count += 1
    self
  end
end

def export(items, target)
  items.each { |item| target << item.to_s }
  target
end

p export([1, 2], [])
p export([1, 2], +"")
puts export([1, 2, 3], Tally.new).count

פלט:

["1", "2"]
"12"
3

respond_to?(:name) בודקת אם לאובייקט יש מתודה ציבורית, בלי לקרוא לה. השתמשו בה כשייתכן שאובייקט תומך בתכונה אופציונלית או לא:

class Printer
  def print_page(text)
    "printing #{text}"
  end
end

class Scanner
end

[Printer.new, Scanner.new].each do |device|
  if device.respond_to?(:print_page)
    puts device.print_page("report")
  else
    puts "#{device.class} cannot print"
  end
end

פלט:

printing report
Scanner cannot print

כאשר לאובייקט אין את השיטה, הקריאה גורמת ל־NoMethodError, שההודעה שלו מציינת את השיטה ואת האובייקט. טיפוס ברווז מסתמך על כך שכל אובייקט שמועבר עונה לשיטות שנשלחות אליו:

def loudest(things)
  things.map(&:speak).max_by(&:size)
end

class Cat
  def speak
    "Meow"
  end
end

puts loudest([Cat.new, Cat.new])
begin
  loudest([Cat.new, 42])
rescue NoMethodError => e
  puts e.message
end

פלט:

Meow
undefined method `speak' for an instance of Integer
challenge icon

אתגר

קל

השלימו את המחלקות Printer ו־LineCounter ואת פונקציית העזר export(items, target) בקובץ functions.rb. הפונקציה export שולחת כל פריט אל היעד באמצעות target << item.to_s ומחזירה את היעד. Printer#<< מדפיסה את הטקסט עם מספר שורה, 1: text, ומחזירה את המדפסת. LineCounter#<< סופרת שורות ותווים ומחזירה את המונה; הפונקציה to_s שלה מחזירה 3 lines, 12 chars.

הקוד שסופק קורא פריטים ומייצא אותם למערך (שמוצג באמצעות p), למחרוזת חדשה (שמוצגת באמצעות p), אל Printer ואל LineCounter (שמוצג באמצעות puts).

הקוד שלך ייכתב בקבצים printer.rb, line_counter.rb ו־functions.rb. הקובץ main.rb מכיל את קוד הקלט/פלט שסופק, ואי אפשר לערוך אותו.

נסו בעצמכם

require_relative 'printer'
require_relative 'line_counter'
require_relative 'functions'

# קוד קלט/פלט שסופק: יש להשאיר אותו כפי שהוא
input = []
while (line = gets)
  input << line.chomp
end
p export(input, [])
p export(input, +"")
export(input, Printer.new)
puts export(input, LineCounter.new)
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Ruby אונליין