Class методы в ruby
Не так давно, занявшись изучением ruby, я столкнулся с тем, что не понимаю, что такое class методы, точнее в чем их отличие от instance и зачем они вообще нужны. В учебнике, который я изучаю на данный момент, эта тема была описана не достаточно подробно или я не дочитал до подробного описания, но в любом случае мне стало интересно разобраться и я полез искать ответы в google. Данный пост является всем тем, что мне удалось найти и понять. Конечно, для опытных ruby разработчиков тут интересного мало, но я надеюсь, что смогу помочь таким же новичкам в языке как и я. Если я вас заинтриговал — прошу под кат.
Для начала, давайте определимся: в ruby все объекты. Это нужно впитать, усвоить и всегда помнить. Даже классы — это объекты имя которых — константа. И с каждым объектом можно совершать какие либо действия благодаря методам. Следовательно, возникает резонный вопрос: можно ли что-то делать с классами благодаря методам?
Думаю, что многие догадаются, что ответ на этот вопрос будет положительный, даже больше скажу: в ruby каждый метод является либо методом экземпляра (instance method) либо методом класса (class method соответственно). Отличаются они, кроме способа создания, только тем, что первые методы вызываются с экземпляром класса, а вторые — с классом. Важно понимать, в чем заключается различие между этими двумя методами и уметь определять когда и какой метод использовать. Поэтому рассмотрим методы класса (class methood), но для начала напомню, а может для кого и расскажу, что такое методы экземпляра.
Методы экземпляра (instance metods):
Часто используемые, обычно с таких методов начинается изучение языка практически во всех учебниках. Обычно создаются они тремя способами:
Ничего сложного и все понятно. Используются они везде и всюду. Например: в rails модули экземпляра могут отвечать за создание и удаление тех же постов, ну или часто встречающийся метод — метод сложения.
Методы класса (class methods):
Руби очень гибкий и лаконичный язык, поэтому он предоставляет нам аж целых четыре различных способа создания методов класса:
Собственно создание данных методов тоже не представляет сложностей. Все представленные способы одинаково работают и единственное что их различает — вкус разработчика. В первом и во втором способе используется одна и та же конструкция, с единственным различием в переменной self . Третий случай интересен тем, что создается анонимный класс, а последний — очень похож на создание синглтона. Когда я вижу код, похожий на self.name_class_method , я понимаю, что это метод класса, поэтому я соглашаюсь со мнением людей, утверждающих, что в первом случае код более читаемый, так как он создает меньше путаницы.
Когда стоит пользоваться данными методами? Обычно их используют, когда вы имеете дело не с отдельными экземплярами класса. Самый банальный пример — методы валидации в rails. Выглядит код примерно так:
К этому примеру можно так же отнести все методы arrt_* семейства. Так же, есть замечательный метод new , который содержат в себе все экземпляры класса Class .
Взаимодействие instance и class методов между собой.
Бывают случаи, когда в методе класса необходимо вызвать метод экземпляра, ruby для этих целей предоставляет элегантный способ:
А иногда бывают случаи когда наоборот, нужно вызвать метод класса в методе экземпляра. Для этих целей нужно использовать метод class :
Важно понимать, что self возвращает значение конкретного класса, поэтому иногда происходит путаница, когда нужно, что бы и наследники такого класса возвращали метод родителя. Для этих целей нужно использовать вместо self непосредственно имя класса родителя:
Источник
Ruby: cheatsheet для изучения
Сразу оговорюсь, что текст под этим спойлером отличается от основной «объективной» части статьи, т.к. здесь изложено мое личное мнение и впечатление.
Язык программирования — это не только синтаксис, сборщик мусора, не только парадигма языка, и даже не столько его философия, в первую очередь — это коммьюнити и та кодовая база, которую это коммьюнити создало. Особенно сейчас, в эпоху OpenSource. И тут у Ruby первый жирный плюс в карму. Одна из особенностей — во всем читается прагматичная лень, начиная c опциональности скобок при вызове методов и точек с запятой в конце строки, продолжая емким и выразительным синтаксисом, и заканчивая общим ощущением от проектов — многие из них сделаны работающими из коробки, и требующих минимальных усилий, чтобы сконфигурировать их.
Многие выбирают Ruby, потому что это комфортно и приятно. Удовольствие и радость от программирования можно получить на разных языках — и в Ruby оно похоже на езду на хорошем авто, сидя за рулем которого будешь думать не столько о дороге, сколько о более важных вещах — хотя бы о маршруте и конечной цели поездки.
Также можно сравнить с игрой в Lego (и это во многом благодаря Gems). Хотя кто-то любит сварку арматуры, а кому-то достаточно картона и клея.
Есть несколько утверждений, которые иногда можно встретить о Ruby и Rails — попробую внести в них ясность.
Известно утверждение о том, что Ruby медленный. И поспорить сложно, ведь Ruby интерпретируемый язык. И что характерно, чаще всего я это слышу от тех кто пишет (исключительно) на PHP, который тоже интерпретируем, и по скорости в синтетических тестах находится примерно на том же уровне. Скорее всего, это отголоски дурной славы старых версий. По факту, мне приходилось работать и с Rails и с Symfony — на реальных приложениях 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 на #< os_name >?
Сами ссылки:
- Win. По той же ссылке можно найти DevKit, которой пригодится для работы с БД и установки Native Extensions
- Rails Installer установит сразу Ruby + DevKit, Git, Rails, Bundler и SQLite, на Windows или MacOS. Ruby, правда, 1.9.3, а установщик с 2.0 еще в alpha. (по совету Jabher)
- *nix — ищите в своих репозиториях, или legacy
Кроме того, есть такая штука как RVM. Она позволяет установить несколько версий Ruby на одной ОС и переключаться между ними. На старте в ней потребности нет, но бывает полезна, если уже есть несколько проектов на локальной машине или на сервере — обновляться на всех разом до новой версии сразу не особо здорово. Пока — просто имейте ввиду, что она есть.
Подробно про RVM на хабре.
Тут же стоит упомянуть про среду разработки. Я приверженец продуктов JetBrains, поэтому рекомендую RubyMine, но ввиду того, что продукт коммерческий кому-то может прийтись по вкусу свободная Aptana Studio. Если же приятнее пользоваться легкими текстовыми редакторами — синтаксис Ruby поддерживается многими.
Прямо в браузере в интерактивном режиме Ruby можно попробовать на tryruby.org
Ruby сильно приправлен «синтаксическим сахаром», благодаря которому зачастую не нужно городить кашу из различных скобок, точек с запятыми и прочего. А под ним — прост и логичен, и сохраняет парадигму «все — объект».
В вызовах методов, в if можно не ставить скобки, если нет неоднозначности
А еще — есть символы. По сути, символы — это неизменяемые строки. Например, они часто используются как ключи в хэшах.
С ними связано еще немного пудры:
Раз уж тема зашла:
И добьем тему припудривания немного уродливым, но зато удобным способом записи:
Кстати, в Ruby есть многим до боли знакомая точка с запятой — пригодиться она может чтобы записать несколько выражений в одну строку
Но однострочные if лучше писать так
Классы в Ruby вполне очевидны, но в возможностях работы с ними кроется вся сила и прелесть Ruby.
Module — к нему можно относиться и как к примеси, и как к пространству имен. Внезапно? По сути — это набор классов, методов и констант, и пользоваться им можно на свое усмотрение.
В Ruby классы мутабельны, и их можно патчить после их создания. И тут будьте осторожны: здесь начинаются те самые возможности, при помощи которых можно «выстрелить себе в ногу» — так что, делая что-то подобное нужно всегда отдавать отчет: зачем, что получится, кто виноват и что делать и если что — виноваты сами.
А что если сделать instance_eval для класса? Конечно же, добавятся статические методы.
Играться с этим можно вдоволь, главное помните — берегите ноги.
Как раз такой подход используется на практике — по сути, получается что-то вроде примеси, в которую можно передавать параметры. Это кажется магией, если не знать, как это делается. Патчить можно и базовые классы, особенно любимы Array и String — но всегда стоит подумать трижды, прежде чем начинать их мучить: одно дело методы вроде .blank? (его добавляет Rails: что-то вроде def blank?; nil? || empty? end), другое — когда код метода специфичен для проекта, тогда логично предположить, что он относится к каким-то классам внутри проекта.
По такому принципу работает, например accessor. Что мы сделаем, чтобы добавить публичный параметр в Ruby-класс?
Представляете так писать для десятка-другого параметров? В Ruby много кода по накатанному — смертный грех: DRY. Так что, можно сделать короче.
Ruby 2.0 поддерживает именованные аргументы методов:
В предыдущих версиях добиться такого же поведения можно, разбирая атрибуты:
Начиная с Ruby 2.1 появилась возможность добавлять обязательные именованные аргументы.
Некоторое недоумение поначалу вызывают блоки, замыкания и класс Proc — зачем столько всего? Вкратце — на самом деле, есть только Proc.
Подробно — ссылки внизу, а сейчас — на что стоит обратить внимание.
Первыми рассмотрим блоки. Блок — это просто кусок куда, и даже не объект, просто часть синтаксиса Ruby. Блок используется чтобы передать какой-то код в метод. И уже в методе он оказывается завернут его в класс Proc.
В разделе про классы и методы они уже использовались:
Но возьмем более базовый пример, он же «как сделать foreach в Ruby»:
Если же мы хотим передавать блок в собственный метод:
Стоит отметить, что блок идет всегда последним параметром, и если нужно передать несколько блоков — нужно их передавать как обычные параметры, а значит создавать Proc.new, или lambda.
Из блока всегда получается объект класса Proc, но сам блок это часть синтаксиса: мы можем его передать в метод, где он станет Proc, мы можем его передать в конструктор Proc, или использовать lambda, но нельзя просто записать блок в переменную.
Мир Ruby, наверное, был бы совсем другим, если бы не RubyGems.
С ними процесс дополнения проекта библиотеками выглядит очень просто:
- выбираем что нам нужно с rubygems.org (или через ruby-toolbox.com), например, json_pure — JSON парсер на чистом Ruby (без C)
- вводим в консоли gem install json_pure
- а в нашем rb-файле:
Для удобства управления зависимостями есть bundler:
- gem install bundler
- bundler init
- в появившемся Gemfile вписываем зависимости:
- bundler install
- И в своем rb-файле
В реальных проектах список зависимостей может разрастись на несколько экранов, поэтому при переносе проекта на сервер гораздо удобнее выполнять bundle install, чем вручную смотреть что нужно и для каждого гема выполнять gem install. Ну а в Rails bundler используется из коробки.
Сами Gems обязательно рассмотрю в статье про Rails.
Далеко не последняя по важности возможность RubyGems — Native Extensions. Все просто — вместе с гемом может быть скомпилирован прилагающийся код на C и вызван из кода самого гема. Благодаря этому, среди них есть достаточно шустрые парсеры, можно установить JavaScript’овый V8 в виде гема, и много других вкусностей.
А это нужно просто иметь ввиду: Inline C, может пригодится. Если коротко — в коде Ruby можно исполнять код на C, что полезно, например, при реализации численных алгоритмов.
Простой пример с потоком:
Код выведет в консоль «thread started 100000».
Более низкоуровневые fibers (волокна) предлагают немного другой синтаксис, позволяющий управлять последовательностью исполнения, а также имеют меньшие издержки по памяти и времени инициализации, чем threads.
Код выведет «fiber 1 context fiber 2».
Ruby поддерживает многопоточность, и различные версии интерпретатора отличаются ее реализацией. GIL в основной ветке сводит распараллеливание вычислений на нет, но использование потоков в нем имеет смысл для реализации асинхронности. Самый простой пример: мы можем слушать пользовательский интерфейс, параллельно выполняя какие-то операции. Или можем отправить запрос к БД и ждать ответа в одном потоке, отправлять email в другом, и не дожидаясь завершения отправить ответ пользователю. Но в суммарном времени исполнения выигрыша не будет, т.к. фактически в каждый момент времени будет нагружаться только одно ядро.
Чтобы обойти это ограничение можно использовать версии без GIL — jRuby или Rubinius (и при этом помнить, что потокобезопасность в них существенно ниже — для нее и нужен GIL). Другой вариант — запускать несколько отдельных копий программы, или использовать UNIX-форки (естественно, пулом таких воркеров вполне можно управлять Ruby-скриптом).
Узнав все это начинающий рубист может прийти в замешательство (желая использовать всю мощь своего 48-поточного сервера без лишней головной боли). На практике реальная многопоточность не всегда нужна (а иногда — если и нужна, то когда-нибудь потом). Кроме того, для многих задач есть соответствующие gem’ы, реализующие разные подходы, в том числе готовые HTTP-серверы (которые будут рассмотрены в статье про gems) и асинхронные фреймворки.
GIL нужен для этого:
Код выведет 1 000 000 в MRI, и черт знает что (от 100 000 до 1 000 000) в jRuby и Rubinius.
MRI (Matz’s Ruby Interpreter) — основная ветка Ruby от его создателя Yukihiro Matsumoto, или просто, Matz. Реализована на C. Когда просто говорят «Ruby» обычно имеют ввиду ее. Начиная с версии 1.9 объединена с проектом YARV (Yet another Ruby VM). Одна из основных ее особенностей — так называемый GIL (Global Interpreter Lock), на Хабре про нее писали (с продолжением). Сейчас актуальная версия Ruby 2.0 UPD: вышел Ruby 2.1. Чего нам ждать от Ruby 2.1?
jRuby, который написан на Java и работает в JVM, и соответственно интегрируется с кодом на Java. К сожалению, версия языка отстает от MRI (сейчас реализован Ruby 1.9.3), но тот же Rails заводится на нем с пол оборота.
Rubinius, который основан на MRI, но использует потоки операционной системы, а так же по максимуму написан на самом Ruby. По версии обычно up do date.
Скорость всех трех реализаций относительно друг друга разнится от задачи к задаче, а по потреблению памяти из троицы самый прожорливый — jRuby.
MacRuby — работает в связке с Objective-C на LLVM, заменив тем самым более ранний проект RubyCocoa. Для разработки под iOS существует форк MacRuby — RubyMotion.
IronRuby — реализация на платформе .NET. На протяжении своей жизни то забрасывается, то снова возобновляется разработка.
Opal — транслятор Ruby в JavaScript. Но не надо ждать от него чего-то выдающегося, это не jRuby для Node.js — он просто дает возможность писать ваш jQuery-код на Ruby. Или Express-код под Node.js. В общем, вариация на тему CoffeeScript.
Ruby Enterprise Edition (REE) — Ruby на стероидах. Проект завершил свое существование, т.к. новые версии и без наркотиков неплохо бегают.
Можно упомянуть MagLev — специфическая версия, может пригодится для разворачивания облачной инфраструктуры.
Также интересен проект mruby, в котором участвует Matz. Это — встраиваемый Ruby. Проект еще не закончен, но весьма многообещающе выглядит. Так что, ждем ruby на Arduino. mruby-arduino. На нем же основан MobiRuby, предназначенный для разработки мобильных приложений.
Ну и на закуску, KidsRuby, по смыслу напоминающий старичка Logo.
Источник