|
Предлагаю вашему вниманию небольшую коллекцию самописных классов и процедур (20 Kb).
Не судите сторого -- все это я сначала писал для себя, и только
потом мне пришла в голову идея вынести все это на суд общественности.
В этом файле содержится только один класс:
Представляет собой достаточно умную читалку текстовых конфигов, выполненую
в виде класса языка Object REXX. Поддерживает макроопределения, вложения файлов,
значения по умолчанию для директив. Класс содержит следующие методы:
| ~new(filename,keys) | инициализирует класс для чтения конфигурационного файла с заданным именем.
| 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 в угловых скобках. Если аргумент не указан, то имя определяется содержащим пустую cтроку |
| #UNDEF name | отменяет определение для name |
#IFDEF name ... #END | читает находящееся между #IFDEF и #END только если name определено. |
#IFNDEF name ... #END | читает находящееся между #IFDEF и #END только если name НЕ определено. |
| #INCLUDE filename | "включает" файл filename в текущий файл. Вложенность не ограничена. |
В этом файле содержатся сразу 3 класса: .roller, .slider и .progressbar
К сожалению, классы писались в разное время и для разных целей, и потому не стандартизированы.
Конечно их стоило бы наследовать от одного и того же абстрактного суперкласса, но переделывать все это мне что-то не хочется. Может быть, в следующий раз... :)
Эти классы представляют собой 3 растпространенных индикатора того, что в программе что-то происходит.
- .roller
- представляет собой крутящуюся палочку.
- .slider
- представляет собой индикатор предложеный IBM'ом. В системе он выводится при установке, в момент поиска p'n'p.
По-моему неплохая альтернатива для: "Если ваш винчестер длительное время не подает признаков жизни..." (с)
- .progressbar
- ну тут комментарии излишни. Этот индикатор попадается решительно везде, где только можно.
Теперь подробнее:
Имеет следующие методы:
| ~new(symbols,speed) | инициализирует класс.
| symbols | задает символы для вращения. Собственно не обязательно вращения...
По умолчанию используются '-\|/', что как раз и создает эффект вращения. |
| speed | Задает скорость как количество изменений в секунду. По умолчанию 2. |
|
| ~show | выводит некую информацию о классе. Полезен только при отладке. |
| ~start | запускает индикатор, после чего тот крутится до вызова метода ~stop. |
| ~stop | останавливает индикатор. |
Индикатор не зависит от хода выполнения основной программы.
В этом смысле он пригоден скорее для развлечения пользователя, чем для определения,
не повис ли скрипт. С другой стороны, покажите мне повисший скрипт на Rexx'е... :)
Индикатор сам определяет текущую (на момент ~start) позицию курсора на экране,
и крутится в ней. Поэтому выводить что-либо на экран в процессе вращения индикатора лучше не надо.
Имеет следующие методы:
| ~new(len,speed) | инициализирует класс.
| len | задает горизонтальный размер индикатора в символах. |
| speed | Задает скорость как количество изменений в секунду. По умолчанию 2. |
|
| ~show | выводит некую информацию о классе. Полезен только при отладке. |
| ~start | запускает индикатор, после чего тот крутится до вызова метода ~stop. |
| ~stop | останавливает индикатор. |
Как и .roller, .slider не зависит от хода выполнения основной программы.
И так же как и для roller'а, не стоит выводить ничего на экран, пока индикатор рисует себя.
На самом деле, я знаю как это все исправить, и сделать очень удобно, но... в следующий раз. :)
Имеет следующие методы:
| ~new(start,max,len) | инициализирует класс.
| start | задает начальное значение некоторой величины, т. е. значение для 0%. |
| max | задает максимальное (конечное) значение некоторой величины, т. е. значение для 100%. |
| len | задает горизонтальный размер индикатора в символах. |
|
| ~step | переходит к следующему значению некоторой величины. Заметьте: не к следующему проценту, а именно к следующему значению величины. |
| ~stepto | переходит к заданному значению некоторой величины. |
| ~stop | останавливает индикатор. |
Что такое "некоторая величина"? Например, Вам нужно скопировать 5 файлов. Тогда
создание класса будет выглядеть следующим образом:
p = .progressbar~new(0,5,50)
Имеем:
- значение 0%:
- 0 фалов скопировано.
- значение 100%:
- 5 фалов скопировано.
- размеры:
- на индикатор отведено 50 символов по горизонтали. Учтите, что по вертикали
.progressbar занимает 2 строки.
При этом метод ~step будет изменять показания прогрессбара на 20%.
Если Вы хотите вывести показания для момента завершения копирования 3-го файла, вызывайте:
p~stepto(3)
Как Вы, наверное, догадались, при использовании этого индикатора тоже не стоит ничего выводить на экран.
Этот файл содержит два крайне полезных, на мой взгляд, класса: .mutex и .event.
Из названий, думаю, понятно, что это обертки для системных семафоров, которые
настолько упрощают работу с ними, что делают ее даже проще, чем работу с файлами-флагами.
Содержит следующие методы:
| ~new(name) | инициализирует класс. name задает имя семафора. |
| ~post | постит семафор. |
| ~reset | сбрасывает семафор. |
| ~query | возвращает .true, если семафор запощен. |
| ~wait | ожидает, пока семафор будет запощен. |
| ~defaultname | возвращает информацию о семафоре в формате name (handle) state |
Очень удобно использовать этот класс для организации общения между скриптами или между скриптом и
программой, понимающей семафоры, например с T-Mail'ом.
Содержит следующие методы:
| ~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. Такой "зомбированый" семафор автоматически будет пересоздан.
Это сборник полезных, на мой взгляд, процедур. Ничего сложного, но удобно.
| makepath(path) | создает путь path, опускаясь вниз по дереву. |
| log(file,string) | записывает строку string в файл file, предваряя ее датой и временем. Удобно для ведения логов. |
| setenv(var,val) | аналогична стандартной функции value, но с фиксированым третьим параметром: 'OS2ENVIRONMENT'.
Возвращает значение переменной среды, заданной в var. Если указано val, то заодно устанавливает новое значение. |
| 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) | устанавливает текущий цвет символов. |
Если у Вас возникнут какие-нибудь глобальные идеи по поводу этих скриптов, или Вы захотите указать мне на мои ошибки,
или Вы чего-то не поймете, то пишите мне.
Обсудить материал (число отзывов:0)
предыдущий материал | следующий материал |