понедельник, 29 декабря 2008 г.

Создание собственного LiveCD на базе Mandriva One 2008

Введение

Под термином LiveCD понимают полноценный дистрибутив операционной системы, позволяющий загружаться прямо с исходного носителя (CD, DVD, USB Flash) без необходимости установки на жесткий диск. Вот наиболее типичные сценарии использования LiveCD:
  • Независимое мобильное рабочее место
  • Аварийный диск восстановления системы
  • Медиа-центр: аудио, видео, интернет
  • Демонстрационный диск с вашим продуктом
На сегодняшний день существует множество LiveCD дистрибутивов для самых разнообразных целей, так зачем же еще что-то придумывать? Дело в том, что у каждого пользователя свои требования и свое понимание "идеальной системы". Допустим вам не хватает какой-то программы или, наоборот, установлено слишком много лишнего, наконец, нужно заранее преднастроить систему: язык, кодировка, сетевые параметры, оформление и т.д.

В этой статье рассказывается о том как приспособить LiveCD дистрибутив Mandriva One 2008 под ваши нужды. В качестве хост-системы использовалась Mandriva 2008 PowerPack. Если вы пользуетесь другой системой - не спешите уходить! Поняв основной принцип вы разберетесь и со своим дистрибутивом. Итак, приступим.

Инструменты

Для пересборки LiveCD потребуются утилиты readcd, mkisofs и cdrecord из пакета Cdrtools, а также mksquashfs из пакета squashfs-tools. Вместо Cdrtools можно так же использовать пакет Cdrkit, входящий в стандартную поставку Mandriva, но тут могут быть подводные камни. Пакета squashfs-tools в моей поставке не оказалось, поэтому пришлось его скачать: squashfs-tools-3.2-1.r2.2mdv2007.1.i586.rpm (~80 Кб).

Сборка LiveCD

Для начала создадим отдельную директорию и сохраним ее в переменной окружения LIVE_CD. Внутри этой директории и развернутся самые интересные события:
mkdir LiveCD
cd LiveCD
export LIVE_CD=`pwd`
Теперь необходимо вставить оригинальный LiveCD в CD-ROM и сохранить его в виде ISO-образа. Если у вас уже есть готовый ISO-образ то можете пропустить этот шаг:
readcd dev=/dev/cdrom f="$LIVE_CD/mandriva_orig.iso"
В директории LIVE_CD должен появиться файл mandriva_orig.iso Теперь создадим директорию orig_iso/ и смонтируем в нее созданный ISO-образ:
mkdir "$LIVE_CD/orig_iso"
sudo mount -r -t iso9660 -o loop "$LIVE_CD/mandriva_orig.iso" \
"$LIVE_CD/orig_iso"
Посмотрим что внутри:
ls "$LIVE_CD/orig_iso"

boot/ isolinux/ LISEZMOI.pdf loopbacks/ README.pdf
Как и следовало ожидать, внутри директории orig_iso/ мы видим содержимое оригинального компакт диска.

Итак, мы подошли к первому препятствию: нам необходимо вносить изменения в файловую систему iso9660, смонтировать которую можно только на чтение. Эта задача решается в два приема: во-первых, создадим в памяти файловую систему tmpfs:
mkdir "$LIVE_CD/tmp_iso"
sudo mount -t tmpfs none "$LIVE_CD/tmp_iso"
Эта файловая система доступна как на чтение так и на запись. Все что мы запишем в tmp_iso/ будет сохраняться в памяти. Теперь объединим файловые системы iso9660 (ro) и tmpfs (rw) в одну при помощи файловой системы unionfs:
mkdir "$LIVE_CD/union_iso"
sudo mount -o dirs="$LIVE_CD/tmp_iso=rw:$LIVE_CD/orig_iso=ro" \
-t unionfs unionfs "$LIVE_CD/union_iso"
Посмотрим что внутри:
ls "$LIVE_CD/union_iso"

boot/ isolinux/ LISEZMOI.pdf loopbacks/ README.pdf
На первый взгляд ничего не изменилось - все те же файлы, что и на оригинальном CD. Тем не менее отличие есть: union_iso/ доступна на запись:
mount | grep union_iso

unionfs on /home/xander/LiveCD/union_iso type unionfs \
(rw,dirs=/home/xander/LiveCD/tmp_iso=rw:/home/xander/LiveCD/orig_iso=ro)
Все изменения которые мы сделаем в union_iso/ будут прозрачно сохраняться в памяти.

Двигаемся дальше. Давайте заглянем в папку loopbacks/ оригинального CD:
ls -lh "$LIVE_CD/orig_iso/loopbacks"

-rwx------ 1 root root 688M 2007-10-09 02:01 distrib.sqfs
Обратите внимание на размер файла distrib.sqfs - 688 мегабайт. Он занимает почти весь CD-диск. Это образ сжатой файловой системы squashfs в котором хранится файловая система LiveCD. Как и iso9660 смонтировать squashfs можно только на чтение:
mkdir "$LIVE_CD/orig_sqfs"
sudo mount "$LIVE_CD/orig_iso/loopbacks/distrib.sqfs" -o ro,loop \
-t squashfs "$LIVE_CD/orig_sqfs"
Посмортим что внутри:
ls "$LIVE_CD/orig_sqfs"

bin/ dev/ home/ lib/ mnt/ proc/ sbin/ tmp/ var/
boot/ etc/ initrd/ media/ opt/ root/ sys/ usr/
Ага! Это действительно похоже на файловую систему LiveCD. По отработанной схеме сделаем ее доступной для записи. Сначала создадим временную файловую систему в памяти:
mkdir "$LIVE_CD/tmp_sqfs"
sudo mount -t tmpfs none "$LIVE_CD/tmp_sqfs"
Теперь объединим файловые системы tmpfs (rw) и squashfs (ro) при помощи файловой системы unionfs:
mkdir "$LIVE_CD/union_sqfs"
sudo mount -o dirs="$LIVE_CD/tmp_sqfs=rw:$LIVE_CD/orig_sqfs=ro" \
-t unionfs unionfs "$LIVE_CD/union_sqfs"
Для проверки заглянем внутрь union_sqfs/:
ls "$LIVE_CD/union_sqfs"

bin/ dev/ home/ lib/ mnt/ proc/ sbin/ tmp/ var/
boot/ etc/ initrd/ media/ opt/ root/ sys/ usr/
Все как в orig_sqfs/, но теперь с возможностью записи:
mount | grep union_sqfs

unionfs on /home/xander/LiveCD/union_sqfs type unionfs \
(rw,dirs=/home/xander/LiveCD/tmp_sqfs=rw:/home/xander/LiveCD/orig_sqfs=ro)
Теперь, когда все подготовительные действия выполнены, можно приступить к редактированию дистрибутива. Для примера установим на LiveCD программу Midnight Commander (на стандартном LiveCD ее не оказалось):
sudo urpmi --quiet --auto --root="$LIVE_CD/union_sqfs" mc
Для тех кто не сталкивался с Mandriva Linux я поясню смысл последней команды. Утилита urpmi устанавливает RPM-пакеты с учетом их зависимостей. Ключ --auto просит urpmi не задавать лишних вопросов - этот режим часто используется в неинтерактивных скриптах. Ключ --quiet подавляет лишний вывод. Ключ --root заслуживает особого внимания. Поскольку в качестве хост-системы в данном примере также используется Mandriva Linux мы можем использовать RPM-репозиторий хост-системы для установки пакетов на LiveCD. Очень изящно и красиво!

Также просто можно удалить программу если она вам не нужна. В Mandriva Linux для этой цели используется утилита urpme. Давайте в качестве примера удалим OpenOffice:
sudo urpme -a --auto --root="$LIVE_CD/union_sqfs" openoffice
Ключ -a заставит urpme удалить все пакеты в названиях которых есть openoffice.

При необходимости можно редактировать любые конфигурационные файлы внутри LiveCD. Все изменения попадут в итоговую систему.

Итак, допустим мы внести все необходимые коррективы в наш будущий LiveCD-дистрибутив. Что дальше? Для начала давайте пересоберем squashfs-образ с учетом всех сделанных изменений, ведь пока все они хранятся в памяти!
sudo mksquashfs "$LIVE_CD/union_sqfs" \
"$LIVE_CD/distrib_new.sqfs"

Parallel mksquashfs: Using 2 processors
...

sudo mv -f "$LIVE_CD/distrib_new.sqfs" \
"$LIVE_CD/union_iso/loopbacks/distrib.sqfs"
Первая команда создает новый сжатый образ distrib_new.sqfs, а вторая - заменяет им оригинальный distrib.sqfs. Обратите внимание на сообщение Parallel mksquashfs: Using 2 processors. Приятно, что программа использует возможности многоядерных CPU.

Итак, образ squashfs пересобран и помещен в нужное место. Теперь необходимо пересобрать ISO-образ с новым файлом distrib.sqfs. Делается это следующей командой:
sudo mkisofs -quiet -o "$LIVE_CD/mandriva_new.iso" -input-charset iso8859-1 \
-J -R -V "MandrivaOne" -b isolinux/isolinux.bin -c isolinux/boot.cat \
-no-emul-boot -boot-load-size 4 -boot-info-table "$LIVE_CD/union_iso"
Обратите внимание на опции -b и -c. Они необходимы для того чтобы сделать CD загрузочным. Опции -no-emul-boot, -boot-load-size 4 и -boot-info-table так же специфичны для создания загрузочных дисков. Внимательно читайте mkisofs(1).

Опции -J и -R включают расширения Joliet и Rock Ridge соответственно. Опция -V задает метку тома. Если указать метку отличную от "MandrivaOne" то система откажется загружаться. Так что лучше устанавливайте на "свой" ISO такую же метку какая была на оригинальном диске.

Итак, пересобранный образ mandriva_new.iso готов, но не спешите записывать его на болванку! Сначала проверьте его в эмуляторе, например, в VirtualBox.

Для создания новой виртуальной машины выберите МашинаСоздатьДалее. Присвойте машине название и укажите тип ОС Linux 2.6. Раздел жесткого диска создавать не обязательно.

Для того чтобы "загрузиться" с ISO-образа как с CD-ROM нажмите на иконку CD/DVD-ROM, установите флажок Подключить CD/DVD и выберите опцию Файл ISO-образа. В открывшемся диалоге укажите путь к файлу mandriva_new.iso:


Теперь виртуальную машину можно запустить:


Примите поздравления! Система успешно загрузилась. Теперь ее можно записать на болванку и проверить на "настоящем" компьютере:
sudo cdrecord dev=/dev/cdrw -v -eject "$LIVE_CD/mandriva_new.iso"
Перед тем как пойти на перезагрузку не забудьте отмонтировать файловые системы, созданные в процессе сборки:
sudo umount "$LIVE_CD/union_sqfs"
sudo umount "$LIVE_CD/tmp_sqfs"
sudo umount "$LIVE_CD/orig_sqfs"
sudo umount "$LIVE_CD/union_iso"
sudo umount "$LIVE_CD/tmp_iso"
sudo umount "$LIVE_CD/orig_iso"
А вот теперь:
sudo reboot
Заключение

Как вы могли убедиться, приспособить LiveCD под свои нужны совсем не сложно. Все описанные команды можно оформить в виде shell-скриптов и автоматизировать процесс от начала до конца. Отмечу, что описанная методика не специфична исключительно для Mandriva Linux. Поняв основную идею вы разберетесь с любым дистрибутовом.

Ссылки

Статья опубликована на портале CITKIT

пятница, 5 декабря 2008 г.

Запись CD/DVD/BluRay дисков с помощью Cdrtools

Введение

В этой статье рассказывается о том как записывать CD, DVD и BluRay диски при помощи консольных утилит из пакета Cdrtools. Это идеальное решение для задач автоматизации резервного копирования и прожига дисков в системах без графического интерфейса.

Cdrtools и Cdrkit

Поддержкой пакета Cdrtools занимается Jörg Schilling. За более чем десятилетнюю историю этот проект пережил несколько ответвлений: наиболее известная ветка называется Cdrkit. Причиной ее создания стало решение Jörg Schilling о смене лицензии с GPL на CDDL. На эту тему была очень бурная полемика между разработчиками Debian, инициировавшими создание ветки, и автором оригинальной программы. Вот несколько интересных материалов на эту тему:
Утилиты из пакета Cdrkit совместимы с Cdrtools на уровне опций командной строки. Сами программы называются по другому, но символические ссылки со "старыми" именами решают эту проблему. Обычный пользователь не должен заметить подмены.

Из за смены лицензии во многие Linux-дистрибутивы (Debian, Red Hat, SUSE, Mandriva) вместо Cdrtools стали включать Cdrkit. Если в вашем дистрибутиве установлен Cdrkit и он вас устраивает, то наверное нет особого смысла возвращаться к Cdrtools. Однако, если в вашем дистрибутиве старая версия Cdrkit, содержащая ошибки подобно этой, я советую скачать и установить оригинальную версию пакета Cdrtools. В следующем разделе рассказывается о том как это сделать.

Установка

Скачать Cdrtools можно отсюда. Для написания этой статьи использовалась версия cdrtools-2.01.01a53.tar.gz (~2 Мб). Процедура сборки достаточно типична:
$ tar -xzf cdrtools-2.01.01a53.tar.gz
$ cd cdrtools-2.01.01
# ./Gmake.linux INS_BASE=/usr/local install
При необходимости отредактируйте переменную окружения PATH. В данном примере PATH=$PATH:/usr/local/bin.

Если в вашей системе уже есть пакет Cdrkit, то установка Cdrtools в /usr/local позволит вам пользоваться одним или другим пакетом по вашему выбору: достаточно лишь удалить символические ссылки, созданные Cdrkit для совместимости.

В пакет Cdrtools входит несколько утилит. Вот наиболее важные:
  • cdrecord - прожиг дисков
  • mkisofs - создание файловой системы ISO9660
  • readcd - создание образа с компакт-диска
  • isoinfo - исследование ISO-файлов
Вот как должен выглядеть вывод команд cdrecord и mkisofs из пакета Cdrtools:
cdrecord -version

Cdrecord-ProDVD-ProBD-Clone 2.01.01a53 (i686-pc-linux-gnu) Copyright (C) 1995-2008 Jorg Schilling

mkisofs -version

mkisofs 2.01.01a53 (i686-pc-linux-gnu) Copyright (C) 1993-1997 Eric Youngdale (C) 1997-2008 Jorg Schilling
Если же вы получите что-то вроде
cdrecord -version

Wodim 1.1.7.1
Copyright (C) 2006 Cdrkit suite contributors
Based on works from Joerg Schilling, Copyright (C) 1995-2006, J. Schilling

mkisofs -version

genisoimage 1.1.6 (Linux)
то значит в вашей системе cdrecord и mkisofs являются символическими ссылками на программы-двойники wodim и genisoimage из пакета Cdrkit. Эти ссылки необходимо удалить.

Пример

Для записи данных на диск необходимо подготовить ISO-образ:
mkisofs -quiet -R -J -l -o image.iso /tmp/data/
Опции mkisofs которые мы использовали:
  • -quiet подавление вывода
  • -R создать расширения RockRidge
  • -J создать расширения Joliet
  • -l разрешить длинные имена файлов
  • -o файл ISO-образа
Подготовленный образ можно теперь записать на диск:
cdrecord -scanbus

Cdrecord-ProDVD-ProBD-Clone 2.01.01a53 (i686-pc-linux-gnu) Copyright (C) 1995-2008 Jorg Schilling
Linux sg driver version: 3.5.34
Using libscg version 'schily-0.9'.
scsibus1:
1,0,0 100) 'ATA ' 'ST3160815AS ' '3.AA' Disk
1,1,0 101) *
1,2,0 102) *
1,3,0 103) *
1,4,0 104) *
1,5,0 105) *
1,6,0 106) *
1,7,0 107) *
scsibus4:
4,0,0 400) 'PIONEER ' 'DVD-RW DVR-112D' '1.21' Removable CD-ROM
4,1,0 401) *
4,2,0 402) *
4,3,0 403) *
4,4,0 404) *
4,5,0 405) *
4,6,0 406) *
4,7,0 407) *

cdrecord dev=4,0,0 blank=fast -sao -eject image.iso

Cdrecord-ProDVD-ProBD-Clone 2.01.01a53 (i686-pc-linux-gnu) Copyright (C) 1995-2008 Jorg Schilling
scsidev: '4,0,0'
scsibus: 4 target: 0 lun: 0
Linux sg driver version: 3.5.34
Using libscg version 'schily-0.9'.
Device type : Removable CD-ROM
Version : 5
Response Format: 2
Capabilities :
Vendor_info : 'PIONEER '
Identifikation : 'DVD-RW DVR-112D'
Revision : '1.21'
Device seems to be: Generic mmc2 DVD-R/DVD-RW/DVD-RAM.
Using generic SCSI-3/mmc CD-R/CD-RW driver (mmc_cdr).
Driver flags : MMC-3 SWABAUDIO BURNFREE
Supported modes: TAO PACKET SAO SAO/R96P SAO/R96R RAW/R16 RAW/R96P RAW/R96R LAYER_JUMP
Starting to write CD/DVD/BD at speed 10 in real SAO mode for single session.
Last chance to quit, starting real write 0 seconds. Operation starts.
Track 01: Total bytes read/written: 23975936/23975936 (11707 sectors).
Первой командой мы опросили все SCSI-устройства на всех SCSI-шинах и нашли там DVD-рекордер. Второй командой мы запустили прожиг CD-RW диска предварительно попросив его очистить. Дополнительную информацию читайте в руководстве: mkisofs(1) и cdrecord(1).

Заключение

В этой статье рассказано о том как записывать CD/DVD/BluRay диски при помощи консольных утилит из пакета Cdrtools. Это неоценимый и очень мощный инструмент! Также рассмотрен пакет Cdrkit и его связь с Cdrtools. Надеюсь эта статья поможет обойти подводные камни если вам понадобится параллельно с Cdrkit установить на свою машину оригинальный пакет Cdrtools.

Ссылки

Статья опубликована на портале OpenNET

среда, 3 декабря 2008 г.

Работа с CSV-файлами на Ruby

Формат CSV (Comma Separated Values) очень часто используется для переноса данных из одной системы в другую. В Ruby есть стандартная библиотека CSV, позволяющая создавать и обрабатывать такие файлы. В самом простейшем случае создание CSV-файла выглядит так:


1
2
3
4
5
6
7
8
9
#!/usr/bin/ruby

require 'csv'

CSV.open('test.csv', 'w') do |writer|
writer << ['r1c1', 'r1c2']
writer << ['r2c1', 'r2c2']
writer << [nil, nil]
end

Прочитать созданный файл можно следующим образом:


1
2
3
4
5
6
7
#!/usr/bin/ruby

require 'csv'

CSV.open('test.csv', 'r') do |row|
p row
end

Если вы обрабатываете большие объемы данных то имеет смысл попробовать библиотеку FasterCSV. Она работает быстрее и обладает большим количеством возможностей.

среда, 12 ноября 2008 г.

Работа с SVN через прокси

Система контроля версий Subversion поддерживает несколько протоколов доступа, в их числе есть протоколы HTTP и HTTPS. В случае если вы подключены к интернету через прокси потребуется дополнительная настройка клиентской программы svn. Для этого откройте файл ~/.subversion/servers и внесите в него следующие изменения:
...
[groups]
new_group = my.svn.repository.com

[new_group]
http-proxy-host = <hostname>
http-proxy-port = <port>
http-proxy-username = <username>
http-proxy-password = <password>
...
При необходимости, настройки прокси можно задать в секции global. В этом случае они будут применяться ко всем репозиториям.

Отмечу, что вариант с протоколом HTTPS более предпочтителен нежели HTTP и дело тут не только в безопасности подключения. При использовании протокола HTTP может потребоваться дополнительная настройка прокси-сервера. Более подробно об этом можно почитать тут.

суббота, 11 октября 2008 г.

Тестирование web-приложений с помощью Ruby

Введение

Тестирование web-приложений является неотъемлемой частью процесса их разработки. Существуют различные уровни тестирования, вот некоторые из них:
  • модульное тестирование;
  • интеграционное тестирование;
  • системное тестирование;
  • приемочное тестирование.
В рамках модульного тестирования проверяются минимально возможные компоненты, например, отдельные классы или функции. Интеграционное тестирование предназначено для проверки связи между компонентами. Задачей системного тестирования является проверка как функциональных, так и не функциональных требований к системе в целом. Приемочное тестирование проверяет поведение системы на предмет удовлетворения требований заказчика.

В этой статье рассказывается о высокоуровневой методике тестирования web-приложений которую можно использовать как для приемочного так и для системного тестирования. Ключевую роль при этом играет Ruby-библиотека Watir (Web Application Testing In Ruby). Библиотека Watir позволяет запрограммировать действия браузера Internet Explorer на языке Ruby. Таким образом можно автоматизировать значительную часть ручной работы тестеров по заполнению форм, переходу по ссылкам, проверке User-Stories т.д.

Библиотека Watir

Для управления браузером библиотека Watir использует протокол OLE. Это накладывает определенные ограничения как на выбор платформы, так и на выбор браузера. Так, на момент написания этих строк Watir работает только под Windows и только с Internet Explorer. Не отчаивайтесь раньше времени если у вас другая система или вы пользуетесь другим браузером! Существуют версии Watir для Firefox и для Safari:
  • FireWatir - работает с Firefox под Linux, Windows и Mac;
  • SafariWatir - работает с Safari под Mac.
В перспективе разработчики планируют объединить все три версии в один проект. Отмечу, что аналоги Watir есть и для других языков программирования:
  • Watij - версия Watir для Java;
  • WatiN - версия Watir для .Net;
  • BrowserUnit - еще одна версия Watir для .Net.
Очень подробный каталог инструментов, аналогичных Watir можно найти тут. Почти наверняка вы найдете подходящее решение для вашей платформы и языка программирования. В этой же статье речь пойдет только об оригинальной версии Watir.

Установка

Если вы подключены к интернету напрямую, то для установки Watir достаточно всего одной команды:
gem install watir

Bulk updating Gem source index for: http://gems.rubyforge.org
Install required dependency win32-process? [Yn] Y
Install required dependency windows-pr? [Yn] Y
Install required dependency windows-api? [Yn] Y
Install required dependency win32-api? [Yn] Y
Select which gem to install for your platform (i386-mswin32)
1. win32-api 1.2.0 (ruby)
2. win32-api 1.2.0 (x86-mswin32-60)
3. win32-api 1.1.0 (x86-mswin32-60)
4. win32-api 1.1.0 (ruby)
5. Skip this gem
6. Cancel installation
> 2
Install required dependency win32-api? [Yn] Y
Select which gem to install for your platform (i386-mswin32)
1. win32-api 1.2.0 (x86-mswin32-60)
2. win32-api 1.2.0 (ruby)
3. Skip this gem
4. Cancel installation
> 1
Install required dependency activesupport? [Yn] Y
Successfully installed watir-1.5.6
Successfully installed win32-process-0.5.9
Successfully installed windows-pr-0.9.4
Successfully installed windows-api-0.2.4
Successfully installed win32-api-1.2.0-x86-mswin32-60
Successfully installed win32-api-1.2.0-x86-mswin32-60
Successfully installed activesupport-2.1.1
Installing ri documentation for watir-1.5.6...
Installing ri documentation for win32-process-0.5.9...
Installing ri documentation for windows-pr-0.9.4...
Installing ri documentation for windows-api-0.2.4...
Installing ri documentation for win32-api-1.2.0-x86-mswin32-60...
Installing ri documentation for win32-api-1.2.0-x86-mswin32-60...
Installing ri documentation for activesupport-2.1.1...
Installing RDoc documentation for watir-1.5.6...
Installing RDoc documentation for win32-process-0.5.9...
Installing RDoc documentation for windows-pr-0.9.4...
Installing RDoc documentation for windows-api-0.2.4...
Installing RDoc documentation for win32-api-1.2.0-x86-mswin32-60...
Installing RDoc documentation for win32-api-1.2.0-x86-mswin32-60...
Installing RDoc documentation for activesupport-2.1.1...
Если вы подключены через прокси, то перед инсталляцией потребуется задать переменную окружения http_proxy в следующем виде:
http://user:password@host:port
Для установки переменной окружения выберите "Мой компьютер" -> "Свойства" -> "Дополнительно" -> "Переменные среды"-> "Создать".

После установки запустите интерактивную консоль Ruby irb и наберите:
irb(main):001:0> require 'watir'

=> true

irb(main):002:0>
Если при загрузке модуля watir не возникло ошибок, значит установка прошла успешно.

Пример

Следующий пример демонстрирует базовые принципы работы с библиотекой Watir. Сохраните этот код в файле и запустите его на выполнение. Со стороны будет казаться, что браузер делает все сам: загружает страницы, заполняет формы, нажимает на кнопки и т.д. Для удобства, активный элемент подсвечивается желтым цветом.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#
# simple_example.rb
#
# Александр Симаков, <xdr (тчк) box на Google Mail>
# http://alexander-simakov.blogspot.com/
#

# Подключаем библиотеку Watir
require 'watir'

# Открываем новое окно IE
ie = Watir::IE.new

# Переходим на страницу Google
ie.goto "http://www.google.ru/"

# Заполняем поисковый запрос
ie.text_field(:name, "q").set "Watir home page"

# Нажимаем на кнопку "Мне повезет!"
ie.button(:name, "btnI").click

# Проверяем, есть ли на странице указанный текст
if ie.text.include? "Web App Testing in Ruby"
puts "Yes!"
end

Итак, давайте разберемся как работает эта программа. В начале мы открываем новое окно Internet Explorer. Отмечу, что Watir также позволяет подключаться и к уже открытым окнам. Нужное окно при этом можно найти либо по ссылке, которая указана в адресной строке, либо по заголовку окна.

Далее мы переходим на сайт Google. На главной странице имеется поле для ввода запроса и две кнопки. Watir позволяет искать элементы расположенные на странице по многим параметрам: по атрибутам id, name, class, по заголовку, по ссылке, по порядковому номеру, по выражению xpath и т.д. В зависимости от типа элемента к которому вы хотите обратиться этот список может несколько отличаться. Так в строке 18 листинга мы обращаемся к текстовому полю у которого атрибут name имеет значение q. Если такой элемент существует, то Watir вернет объект класса TextField. В этом классе определен метод set, который заполняет текстовое поле: мы хотим найти домашнюю страницу Watir.

Теперь нажмем на кнопку "Мне повезет!". В отличие от обычного поиска мы автоматически перейдем по самой релевантной ссылке. Поскольку наш запрос достаточно точен мы с очень высокой долей вероятности попадем на домашнюю страницу проекта Watir.

Отмечу, что библиотека Watir позволяет не только находить объекты по различным критериям и манипулировать ими, но и анализировать результат. Так в строке 24 листинга мы проверяем содержит ли страница на которую мы перешли строку "Web App Testing in Ruby". Эту возможность можно использовать для написания модульных тестов.

IE Developer Toolbar

Неоценимую помощь в написании тестовых сценариев оказывает IE Developer Toolbar - специальная отладочная панель для Internet Explorer. С ее помощью можно без труда просмотреть атрибуты любого элемента на странице:


Скачать IE Developer Toolbar можно отсюда (~ 700 Kb). В качестве альтернативы можно также попробовать другую панель - DebugBar.

Интерактивная консоль Ruby

Если при написании тестового сценария вы зашли в тупик, например, не можете найти элемент, генерируемый автоматически при помощи JavaScript, попробуйте irb - интерактивную консоль Ruby. Это незаменимый и универсальный инструмент Ruby-разработчика на все случаи жизни. Продемонстрируем методику использования irb на простом примере:
irb(main):001:0> require 'watir'

=> true

irb(main):002:0> ie = Watir::IE.new

=> #<Watir::IE:0x340db40 @ole_object=nil, @typingspeed=0.08 ...

irb(main):003:0> ie.goto "http://www.google.ru/"

=> 1.015

irb(main):004:0> ie.show_all_objects

-----------Objects in page -------------
...
hidden name=hl id= value=ru alt= src=
text name=q id= value= alt= src=
submit name=btnG id= value=Поиск в Google alt= src=
submit name=btnI id= value=Мне повезёт! alt= src=
radio name=lr id=all value= alt= src=
radio name=lr id=il value=lang_ru alt= src=
hidden name=aq id= value=f alt= src=
hidden name=oq id= value= alt= src=
...
=> nil

irb(main):005:0> ie.button(:name, "btnG").flash

=> nil

irb(main):006:0>

В этом примере мы загрузили библиотеку Watir, открыли новое окно, перешли на сайт Google и попросили вывести все доступные на данной странице объекты. В этом списке имеются две кнопки: btnG и btnI. Последняя команда заставляет кнопку "Поиск в Google" мерцать желтым цветом некоторое время. Этот прием удобно использовать для поиска элементов.

Что дальше

В этой статье мы познакомились с библиотекой Watir. Это очень мощный и гибкий инструмент с помощью которого можно автоматизировать тестирование любого web-приложения. За время существования проекта вокруг него сформировалось внушительное сообщество пользователей. На WiKi-портале сообщества можно найти статьи, обзоры, учебники, FAQ, спецификации и другую полезную информацию по Watir. Заходите и учитесь!

Статья опубликована на портале CITForum

вторник, 2 сентября 2008 г.

Книжная полка

Язык программирования Perl

Программирование на Perl, 3-е издание
Ларри Уолл, Том Кристиансен, Джон Орвант

Знаменитая "Кэмел-бук"! Главная книга по Perl, написанная создателем языка. Эту книгу нельзя назвать ни учебником для начинающих (простой материал чередуется со сложным) ни чистым справочником (книгу можно с интересом прочитать "от корки до корки"). Скорее это всеобъемлющая энциклопедия в которой описаны все тонкости и нюансы программирования на Perl.

Оценка по шкале ИМХО: 5

Perl: изучаем глубже, 2-е издание
Рэндал Шварц, Фой Брайан, Том Феникс

Эта книга - продолжение классического учебника по языку Perl известного как "Лама". Рассмотрены пакеты и пространства имен, ссылки и области видимости, создание и использование модулей, создание дистрибутивов и аспекты тестирования. Очень понятно и доходчиво объясняются механизмы ООП в контексте языка Perl. Если вы уже знакомы с языком Perl и хотите расширить свои познания, то эта книга придется в самый раз.

Оценка по шкале ИМХО: 5

Разработка сетевых программ на Perl
Линкольн Штайн

В этой книге Линкольн Штайн, известный специалист по языку Perl, рассказывает о том как использовать наиболее популярные сетевые протоколы (HTTP, SMTP, POP3, FTP, Telnet и т.д.) в своих программах. Кроме этого рассматриваются низкоуровневое программирование TCP/UDP сокетов, различные модели ввода-вывода и основы создания параллельных (ветвящихся) сетевых серверов. На мой взгляд очень полезная книга.

Оценка по шкале ИМХО: 4

Perl отладчик. Карманный справочник.
Ричард Фоули

Небольшой и удобный справочник по функциям отладчика Perl. В этой книге подробно рассматриваются всевозможные команды, опции и переменные отладчика. Приводятся примеры, облегчающие процесс отладки приложений.

Оценка по шкале ИМХО: 4


Mastering Perl/Tk
Stephen O. Lidie, Nancy Walsh

Хотя в языке Perl и имеется поддержка наиболее распространенных графических тулкитов, GUI разработанные на Perl - довольно большая редкость. Одна из причин - отсутствие хороших книг по данной тематике. Книга "Mastering Perl/Tk" явление совершенно уникальное: Tk - единственный графический тулкит, чей Perl-интерфейс удостоился отдельной книги. Данная книга представляет из себя увлекательный и интересный учебник: изложение ведется от простого к сложному. В книге масса примеров и полезных советов. В заключительной её части приводится справочная информация для тех, кто уже овладел Perl/Tk.

К сожалению, версия Tk, описываемая в этой книге, сильно устарела. Сама книга также не первой свежести - 2002 год издания. Тем не менее, большая часть информации актуальна и по сей день.

Оценка по шкале ИМХО: 5

Язык программирования Python

Программирование на Python, 2-е издание
Марк Лутц

Если у вас уже есть некоторый опыт программирования на Python, то эта книга придется очень кстати. В ней рассказывается о том как эффективно решать типовые задачи программирования на языке Python. Книга фактически содержит в себе четыре части, которые освещают создание сценариев для Интернета, системное программирование, программирование GUI с использованием Tkinter и интеграцию с языком C. В ней также рассказывается о новых инструментах и приложениях Python, включая: Jython - версию Python, компилируемую в виде байт-кодов Java; расширения Active Scripting и COM; Zope - систему веб-приложений с открытым исходным кодом; генераторы кода HTMLgen и SWIG; поддержку потоков; модули CGI и протоколов Интернета.

Оценка по шкале ИМХО: 4

Язык программирования Ruby

Программирование на языке Ruby. Идеология языка, теория и практика применения, 2-е издание
Хэл Фултон

Это одна из первых книг по языку Ruby, переведенных на русский. В книге дается обзор терминологии и основных принципов Ruby: объектно-ориентированное программирование, базы данных, работа с графическим интерфейсом и многое другое. Всего приводится свыше 400 примеров, разбитых по различным аспектам программирования. По своей структуре эта книга напоминает что-то среднее между сборником готовых рецептов и справочником по языку. Если у вас уже есть опыт программирования на Ruby, то в этой книге вы найдете для себя много нового. Если вы новичок в Ruby - поищете лучше какой-нибудь учебник.

Оценка по шкале ИМХО: 4

Гибкая разработка веб-приложений в среде Rails
Томас Д., Ханссон Д. Х.

Хорошая книжка по фреймворку Ruby on Rails, написанная его создателем. Книгу можно условно разделить на две части. В первой части читатель знакомится с основными возможностями Rails на примере простого книжного магазина. Во второй части детально излагается внутренее устройство Rails, тестирование, развертывание и другие темы. Стоит отметить, что эта книга была написана во времена Rails 1.x и с выходом Rails 2.x она несколько устарела. Разумеется это не минус книге, а скорее плюс фреймворку Rails, который развивается очень быстро.

Оценка по шкале ИМХО: 4

СУБД MySQL

MySQL. Руководство администратора
MySQL AB

Руководство по администрированию MySQL от производителя. Книга основана на официальной документации и видимо поэтому написана несколько суховатым языком. В остальном, неплохой источник информации.

Оценка по шкале ИМХО: 4

MySQL. Справочник по языку
МySQL AB

Справочник по языку MySQL от разработчика СУБД. Книга, также как и предыдущая, основана на официальной документации, поэтому стить изложения очень конспективный. С другой стороны, справочник таким и должен быть.

Оценка по шкале ИМХО: 4

MySQL. Сборник рецептов
Поль Дюбуа

Отличная книга для тех, кто привык учиться на примерах: в книге их огромное число. Особенность предлагаемых примеров в том, что они решают задачи, ежедневно возникающие у программистов. Каждой задаче, обсуждаемой в книге, соответствует проработанное решение или рецепт с небольшим фрагментом кода на Perl, Python, Java или PHP, который можно вставлять прямо в приложение. Но и это ещё не всё. Работа каждого фрагмента подробно поясняется, что позволяет разобраться, как и почему все это работает, и применить приемы к схожим ситуациям. Единственный нюанс - в книге рассматривается четвёртая версия MySQL, что не позволяет использовать многие возможности последних версий этой СУБД.

Оценка по шкале ИМХО: 5

Программирование для UNIX

UNIX: разработка сетевых приложений, 2-е издание
Стивенс

Эта книга - настоящий клад для тех кто хочет разобраться с программированием сетевых приложений под UNIX. Автор излагает материал очень полно, доступно и интересно: книга читается буквально на "одном духу". Каждую идею Стивенс демонстрирует на конкретном примере, который тут же можно набрать на клавиатуре и увидеть все воочию. Настоятельно рекомендую каждому UNIX-оиду! Кстати, в продаже уже есть 3-е издание на русском.

Оценка по шкале ИМХО: 5

UNIX: взаимодействие процессов, 2-е издание
Стивенс

В оригинале эта книга называется "UNIX Network Programming, Volume 2, Second Edition: Interprocess Communications" и по сути является продолжением предыдущей. В этой книге автор делает акцент на описание таких средств межпроцессного взаимодействия в UNIX как передача сообщений, разделяемая память, удаленный вызов процедур. Также рассматриваются вопросы многопоточного программирования и средств синхронизации. Это ещё одна великолепная книга Стивенса, которую можно порекомендовать любому программисту на UNIX.

Оценка по шкале ИМХО: 5

Компьютерные сети

Компьютерные сети, 4-е издание
Эндрю Таненбаум

Классическая книга по устройству компьютерных сетей, написанная признанным специалистом. Эндрю Таненбаум является автором учебной операционной системы MINIX и курса по операционным системам. В этой книге подробно и доступно изложены основные концепции, определяющие современное состояние и тенденции развития компьютерных сетей. Отличная книга.

Оценка по шкале ИМХО: 5

Методики разработки ПО

Человеческий фактор: успешные проекты и команды
Том Демарко, Тимоти Листер

Том Демарко и Тимоти Листер возглавляют консалтинговую компанию, специализируясь на оценках, производительности, руководстве и корпоративной культуре. Они на примере реальных историй рассказывают обо всем что на самом деле мешает продуктивно работать программистам и руководителям проектов, а так же о том, что сложнейшие проблемы разработки ПО имеют человеческую, а не техническую природу. Они не дают готовых рецептов, но заставляют глубоко задуматься и переосмыслить многие вещи. Отличная книга!

Оценка по шкале ИМХО: 5

Мифический человеко-месяц, или Как создаются программные системы
Фредерик Брукс

Это одна из наиболее цитируемых и известных книг по методикам разработки ПО. Не могу сказать, что эта книга произвела на меня сильное впечатление, но ради интереса прочитать стоит.

Оценка по шкале ИМХО: 4

Совершенный код. Практическое руководство по разработке программного обеспечения
Стив Макконнелл

В этой книге автор делится опытом коммерческих разработок ПО и представляет практическое руководство для широкого круга программистов. В подтверждение каждого аргумента приводится пример кода (как правило на C++ или Java). Довольно интересная книга если вы хотите увеличить свою продуктивность и повысить качество кода.

Оценка по шкале ИМХО: 4

Профессиональная разработка программного обеспечения
Стив Макконнелл

В этой книге автор рассказывает о типичных проблемах с которыми сталкиваются при разработке программных продуктов: срыв сроков поставки, превышение бюджета, низкое качество и т.д. Всю книгу пронизывают рассуждения о кодексе этики и профессионального поведения инженеров ПО, о программах сертификации инженеров ПО, о фирме которой успешно руководит Стив, об индустрии разработки ПО в целом, ее перспективах и проблемах. Другими словами, ожидать от этой книги слишком многого не стоит. ИМХО, только троечка.

Оценка по шкале ИМХО: 3

Приемы объектно-ориентированного проектирования
Гамма Э., Хелм Р., Джонсон Р., Влиссидес Дж.

Это, пожалуй, самая известная и именитая книга по шаблонам объектно-ориентированного проектирования. Эту книгу можно порекомендовать всем, кто изучает ООП, но следует иметь в виду, что книга довольно сложная и скорее всего для полного понимания её придется перечитать не один раз.

Оценка по шкале ИМХО: 5

Прочее

Регулярные выражения, 3-е издание
Джеффри Фридл

Если вы думаете что неплохо разбираетесь в регулярных выражениях, настоятельно советую приобрести эту книгу. После прочтения первых глав вы поймете какой величины айсберг был скрыт от ваших глаз. В этой уникальной в своем роде книге автор предельно понятно и доступно рассказывает что же на самом деле происходит за "кулисами" регулярных выражений и как их использовать максимально эффективно. Обсудив механизм работы регулярных выражений в целом, автор рассказывает об особенностях их реализации в таких языках как: Perl, PHP, Java, Python, Ruby, MySQL, VB.NET, C# (и других языках платформы .NET). Просто потрясающая книга!

Оценка по шкале ИМХО: 5

DNS и BIND, 4-е издание
Ли К., Альбитц П.

Если вы хотите детально разобраться с системой DNS вообще и пакетом BIND в частности, то эта книга - лучший выбор. В ней рассмотрены: функциональность, принципы работы, причины использования DNS; поиск собственного места в пространстве имен Интернета; установка и настройка серверов имен; применение MX-записей для маршрутизации почты; настройка узлов на работу с DNS; разделение доменов на поддомены; обеспечение безопасности DNS а также множество других вопросов. Пятое издание этой книги уже переведено на русский.

Оценка по шкале ИМХО: 5

четверг, 28 августа 2008 г.

Веб-сервисы и Ruby

Введение

Веб-сервисы - это технология, позволяющая приложениям, написанным на разных языках программирования и работающих на различных программно-аппаратных платформах легко обмениваться данными через четко-определенные интерфейсы. По своей сути, веб-сервисы являются одним из воплощений технологии RPC - удаленного вызова процедур. В основе веб-сервисов лежат следующие стандарты:
  • XML - для передачи структурированных данных;
  • SOAP - протокол обмена сообщениями на базе XML;
  • WSDL - язык описания интерфейсов веб-сервисов;
  • UDDI - каталог веб-сервисов.
В этой статье рассказывается о том как подключаться к веб-сервисам с использованием языка программирования Ruby. В качестве примера мы рассмотрим веб-сервис ЦБРФ для получения курса валют.

Установка

Для работы с веб-сервисами потребуется библиотека SOAP4R. Не смотря на то, что облегченная версия этой библиотеки уже включена в стандартную поставку Ruby, настоятельно рекомендуется установить полную версию. Если вы подключены к интернету напрямую, то достаточно всего одной команды:
# gem install soap4r

Bulk updating Gem source index for: http://gems.rubyforge.org
Install required dependency httpclient? [Yn] Y
Successfully installed soap4r-1.5.8
Successfully installed httpclient-2.1.2
Installing ri documentation for httpclient-2.1.2...
Installing RDoc documentation for httpclient-2.1.2...
Если вы подключены через прокси, то перед инсталляцией потребуется задать переменную окружения http_proxy. В Линуксе это можно сделать следующим образом:
export http_proxy=http://user:password@host:port
Для установки переменной окружения под Windows выберите "Мой компьютер" -> "Свойства" -> "Дополнительно" -> "Переменные среды"-> "Создать".

Если при работе через прокси-сервер вы столкнетесь с ошибкой "407 Proxy Authentication Required", прочитайте этот пост. Там описывается решение проблемы.

Подключение к веб-сервису

Описание веб-сервиса, к которому мы собираемся подключаться, расположено по адресу http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL. Описание задается на языке WSDL - Web Service Description Language. Фактически, это XML-документ определенной структуры.

В описании указывается какие методы предоставляет веб-сервис и как их следует вызывать. Нас интересует метод getCursOnDateXML. Он принимает в качестве аргумента дату и возвращает массив записей следующего вида:
  • Название валюты (Vname);
  • Номинал (Vnom);
  • Курс (Vcurs);
  • Цифровой код валюты (Vcode);
  • Символьный код валюты (VchCode).
Для того чтобы воспользоваться веб-сервисом нам необходимо сгенерировать клиентские заглушки (stubs). Эта процедура выполняется при помощи программы wsdl2ruby.rb, которая входит в состав библиотеки SOAP4R:
wsdl2ruby.rb --wsdl http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?WSDL --type client

ignored element: {http://schemas.xmlsoap.org/wsdl/soap12/}binding
ignored element: {http://schemas.xmlsoap.org/wsdl/soap12/}operation
ignored element: {http://schemas.xmlsoap.org/wsdl/soap12/}body
ignored element: {http://schemas.xmlsoap.org/wsdl/soap12/}address
I, [2008-09-07T00:04:04.847391 #5995] INFO -- app: Creating class definition.
I, [2008-09-07T00:04:04.847750 #5995] INFO -- app: Creates file 'default.rb'.
I, [2008-09-07T00:04:05.060365 #5995] INFO -- app: Creating mapping registry definition.
I, [2008-09-07T00:04:05.060776 #5995] INFO -- app: Creates file 'defaultMappingRegistry.rb'.
I, [2008-09-07T00:04:05.119316 #5995] INFO -- app: Creating driver.
I, [2008-09-07T00:04:05.119752 #5995] INFO -- app: Creates file 'defaultDriver.rb'.
I, [2008-09-07T00:04:05.219052 #5995] INFO -- app: Creating client skelton.
I, [2008-09-07T00:04:05.219560 #5995] INFO -- app: Creates file 'DailyInfoClient.rb'.
I, [2008-09-07T00:04:05.319125 #5995] INFO -- app: End of app. (status: 0)
Как видно из отладочного вывода, программа сгенерировала четыре файла:
  • default.rb;
  • defaultMappingRegistry.rb;
  • defaultDriver.rb;
  • DailyInfoClient.rb.
Для работы с веб-сервисом необходимы первые три. Последний файл не обязателен. Это пример клиентского кода. Итак, теперь все готово для написания тестового приложения:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/usr/bin/ruby

#
# get_curs.rb
#
# Александр Симаков, <xdr (тчк) box на Google Mail>
# http://alexander-simakov.blogspot.com/
#

# Подключаем библиотеку SOAP4R
require 'rubygems'
require_gem 'soap4r'

# Подключаем клиентские заглушки
require 'defaultDriver.rb'

# При помощи этого объекта мы будем вызывать
# методы веб-сервиса
serv = DailyInfoSoap.new

# Выводить отладочную информацию если ruby
# был запущен с ключом -d
serv.wiredump_dev = STDERR if $DEBUG

# Формируем запрос
request = GetCursOnDateXML.new(DateTime.now)

# Отправляем запрос на сервер и получаем ответ
response = serv.getCursOnDateXML(request)

# Анализируем ответ и выводим результат
items = response.getCursOnDateXMLResult.valuteData.valuteCursOnDate

items.each do |item|
puts "---------------------------------"
puts "Название: " + item['Vname'].strip
puts "Числовой код: " + item['Vcode']
puts "Символьный код: " + item['VchCode']
puts "Номинал: " + item['Vnom']
puts "Курс: " + item['Vcurs']
end

Сохраните этот файл в той же директории и запустите его на выполнение. Вот как выглядел результат на момент написания статьи:
---------------------------------
Название: Австралийский доллар
Числовой код: 36
Символьный код: AUD
Номинал: 1
Курс: 21.0261
---------------------------------
Название: Фунт стерлингов Соединенного королевства
Числовой код: 826
Символьный код: GBP
Номинал: 1
Курс: 44.9826
---------------------------------
Название: Белорусский рубль
Числовой код: 974
Символьный код: BYR
Номинал: 1000
Курс: 11.9615
---------------------------------
Название: Датская крона
Числовой код: 208
Символьный код: DKK
Номинал: 10
Курс: 48.5829
---------------------------------
Название: Доллар США
Числовой код: 840
Символьный код: USD
Номинал: 1
Курс: 25.2626
---------------------------------
Название: Евро
Числовой код: 978
Символьный код: EUR
Номинал: 1
Курс: 36.2670
---------------------------------
Название: Исландская крона
Числовой код: 352
Символьный код: ISK
Номинал: 100
Курс: 28.8435
---------------------------------
Название: Казахский тенге
Числовой код: 398
Символьный код: KZT
Номинал: 100
Курс: 21.1120
---------------------------------
Название: Канадский доллар
Числовой код: 124
Символьный код: CAD
Номинал: 1
Курс: 23.8642
---------------------------------
Название: Китайский юань Жэньминьби
Числовой код: 156
Символьный код: CNY
Номинал: 10
Курс: 36.9304
---------------------------------
Название: Норвежская крона
Числовой код: 578
Символьный код: NOK
Номинал: 10
Курс: 45.2719
---------------------------------
Название: СДР (специальные права заимствования)
Числовой код: 960
Символьный код: XDR
Номинал: 1
Курс: 39.0691
---------------------------------
Название: Сингапурский доллар
Числовой код: 702
Символьный код: SGD
Номинал: 1
Курс: 17.7668
---------------------------------
Название: Новая турецкая лира
Числовой код: 949
Символьный код: TRY
Номинал: 1
Курс: 20.7564
---------------------------------
Название: Украинская гривна
Числовой код: 980
Символьный код: UAH
Номинал: 10
Курс: 53.5225
---------------------------------
Название: Шведская крона
Числовой код: 752
Символьный код: SEK
Номинал: 10
Курс: 38.3377
---------------------------------
Название: Швейцарский франк
Числовой код: 756
Символьный код: CHF
Номинал: 1
Курс: 22.5962
---------------------------------
Название: Японская иена
Числовой код: 392
Символьный код: JPY
Номинал: 100
Курс: 23.2653
Отмечу, что данные возвращаются в кодировке UTF-8. Таким образом, если на вашем компьютере используется другая кодировка, то названия валют будут нечитаемыми. В этом случае придется конвертировать данные вручную.

Как это работает

Итак, давайте разберемся как работает эта программа. Нам известно, что метод getCursOnDateXML получает на вход дату и возвращает информацию о курсе валют. Но каким образом передать методу аргумент и как интерпретировать полученный ответ? Для начала, откроем файл defaultDriver.rb и найдем в нем название интересующего нас метода:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
require 'default.rb'
require 'defaultMappingRegistry.rb'
require 'soap/rpc/driver'

class DailyInfoSoap < ::SOAP::RPC::Driver
DefaultEndpointUrl = "http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx"

Methods = [
...
[ "http://web.cbr.ru/GetCursOnDateXML",
"getCursOnDateXML",
[ ["in", "parameters", ["::SOAP::SOAPElement", "http://web.cbr.ru/", "GetCursOnDateXML"]],
["out", "parameters", ["::SOAP::SOAPElement", "http://web.cbr.ru/", "GetCursOnDateXMLResponse"]] ],
{ :request_style => :document, :request_use => :literal,
:response_style => :document, :response_use => :literal,
:faults => {} }
],
...
end
end

Видно, что на вход поступает объект класса GetCursOnDateXML, а на выходе мы получаем объект класса GetCursOnDateXMLResponse. Определение этих классов находится в файле default.rb:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
require 'xsd/qname'

...

# {http://web.cbr.ru/}GetCursOnDateXML
# on_date - SOAP::SOAPDateTime
class GetCursOnDateXML
attr_accessor :on_date

def initialize(on_date = nil)
@on_date = on_date
end
end

# {http://web.cbr.ru/}GetCursOnDateXMLResponse
# getCursOnDateXMLResult -
# GetCursOnDateXMLResponse::GetCursOnDateXMLResult
class GetCursOnDateXMLResponse

# inner class for member: GetCursOnDateXMLResult
# {http://web.cbr.ru/}GetCursOnDateXMLResult
class GetCursOnDateXMLResult
attr_reader :__xmlele_any

def set_any(elements)
@__xmlele_any = elements
end

def initialize
@__xmlele_any = nil
end
end

attr_accessor :getCursOnDateXMLResult

def initialize(getCursOnDateXMLResult = nil)
@getCursOnDateXMLResult = getCursOnDateXMLResult
end
end

...

С классом GetCursOnDateXML все достаточно очевидно. В его конструктор достаточно передать дату, что мы и делаем в строке 26 листинга get_curs.rb. Класс GetCursOnDateXMLResponse выглядит несколько сложнее. В нем определен метод getCursOnDateXMLResult который, судя по всему, и возвращает результат. Но в каком формате? Давайте заглянем в WSDL-файл и найдем там описание типа GetCursOnDateXMLResult:
...
<s:element minOccurs="0" maxOccurs="1" name="GetCursOnDateXMLResult">
<s:complexType mixed="true">
<s:sequence>
<s:any/>
</s:sequence>
</s:complexType>
</s:element>
...
Из этого фрагмента можно заключить, что GetCursOnDateXMLResult - это список "чего угодно" (s:any). В таких ситуациях на помощь приходит включение отладочного вывода (см. строку 23 листинга get_curs.rb) и irb - интерактивная консоль Ruby. При помощи irb можно наблюдать как исполняется код по мере его написания.

Итак, запускаем irb (из директории где находятся наши файлы), загружаем библиотеку SOAP4R и клиентские заглушки:
$ irb
irb(main):001:0> require 'rubygems'

=> true

irb(main):002:0> require_gem 'soap4r'

=> true

irb(main):003:0> require 'defaultDriver.rb'

=> true

irb(main):004:0>
Создаем объект-драйвер для работы с веб-сервисом и включаем отладочный вывод:
irb(main):004:0> serv = DailyInfoSoap.new

=> #<DailyInfoSoap:#<SOAP::RPC::Proxy:http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx>>

irb(main):005:0> serv.wiredump_dev = STDERR

=> #<IO:0xb7c4ff60>

irb(main):006:0>
Далее создаем запрос с текущей датой и отправляем его на сервер:
irb(main):006:0> request = GetCursOnDateXML.new(DateTime.now)

=> #<GetCursOnDateXML:0xb76797d0 @on_date=#<DateTime: 70695916331796971/28800000000,1/6,2299161>>

irb(main):007:0> response = serv.getCursOnDateXML(request)

Wire dump:

= Request

! CONNECT TO www.cbr.ru:80
! CONNECTION ESTABLISHED
POST /DailyInfoWebServ/DailyInfo.asmx HTTP/1.1
SOAPAction: "http://web.cbr.ru/GetCursOnDateXML"
Content-Type: text/xml; charset=utf-8
User-Agent: SOAP4R/1.5.8 (/187, ruby 1.8.6 (2007-03-13) [i586-linux-gnu])
Date: Tue, 09 Sep 2008 19:36:45 GMT
Content-Length: 405
Host: www.cbr.ru

<?xml version="1.0" encoding="utf-8" ?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<n1:GetCursOnDateXML xmlns:n1="http://web.cbr.ru/">
<n1:On_date>2008-09-09T23:36:35.390913+04:00</n1:On_date>
</n1:GetCursOnDateXML>
</env:Body>
</env:Envelope>

= Response

HTTP/1.1 200 OK
Date: Tue, 09 Sep 2008 19:40:34 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Content-Type: text/xml; charset=utf-8
Content-Length: 7601

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas. xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance "
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetCursOnDateXMLResponse xmlns="http://web.cbr.ru/">
<GetCursOnDateXMLResult>
<ValuteData xmlns="">
<ValuteCursOnDate>
<Vname>Австралийский доллар</Vname>
<Vnom>1</Vnom>
<Vcurs>21.0261</Vcurs>
<Vcode>36</Vcode>
<VchCode>AUD</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Фунт стерлингов Соединенного королевства</Vname>
<Vnom>1</Vnom>
<Vcurs>44.9826</Vcurs>
<Vcode>826</Vcode>
<VchCode>GBP</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Белорусский рубль</Vname>
<Vnom>1000</Vnom>
<Vcurs>11.9615</Vcurs>
<Vcode>974</Vcode>
<VchCode>BYR</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Датская крона</Vname>
<Vnom>10</Vnom>
<Vcurs>48.5829</Vcurs>
<Vcode>208</Vcode>
<VchCode>DKK</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Доллар США</Vname>
<Vnom>1</Vnom>
<Vcurs>25.2626</Vcurs>
<Vcode>840</Vcode>
<VchCode>USD</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Евро</Vname>
<Vnom>1</Vnom>
<Vcurs>36.2670</Vcurs>
<Vcode>978</Vcode>
<VchCode>EUR</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Исландская крона</Vname>
<Vnom>100</Vnom>
<Vcurs>28.8435</Vcurs>
<Vcode>352</Vcode>
<VchCode>ISK</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Казахский тенге</Vname>
<Vnom>100</Vnom>
<Vcurs>21.1120</Vcurs>
<Vcode>398</Vcode>
<VchCode>KZT</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Канадский доллар</Vname>
<Vnom>1</Vnom>
<Vcurs>23.8642</Vcurs>
<Vcode>124</Vcode>
<VchCode>CAD</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Китайский юань Жэньминьби</Vname>
<Vnom>10</Vnom>
<Vcurs>36.9304</Vcurs>
<Vcode>156</Vcode>
<VchCode>CNY</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Норвежская крона</Vname>
<Vnom>10</Vnom>
<Vcurs>45.2719</Vcurs>
<Vcode>578</Vcode>
<VchCode>NOK</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>СДР (специальные права заимствования)</Vname>
<Vnom>1</Vnom>
<Vcurs>39.0691</Vcurs>
<Vcode>960</Vcode>
<VchCode>XDR</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Сингапурский доллар</Vname>
<Vnom>1</Vnom>
<Vcurs>17.7668</Vcurs>
<Vcode>702</Vcode>
<VchCode>SGD</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Новая турецкая лира</Vname>
<Vnom>1</Vnom>
<Vcurs>20.7564</Vcurs>
<Vcode>949</Vcode>
<VchCode>TRY</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Украинская гривна</Vname>
<Vnom>10</Vnom>
<Vcurs>53.5225</Vcurs>
<Vcode>980</Vcode>
<VchCode>UAH</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Шведская крона</Vname>
<Vnom>10</Vnom>
<Vcurs>38.3377</Vcurs>
<Vcode>752</Vcode>
<VchCode>SEK</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Швейцарский франк</Vname>
<Vnom>1</Vnom>
<Vcurs>22.5962</Vcurs>
<Vcode>756</Vcode>
<VchCode>CHF</VchCode>
</ValuteCursOnDate>
<ValuteCursOnDate>
<Vname>Японская иена</Vname>
<Vnom>100</Vnom>
<Vcurs>23.2653</Vcurs>
<Vcode>392</Vcode>
<VchCode>JPY</VchCode>
</ValuteCursOnDate>
</ValuteData>
</GetCursOnDateXMLResult>
</GetCursOnDateXMLResponse>
</soap:Body>
</soap:Envelope>
=> #<GetCursOnDateXMLResponse:0xb7658c74 @getCursOnDateXMLResult=#<GetCursOnDate
...
В отладочном выводе хорошо видно как вызов метода трансформируется в SOAP-сообщение. Ответ также очень наглядный: мы видим последовательность вложенных тегов: GetCursOnDateXMLResponse, GetCursOnDateXMLResult и ValuteData. Внутри ValuteData находится список тегов ValuteCursOnDate по одному на каждую валюту. Названия атрибутов также вполне ожидаемые - Vname, Vnom, Vcurs, Vcode и VchCode. Но как нам получить доступ к этим данным из кода Ruby? Для ответа на этот вопрос давайте выведем имена всех доступных методов объекта response в алфавитном порядке:
irb(main):008:0> response.methods.sort

=> ["==", "===", "=~", "__id__", "__send__", "class", "clone", "dclone",
"display", "dup", "eql?", "equal?", "extend", "freeze", "frozen?", "gem",
"getCursOnDateXMLResult", "getCursOnDateXMLResult=", "hash", "id", "inspect",
"instance_eval", "instance_of?", "instance_variable_defined?",
"instance_variable_get", "instance_variable_set", "instance_variables", "is_a?",
"kind_of?", "method", "methods", "nil?", "object_id", "private_methods",
"protected_methods", "public_methods", "require", "require_gem", "respond_to?", "send",
"singleton_methods", "taint", "tainted?", "to_a", "to_s", "type", "untaint"]

irb(main):009:0>
Обратите внимание на метод getCursOnDateXMLResult. Посмотрим, что он возвращает:
irb(main):009:0> response.getCursOnDateXMLResult.methods.sort

=> ["==", "===", "=~", "__id__", "__send__", "__xmlele_any", "class", "clone",
"dclone", "display", "dup", "eql?", "equal?", "extend", "freeze", "frozen?",
"gem", "hash", "id", "inspect", "instance_eval", "instance_of?",
"instance_variable_defined?", "instance_variable_get", "instance_variable_set",
"instance_variables", "is_a?", "kind_of?", "method", "methods", "nil?",
"object_id", "private_methods", "protected_methods", "public_methods",
"require", "require_gem", "respond_to?", "send", "set_any", "singleton_methods",
"taint", "tainted?", "to_a", "to_s", "type", "untaint", "valuteData","valuteData="]

irb(main):010:0>
В списке имеется метод valuteData. Посмотрим что внутри:
irb(main):010:0> response.getCursOnDateXMLResult.valuteData.methods.sort

=> ["==", "===", "=~", "[]", "[]=", "__add_xmlele_value", "__id__", "__send__",
"__xmlattr", "__xmlele", "class", "clone", "dclone", "display", "dup", "eql?",
"equal?", "extend", "freeze", "frozen?", "gem", "hash", "id", "inspect",
"instance_eval", "instance_of?", "instance_variable_defined?",
"instance_variable_get", "instance_variable_set", "instance_variables", "is_a?",
"kind_of?", "marshal_dump", "marshal_load", "method", "methods", "nil?",
"object_id", "private_methods", "protected_methods", "public_methods",
"require", "require_gem", "respond_to?", "send", "singleton_methods", "taint",
"tainted?", "to_a", "to_s", "type", "untaint", "valuteCursOnDate","valuteCursOnDate="]

irb(main):011:0>
Мы почти у цели. Посмотрим, какой объект возвращает метод valuteCursOnDate:
irb(main):011:0> response.getCursOnDateXMLResult.valuteData.valuteCursOnDate.class

=> Array

irb(main):012:0> response.getCursOnDateXMLResult.valuteData.valuteCursOnDate.length

=> 18

irb(main):013:0>
Ага! Этот метод возвращает массив из 18 элементов. По всей видимости это и есть список валют. Для проверки нашей догадки, возьмем какой-нибудь элемент массива и посмотрим как он выглядит:
irb(main):013:0> response.getCursOnDateXMLResult.valuteData.valuteCursOnDate[4].methods.sort

=> ["==", "===", "=~", "[]", "[]=", "__add_xmlele_value", "__id__", "__send__",
"__xmlattr", "__xmlele", "class", "clone", "dclone", "display", "dup", "eql?",
"equal?", "extend", "freeze", "frozen?", "gem", "hash", "id", "inspect",
"instance_eval", "instance_of?", "instance_variable_defined?",
"instance_variable_get", "instance_variable_set", "instance_variables", "is_a?",
"kind_of?", "marshal_dump", "marshal_load", "method", "methods", "nil?",
"object_id", "private_methods", "protected_methods", "public_methods",
"require", "require_gem", "respond_to?", "send", "singleton_methods", "taint",
"tainted?", "to_a", "to_s", "type", "untaint", "vchCode", "vchCode=", "vcode",
"vcode=", "vcurs", "vcurs=", "vname", "vname=", "vnom", "vnom="]

irb(main):014:0> response.getCursOnDateXMLResult.valuteData.valuteCursOnDate[4].vchCode

=> "USD"

irb(main):015:0> response.getCursOnDateXMLResult.valuteData.valuteCursOnDate[4]['VchCode']

=> "USD"

irb(main):016:0>
Действительно, каждый элемент массива соответствует определенной валюте. К атрибутам можно обратиться либо при помощи методов vname, vnom, vcurs, vcode, vchCode либо как к элементам хеша. Названия ключей при этом совпадают с названиями тегов в ответном XML-файле: Vname, Vnom, Vcurs, Vcode и VchCode. Теперь код тестовой программы становится очевидным: мы формируем запрос, отправляем его на сервер, получаем ссылку на массив валют, а затем бежим по этому массиву и выводим значения атрибутов. Вот и все!

Отмечу, что в более сложных ситуациях неоценимую помощь оказывают инструменты для отладки веб-сервисов, например, soapUI. При помощи этой программы можно вручную формировать SOAP-запросы и анализировать ответ от сервера.

Заключение

Веб-сервисы - это идеальное решение для интеграции программных систем. По сути, это единый язык на котором могут говорить приложения, написанные разными людьми на разных языках программирования и работающих на разных программно-аппаратных платформах. Сама технология базируется на открытых стандартах и имеет хорошую поддержку во всех современных языках программирования. Не исключение и Ruby. Как мы смогли убедиться, код на Ruby получается очень простым, компактным и выразительным.

Статья опубликована на портале CITForum