Ruby Advanced

Часть I Марченко Светлана

Ruby Advanced

 Графические интерфейсы для Ruby  Потоки в Ruby  Сценарии и системное администрирование  Тестирование и отладка  Создание пакетов и распространение программ  Ruby и Web приложения  Ruby tricks

Графические интерфейсы для Ruby (, GTK+, FOX, QtRuby)

 Ruby/Tk  Tk — платформо-независимая система

, Tcl (Perl/Tk)

 Переносимость, стабильность

 Корневой контейнер с виджетами + геометрический менеджер(pack, grid, place)

 Блоки вычисляются в контексте вызываемого объекта (instance_eval), а не в контексте вызывающей программы

Ruby/GTK2

 Ruby/GTK2 (GIMP Toolkit)  Лежит в основе графического менеджера GNOME, но MS Windows, MAC OS X

 Расширение Ruby/GTK2 (GTK+ 2.0) НЕ ПУТАТЬ c Ruby/GTK (GTK+ 1.2), которое несовместимо и считается устаревшим

 GNU LGPL

 Концепция фреймов, диалогов, окон и менеджеров размещения

 Располагает богатым набором виджетов (стандартные + более сложные, например, деревья, многоколонные списки)

 GTK+ написана на С, но спроектирована в ОО манере

 Ruby/GTK2 предоставляет объектно-ориентированный API

 GTK2 написана вручную → API выдержан в духе Ruby (с использованием блоков, необязательных аргументов и т.д)

 GTK+ на базе Glib, Pango, ATK, Cairo, GDK

Графические интерфейсы для Ruby

 Недостатки  недостаточно богатый набор стандартных диалоговых окон

 все строки должны быть в UTF-8 (в начало сценария $KCODE= "U")

 FXRuby (FOX — Free Objects for X) относительно новая технология  акцент на быстродействие и межплатформенную совместимость

 не обертка платформенного API

 написана на С++, объектно-ориентированная

 FXRuby — привязка к Ruby библиотеки FOX (Lyle Johnson)

 также перенесена на платформу MS Windows

 парадигма сообщение/получатель

 парадигма автоматического обновления

 широкие возможности(связь между приложениями и его окружением, сигналы)

 гибкость (поддерживает API для работы с OpenGL) Графические интерфейсы для Ruby

 QtRuby  акцент на кросс-платформенность (Windows, Mac, )

(GPL and Commercial License)

 концепция сигналов и слотов

 Qt написан на С++, для Ruby вводится некая избыточность для возможности «рубистских »выражений Qt::Widget::minimumSizeHint Qt::Widget::minimum_size_hint

widget.setMinimumSize(50); widget.minimumSize = 50; widget.minimum_size = 50;

a.isVisible();

a.visible? Потоки в Ruby

 Потоки определены на пользовательском уровне и не зависят от ОС  Создание потоков thread = Thread.new #действия этого потока end  Передача им входной информации (параметры, передаваемые в блок)  Останов  Синхронизация – может быть очень дорогой

Создание потоков и манипулирование ими

 new возвращает объект типа Thread (синоним fork) a = 1 b = 2 c = 3 thread2 = Thread.new(a,b) do |a, x| с = 4 # доступ ко всем переменным из внешней области видимости а = 2 # любые другие манипуляции end  Доступ к локальным переменным потока через специальный механизм (организован как хэш) из любого места видимости объекта Thread Thread.current[:var1] = «var_value» #внутри потока Thread.current[«var2»] = 3 x = thread2[:var1] y = thread2.key?(«var2») # проверяет используется ли в потоке указанное имя

Опрос и изменение состояния потока

 list — массив «живых» потоков  main — возвращает ссылку на главный поток  current — позволяет потоку идентифицировать себя  exit, pass, start, stop, kill — позволяют управлять потоком изнутри и извне Thread.exit, Thread.pass  Не существует метода экземпляра stop → поток только может приостановить собственное выполнение, но не выполнение другого потока  alive?, stop?, status (run, sleep, nil)  $SAFE, safe_level  join — не может быть вызван самим потоком у себя, только у другого потока Thread.list.each{ |t| t.join if t != Thread.main } интерпретатор обнаружит тупиковую ситуацию: два потока вызвали друг у друга join метод value неявно вызывает join

Опрос и изменение состояния потока (пример)

max = 1000 thr = Thread.new do sum = 0 1.upto(max) {|i| sum += i} sum end guess = (max*(max+1))/2 if guess == thr.value puts «правильно » else puts «неправильно » end

Обработка исключений и группы потоков  Theread.abort_on_exception = true (t1.abort_on_exception = true)  Группы позволяют логически связывать потоки (по умолчанию все потоки в группе Default) file_threads = ThreadGroup.new file_threads.add f1 file_threads.add f2  В любой момент поток принадлежит только одной группе  class ThreadGroup (new, add, list)  В класс ThreadGroup можно добавлять свои методы, например: возобновление потоков в группе групповое ожидание групповое завершение class ThreadGroup def join #... end

... end Синхронизация потоков

 Критические секции — простейший способ синхронизации Thread.critical = true #код , который хотим защитить Thread.critical = false Применять только в самых простых случаях! Возможны такие комбинации операций с потоками, что поток планируется даже, если другой поток в критической секции.  Синхронизация доступа к ресурсам (mutex.rb) lock, try_lock, unlock mutex = Mutex.new mutex.lock #если мьютекс занят , ждет освобождения #something mutex.unlock

Синхронизация потоков mutex.rb

 if mutex.try_lock #не ждет освобождения , возвращает false, если занят #something else #something end

 mutex.synchronize do #something end synchronize захватывает мьютекс и автоматически освобождает его  объекты могут выступать в роли мьютекса  Библиотека mutex_m с модулем Mutex_m, который расширяет пользовательский класс: у объектов класса можно вызывать методы мьютекса

Синхронизация потоков

 Библиотека sync.rb предоставляет еще один способ синхронизации: блокировка со счетчиком locked?, shared?, exclusive?, lock, unlock, try_lock  Условная переменная — используется вместе с мьютексами (очередь потоков) require 'thread' @music = Mutex.new @violin = ConditionalVariable.new @violins_free = 2 @music.synchronize do @violin.wait(@music) while @violins_free == 0 #... end

Синхронизация потоков monitor.rb

 Monitor(monitor.rb) — еще один способ синхронизации: захваты одного и того же мьютекса могут быть вложенными Например, может понадобиться при рекурсивном вызове метода применяется для расширения класса class ConditionalVariable в библиотеке monitor.rb — расширенный по сравнению с условными переменными в Thread:  new_cond — создание условной переменной

 wait_until, wait_while — методы, блокирующие поток в ожидании выполнения условия

 wait(timeout) - можно определить timeout при ожидании (в секундах)

Сценарии и системное администрирование

 Универсальность Ruby позволяет использовать его для взаимодействия с ОС на высоком уровне (все, что есть в bash, можно реализовать с Ruby)  Запуск внешних программ

 Перехват вывода программы

 Манипулирование процессами

 Стандартный ввод/вывод

 Не всегда удобно использовать из-за сложности синтаксиса (использование различных библиотек)  Библиотека Shell (не всегда работает на Windows)  ActiveScriptRuby — язык, предоставляющий мост между COM и Ruby для Windows приложений  Ruby можно использовать в html

Сценарии и системное администрирование shell.rb

 sh = Shell.new #создали объект , ассоциированныйс текущимкаталогом sh1 = Shell.cd (''/tmp/hal'') #объект , ассоциированный с указанным каталогом

 Встроенные команды (например, , cat, tee) возвращают объекты класса Filter sh.cat (''/etc/modt'') > STDOUT ! Автоматически shell вывод команд никуда не направляет  Class Filter  понимает, что такое перенаправление ввода/вывода

 Операторы >, <, |

 Метод def_system_command позволяет «инсталлировать» системные команды по своему выбору Shell.def_system_command ''ls''

Различные сценарии

 AllInOneRuby — дистрибутив Ruby в одном файле (интерпретатор, системные классы, стандартные библиотеки)  Tar2RubyScript — программа получает дерево каталогов и создает самораспаковывающийся архив: Ruby программа и tar архив (если не библиотека, нужен файл init.rb)  Созданный архив можно запустить на любой машине, где установлен Ruby

 RubyScript2Exe — преобразует Ruby приложение в один двоичный файл(подходит для Windows, , Mac OS X):  Не компилятор

 Собирает файлы, являющиеся частью установленного дистрибутива Ruby на вашей машине (не нуждается в кросс-компиляции)

 Исполняемый файл «усечен» - в нем нет неиспользуемых библиотек

 Не требует установленного Ruby для запуска, т. к. включает интерпретатор Ruby, среду исполнения и необходимые внешние программы

 Модуль Etc — получает информацию из /etc/passwd и /etc/group  login пользователя, от имени которого запущена программа

 Структуру passwd (name, dir, shell)  Аналогичные функции для групп Тестирование и отладка

 Библиотека Test::Unit (включена в дистрибутив с 2001 года)  для анализа тестового кода применяется отражение

 для наследника класса Test::Unit::TestCase все методы, имена которых начинаются с test считаются тестовыми

 тесты выполняются в алфавитном порядке

 методы setup, teardown используются для создания особой среды выполнения тестов, вызываются для каждого теста

 утверждения assert_equal (expected, actual)

 любой исполнитель тестов можно вызвать методом run и передать параметр, описывающий набор тестов

Тестирование и отладка

 Комплект инструментов ZenTest Основной инструмент — исполняемая программа, которая генерирует файл с тестами тестируемый класс — основа для создания тестового класса:  Создается класс с именем тестируемого класса и префикса Test, наследованный от Test::Unit::TestCase, и все методы c префиксом test_

 Разработчику (или тестеру) остается только реализовать тело тестовых методов unit_diff — программа, которую следует вызывать как фильтр после тестовой программы autotest — прогоняет все тесты по мере их обновления multiruby — позволяет тестировать код относительно разных версий Ruby

Тестирование и отладка

 Отладчик Ruby (библиотека debug) ruby -rdebug myfile.rb {rdb:1} list, , break, catch, delete, help, next, quit позволяет просматривать стек вызовов и перемещаться по нему  Использование irb библиотека ruby-breakpoint (метод breakpoint) не входит в стандартный дистрибутив сеанс irb (программа интерактивной работы с Ruby) — вызывается, когда в процессе исполнения встречается точка прерывания, также позволяет вызывать ранее определенные методы и изменять значения переменных клиент drb - позволяет удаленно отлаживать программу Ruby, работающую в другом процессе

Тестирование и отладка

 Измерение покрытия кода rcov собирает статистику выполнения программы (в каталоге coverage) — очень простая утилита в файле index.html предоставляет сводную статистику и ссылки на исходные тексты, где подсвечена каждая строка, которая выполнялась хотя бы один раз имеет параметры для настройки предоставляет API для написания своих инструментов анализа  Измерение производительности профилировщик profile — выдает статистику выполнения программы, какие методы как часто вызывались и какое время это заняло библиотека benchmark — при вызове можно передать блок кода, на выходе: время, затраченное процессором в режиме пользователя, в режиме ядра, полное затраченное время  Метод inspect — предназначен для вывода объектов в виде, удобном для чтения человеком

Создание пакетов и распространение программ

 Rdoc — инструмент документирования для Ruby  Можно использовать даже, если в исходном тексте нет комментариев (анализирует текст программы и собирает информацию о классах, модулях, методах и т.д.)

 На выходе каталог doc и html-файлы в нем

 Ассоциирует комментарии с конкретными частями программы

 Документация API ссылается на сам код

 Обладает собственным механизмом разметки, чтобы не редактировать выходной html-файл вручную

 Модификаторы документации - указывают, какие части текста нужно документировать

 :doc

 :nodoc, :nodoc: all

 :notnew — предотвращает документирование метода new

Установка и подготовка пакета setup.rb

 Библиотека setup  Создать дерево каталогов с определенной структурой(lib, ext, bin, data and etc.)

 3 основных этапа — config, setup, install

 lib/foobar/pre-setup.rb

 pre или post-[имя задачи].rb (config, setup, install, test, clean, dist-clean)

 hook API, упрощающее решение ряда задач (установить значение конфигурационного параметра, получить путь к текущему исходному каталогу )  Файл на верхнем уровне дерева каталогов metaconfig содержит глобальные конфигурационные параметры (config API)

Установка и подготовка пакета RubyGems

 Простота установки и удаления gem-пакетов  Поддержка нескольких версий  Управление зависимостями  Механизм запросов и поиска пакетов  Специальное именование gem-пакетов (описательное_слово-номер_версии)  Создание gem-пакета:  Дерево каталогов со специальной структурой

 Спецификация gemspec — исполняемый файл на Ruby name, version, author, platform, summary, test_file, add_dependency

 Собственно создание пакета: выполнить созданный gemspec или вызвать gem build и передать файл спецификации — результат один и тот же

 Распространение: сайт RubyForge, архив приложений Ruby (RAA)

Ruby и Web приложенияB

 Программирование CGI(Common Gateway Interface)  Библиотека cgi.rb включена в стандартный дистрибутив (вывод и обработка форм, поддержка работы с cookies и сеансами пользователей)

 FastCGI (можно использовать недостающие функции из библиотеки cgi.rb)

 Web серверы  WEBrick — библиотека создания полноценного HTTP-сервера

 Входит в стандартный дистрибутив

 Ничего не знает о деталях Web приложений

 Оперирует сервлетами, работающими независимо друг от друга

 Обработчики монтирования и обработчики сигналов

— основная цель: повысить производительность по сравнению с WEBrick

 Часто используют с Rails

 Можно запустить как приложение(start, stop, restart)

 Система GemPlugin — автозагружаемые gem-пакеты расширяют функциональность сервера Ruby и Web приложения

— каркас для Web, построен на основе MVC (быстрая разработка Web приложений)  Nitro — комплект инструментов для разработки Web приложений  Поддерживает много архитектур и паттернов

 Облегчает разработку сложных приложений с поддержкой DB (ORM Og)

 DRY (Don`t Repeat Yourself)

 Wee (Web Engineering Easy) - «каркас для создания очень динамичных, компонентных Web приложений, на дизайн которого оказал большое влияние продукт Seaside»  Использовать вместе с Nitro

 В основе — идея компонентов

 Каркас IOWA (Interpreted Objects for Web Applications)  Работает как фоновый процесс, прослушивающий сокет в ожидании запросов

 Включает различные адаптеры (CGI, Mongrel, WEBrick)

Ruby tricks

 Единообразно обработать коллекции и объекты, не являющиеся коллекциями (обычный объект рассматривается как коллекция, содержащая только один элемент — сам объект) [*items].each do |item| # ... end

 === по сути является алиасом вызова объекта класса Proc, это означает, что объекты Proc можно использовать таким образом: def multiple_of(factor) Proc.new{|product| product.modulo(factor).zero?} end case number when multiple_of(3) puts "Multiple of 3" when multiple_of(7)

puts "Multiple of 7" end Ruby tricks

 Создать Hash для одномерного массива fruit = ["apple","red","banana","yellow"] => ["apple", "red", "banana", "yellow"]

Hash[*fruit] => {"apple"=>"red", "banana"=>"yellow"}

 match, text, number = *"Something 981".match(/([A­z]*) ([0­9]*)/)

Job = Struct.new(:name, :occupation) tom = Job.new("Tom", "Developer") name, occupation = *tom

 1.upto(100) do |i| puts i if (i == 3)..(i == 15) end Ruby tricks

 || and && string &&= string + "suffix" эквивалентно if string string = string + "suffix" end  convert a Fixnum into any base up to 36 >> 1234567890.to_s(24) => "6b1230i"

>> 1234567890.to_s(36) => "kf12oi"

Источники

 Хэл Фултон «Программирование на языке Ruby»  http://ruby-gnome2.sourceforge.jp/ - справочное руководство Ruby/GTK2  http://www.gtk.org/  http://fxruby.org/ - сайт FXRuby  http://www.erikveen.dds.nl/ruby.html - сайт автора пакетов AllInOneRuby, Tar2RubyScript, RubyScript2Exe  http://ruby-doc.org/  http://stackoverflow.com/questions/63998/hidden-features-of-ruby - Hidden features of Ruby