TODO: връщане на стойности? Къде да се вмъкне? По-добър пример?
TODO: повече за класове? Отделна статия?
TODO: внимание при monkey-patching
TODO: липса на скоби
TODO: това трябва да се изговори на живо и да се реши доколко тия неща са разбираеми. След това вероятно ще трябва да се пренапише с feedback-а от живите сесии.
"Метод" е термин, който често може да се замести с "действие". Накратко, това е парче код, което си има някакво име, и може да се изпълни на друго място чрез това име.
Един прост пример:
def say_hello
puts "Hello!"
puts "It's such a wonderful day, isn't it?"
end
Този код дефинира метод с името say_hello
, който при изпълнение извежда на екрана два реда текст. Изпълнението на метода става просто с именуването му:
say_hello
Това е прост начин за преизползване на код. Ако искаме да напишем някаква сложна логика на две различни места, можем да я сложим в метод и да я извикваме и на двете места с по един ред.
Рядко обаче имаме съвсем същата логика на две места. Обикновено тя се различава по някакви малки начини. Примерно, ако искаме метода say_hello
да поздрави някого по име, трябва това име да дойде отнякъде. Това става с параметри:
def say_hello(name, adjective)
puts "Hello, #{name}!"
puts "It's such a #{adjective} day, isn't it?"
end
В скоби слагаме параметрите на метода, разделени със запетаи. В случая имаме два: name
за името, което поздравяваме и adjective
за прилателното, което използваме за деня. По този начин, можем да изпълним следния код:
say_hello("John", "wonderful")
say_hello("Jane", "beautiful")
При изпълнение на тези два реда ще се изведе:
Hello, John!
It's such a wonderful day, isn't it?
Hello, Jane!
It's such a beautiful day, isn't it?
Така можем да пишем доста сложни методи, които използват параметрите си за да решат какво точно да направят.
Въпреки, че ги наричаме "методи", в доста други езици тези парчета код биха били наричани "функции". Разликата е, че "методи" се извикват върху някакъв обект. В случая, когато дефинираме say_hello
, просто го дефинираме върху глобалния обект. За да демонстрираме пълната употреба на метод с получател-обект, нека видим следния пример:
me = "John"
def me.say_hello_to(other_person)
puts "Hello, #{other_person}, my name is #{self}."
end
me.say_hello_to("Jane")
me.say_hello_to("Sally")
Изпълнението на този код ще доведе до:
Hello, Jane, my name is John.
Hello, Sally, my name is John.
Забележете, че дефинираме метода със def me.say_hello_to
. Тоест, вземаме обекта, към който сочи me
(който в случая е низа "John"), и добавяме метод върху него. По този начин този обект вече има способността да поздравява когото и да е. В рамките на дефиницията на метода (между реда с def
и реда с end
), променливата self
има стойността на точно този обект. Така можем да го използваме в поздрава.
Това обаче работи само върху точно този обект -- точно този низ "John". Ако след това извикаме просто "John".say_hello_to("Sally")
, ще получим грешка.
Ако искаме всички низове да имат способността да поздравяват, ще трябва да опишем, че всички низове някога създадени вече имат този метод дефиниран върху тях. Това става като отворим класа String
:
class String
def say_hello_to(other_person)
puts "Hello, #{other_person}, my name is #{self}."
end
end
Класът е нещо като схематика на обект. Той описва какви методи ще има обект, създаден през него. Класът String
описва всички низове, които някога създадем. С този код получаваме възможността да кажем:
"John".say_hello_to("Sally")
"Sally".say_hello_to("Jane")
Списъците имат метод, който се казва include?
. Той се използва по следния начин:
user_choice = gets.chomp
if ["rock", "paper", "scissors"].include? user_choice
puts "Valid move"
else
puts "Invalid move"
end
Израза ["rock", "paper", "scissors"].include? user_choice
обаче е малко тромав. Вместо да попитаме "Намира ли се избора на потребителя в ето този списък?", използваме "Този списък съдържа ли избора на потребителя?". За много хора това не е толкова интиутивно като словоред. Така че ще се опитаме да обърнем нещата.
class Object
def in?(list)
list.include?(self)
end
end
Първо, отваряме класа Object
. Той е базовия клас, който е схематика на всички обекти в системата. След това, дефинираме метод in?
, който просто приема списък и връща резултата от изпълнението на метода include?
върху него. Крайния резултат е, че вече можем да напишем следното:
user_choice = gets.chomp
if user_choice.in? ["rock", "paper", "scissors"]
puts "Valid move"
else
puts "Invalid move"
end
Което се чете малко по-приятно.