Это — статья-roadmap-cheatsheet для изучающих Ruby и Rails (Rails и Gems запланированы на вторую часть). Вместо того, чтобы рассказывать очередной how-to я постараюсь расписать все те вещи, которые, на мой взгляд, можно изложить кратко и емко, с упором на то, что программисту пришедшему с других языков и платформ может показаться не очевидным, антипоисковым и проcто затратным по времени на изучение без подсказок — на остальное просто дам ссылки (и есть Google — но ведь не всегда, особенно в начале пути, очевидно что у него нужно спрашивать). Не смотря на то, что в природе существует множество туториалов/кастов/книг/чего угодно по чему угодно — именно такого формата мне самому всегда не хватает. И по сути, это те вещи, которые чаще всего рассказываю при вопросах «а как оно вообще?», «с чего начать?», «а как делается такая вот штука?», «а какой gem лучше?» — теперь буду кидать ссылку сюда) Кстати, пока работал над этой статьей на Хабре появилась похожая про Python — видимо, идея витает в воздухе.
Язык программирования — это не только синтаксис, сборщик мусора, не только парадигма языка, и даже не столько его философия, в первую очередь — это коммьюнити и та кодовая база, которую это коммьюнити создало. Особенно сейчас, в эпоху OpenSource. И тут у Ruby первый жирный плюс в карму. Одна из особенностей — во всем читается прагматичная лень, начиная c опциональности скобок при вызове методов и точек с запятой в конце строки, продолжая емким и выразительным синтаксисом, и заканчивая общим ощущением от проектов — многие из них сделаны работающими из коробки, и требующих минимальных усилий, чтобы сконфигурировать их.
Многие выбирают Ruby, потому что это комфортно и приятно. Удовольствие и радость от программирования можно получить на разных языках — и в Ruby оно похоже на езду на хорошем авто. Не на суперкаре, подвеска которого пересчитывает каждую колдобину, но зато все вокруг в восторге, не на вседорожнике, на котором если вдруг приспичит можно помесить грязь, не на «зажигалке», чтобы со всеми гоняться с перекрестка, и не малолитражке (зато дешево и экологично) — именно на хорошей достойной машине, сидя за рулем которой будешь думать не столько о дороге, сколько о более важных вещах, хотя бы о маршруте и конечной цели поездки. И слушать любимую музыку, конечно.
Или же, можно сказать, что программирование на Ruby похоже на игру в Lego (и это во многом благодаря Gems). Хотя кто-то любит сварку арматуры, а кому-то достаточно картона и клея.
Но аналогии аналогиями. Есть несколько утверждений, которые иногда можно встретить о Ruby и Rails — попробую внести в них ясность.
Известно утверждение о том, что Ruby медленный. И поспорить сложно, ведь Ruby интерпретируемый язык. И что характерно, чаще всего я это слышу от тех кто пишет (исключительно) на PHP, который тоже интерпретируем, и по скорости в синтетических тестах находится примерно на том же уровне. Скорее всего, это отголоски дурной славы старых версий. По факту, мне приходилось работать и с Rails и с Symfony2 — на реальных приложениях Rails быстрее при одинаковом уровне оптимизации (и в обоих правильное кэширование — залог успеха). Если нужна скорость и компактность в памяти — пишите на ассемблере используйте Node.js. Но парадокс в том, что на нем как раз часто пишут рубисты — когда это действительно оправданно. И дело тут вот в чем: важна не только скорость работы, но и скорость написания приложения. И Ruby, и все то, что можно найти на github всячески помогает достичь действительно высокой производительности программиста — в том числе и в возможностях оптимизации приложения. И не нужно забывать, что и главная нагрузка, и бутылочные горлышки, зачастую — это базы данных, а веб-приложения это всего-лишь прослойка бизнес-логики. А такая прослойка неплохо масштабируется.
Есть еще своеобразный миф про высокие зарплаты Ruby-разработчиков с одной стороны, с другой — что работы на Ruby мало. Обычно сравнивают с зарплатами со средней по рынку на PHP, и количеством работы на нем же. Средний уровень зарплат на PHP — это классическая «средняя зарп температура по больнице». Если же сравнить специалистов по Yii/Symfony/Zend и Rails (можно еще добавить Django на Python) — картина выйдет совсем другая, а именно: и зарплаты и объем рынка примерно одинаковы. Действительно, хорошим программистам неплохо платят. И более того, когда берешься за проект с нуля — зачастую выбор платформы за тобой и твоей командой, а не заказчиком/начальством.
Так что, есть множество прекрасных языков и фреймворков для написания веб-приложений, и Ruby с Rails не являются серебряной пулей, которая убьет всех зайцев кроликов-оборотней сразу. Просто, на мой взгляд, если брать совокупность важных критериев, а не пытаться выбрать по одному-двум из них, RoR набирает действительно много очков. В том числе и по зрелости — это уже давно не хипстерская платформа, в которой есть только потенциал, но еще и не старичок (а примеров и тех и других уйма). И старичком, я думаю, еще долго не станет, т.к. потенциал для роста и развития еще есть и у Ruby и у Rails — но это тема для отдельной статьи.
И конечно, несмотря на направленность статьи на Rails, и популярность именно этой платформы — Ruby это далеко не только Rails.
В любом случае, я убежден, что программист не должен сидеть в своем маленьком мирке того, за что ему сегодня платят зарплату. Ruby дает в этом смысле не только +1 язык в резюме, но и, за счет своей ооп-направленности и широким возможностям метапрограммирования, опыт, который пригодится на разных языках и платформах.
Ruby
Как установить Ruby на #{ os_name }?
Сами ссылки:
- win. По той же ссылке можно найти DevKit, которой пригодится для работы с БД и установки Native Extensions
- *nix — ищите в своих репозиториях, или legacy
Кроме того, есть такая штука как RVM. Она позволяет установить несколько версий Ruby на одной ОС и переключаться между ними. На старте в ней потребности нет, но бывает полезна, если уже есть несколько проектов на локальной машине или на сервере — обновляться на всех разом до новой версии сразу не особо здорово. Пока — просто имейте ввиду, что она есть.
Подробно про RVM на хабре.
Тут же стоит упомянуть про среду разработки. Я приверженец продуктов JetBrains, поэтому рекомендую RubyMine, но ввиду того, что продукт коммерческий кому-то может прийтись по вкусу свободная Aptana Studio. Если же приятнее пользоваться легкими текстовыми редакторами — синтаксис Ruby поддерживается многими.
Прямо в браузере в интерактивном режиме Ruby можно попробовать на tryruby.org
'Hello world'.class # String nil.class # NilClass String.class # Class nil.nil? # true Object.new.methods # вернет методы объекта класса Object; тут же видно как создается новый объект - тоже вызовам метода nil.respond_to?('nil?') # true
По поводу последнего: это важно для утиной типизации.
a == b # то же, что и a.==(b) # то есть .==() - это метод
В вызовах методов, в if можно не ставить скобки, если нет неоднозначности
nil.respond_to?('nil?') # true nil.respond_to? 'nil?' # true # все однозначно: if nil.respond_to? 'nil?' puts 'ok' end # тоже if 10.between? 1, 5 puts 'ok' end # а вот так получится не тот приоритет вызовов, поэтому нужны скобки if 10.between?(1, 50) && 20.between?(1, 50) puts 'ok' end
А еще — есть символы. По сути, символы — это неизменяемые строки. Например, они часто используются как ключи в хэшах.
a = :nil? # символ b = 'nil?' # строка nil.respond_to? a # true nil.respond_to? b # true # поиграемся a == b # false a.to_s == b && a == b.to_sym # true; символ и строка преобразуются друг в друга
С ними связано еще немного пудры:
a = {:key1 => 'value1', :key2 => 'value2'} # создаем хэш (ассоциативный массив) a = {key1: 'value1', key2: 'value2'} # если ключи - символы, то можно так (Ruby >= 1.9.3)
Раз уж тема зашла:
a = ['value1', 'value2'] # это массив s = 'String' s = "Double-quoted #{s}" # "Double-quoted String" - это, думаю, ясно
И добьем тему припудривания немного уродливым, но зато удобным способом записи:
%w[value1 value2] # ["value1", "value2"] - тот же массив, что и выше %i[value1 value2] # [:value1, :value2] - массив символов, (Ruby >= 2.0) s = %q(String) s = %Q(Double-quoted #{s}) %x('ls') # команда консоли %r(.*) == /.*/ # true; два способа создать регулярное выражение
Кстати, в Ruby есть многим до боли знакомая точка с запятой — пригодиться она может чтобы записать несколько выражений в одну строку
a = 10; puts a # выведет в консоль 10 if nil.respond_to? 'nil?'; puts 'ok'; end # чтобы было понятно - так тоже можно
Но однострочные if лучше писать так
puts 'ok' if nil.respond_to? 'nil?'
Сразу стоит посмотреть методы базовых классов, во всех — какие бывают each_ и to_.
String (тут — первым делом match, sub)
Array (map, join, include?)
Hash (has_key?, has_value?, merge)
Если хочется продолжения банкета: Интересный паблик с подборкой магии на Руби.
class Foo def bar 10 # любой метод возвращает значение - результат выполнения последнего выражения end def baz(a) bar + 20 end end puts Foo.new.baz(10) # 30
Module — к нему можно относиться и как к примеси, и как к пространству имен. Внезапно? По сути — это набор классов, методов и констант, и пользоваться им можно на свое усмотрение.
module B # как пространство имен class Foo # конструктор def initialize(k) @k = k end # запишем методы в одну строку def bar; @k + 20 end end end puts B::Foo.new(3).bar # 23 module C # как примесь def bar; @k + 25 end end class Foo include C; def initialize(k) @k = k end end puts Foo.new(3).bar # 28
В Ruby классы мутабельны, и их можно патчить после их создания. И тут будьте осторожны: здесь начинаются те самые возможности, при помощи которых можно «выстрелить себе в ногу» — так что, делая что-то подобное нужно всегда отдавать отчет: зачем, что получится, кто виноват и что делать и если что — виноваты сами.
class Foo def bar; 20 end end class Foo # патчим def baz; bar + 2 end end puts Foo.new.baz # 22 # или лучше - так: сразу понятно что это патч Foo.class_eval do def bazz; bar + 3 end end puts Foo.new.bazz # 23 # но если нет на то веской причины - используйте примеси или наследование class Boo < Foo def boo; bar + 2 end end puts Boo.new.boo # 22 # или же - можно пропатчить только объект, а не сам класс a = Foo.new a.instance_eval do # патчим объект def booo; bar + 3 end end puts a.booo # 23 puts Foo.new.booo rescue puts 'error' # error; кстати, так перехватываются ошибки puts a.respond_to? :booo # true puts Foo.new.respond_to? :booo # false
А что если сделать instance_eval для класса? Конечно же, добавятся статические методы.
class Foo def self.bar; 10 end # обычный статический метод end puts Foo.bar # 10 Foo.instance_eval do def baz; bar + 1 end end puts Foo.baz # 11
Играться с этим можно вдоволь, главное помните — берегите ноги.
class Foo def self.add_bar # добавим статический метод, который патчит класс self.class_eval do def bar; 'bar' end end end end puts Foo.new.respond_to? :bar # false class Boo < Foo # отнаследуемся add_bar # пропатчим end puts Boo.new.bar # bar # а теперь все то же самое, но пропатчим уже существующий класс Foo.instance_eval do def add_baz self.class_eval do def baz; 'baz' end end end end class Baz < Foo add_baz end puts Baz.new.baz # baz
Как раз такой подход используется на практике — по сути, получается что-то вроде примеси, в которую можно передавать параметры. Это кажется магией, если не знать, как это делается. Патчить можно и базовые классы, особенно любимы Array и String — но всегда стоит подумать трижды, прежде чем начинать их мучить: одно дело методы вроде .blank? (его добавляет Rails: что-то вроде def blank?; nil? || empty? end), другое — когда код метода специфичен для проекта, тогда логично предположить, что он относится к каким-то классам внутри проекта.
По такому принципу работает, например acceessor. Что мы сделаем, чтобы добавить публичный параметр в Ruby-класс?
class Foo def bar # геттер @bar # возвращаем параметр end def bar=(val) # сеттер @bar = val # присваиваем значение параметру end end
Представляете так писать для десятка-другого параметров? В Ruby много кода по накатанному — смертный грех: DRY. Так что, можно сделать короче.
class Foo attr_accessor :bar, :baz # добавим сразу парочку атрибутов attr_reader :boo # только геттер attr_writer :booo # только сеттер end
Готовы дальше? Тогда:
Вникаем в метаклассы Ruby
Metaprogramming patterns — про monkey patching, Reuse в малом — bang!, eval
Подробно — ссылки внизу, а сейчас вкратце — на что стоит обратить внимание.
Первыми рассмотрим блоки. Блок — это просто кусок куда, и даже не объект, просто часть синтаксиса Ruby. Блок используется чтобы передать какой-то код в метод. И уже в методе он оказывается завернут его в класс Proc.
В разделе про классы и методы они уже использовались:
Foo.instance_eval do # передаем в метод instance_eval блок с определением метода def baz; bar + 1 end end
Но возьмем более базовый пример, он же «как сделать foreach в Ruby»:
[1,2,3].each do |val| p val # кстати, p(val) - это shortcut для puts(val.inspect) end # выводит 1 2 3 # то же, в одну строчку [1,2,3].each { |val| p val } # выводит 1 2 3 [1,2,3].each_with_index { |val, i| puts val.to_s + ' ' + i.to_s } # на заметку
Если же мы хотим передавать блок в собственный метод:
def foo puts yield # 2; выполняем блок puts yield + yield # 4; и еще, и еще выполняем end foo { 2 } def bar(&block) # или, если поменьше пудры puts yield block # 3 end bar { 3 }
Стоит отметить, что блок идет всегда последним параметром, и если нужно передать несколько блоков — нужно их передавать как обычные параметры, а значит создавать Proc.new, или lambda.
Из блока всегда получается объект класса Proc, но сам блок это часть синтаксиса: мы можем его передать в метод, где он станет Proc, мы можем его передать в конструктор Proc, или использовать lambda, но нельзя просто записать блок в переменную.
proc = Proc.new { |a| a - 1 } # через конструктор p proc.call(10) #9 p proc.class # Proc l = lambda { |a| a + 1 } # создаем лямбду p l.call(10) #11 p l.class # Proc new_l = ->(a) { a + 2 } # тоже лямбда (Ruby >= 2.0) p new_l.call(10) #12
Различия в поведении Proc созданными разными способами есть, читаем статью.
Здесь замыкания и блоки в Ruby разобраны вдоль и попрек
На Хабре про блоки, про замыкания
Вкратце, frequently used:
- Отступы в 2 пробела
- Названия методов строчными буквами через подчеркивание: def method_name
- Названия классов и модулей с больших букв: class ClassName
- Если метод возвращает true/false, название должно заканчиваться на вопрос (тот же, nil?)
- Если есть два метода, один из которых изменяет объект, а другой возвращает новый — первый оканчивается на ‘!’ (например )
- Вместо if(!value) лучше использовать алиас unless(value)
- Блок однострочный берется в скобки {… }, а многострочный — в do… end
С ними процесс дополнения проекта библиотеками выглядит очень просто:
- выбираем что нам нужно с rubygems.org (или через ruby-toolbox.com), например, json_pure — JSON парсер на чистом Ruby (без C)
- вводим в консоли gem install json_pure
- а в нашем rb-файле:
require 'json/pure' # какой именно путь должен быть стоит в доках посмотреть, обычно на github
Для удобства управления зависимостями есть bundler:
- gem install bundler
- bundler init
- в появившемся Gemfile вписываем зависимости:
source 'https://rubygems.org' gem 'json_pure'
- bundler install
- И в своем rb-файле
require 'rubygems' require 'bundler/setup'
В реальных проектах список зависимостей может разрастись на несколько экранов, поэтому при переносе проекта на сервер гораздо удобнее выполнять bundle install, чем вручную смотреть что нужно и для каждого гема выполнять gem install. Ну а в Rails bundler используется из коробки.
Сами Gems обязательно рассмотрю в статье про Rails.
А это нужно просто иметь ввиду: Inline C, может пригодится. Если коротко — в коде Ruby можно исполнять код на C, что полезно, например, при реализации численных алгоритмов.
jRuby, который написан на Java и работает в JVM, и соответственно интегрируется с котом на Java. К сожалению, версия языка отстает от MRI, но тот же Rails заводится на нем с пол оборота.
Rubinius, который основан на MRI, но использует потоки операционной системы, а так же по максимуму написан на самом Ruby. По версии обычно up do date.
Скорость всех трех реализаций относительно друг друга разнится от задачи к задаче, а по потреблению памяти из троицы самый прожорливый — jRuby.
MacRuby — он уже стоит на вашем MacBook и работает в связке с Objective-C. Его, к примеру, использует RubyMotion — инструмент для разработки iOS приложений.
Opal — транслятор Ruby в JavaScript. Но не надо ждать от него чего-то выдающегося, это не jRuby для Node.js — он просто дает возможность писать ваш jQuery-код на Ruby.
Ruby Enterprise Edition (REE) — Ruby на стероидах. Проект завершил свое существование, т.к. новые версии и без наркотиков неплохо бегают.
Можно упомянуть MagLev — специфическая версия, может пригодится для разворачивания облачной инфраструктуры.
Также интересен проект mruby, в котором участвует Matz. Это — встраиваемый Ruby. Проект еще не закончен, но весьма многообещающе выглядит. Так, что ждем ruby на Arduino. mruby-arduino
ссылка на оригинал статьи http://habrahabr.ru/post/206416/
Добавить комментарий