ruby.md

Личный сайт Go-разработчика из Казани

1# Это комментарий 2 3=begin 4Это многострочный комментарий 5Никто их не использует 6И они не рекомендуются к использованию 7=end 8 9# Первое и самое главное: Всё является объектом. 10 11# Числа это объекты 12 133.class #=> Fixnum 14 153.to_s #=> "3" 16 17 18# Немного простой арифметики 191 + 1 #=> 2 208 - 1 #=> 7 2110 * 2 #=> 20 2235 / 5 #=> 7 232**5 #=> 32 245 % 3 #=> 2 25 26# Побитовые операторы 273 & 5 #=> 1 283 | 5 #=> 7 293 ^ 5 #=> 6 30 31# Арифметика -- это синтаксический сахар 32# над вызовом метода для объекта 331.+(3) #=> 4 3410.* 5 #=> 50 35 36# Логические величины -- это объекты 37nil # Здесь ничего нет 38true # истина 39false # ложь 40 41nil.class #=> NilClass 42true.class #=> TrueClass 43false.class #=> FalseClass 44 45# Операция равенства 461 == 1 #=> true 472 == 1 #=> false 48 49# Операция неравенства 501 != 1 #=> false 512 != 1 #=> true 52 53# nil -- имеет такое же логическое значение, как и false 54 55!nil #=> true 56!false #=> true 57!0 #=> false 58 59# Больше операций сравнения 601 < 10 #=> true 611 > 10 #=> false 622 <= 2 #=> true 632 >= 2 #=> true 64 65# Оператор сравнения <=> 661 <=> 10 #=> -1 6710 <=> 1 #=> 1 681 <=> 1 #=> 0 69 70# Булевы операторы 71true && false #=> false 72true || false #=> true 73!true #=> false 74 75# Существуют альтернативные версии логических операторов с гораздо меньшим 76# приоритетом. Они используются для связывания операций, пока одна из них 77# не вернёт false или true 78 79# `do_something_else` будет вызван если `do_something` вернёт истинное значение 80do_something() and do_something_else() 81# `log_error` будет вызван если `do_something` вернёт (nil/false) 82do_something() or log_error() 83 84 85# Строки -- это объекты 86 87'Я строка'.class #=> String 88"Я тоже строка".class #=> String 89 90placeholder = "использовать интерполяцию строк" 91"Я могу #{placeholder}, когда создаю строку с двойными кавычками" 92#=> "Я могу использовать интерполяцию строк, 93# когда создаю строку с двойными кавычками" 94 95# Конкатенация строк 96'hello ' + 'world' #=> "hello world" 97'hello ' + 3 #=> TypeError: can't convert Fixnum into String 98'hello ' + 3.to_s #=> "hello 3" 99 100# Умножение строк 101'hello ' * 3 #=> "hello hello hello " 102 103# Добавление к строке 104'hello' << ' world' #=> "hello world" 105 106# печатать в стандартный вывод 107puts "Я печатаюсь!" 108 109# Переменные 110x = 25 #=> 25 111x #=> 25 112 113# Присваивание значения возвращает то самое присвоенное значение. 114# Это позволяет делать множественные присваивания: 115 116x = y = 10 #=> 10 117x #=> 10 118y #=> 10 119 120# По соглашению, используйте snake_case для имён переменных 121snake_case = true 122 123# Используйте подробные имена для переменных 124# Но не переборщите! 125path_to_project_root = '/good/name/' 126path = '/bad/name/' 127 128# Идентификаторы (тоже объекты) 129 130# Идентификаторы -- это неизменяемые, многоразовые константы. 131# Для каждого идентификатора (кроме текста) сохраняется цифровой хэш. 132# При последующем использовании идентификатора, заместо создания нового объекта, 133# будет найден уже существующий по цифровому хэшу. 134# Они часто используются вместо строк для ускорения работы приложений 135 136:pending.class #=> Symbol 137 138status = :pending 139 140status == :pending #=> true 141 142status == 'pending' #=> false 143 144status == :approved #=> false 145 146# Массивы 147 148# Это массив 149array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] 150 151# Массив может содержать различные типы значений 152 153[1, "hello", false] #=> [1, "hello", false] 154 155# Значение в массиве можно получить по индексу с левой границы 156array[0] #=> 1 157array.first #=> 1 158array[12] #=> nil 159 160# Как и арифметика, доступ к значению в массиве 161# это синтаксический сахар над вызовом метода для объекта 162array.[] 0 #=> 1 163array.[] 12 #=> nil 164 165# Также, можно получить по индексу с правой границы 166array[-1] #=> 5 167array.last #=> 5 168 169# Задавая индекс и количество элементов 170array[0,2] #=> [1, 2] 171array[0,999] #=> [1, 2, 3, 4, 5] 172 173# Или с использованием диапазона значений 174array[1..3] #=> [2, 3, 4] 175 176# Перестановка элементов в обратном порядке 177a = [1, 2, 3] 178a.reverse #=> [3, 2, 1] 179 180# Вот так можно добавить значение в массив 181array << 6 #=> [1, 2, 3, 4, 5, 6] 182# Или так 183array.push(6) #=> [1, 2, 3, 4, 5, 6] 184 185# Проверка включения элемента в массив 186array.include?(1) #=> true 187 188# Хэши -- это массив пар "ключ => значение". 189# Хэши объявляются с использованием фигурных скобок: 190hash = {'color' => 'green', 'number' => 5} 191 192hash.keys #=> ['color', 'number'] 193hash.values #=> ['green', 5] 194 195# Значение в хэше легко может быть найдено по ключу: 196hash['color'] #=> 'green' 197hash['number'] #=> 5 198 199# Поиск по ключу, которого в хэше нет вернёт nil: 200hash['nothing here'] #=> nil 201 202# начиная с Ruby 1.9, существует специальный синтаксис 203# при использовании идентификаторов как ключей хэша: 204 205new_hash = { defcon: 3, action: true} 206 207new_hash.keys #=> [:defcon, :action] 208 209# Проверка существования ключа и значения в хеше 210new_hash.key?(:defcon) #=> true 211new_hash.value?(3) #=> true 212 213# Массивы и Хэши -- перечисляемые типы данных 214# У них есть много полезных методов, например: each, map, count и другие 215 216# Управление ходом выполнения (Управляющие структуры) 217 218# Условия 219if true 220 'Если истина' 221elsif false 222 'Иначе, если ложь (опционально)' 223else 224 'Во всех других случаях (тоже опционально)' 225end 226 227# Если условие контролирует выполнение не блока кода, а единственного выражения, 228# можно использовать постфиксную запись условного оператора 229warnings = ['Отсутствует отчество', 'Слишком короткий адрес'] 230puts("Обратите внимание:\n" + warnings.join("\n")) if !warnings.empty? 231 232# Иногда условие лучше звучит с `unless`, чем с `if` 233puts("Обратите внимание:\n" + warnings.join("\n")) unless warnings.empty? 234 235# Циклы 236for counter in 1..5 237 puts "итерация #{counter}" 238end 239#=> итерация 1 240#=> итерация 2 241#=> итерация 3 242#=> итерация 4 243#=> итерация 5 244 245# Однако, никто не использует "for" для циклов. 246# Вместо него Вы должны использовать метод "each" вместе с блоком кода. 247# 248# Блок кода -- это один из вариантов создания замыканий (лямбды, 249# анонимные функции). 250# Блок может только передаваться методу, сам по себе он существовать не может. 251# "for" не имеет своей области видимости и все переменные, объявленные в нём 252# будут доступны отовсюду. "each" вместе с блоком создаёт свою область видимости 253 254# Метод "each" для диапазона значений запускает блок кода один раз 255# для каждого из значений диапазона 256# Блок передаёт счётчик (counter) в качестве параметра. 257# Вызов метода "each" с блоком выглядит следующим образом: 258 259(1..5).each do |counter| 260 puts "итерация #{counter}" 261end 262#=> итерация 1 263#=> итерация 2 264#=> итерация 3 265#=> итерация 4 266#=> итерация 5 267 268# Вы также можете ограничивать блоки фигурными скобками: 269(1..5).each { |counter| puts "итерация #{counter}" } 270 271# Содержимое структурных данных также можно перебирать используя "each": 272array.each do |element| 273 puts "#{element} -- часть массива" 274end 275hash.each do |key, value| 276 puts "#{key} -- это #{value}" 277end 278 279# Если вам нужен индекс вы можете использовать "each_with_index" 280# В этом случае индекс будет начинаться с 0 281array.each_with_index do |element, index| 282 puts "#{element} is number #{index} in the array" 283end 284 285# Если индекс должен начинаться с произвольного значения, 286# используйте "each.with_index" 287[:q, :w, :e].each.with_index(100) do |element, index| 288 puts "#{element} -> #{index}" 289end 290#=> :q -> 100 291#=> :w -> 101 292#=> :e -> 102 293 294counter = 1 295while counter <= 5 do 296 puts "итерация #{counter}" 297 counter += 1 298end 299#=> итерация 1 300#=> итерация 2 301#=> итерация 3 302#=> итерация 4 303#=> итерация 5 304 305# Существует большое количество других полезных функций, 306# например "map", "reduce", "inject", и так далее. Например, "map" 307# выполняет связанный с ним блок для каждого элемента перечисляемого объекта, 308# возвращая массив результатов. 309array = [1, 2, 3, 4, 5] 310doubled = array.map do |element| 311 element * 2 312end 313puts doubled 314#=> [2, 4, 6, 8, 10] 315puts array 316#=> [1, 2, 3, 4, 5] 317 318grade = 'B' 319 320case grade 321when 'A' 322 puts 'Так держать, детка!' 323when 'B' 324 puts 'Тебе повезёт в следующий раз' 325when 'C' 326 puts 'Ты можешь сделать лучше' 327when 'D' 328 puts 'Выскоблил последнее' 329when 'F' 330 puts 'Ты провалился!' 331else 332 puts 'Альтернативная система оценок, да?' 333end 334#=> 'Тебе повезёт в следующий раз' 335 336# в when также можно использовать диапазоны 337grade = 82 338case grade 339when 90..100 340 puts 'Ура!' 341when 80...90 342 puts 'Хорошая работа!' 343else 344 puts 'Вы не справились!' 345end 346#=> 'Хорошая работа!' 347 348# Обработка исключений 349begin 350 # здесь код, который может вызвать исключение 351 raise NoMemoryError, 'У вас закончилась память.' 352rescue NoMemoryError => exception_variable 353 puts 'Был вызван NoMemoryError', exception_variable 354rescue RuntimeError => other_exception_variable 355 puts 'Был вызван RuntimeError' 356else 357 puts 'Этот код будет выполнятся, если исключения не были вызваны' 358ensure 359 puts 'Этот код выполняется всегда' 360end 361#=> Был вызван NoMemoryError 362#=> У вас закончилась память. 363#=> Этот код выполняется всегда 364 365# Функции 366 367def double(x) 368 x * 2 369end 370 371# Функции (и все блоки) неявно возвращают значение последней операции 372double(2) #=> 4 373 374# Скобки необязательны, если возвращаемый результат однозначен 375double 3 #=> 6 376 377double double 3 #=> 12 378 379def sum(x,y) 380 x + y 381end 382 383# Аргументы метода разделены запятой 384sum 3, 4 #=> 7 385 386sum sum(3,4), 5 #=> 12 387 388# yield 389# Все методы имеют неявный, опциональный параметр, 390# который может быть вызван с помощью инструкции "yield" 391 392def surround 393 puts "{" 394 yield 395 puts "}" 396end 397 398surround { puts 'hello world' } 399 400# { 401# hello world 402# } 403 404 405# Вы можете передать блок методу 406# "&" отмечает ссылку на переданный блок 407def guests(&block) 408 block.call 'some_argument' 409end 410 411# Чтобы метод принимал произвольное количество аргументов, спереди 412# одного из параметров ставится префикс "*" 413def method(first, *rest) 414 p rest 415end 416method(1, 2, 3, 4) #=> [2, 3, 4] 417 418# Если метод возвращает массив. можно использовать множественное присваивание 419def foods 420 ['pancake', 'sandwich', 'quesadilla'] 421end 422breakfast, lunch, dinner = foods 423breakfast #=> 'pancake' 424dinner #=> 'quesadilla' 425 426# По соглашению, все методы, возвращающие булево значение 427# оканчиваются символом "?" 4285.even? #=> false 4295.odd? #=> true 430 431# Если метод заканчивается восклицательным знаком, значит он делает что-то 432# опасное или необратимое, например изменяет внутреннее состояние объекта. 433# Многие из таких методов-мутаторов часто имеют "безопасную" версию без "!" 434# которая возвращает новое значение 435company_name = "Dunder Mifflin" 436company_name.upcase #=> "DUNDER MIFFLIN" 437company_name #=> "Dunder Mifflin" 438company_name.upcase! # Изменяем зачение company_name! 439company_name #=> "DUNDER MIFFLIN" 440 441 442# Определение класса с помощью ключевого слова "class" 443class Human 444 445 # Переменная класса, она является общей для всех экземпляров класса 446 @@species = "H. sapiens" 447 448 # Базовый метод-конструктор 449 def initialize(name, age=0) 450 # Присвоить аргумент "name" переменной "name" экземпляра класса 451 @name = name 452 # Если аргумент "age" не задан, 453 # мы используем значение по умолчанию из списка аргументов 454 @age = age 455 end 456 457 # Базовый метод установки значения для переменной (setter) 458 def name=(name) 459 @name = name 460 end 461 462 # Базовый метод получения значения переменной (getter) 463 def name 464 @name 465 end 466 467 # Тоже самое можно определить с помощью attr_accessor 468 attr_accessor :name 469 470 # Также можно создать методы только для записи или чтения 471 attr_reader :name 472 attr_writer :name 473 474 # Метод класса определяется с ключевым словом "self", 475 # чтобы можно было отличить его от метода экземпляра класса. 476 # Он может быть вызван только на уровне класса, но не экземпляра. 477 def self.say(msg) 478 puts "#{msg}" 479 end 480 481 def species 482 @@species 483 end 484 485end 486 487 488# Создание экземпляра класса 489jim = Human.new("Jim Halpert") 490 491dwight = Human.new("Dwight K. Schrute") 492 493# Давайте вызовем несколько методов 494jim.species #=> "H. sapiens" 495jim.name #=> "Jim Halpert" 496jim.name = "Jim Halpert II" #=> "Jim Halpert II" 497jim.name #=> "Jim Halpert II" 498dwight.species #=> "H. sapiens" 499dwight.name #=> "Dwight K. Schrute" 500 501# Вызов метода класса 502Human.say("Hi") #=> "Hi" 503 504# Область видимости переменной определяется тем, как мы даём имя переменной. 505# Переменные, имя которых начинается с "$" имеют глобальную область видимости 506$var = "I'm a global var" 507defined? $var #=> "global-variable" 508 509# Переменная экземпляра класса, она видна только в экземпляре 510@var = "I'm an instance var" 511defined? @var #=> "instance-variable" 512 513# Переменная класса, видна для всех экземпляров этого класса и в самом классе 514@@var = "I'm a class var" 515defined? @@var #=> "class variable" 516 517# Имена переменных с большой буквы используются для создания констант 518Var = "I'm a constant" 519defined? Var #=> "constant" 520 521# Класс тоже объект в Ruby. Класс может иметь переменные экземпляра. 522# Переменная класса доступна в классе, его экземплярах и его потомках. 523 524# Пример класса 525class Human 526 @@foo = 0 527 528 def self.foo 529 @@foo 530 end 531 532 def self.foo=(value) 533 @@foo = value 534 end 535end 536 537# Производный класс (класс-потомок) 538class Worker < Human 539end 540 541Human.foo # 0 542Worker.foo # 0 543 544Human.foo = 2 # 2 545Worker.foo # 2 546 547# Переменная экземпляра класса недоступна в потомках этого класса. 548 549class Human 550 @bar = 0 551 552 def self.bar 553 @bar 554 end 555 556 def self.bar=(value) 557 @bar = value 558 end 559end 560 561class Doctor < Human 562end 563 564Human.bar # 0 565Doctor.bar # nil 566 567module ModuleExample 568 def foo 569 'foo' 570 end 571end 572 573# Включение модулей в класс добавляет их методы в экземпляр класса 574# Или в сам класс, зависит только от метода подключения 575class Person 576 include ModuleExample 577end 578 579class Book 580 extend ModuleExample 581end 582 583Person.foo # => NoMethodError: undefined method `foo' for Person:Class 584Person.new.foo # => 'foo' 585Book.foo # => 'foo' 586Book.new.foo # => NoMethodError: undefined method `foo' 587 588# Коллбэки при подключении модуля 589 590module ConcernExample 591 def self.included(base) 592 base.extend(ClassMethods) 593 base.send(:include, InstanceMethods) 594 end 595 596 module ClassMethods 597 def bar 598 'bar' 599 end 600 end 601 602 module InstanceMethods 603 def qux 604 'qux' 605 end 606 end 607end 608 609class Something 610 include ConcernExample 611end 612 613Something.bar # => 'bar' 614Something.qux # => NoMethodError: undefined method `qux' 615Something.new.bar # => NoMethodError: undefined method `bar' 616Something.new.qux # => 'qux'