Небольшая коллекция самописных классов и процедур на REXX
Автор:
Источник: OS2.ru
Дата: 10.02.2001
Предлагаю вашему вниманию небольшую коллекцию самописных классов и процедур (20 Kb). Не судите сторого -- все это я сначала писал для себя, и только потом мне пришла в голову идея вынести все это на суд общественности.
| config.class | |
|---|---|
| .config | класс для чтения конфигурационных файлов. | 
| progress.class | |
| .roller | класс для отображения индикатора активности в виде вращающейся палочки. | 
| .slider | класс для отображения индикатора активности в виде предложеном IBM'ом. :) | 
| .progressbar | класс для чтения конфигурауционных файлов. | 
| sems.class | |
| .event | класс для чтения конфигурауционных файлов. | 
| .mutex | класс для чтения конфигурауционных файлов. | 
| works.procs | |
| подборка процедур. | |
CONFIG.CLASS
В этом файле содержится только один класс:
.config
Представляет собой достаточно умную читалку текстовых конфигов, выполненую в виде класса языка Object REXX. Поддерживает макроопределения, вложения файлов, значения по умолчанию для директив. Класс содержит следующие методы:
| ~new(filename,keys) | инициализирует класс для чтения конфигурационного файла с заданным именем. 
 | ||||
| ~read | cчитывает файл и возвращает структуру values, содержащую информацию из конфига. | ||||
| ~show | выводит на экран информацию о считаных данных. Представляет ценность только во время отладки. | ||||
| ~getfilename | возвращает имя конфига, подлежащего чтению. | ||||
| ~getvalues | возвращает структуру values, содержащую информацию из конфига. | ||||
| ~requires | предназначен для переопределения. Вызывается в том случае, если в конфиге не найдена хотя бы одна директива, помеченная как requiers По умолчанию выдает сообщение и вызывает ~abort. | ||||
| ~invalid | предназначен для переопределения. Вызывается в том случае, если в в конфиге найдена директива, не указанная в keys По умолчанию выдает сообщение и вызывает ~abort. | ||||
| ~abort(message) | выводит на экран сообщение message и выходит из скрипта. | ||||
| ~filenotfound | предназначен для переопределения. Вызывается если не найден файл для чтения. По умолчанию выводит на экран сообщение message и вызывает ~abort. | ||||
| ~include | не трогайте его. Вызывается при нахождении директивы #include. | ||||
| ~setting | опять же не трогайте его. Вызывается при нахождении правильной директивы. | ||||
| ~setmethod | и его не трогайте. Он простой и позволяет переопределять методы. | 
Методы ~read и ~getvalues возвращают структуру values, которая является классом .directory индексы которого соответствуют директивам, а значения полей, являются либо строками (для single), либо массивами строк (для multi).
метод ~new принимает структуру keys, которая также является классом .directory, индексами которого являются имена директив, а значениями параметры:
| single | multi | |
| optional | директива не обязательна, причем если директива попадается несколько раз, будет использовано последнее значение. Кроме того, через ':' можно указать значение по умолчанию. | директива не обязательна, причем если директива попадается несколько раз, будет заведен массив со всеми значениями. Кроме того, через ':' можно указать несколько значений по умолчанию, разделенных ';' | 
| requied | директива обязательна, причем если директива попадается несколько раз, будет использовано последнее значение. | директива обязательна, причем если директива попадается несколько раз, будет заведен массив со всеми значениями. | 
Например:
keys = .directory~new
keys~key1 = 'single,required'
keys~key2 = 'single,optional:default for key2'
keys~key3 = 'multi,required'
keys~key4 = 'multi,optional:default1 for key4;default2 for key4'
keys~key5 = 'single,optional'
keys~key6 = 'multi,optional' 
Из конфигурационного файла будет прочитано следующее:
- key1
- будет прочитано последнее из указанных значений, причем если не попадется ни одного значения, работа скрипта будет остановлена.
- key2
- 
		   будет прочитано последнее из указанных значений, причем если не попадется ни одного значения, будет установлено значение 'default for key2'
- key3
- будут считаны в массив все значения, причем если не попадется ни одного значения, работа скрипта будет остановлена.
- key4
- 
		   будут считаны в массив все значения, причем если не попадется ни одного значения, будут установлены значения 'default1 for key4' и 'default2 for key4'
 Если попадется хотя бы одно значение, то все значения по умолчанию будут проигнорированы.
- key5 и key6
- в принципе, аналогично key2/key4, но параметр по умолчанию отсутствует. Для key5 будет установлена пустая строка, а для key6 -- массив без элементов.
Кроме того, в конфигурационном файле поддерживаются следующие директивы:
| #DEFINE name [argument] | определяет name. Если указан аргумент, то можно выполнить его макроподстановку. Для этого нужно указать name в угловых скобках. | 
| #UNDEF name | отменяет определение для name | 
| #IFDEF name ... #END | читает находящееся между #IFDEF и #END только если name определено. | 
| #IFNDEF name ... #END | читает находящееся между #IFDEF и #END только если name НЕ определено. | 
| #INCLUDE filename | "включает" файл filename в текущий файл. Вложенность не ограничена. | 
PROGRESS.CLASS
В этом файле содержатся сразу 3 класса: .roller, .slider и .progressbar
К сожалению, классы писались в разное время и для разных целей, и потому не стандартизированы. Конечно их стоило бы наследовать от одного и того же абстрактного суперкласса, но переделывать все это мне что-то не хочется. Может быть, в следующий раз... :)
Эти классы представляют собой 3 растпространенных индикатора того, что в программе что-то происходит.
- .roller
- представляет собой крутящуюся палочку.
- .slider
- представляет собой индикатор предложеный IBM'ом. В системе он выводится при установке, в момент поиска p'n'p. По-моему неплохая альтернатива для: "Если ваш винчестер длительное время не подает признаков жизни..." (с)
- .progressbar
- ну тут комментарии излишни. Этот индикатор попадается решительно везде, где только можно.
Теперь подробнее:
.roller
Имеет следующие методы:
| ~new(symbols,speed) | инициализирует класс. 
 | ||||
| ~show | выводит некую информацию о классе. Полезен только при отладке. | ||||
| ~start | запускает индикатор, после чего тот крутится до вызова метода ~stop. | ||||
| ~stop | останавливает индикатор. | 
Индикатор не зависит от хода выполнения основной программы. В этом смысле он пригоден скорее для развлечения пользователя, чем для определения, не повис ли скрипт. С другой стороны, покажите мне повисший скрипт на Rexx'е... :)
Индикатор сам определяет текущую (на момент ~start) позицию курсора на экране, и крутится в ней. Поэтому выводить что-либо на экран в процессе вращения индикатора лучше не надо.
.slider
Имеет следующие методы:
| ~new(len,speed) | инициализирует класс. 
 | ||||
| ~show | выводит некую информацию о классе. Полезен только при отладке. | ||||
| ~start | запускает индикатор, после чего тот крутится до вызова метода ~stop. | ||||
| ~stop | останавливает индикатор. | 
Как и .roller, .slider не зависит от хода выполнения основной программы.
И так же как и для roller'а, не стоит выводить ничего на экран, пока индикатор рисует себя.
На самом деле, я знаю как это все исправить, и сделать очень удобно, но... в следующий раз. :)
.progressbar
Имеет следующие методы:
| ~new(start,max,len) | инициализирует класс. 
 | ||||||
| ~step | переходит к следующему значению некоторой величины. Заметьте: не к следующему проценту, а именно к следующему значению величины. | ||||||
| ~stepto | переходит к заданному значению некоторой величины. | ||||||
| ~stop | останавливает индикатор. | 
Что такое "некоторая величина"? Например, Вам нужно скопировать 5 файлов. Тогда создание класса будет выглядеть следующим образом:
p = .progressbar~new(0,5,50)
Имеем:
- значение 0%:
- 0 фалов скопировано.
- значение 100%:
- 5 фалов скопировано.
- размеры:
- на индикатор отведено 50 символов по горизонтали. Учтите, что по вертикали .progressbar занимает 2 строки.
При этом метод ~step будет изменять показания прогрессбара на 20%.
Если Вы хотите вывести показания для момента завершения копирования 3-го файла, вызывайте:
p~stepto(3)
Как Вы, наверное, догадались, при использовании этого индикатора тоже не стоит ничего выводить на экран.
SEMS.CLASS
Этот файл содержит два крайне полезных, на мой взгляд, класса: .mutex и .event.
Из названий, думаю, понятно, что это обертки для системных семафоров, которые настолько упрощают работу с ними, что делают ее даже проще, чем работу с файлами-флагами.
.event
Содержит следующие методы:
| ~new(name) | инициализирует класс. name задает имя семафора. | 
| ~post | постит семафор. | 
| ~reset | сбрасывает семафор. | 
| ~query | возвращает .true, если семафор запощен. | 
| ~wait | ожидает, пока семафор будет запощен. | 
| ~defaultname | возвращает информацию о семафоре в формате name (handle) state | 
Очень удобно использовать этот класс для организации общения между скриптами или между скриптом и программой, понимающей семафоры, например с T-Mail'ом.
.mutex
Содержит следующие методы:
| ~new(name) | инициализирует класс. name задает имя семафора. | 
| ~request | захватывает семафор. | 
| ~release | отпускает семафор. | 
| ~defaultname | возвращает информацию о семафоре в формате name (handle) | 
Класс незаменим при организации совместного доступа скриптов (или нитей выполнения в скриптах) к каким-либо объектам. Например, у меня этот класс регулирует доступ к почтовой базе:
s = .mutex~new('\sem32\msgbase.sem')
s~request
...
...
s~release
Класс полностью гарантирует, что фрагмент, заключеный между ~request и ~release, будет выплняться в одиночестве, и все остальные (естественно, кто пытается выполнить ~request для семафора с тем же именем) будут дожидаться вызова ~release в скрипте, выполнившем ~request.
Класс полностью исключает ситуацию, которая вполне возможна с файлами-флагами, когда два скрипта, одновременно ждущие пропадения одного и того же флага, одновременно же определяют его пропадение.
Кроме того, класс успешно борется с ситуацией, когда скрипт выполнил ~request и по каким либо причинам не смог выполнить ~release. Такой "зомбированый" семафор автоматически будет пересоздан.
works.procs
Это сборник полезных, на мой взгляд, процедур. Ничего сложного, но удобно.
| makepath(path) | создает путь path, опускаясь вниз по дереву. | 
| log(file,string) | записывает строку string в файл file, предваряя ее датой и временем. Удобно для ведения логов. | 
| setenv(var,val) | аналогична стандартной функции value, но с фиксированым третьим параметром: 'OS2ENVIRONMENT'. | 
| arcmail(filename) | возвращяет .true, если filename является правильным именем arcmail-пакета (это из FTN). | 
| datebase(date,format) | возвращает количество дней между 01.01.0001 и указанной датой. format задает формат, в котором указана дата. По умолчанию 'N'. | 
| datedest(date1,date2,format) | возвращает количество дней между датами. format задает формат, в котором указаны даты. По умолчанию 'N'. | 
| dateago(date,format) | возвращает количество дней, прошедших с указанной даты. format задает формат, в котором указана дата. По умолчанию 'N'. | 
| Стоит заметить, что функции datebase, datedest и dateago в общем-то потеряли смысл при выходе Object REXX'а. Но вот в некоторых моих скриптах они используются, а потому были переписаны под ORexx и оставлены "для удобства". | |
| TimeBase_M(time) | возвращает количество минут, прошедших от полночи. Время принимается в 24-х часовом формате hh:mm:ss. | 
| TimeBase_S(time) | возвращает количество секунд, прошедших от полночи. Время принимается в 24-х часовом формате hh:mm:ss. | 
| Про эти две функции можно сказать то же самое, что и про date*. | |
| arrinsert(arr1,index,arr2) | Возвращает массив, получившийся в результате вставки arr2 в arr1 с позиции index. | 
| expandaddress(address,default) | Преобразует частично заданный адрес в полный, подставляя недостающие части из default. (это из FTN). | 
| YesNo(Q) | возвращяет .true, если Q является утвердительным ответом ('Yes' или 'Да'). | 
| matchaddr(address,mask) | возвращает .true, если address попадает в маску mask. Поддерживаются символы '*' -- все что угодно и '!' -- отрицание. (это из FTN). | 
| match(word,mask) | возвращает .true, если word попадает в маску mask. Поддерживаются символы '*' -- все что угодно и '!' -- отрицание. | 
| FileCopy(source,dest) | копирует файл из source в dest. Не мудрствуя лукаво, пользуется командой copy. | 
| FileMove(source,dest) | перемещает файл из source в dest. Не мудрствуя лукаво, пользуется командой mov. mov.exe лежит тут же... | 
| Abort(message) | выводит на экран message и останавливает работу скрипта. | 
| QSort(array) | сортирует массив Array. Название говорит обо всем. | 
| Color(color) | устанавливает текущий цвет символов. | 
Если у Вас возникнут какие-нибудь глобальные идеи по поводу этих скриптов, или Вы захотите указать мне на мои ошибки, или Вы чего-то не поймете, то пишите мне.
