# Это комментарий=begin
Это многострочный комментарий
Никто их не использует
И они не рекомендуются к использованию
=end# Первое и самое главное: Всё является объектом.# Числа это объекты3.class#=> Fixnum3.to_s#=> "3"# Немного простой арифметики1+1#=> 28-1#=> 710*2#=> 2035/5#=> 72**5#=> 325%3#=> 2# Побитовые операторы3&5#=> 13|5#=> 73^5#=> 6# Арифметика -- это синтаксический сахар# над вызовом метода для объекта1.+(3)#=> 410.*5#=> 50# Логические величины -- это объектыnil# Здесь ничего нетtrue# истинаfalse# ложьnil.class#=> NilClasstrue.class#=> TrueClassfalse.class#=> FalseClass# Операция равенства1==1#=> true2==1#=> false# Операция неравенства1!=1#=> false2!=1#=> true# nil -- имеет такое же логическое значение, как и false!nil#=> true!false#=> true!0#=> false# Больше операций сравнения1<10#=> true1>10#=> false2<=2#=> true2>=2#=> true# Оператор сравнения <=>1<=>10#=> -110<=>1#=> 11<=>1#=> 0# Булевы операторыtrue&&false#=> falsetrue||false#=> true!true#=> false# Существуют альтернативные версии логических операторов с гораздо меньшим# приоритетом. Они используются для связывания операций, пока одна из них# не вернёт false или true# `do_something_else` будет вызван если `do_something` вернёт истинное значениеdo_something()anddo_something_else()# `log_error` будет вызван если `do_something` вернёт (nil/false)do_something()orlog_error()# Строки -- это объекты'Я строка'.class#=> String"Я тоже строка".class#=> Stringplaceholder="использовать интерполяцию строк""Я могу #{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"Я печатаюсь!"# Переменныеx=25#=> 25x#=> 25# Присваивание значения возвращает то самое присвоенное значение.# Это позволяет делать множественные присваивания:x=y=10#=> 10x#=> 10y#=> 10# По соглашению, используйте snake_case для имён переменныхsnake_case=true# Используйте подробные имена для переменных# Но не переборщите!path_to_project_root='/good/name/'path='/bad/name/'# Идентификаторы (тоже объекты)# Идентификаторы -- это неизменяемые, многоразовые константы. # Для каждого идентификатора (кроме текста) сохраняется цифровой хэш.# При последующем использовании идентификатора, заместо создания нового объекта,# будет найден уже существующий по цифровому хэшу.# Они часто используются вместо строк для ускорения работы приложений:pending.class#=> Symbolstatus=:pendingstatus==:pending#=> truestatus=='pending'#=> falsestatus==:approved#=> false# Массивы# Это массивarray=[1,2,3,4,5]#=> [1, 2, 3, 4, 5]# Массив может содержать различные типы значений[1,"hello",false]#=> [1, "hello", false]# Значение в массиве можно получить по индексу с левой границыarray[0]#=> 1array.first#=> 1array[12]#=> nil# Как и арифметика, доступ к значению в массиве# это синтаксический сахар над вызовом метода для объектаarray.[]0#=> 1array.[]12#=> nil# Также, можно получить по индексу с правой границыarray[-1]#=> 5array.last#=> 5# Задавая индекс и количество элементовarray[0,2]#=> [1, 2]array[0,999]#=> [1, 2, 3, 4, 5]# Или с использованием диапазона значенийarray[1..3]#=> [2, 3, 4]# Перестановка элементов в обратном порядкеa=[1,2,3]a.reverse#=> [3, 2, 1]# Вот так можно добавить значение в массив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.values#=> ['green', 5]# Значение в хэше легко может быть найдено по ключу: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)#=> truenew_hash.value?(3)#=> true# Массивы и Хэши -- перечисляемые типы данных# У них есть много полезных методов, например: each, map, count и другие# Управление ходом выполнения (Управляющие структуры)# Условияiftrue'Если истина'elsiffalse'Иначе, если ложь (опционально)'else'Во всех других случаях (тоже опционально)'end# Если условие контролирует выполнение не блока кода, а единственного выражения,# можно использовать постфиксную запись условного оператораwarnings=['Отсутствует отчество','Слишком короткий адрес']puts("Обратите внимание:\n"+warnings.join("\n"))if!warnings.empty?# Иногда условие лучше звучит с `unless`, чем с `if`puts("Обратите внимание:\n"+warnings.join("\n"))unlesswarnings.empty?# Циклыforcounterin1..5puts"итерация #{counter}"end#=> итерация 1#=> итерация 2#=> итерация 3#=> итерация 4#=> итерация 5# Однако, никто не использует "for" для циклов.# Вместо него Вы должны использовать метод "each" вместе с блоком кода.## Блок кода -- это один из вариантов создания замыканий (лямбды,# анонимные функции).# Блок может только передаваться методу, сам по себе он существовать не может.# "for" не имеет своей области видимости и все переменные, объявленные в нём# будут доступны отовсюду. "each" вместе с блоком создаёт свою область видимости# Метод "each" для диапазона значений запускает блок кода один раз# для каждого из значений диапазона# Блок передаёт счётчик (counter) в качестве параметра.# Вызов метода "each" с блоком выглядит следующим образом:(1..5).eachdo|counter|puts"итерация #{counter}"end#=> итерация 1#=> итерация 2#=> итерация 3#=> итерация 4#=> итерация 5# Вы также можете ограничивать блоки фигурными скобками:(1..5).each{|counter|puts"итерация #{counter}"}# Содержимое структурных данных также можно перебирать используя "each":array.eachdo|element|puts"#{element} -- часть массива"endhash.eachdo|key,value|puts"#{key} -- это #{value}"end# Если вам нужен индекс вы можете использовать "each_with_index"# В этом случае индекс будет начинаться с 0array.each_with_indexdo|element,index|puts"#{element} is number #{index} in the array"end# Если индекс должен начинаться с произвольного значения,# используйте "each.with_index"[:q,:w,:e].each.with_index(100)do|element,index|puts"#{element} -> #{index}"end#=> :q -> 100#=> :w -> 101#=> :e -> 102counter=1whilecounter<=5doputs"итерация #{counter}"counter+=1end#=> итерация 1#=> итерация 2#=> итерация 3#=> итерация 4#=> итерация 5# Существует большое количество других полезных функций,# например "map", "reduce", "inject", и так далее. Например, "map"# выполняет связанный с ним блок для каждого элемента перечисляемого объекта,# возвращая массив результатов.array=[1,2,3,4,5]doubled=array.mapdo|element|element*2endputsdoubled#=> [2, 4, 6, 8, 10]putsarray#=> [1, 2, 3, 4, 5]grade='B'casegradewhen'A'puts'Так держать, детка!'when'B'puts'Тебе повезёт в следующий раз'when'C'puts'Ты можешь сделать лучше'when'D'puts'Выскоблил последнее'when'F'puts'Ты провалился!'elseputs'Альтернативная система оценок, да?'end#=> 'Тебе повезёт в следующий раз'# в when также можно использовать диапазоныgrade=82casegradewhen90..100puts'Ура!'when80...90puts'Хорошая работа!'elseputs'Вы не справились!'end#=> 'Хорошая работа!'# Обработка исключенийbegin# здесь код, который может вызвать исключениеraiseNoMemoryError,'У вас закончилась память.'rescueNoMemoryError=>exception_variableputs'Был вызван NoMemoryError',exception_variablerescueRuntimeError=>other_exception_variableputs'Был вызван RuntimeError'elseputs'Этот код будет выполнятся, если исключения не были вызваны'ensureputs'Этот код выполняется всегда'end#=> Был вызван NoMemoryError#=> У вас закончилась память.#=> Этот код выполняется всегда# Функцииdefdouble(x)x*2end# Функции (и все блоки) неявно возвращают значение последней операцииdouble(2)#=> 4# Скобки необязательны, если возвращаемый результат однозначенdouble3#=> 6doubledouble3#=> 12defsum(x,y)x+yend# Аргументы метода разделены запятойsum3,4#=> 7sumsum(3,4),5#=> 12# yield# Все методы имеют неявный, опциональный параметр,# который может быть вызван с помощью инструкции "yield"defsurroundputs"{"yieldputs"}"endsurround{puts'hello world'}# {# hello world# }# Вы можете передать блок методу# "&" отмечает ссылку на переданный блокdefguests(&block)block.call'some_argument'end# Чтобы метод принимал произвольное количество аргументов, спереди# одного из параметров ставится префикс "*"defmethod(first,*rest)prestendmethod(1,2,3,4)#=> [2, 3, 4]# Если метод возвращает массив. можно использовать множественное присваиваниеdeffoods['pancake','sandwich','quesadilla']endbreakfast,lunch,dinner=foodsbreakfast#=> 'pancake'dinner#=> 'quesadilla'# По соглашению, все методы, возвращающие булево значение# оканчиваются символом "?"5.even?#=> false5.odd?#=> true# Если метод заканчивается восклицательным знаком, значит он делает что-то# опасное или необратимое, например изменяет внутреннее состояние объекта.# Многие из таких методов-мутаторов часто имеют "безопасную" версию без "!"# которая возвращает новое значениеcompany_name="Dunder Mifflin"company_name.upcase#=> "DUNDER MIFFLIN"company_name#=> "Dunder Mifflin"company_name.upcase!# Изменяем зачение company_name!company_name#=> "DUNDER MIFFLIN"# Определение класса с помощью ключевого слова "class"classHuman# Переменная класса, она является общей для всех экземпляров класса@@species="H. sapiens"# Базовый метод-конструкторdefinitialize(name,age=0)# Присвоить аргумент "name" переменной "name" экземпляра класса@name=name# Если аргумент "age" не задан,# мы используем значение по умолчанию из списка аргументов@age=ageend# Базовый метод установки значения для переменной (setter)defname=(name)@name=nameend# Базовый метод получения значения переменной (getter)defname@nameend# Тоже самое можно определить с помощью attr_accessorattr_accessor:name# Также можно создать методы только для записи или чтенияattr_reader:nameattr_writer:name# Метод класса определяется с ключевым словом "self",# чтобы можно было отличить его от метода экземпляра класса.# Он может быть вызван только на уровне класса, но не экземпляра.defself.say(msg)puts"#{msg}"enddefspecies@@speciesendend# Создание экземпляра классаjim=Human.new("Jim Halpert")dwight=Human.new("Dwight K. Schrute")# Давайте вызовем несколько методовjim.species#=> "H. sapiens"jim.name#=> "Jim Halpert"jim.name="Jim Halpert II"#=> "Jim Halpert II"jim.name#=> "Jim Halpert II"dwight.species#=> "H. sapiens"dwight.name#=> "Dwight K. Schrute"# Вызов метода классаHuman.say("Hi")#=> "Hi"# Область видимости переменной определяется тем, как мы даём имя переменной.# Переменные, имя которых начинается с "$" имеют глобальную область видимости$var="I'm a global var"defined?$var#=> "global-variable"# Переменная экземпляра класса, она видна только в экземпляре@var="I'm an instance var"defined?@var#=> "instance-variable"# Переменная класса, видна для всех экземпляров этого класса и в самом классе@@var="I'm a class var"defined?@@var#=> "class variable"# Имена переменных с большой буквы используются для создания константVar="I'm a constant"defined?Var#=> "constant"# Класс тоже объект в Ruby. Класс может иметь переменные экземпляра.# Переменная класса доступна в классе, его экземплярах и его потомках.# Пример классаclassHuman@@foo=0defself.foo@@fooenddefself.foo=(value)@@foo=valueendend# Производный класс (класс-потомок)classWorker<HumanendHuman.foo# 0Worker.foo# 0Human.foo=2# 2Worker.foo# 2# Переменная экземпляра класса недоступна в потомках этого класса.classHuman@bar=0defself.bar@barenddefself.bar=(value)@bar=valueendendclassDoctor<HumanendHuman.bar# 0Doctor.bar# nilmoduleModuleExampledeffoo'foo'endend# Включение модулей в класс добавляет их методы в экземпляр класса# Или в сам класс, зависит только от метода подключенияclassPersonincludeModuleExampleendclassBookextendModuleExampleendPerson.foo# => NoMethodError: undefined method `foo' for Person:ClassPerson.new.foo# => 'foo'Book.foo# => 'foo'Book.new.foo# => NoMethodError: undefined method `foo'# Коллбэки при подключении модуляmoduleConcernExampledefself.included(base)base.extend(ClassMethods)base.send(:include,InstanceMethods)endmoduleClassMethodsdefbar'bar'endendmoduleInstanceMethodsdefqux'qux'endendendclassSomethingincludeConcernExampleendSomething.bar# => 'bar'Something.qux# => NoMethodError: undefined method `qux'Something.new.bar# => NoMethodError: undefined method `bar'Something.new.qux# => 'qux'