Ruby Advanced
Total Page:16
File Type:pdf, Size:1020Kb
Ruby Advanced Часть I Марченко Светлана Ruby Advanced Графические интерфейсы для Ruby Потоки в Ruby Сценарии и системное администрирование Тестирование и отладка Создание пакетов и распространение программ Ruby и Web приложения Ruby tricks Графические интерфейсы для Ruby (Tk, GTK+, FOX, QtRuby) Ruby/Tk Tk — платформо-независимая система Perl, Tcl (Perl/Tk) Переносимость, стабильность Корневой контейнер с виджетами + геометрический менеджер(pack, grid, place) Блоки вычисляются в контексте вызываемого объекта (instance_eval), а не в контексте вызывающей программы Ruby/GTK2 Ruby/GTK2 (GIMP Toolkit) Лежит в основе графического менеджера GNOME, но MS Windows, MAC OS X c X Window System Расширение 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, UNIX) Qt (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 <script language= «RubySctipt»> # Здесь код на Ruby </script> Сценарии и системное администрирование shell.rb sh = Shell.new #создали объект, ассоциированныйс текущимкаталогом sh1 = Shell.cd (©©/tmp/hal©©) #объект , ассоциированный с указанным каталогом Встроенные команды (например, echo, 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, Linux, 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 — позволяет