Menu
Coddy logo textTech

טיפוס ברווז

חלק מהיחידה תכנות מונחה עצמים במסלול ה-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 אונליין