mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-27 01:03:19 +03:00
626 lines
20 KiB
Ruby
626 lines
20 KiB
Ruby
---
|
||
language: ruby
|
||
filename: learnruby-ua.rb
|
||
contributors:
|
||
- ["David Underwood", "http://theflyingdeveloper.com"]
|
||
- ["Joel Walden", "http://joelwalden.net"]
|
||
- ["Luke Holder", "http://twitter.com/lukeholder"]
|
||
- ["Tristan Hume", "http://thume.ca/"]
|
||
- ["Nick LaMuro", "https://github.com/NickLaMuro"]
|
||
- ["Marcos Brizeno", "http://www.about.me/marcosbrizeno"]
|
||
- ["Ariel Krakowski", "http://www.learneroo.com"]
|
||
- ["Dzianis Dashkevich", "https://github.com/dskecse"]
|
||
- ["Levi Bostian", "https://github.com/levibostian"]
|
||
- ["Rahil Momin", "https://github.com/iamrahil"]
|
||
- ["Gabriel Halley", "https://github.com/ghalley"]
|
||
- ["Persa Zula", "http://persazula.com"]
|
||
- ["Jake Faris", "https://github.com/farisj"]
|
||
translators:
|
||
- ["Serhii Maksymchuk", "https://github.com/Serg-Maximchuk"]
|
||
lang: uk-ua
|
||
---
|
||
|
||
Rubi — це інтерпретована, повністю об'єктно-орієнтована мова програмування з чіткою динамічною типізацією.
|
||
|
||
```ruby
|
||
# Це коментар
|
||
|
||
=begin
|
||
Це багаторядковий коментар
|
||
Ніхто їх не використовує
|
||
Тобі теж не варто
|
||
=end
|
||
|
||
# В першу чергу: все являється об’єктом.
|
||
|
||
# Числа це об’єкти
|
||
|
||
3.class #=> Fixnum
|
||
|
||
3.to_s #=> "3"
|
||
|
||
|
||
# Базова арифметика
|
||
1 + 1 #=> 2
|
||
8 - 1 #=> 7
|
||
10 * 2 #=> 20
|
||
35 / 5 #=> 7
|
||
2**5 #=> 32
|
||
5 % 3 #=> 2
|
||
|
||
# Побітові оператори
|
||
3 & 5 #=> 1
|
||
3 | 5 #=> 7
|
||
3 ^ 5 #=> 6
|
||
|
||
# Арифметика це просто синтаксичний цукор
|
||
# для виклику методу об’єкта
|
||
1.+(3) #=> 4
|
||
10.* 5 #=> 50
|
||
|
||
# Спеціальні значення теж об’єкти
|
||
nil # еквівалентно null в інших мовах
|
||
true # істина
|
||
false # хиба
|
||
|
||
nil.class #=> NilClass
|
||
true.class #=> TrueClass
|
||
false.class #=> FalseClass
|
||
|
||
# Рівність
|
||
1 == 1 #=> true
|
||
2 == 1 #=> false
|
||
|
||
# Нерівність
|
||
1 != 1 #=> false
|
||
2 != 1 #=> true
|
||
|
||
# Окрім власне false, nil це ще одне "хибне" значення
|
||
|
||
!nil #=> true
|
||
!false #=> true
|
||
!0 #=> false
|
||
|
||
# Інші порівняння
|
||
1 < 10 #=> true
|
||
1 > 10 #=> false
|
||
2 <= 2 #=> true
|
||
2 >= 2 #=> true
|
||
|
||
# Комбінований оператор порівняння
|
||
1 <=> 10 #=> -1
|
||
10 <=> 1 #=> 1
|
||
1 <=> 1 #=> 0
|
||
|
||
# Логічні оператори
|
||
true && false #=> false
|
||
true || false #=> true
|
||
!true #=> false
|
||
|
||
# Є альтернативні версії логічних операторів з набагато меншим
|
||
# прецедентом. Вони використовуються в конструкціях з контролем
|
||
# виконання ланцюга виразів які повертають булевий результат.
|
||
|
||
# `do_something_else` викликається лише якщо `do_something` повертає true.
|
||
do_something() and do_something_else()
|
||
# `log_error` викликається лише якщо `do_something` повертає false.
|
||
do_something() or log_error()
|
||
|
||
|
||
# Strings це об’єкти
|
||
|
||
'Я — рядок'.class #=> String
|
||
"Я теж рядок".class #=> String
|
||
|
||
placeholder = 'використовувати інтерполяцію рядків'
|
||
"Я можу #{placeholder} коли користуюсь рядками в подвійних лапках"
|
||
#=> "Я можу використовувати інтерполяцію рядків коли користуюсь рядками в подвійних лапках"
|
||
|
||
# Варто надавати перевагу рядкам в одинарних лапках де це можливо
|
||
# Рядки в подвійних лапках викликають додаткові внутрішні обчислення
|
||
|
||
# Об’єднуйте рядки, але не з числами
|
||
'hello ' + 'world' #=> "hello world"
|
||
'hello ' + 3 #=> TypeError: can't convert Fixnum into String
|
||
'hello ' + 3.to_s #=> "hello 3"
|
||
|
||
# Об’єднуйте рядки з операторами
|
||
'hello ' * 3 #=> "hello hello hello "
|
||
|
||
# Додавання до рядка
|
||
'hello' << ' world' #=> "hello world"
|
||
|
||
# Вивести рядок з переходом на новий рядок вкінці
|
||
puts "Я надрукований!"
|
||
#=> Я надрукований!
|
||
#=> nil
|
||
|
||
# Вивести рядок без переходу на новий
|
||
print "Я надрукований!"
|
||
#=> Я надрукований! => nil
|
||
|
||
# Змінні
|
||
x = 25 #=> 25
|
||
x #=> 25
|
||
|
||
# Зверніть увагу, оператор присвоєння повертає присвоєне значення
|
||
# Отже можна робити одночасне присвоєння кількох змінних:
|
||
x = y = 10 #=> 10
|
||
x #=> 10
|
||
y #=> 10
|
||
|
||
# Для назв змінних використовується зміїний_регістр
|
||
snake_case = true
|
||
|
||
# Використовуйте назви змінних які їх характеризують
|
||
path_to_project_root = '/good/name/'
|
||
path = '/bad/name/'
|
||
|
||
# Символи (теж об’єкти)
|
||
# Символи є незмінними константами багаторазового використання, внутрішньо
|
||
# представлені цілочисельним значенням. Вони часто використовуються замість
|
||
# рядків щоб ефективно передати конкретні, значущі значення.
|
||
|
||
:pending.class #=> Symbol
|
||
|
||
status = :pending
|
||
|
||
status == :pending #=> true
|
||
|
||
status == 'pending' #=> false
|
||
|
||
status == :approved #=> false
|
||
|
||
# Масиви
|
||
|
||
# Ось масив
|
||
array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
|
||
|
||
# Масиви можуть містити елементи різних типів
|
||
[1, 'hello', false] #=> [1, "hello", false]
|
||
|
||
# Масиви можуть бути проіндексовані
|
||
# З початку
|
||
array[0] #=> 1
|
||
array.first #=> 1
|
||
array[12] #=> nil
|
||
|
||
# Як і арифметика, доступ до елемента масиву у вигляді [індекс] — це лише
|
||
# синтаксичний цукор виклику методу [] об’єкта
|
||
array.[] 0 #=> 1
|
||
array.[] 12 #=> nil
|
||
|
||
# З кінця
|
||
array[-1] #=> 5
|
||
array.last #=> 5
|
||
|
||
# З початковим індексом та довжиною
|
||
array[2, 3] #=> [3, 4, 5]
|
||
|
||
# Реверс масиву
|
||
a=[1,2,3]
|
||
a.reverse! #=> [3,2,1]
|
||
|
||
# Елементи масиву за діапазоном індексів
|
||
array[1..3] #=> [2, 3, 4]
|
||
|
||
# Додавати елементи в масив можна так:
|
||
array << 6 #=> [1, 2, 3, 4, 5, 6]
|
||
# Або так:
|
||
array.push(6) #=> [1, 2, 3, 4, 5, 6]
|
||
|
||
# Перевірити чи масив містить елемент
|
||
array.include?(1) #=> true
|
||
|
||
# Хеш — це масив пар ключ/значення.
|
||
# Хеш оголошується з використанням фігурних дужок:
|
||
hash = { 'color' => 'green', 'number' => 5 }
|
||
|
||
hash.keys #=> ['color', 'number']
|
||
|
||
# Значення в хеші може бути швидко знайдене за ключем:
|
||
hash['color'] #=> 'green'
|
||
hash['number'] #=> 5
|
||
|
||
# Запит значення за неіснуючим ключем повертає nil:
|
||
hash['nothing here'] #=> nil
|
||
|
||
# Починаючи з Ruby 1.9 з’явився спеціальний синтаксис при використанні
|
||
# символів в якості ключів:
|
||
new_hash = { defcon: 3, action: true }
|
||
|
||
new_hash.keys #=> [:defcon, :action]
|
||
|
||
# Перевірка наявності ключів та значень в хеші
|
||
new_hash.key?(:defcon) #=> true
|
||
new_hash.value?(3) #=> true
|
||
|
||
# Хеші та масиви — перелічувальні типи даних
|
||
# Вони мають багато корисних методів, такі як each, map, count, та інші.
|
||
|
||
# Оператор вибору "if"
|
||
if true
|
||
'якщо'
|
||
elsif false
|
||
'інакше якщо, опціонально'
|
||
else
|
||
'інакше, також опціонально'
|
||
end
|
||
|
||
# Оператор циклу "for"
|
||
for counter in 1..5
|
||
puts "ітерація #{counter}"
|
||
end
|
||
#=> ітерація 1
|
||
#=> ітерація 2
|
||
#=> ітерація 3
|
||
#=> ітерація 4
|
||
#=> ітерація 5
|
||
|
||
# Проте, ніхто не використовує "for" в циклах.
|
||
# Замість цього варто використовувати метод "each" і передати йому блок.
|
||
# Блок — це відокремлений код який можна передати в метод, наприклад в "each".
|
||
# Це аналог лямбда-виразів, анонімних функцій або замикань в інших мовах програмування.
|
||
|
||
# Метод "each" для діапазону запускає блок один раз для кожного елементу діапазону.
|
||
# Лічильник передається блоку в якості аргументу.
|
||
|
||
# Виклик методу "each" з блоком виглядає наступним чином:
|
||
(1..5).each do |counter|
|
||
puts "ітерація #{counter}"
|
||
end
|
||
#=> ітерація 1
|
||
#=> ітерація 2
|
||
#=> ітерація 3
|
||
#=> ітерація 4
|
||
#=> ітерація 5
|
||
|
||
# Також можна загорнути блок в фігурні дужки:
|
||
(1..5).each { |counter| puts "ітерація #{counter}" }
|
||
|
||
# Вміст структур даних також може бути ітерований використовуючи метод "each":
|
||
array.each do |element|
|
||
puts "#{element} є елементом масиву"
|
||
end
|
||
hash.each do |key, value|
|
||
puts "#{key} є #{value}"
|
||
end
|
||
|
||
# Якщо є необхідність індексувати ітерацію, можна використати метод "each_with_index":
|
||
array.each_with_index do |element, index|
|
||
puts "#{element} під номером #{index} в масиві"
|
||
end
|
||
|
||
# Оператор циклу "while"
|
||
counter = 1
|
||
while counter <= 5 do
|
||
puts "ітерація #{counter}"
|
||
counter += 1
|
||
end
|
||
#=> ітерація 1
|
||
#=> ітерація 2
|
||
#=> ітерація 3
|
||
#=> ітерація 4
|
||
#=> ітерація 5
|
||
|
||
# Є й інші корисні функції для циклів, такі як "map", "reduce",
|
||
# "inject" та інші. Наприклад "map" в циклі проходить по масиву,
|
||
# виконує над елементами операцію(-ї) в блоці і повертає абсолютно
|
||
# новий масив.
|
||
array = [1,2,3,4,5]
|
||
doubled = array.map do |element|
|
||
element * 2
|
||
end
|
||
puts doubled
|
||
#=> [2,4,6,8,10]
|
||
puts array
|
||
#=> [1,2,3,4,5]
|
||
|
||
# Оператор множинного вибору
|
||
grade = 'B'
|
||
|
||
case grade
|
||
when 'A'
|
||
puts 'Відмінно!'
|
||
when 'B'
|
||
puts 'Пощастить наступного разу'
|
||
when 'C'
|
||
puts 'Ти можеш краще'
|
||
when 'D'
|
||
puts 'Майже четвірка'
|
||
when 'E'
|
||
puts 'Випросив'
|
||
when 'F'
|
||
puts 'Не здав!'
|
||
else
|
||
puts 'Інша система оцінювання, так?'
|
||
end
|
||
#=> "Пощастить наступного разу"
|
||
|
||
# Оператор "case" також може використовувати діапазон:
|
||
grade = 82
|
||
case grade
|
||
when 90..100
|
||
puts 'Ура!'
|
||
when 80...90
|
||
puts 'Хороша робота'
|
||
when 60...80
|
||
puts 'Ну, хоч щось'
|
||
else
|
||
puts 'Не здав!'
|
||
end
|
||
#=> "Хороша робота"
|
||
|
||
# Обробка вийнятків:
|
||
begin
|
||
# код з можливим вийнятком
|
||
raise NoMemoryError, 'Ви використали всю пам’ять.'
|
||
rescue NoMemoryError => exception_variable
|
||
puts 'Помилка NoMemoryError', exception_variable
|
||
rescue RuntimeError => other_exception_variable
|
||
puts 'Помилка RuntimeError'
|
||
else
|
||
puts 'Цей код запуститься якщо вийнятків не було взагалі'
|
||
ensure
|
||
puts 'Цей код запуститься в будь-якому випадку'
|
||
end
|
||
|
||
# Функції
|
||
|
||
def double(x)
|
||
x * 2
|
||
end
|
||
|
||
# Функції (і всі блоки) неявно повертають значення останнього виразу
|
||
double(2) #=> 4
|
||
|
||
# Дужки не є обов’язковими якщо результат недвозначний
|
||
double 3 #=> 6
|
||
|
||
double double 3 #=> 12
|
||
|
||
def sum(x, y)
|
||
x + y
|
||
end
|
||
|
||
# Аргументи методів розділяються комою
|
||
sum 3, 4 #=> 7
|
||
|
||
sum sum(3, 4), 5 #=> 12
|
||
|
||
# yield
|
||
# Всі методи мають неявний, опціональний параметр, який
|
||
# можна викликат за допомогою ключового слова 'yield'
|
||
def surround
|
||
puts '{'
|
||
yield
|
||
puts '}'
|
||
end
|
||
|
||
surround { puts 'привіт світ' }
|
||
|
||
# {
|
||
# привіт світ
|
||
# }
|
||
|
||
|
||
# Ви можете передати блок у функцію
|
||
# "&" позначає посилання на блок
|
||
def guests(&block)
|
||
block.call 'some_argument'
|
||
end
|
||
|
||
# Ви можете передати список аргументів, вони будуть перетворені в масив
|
||
# Для цього існує оператор ("*")
|
||
def guests(*array)
|
||
array.each { |guest| puts guest }
|
||
end
|
||
|
||
# Якщо метод повертає масив, ви можете використати деструктуризацію
|
||
def foods
|
||
['млинці', 'бутерброд', 'лазанья']
|
||
end
|
||
breakfast, lunch, dinner = foods
|
||
breakfast #=> 'млинці'
|
||
dinner #=> 'лазанья'
|
||
|
||
# Зазвичай методи які повертають булевий результат закінчуються знаком питання
|
||
5.even? # false
|
||
5.odd? # true
|
||
|
||
# І якщо метод закінчується знаком оклику, то він робить щось деструктивне
|
||
# типу зміни отриманого аргументу. Багато методів мають версію з "!" які
|
||
# змінюють аргумент, та без "!" що повертають новий об’єкт
|
||
company_name = "Дандер Міфлін"
|
||
company_name.upcase #=> "ДАНДЕР МІФЛІН"
|
||
company_name #=> "Дандер Міфлін"
|
||
company_name.upcase! # змінна company_name зміниться цього разу!
|
||
company_name #=> "ДАНДЕР МІФЛІН"
|
||
|
||
|
||
# Клас оголошується ключовим словом class
|
||
class Human
|
||
|
||
# Змінна класу. Вона поширюється на всі екземпляри цього класу.
|
||
@@species = 'Homo sapiens'
|
||
|
||
# Основний ініціалізатор
|
||
def initialize(name, age = 0)
|
||
# Призначення аргументу "name" до однойменної змінної екземпляру
|
||
@name = name
|
||
# Якщо аргумент "age" не заданий, то йому буде присвоєно дефолтне значення
|
||
# зі списку аргументів
|
||
@age = age
|
||
end
|
||
|
||
# Метод-сетер
|
||
def name=(name)
|
||
@name = name
|
||
end
|
||
|
||
# Метод-ґетер
|
||
def name
|
||
@name
|
||
end
|
||
|
||
# Функціональність вище може бути інкапсульована використовуючи метод attr_accessor:
|
||
attr_accessor :name
|
||
|
||
# Ґетери і сетери можуть бути створені індивідуально, наприклад:
|
||
attr_reader :name
|
||
attr_writer :name
|
||
|
||
# Метод класу позначається ключовим словом "self", щоб відрізнити від
|
||
# методів екземпляра класу.
|
||
# Він може бути викликаний лише в класі, але не в екземплярі.
|
||
def self.say(msg)
|
||
puts msg
|
||
end
|
||
|
||
def species
|
||
@@species
|
||
end
|
||
end
|
||
|
||
|
||
# Ініціалізуємо клас
|
||
jim = Human.new('Джим Галперт')
|
||
|
||
dwight = Human.new('Дуайт Шрут')
|
||
|
||
# Викличемо кілька методів
|
||
jim.species #=> "Homo sapiens"
|
||
jim.name #=> "Джим Галперт"
|
||
jim.name = "Джим Галперт II" #=> "Джим Галперт II"
|
||
jim.name #=> "Джим Галперт II"
|
||
dwight.species #=> "Homo sapiens"
|
||
dwight.name #=> "Дуайт Шрут"
|
||
|
||
# Викликати метод класу
|
||
Human.say('Привіт') #=> "Привіт"
|
||
|
||
# Область видимості змінних визначається способом оголошення імені змінної.
|
||
# Змінні, що починаються на "$" мають глобальну область видимості.
|
||
$var = "Я глобальна змінна"
|
||
defined? $var #=> "global-variable"
|
||
|
||
# Зміннні, що опчинають на "@" мають область видимості екзкмпляра
|
||
@var = "Я змінна екземпляра"
|
||
defined? @var #=> "instance-variable"
|
||
|
||
# Змінні, що починаються на "@@" мають область видимості класу
|
||
@@var = "Я змінна класу"
|
||
defined? @@var #=> "class variable"
|
||
|
||
# Змінні, що починаються з великої букви, є константами
|
||
Var = "Я константа"
|
||
defined? Var #=> "constant"
|
||
|
||
# Клас теж об’єкт. Тому клас може мати змінні екземпляра.
|
||
# Змінна класу поширюється між класом і всіма його нащадками.
|
||
|
||
# Базовий клас
|
||
class Human
|
||
@@foo = 0
|
||
|
||
def self.foo
|
||
@@foo
|
||
end
|
||
|
||
def self.foo=(value)
|
||
@@foo = value
|
||
end
|
||
end
|
||
|
||
# Похідний клас (нащадок)
|
||
class Worker < Human
|
||
end
|
||
|
||
Human.foo # 0
|
||
Worker.foo # 0
|
||
|
||
Human.foo = 2 # 2
|
||
Worker.foo # 2
|
||
|
||
# Змінна екземпляра класу не поширюється між класами-нащадками.
|
||
class Human
|
||
@bar = 0
|
||
|
||
def self.bar
|
||
@bar
|
||
end
|
||
|
||
def self.bar=(value)
|
||
@bar = value
|
||
end
|
||
end
|
||
|
||
class Doctor < Human
|
||
end
|
||
|
||
Human.bar # 0
|
||
Doctor.bar # nil
|
||
|
||
module ModuleExample
|
||
def foo
|
||
'foo'
|
||
end
|
||
end
|
||
|
||
# Включення модулів додає їхні методи до екземплярів класу
|
||
# Розширення модулів додає їхні методи в сам клас
|
||
|
||
class Person
|
||
include ModuleExample
|
||
end
|
||
|
||
class Book
|
||
extend ModuleExample
|
||
end
|
||
|
||
Person.foo # => NoMethodError: undefined method `foo' for Person:Class
|
||
Person.new.foo # => 'foo'
|
||
Book.foo # => 'foo'
|
||
Book.new.foo # => NoMethodError: undefined method `foo'
|
||
|
||
# Колбек виконується при включенні і розширенні модуля
|
||
|
||
module ConcernExample
|
||
def self.included(base)
|
||
base.extend(ClassMethods)
|
||
base.send(:include, InstanceMethods)
|
||
end
|
||
|
||
module ClassMethods
|
||
def bar
|
||
'bar'
|
||
end
|
||
end
|
||
|
||
module InstanceMethods
|
||
def qux
|
||
'qux'
|
||
end
|
||
end
|
||
end
|
||
|
||
class Something
|
||
include ConcernExample
|
||
end
|
||
|
||
Something.bar # => 'bar'
|
||
Something.qux # => NoMethodError: undefined method `qux'
|
||
Something.new.bar # => NoMethodError: undefined method `bar'
|
||
Something.new.qux # => 'qux'
|
||
```
|
||
|
||
## Додаткові ресурси
|
||
|
||
- [Learn Ruby by Example with Challenges](http://www.learneroo.com/modules/61/nodes/338) - A variant of this reference with in-browser challenges.
|
||
- [An Interactive Tutorial for Ruby](https://rubymonk.com/) - Learn Ruby through a series of interactive tutorials.
|
||
- [Official Documentation](http://ruby-doc.org/core)
|
||
- [Ruby from other languages](https://www.ruby-lang.org/en/documentation/ruby-from-other-languages/)
|
||
- [Programming Ruby](http://www.amazon.com/Programming-Ruby-1-9-2-0-Programmers/dp/1937785491/) - An older [free edition](http://ruby-doc.com/docs/ProgrammingRuby/) is available online.
|
||
- [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) - A community-driven Ruby coding style guide.
|
||
- [Try Ruby](http://tryruby.org) - Learn the basic of Ruby programming language, interactive in the browser.
|