SisyphusWiki: Alterator/internals/5 (Версия для печати)

Продолжение истории...

3.  Первый модуль


Мы уже узнали достаточно чтобы попробовать написать свой первый модуль для alterator. Так что не будем медлить с долгими рассказами, и сразу же приступим к делу. Я пока не буду давать лишних комментариев, и объяснять что и почему, просто смотрите как это сделать и всё ;)

Если формат backend'a покажется вам несколько странным, то объясню – он был изначально рассчитан на существование в виде модуля для виртуальной файловой системы – admfs. Сейчас она не используется – а формат остался ... может в будущем мы вернёмся к этой идее, уж больно она красивая.

Для того чтобы создать простейший модуль для alterator, надо:
  1. написать низкоуровневую часть – backend, которая собственно и будет крутить ручки в системе
  2. написать интерфейс

Давайте сделаем модуль, который позволит выбирать пользователю локаль в системе.

3.1 Устройство backend


Интерфейс и backend будут обмениваться между собой посредством команд фиксированного формата: "<объект> <действия>". Объект принято именовать так же как и объекты в файловой системе, то есть последовательность слов, разделённых символом '/'.

Например:


Первая часть имени совпадает с именем файла бакенда.

Например
/users/root – файл backend, называется users
/network/interfaces/eth0 – файл backend называется network

Оставшаяся часть имени передаётся backend и он дальше сам разбирается с тем что с ней делать.

Действия есть последовательность атрибутов со значениями, один атрибут имеет особое значение, зовут его action. action – собственно означает какое действие мы можем предпринять над объектов.

Возможные значения action:
read – прочитать атрибуты объекта
write – изменить некоторые атрибуты объекта
list – получить список объектов которые данный содержит (аналогично ls в каталоге)
new – создать объект
delete – удалить объект

Атрибут action всегда должен присутствовать в команде.

Например:

/users/test action=new uid=506 gecos="Some User"
(создать пользователя тест с UID 506 и комментарием “Some User”)

/network/interfaces/eth0 action="read"
(считать параметры интерфейса, например ip-адрес,шлюз etc.)

Этот язык общения со времён первого alterator носит странное имя WOO.

В нашем случае мы имеем следующие объекты:

/i18n/current – текущее значение локали
/i18n/available – установленные в системе локали
...
/i18n/available/Russian locale for Russia – например одна из локалей в системе.

Как можно догадаться, i18n – это будет имя нашего файла – backend'a.

/i18n/current будет иметь следующие атрибуты:
stdname – стандартное имя локали без кодировки, например “ru_RU”
title – описательное имя локали, например “Russian locale for Russia”
charmap – кодировка, например “KOI8-R”

stdname.charmap – даёт стандартное системное имя, которое обычно
содержится в переменной LANG, в нашем случае это ru_RU.KOI8-R.

Можно было бы сделать один атрибут lang, но удобнее держать отдельно
кодировку.

Чтобы считать текущее значение, команда следующая:
/i18n/current action=read
Чтобы записать новое значение переменной LANG, команда следующая:
/i18n/current action=write lang=ru_RU.KOI8-R

Как видите атрибуты на чтение и запись не обязаны совпадать. Может это не
совсем идеологически верно, зато удобно.

3.1.2 Пишем backend


С языком общения мы вроде как разобрались, теперь собственно формат
backend.

backend – это обычное приложение, написанное на произвольном языке
программирования, который откликается на внешние раздражители следующим образом:

*(action=read)* backend -r объект – выдать на stdout, атрибуты и их значения в формате:
атрибут1:значение1
атрибут2:значение2
....
(соответственно имя атрибута не должно содержать двоеточия – это не очень
сильное ограничение)

объект – это хвост имени объекта, с отрезанным именем backend.
Так «a/b/c/d» – урежется до «b/c/d».

Например: (для woo-команды: /i18n/current action=read)


*(action=list)* backend -l объект – выдать на stdout список подобъектов в формате
«имя[пробел][r|d]" где d ставится рядом с объектом, содержащим другие
объекты, а r – рядом с обычным объектом.


Например: (для woo-команд: /i18n action=list и /i18n/available action=list)


*(action=write,new)* backend -w объект – принять с stdin параметры в виде "атрибут:значение" и записать их в объект.


Например: (для woo-команды: /i18n/current action=write lang=ru_RU.CP1251)
        $echo "lang:ru_RU.CP1251"| ./i18n -w current

Отдельной команды для action=new нет, backend сам в состоянии догадаться, делать ему новый объект или модифицировать имеющийся.

*(action=delete)* backend -d объект – удалить указанный объект

Ну вот собственно и весь формат backend.

Пример скрипта на shell, который всё это реализует приложен к письму. Думаю что вы легко сможете написать и свою версию, возможно даже более правильную и корректную ;)

3.2 Опять про Scheme: Локальные переменные


Проведём небольшое усовершенствование своих познаний по Scheme.

В Scheme в отличие от Common Lisp применяется привычный подход к понятию локальности (так называемый “Lexical Scope” против “Dynamic Scope” в Common Lisp):

* Переменные определённые внутри некоторой функции видны во всех функциях,   определённых внутри данной, но не видны вне её.

* Локальные переменные затеняют глобальные:


Параметры у многоаргументных функций, суть локальные переменные со всеми вытекающими последствиями:



Продолжение следует ...