четверг, 25 декабря 2008 г.

sbcl-slime, clisp-slime and etc

Хотелось бы поделиться двумя советами, которые представляются мне довольно важными при использовании Slime (а если вы работаете с Common Lisp, то почти наверняка используете именно его).

Как известно, какая именно реализация CL будет запущена при запуске Slime определяется переменной inferior-lisp-program. Однако глобальное определение этой переменной и использование команды slime довольно неудобно, поскольку не позволяет легко запускать различные реализации CL. Я же часто запускаю как sbcl, так и clisp, а в планах поработать и с другими реализациями. Не переопределять же эту переменную каждый раз, когда хочешь поработать с другой реализацией? Поэтому, в свой конфиг Emacs я добавил следующее:
(defmacro lisp-slime (lisp path &optional coding)
(let ((funname (intern (format "%s-slime" lisp))))
`(defun ,funname ()
(interactive)
(let ((inferior-lisp-program ,path)
(slime-net-coding-system (or ,coding 'utf-8-unix)))
(slime)))))

(lisp-slime sbcl "/usr/bin/sbcl")
(lisp-slime clisp "/usr/bin/clisp")
Теперь у меня доступны команды sbcl-slime и clisp-slime, которые позволяют легко запустить sbcl или clisp соответственно. Ну а макрос lisp-slime может быть использован для лёгкого добавления других реализаций.

Второй совет связан с использование hyperspec. Функция hyperspec-lookup отрывает документацию по символу в браузере и очень удобно, если это emacs-w3m. Для того, что бы так и происходило (в моей системе по умолчанию запускается Firefox), можно просто переопределить функцию browse-url-default-browser таким образом, что бы она вызывала w3m-browser-url. Однако, в таком случае функция browser-url всегда будет открывать указанный url в emacs-w3m, чего бы мне хотелось избежать (w3m хорош для работы с hyperspec, но для других задач я предпочитаю использовать Firefox). Добиться того, что бы hyperspec открывался в emacs-w3m (в том числе, при использовании slime-hyperspec-lookup), а другие url в браузере по умолчанию (в моём случае в Firefox) можно следующим образом:
(require 'hyperspec)

(defun hyperspec-lookup (&optional symbol-name)
(interactive)
(let ((browse-url-browser-function 'w3m-browse-url))
(if symbol-name
(common-lisp-hyperspec symbol-name)
(call-interactively 'common-lisp-hyperspec))))
Примечание: хотя в моей системе hyperspec загружается автоматически, мне всё же пришлось добавить (require 'hyperspec) до определения hyperspec-lookup, что бы гаранитровать правильный порядок инициализации.

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

Переход на git

Начал эксперимент, по переводу одного из внутренних проектов на git, если всё пройдёт успешно (а думаю, что так оно и будет), то буду переводить все свои проекты с subversion на git.

вторник, 23 декабря 2008 г.

garbage-pools-0.1.1

Добавил в garbage-pools одну функцию: cancel-object-cleanup, которая позволяет отменить регистрацию ранее зарегистрированного в пуле объетка. Это приём в стиле C++ : вообще-то, удалять ресурс не собираемся, но в случае возникновения исключения он должен быть удалён, поэтому готовим его к удалению, а в после успешного прохождения опасной зоны спасаем и используем по назначению.

Поскольку успел заюзать эту функцию в cl-libxml2, то в связи с её новым релизом, пришлось строчо выпустить garbage-pools версии 0.1.1 (чуть не забыл это сделать).

cl-libxml2-0.2.5

Выпустил cl-libxml2 версии 0.2.5. В этой версии:
  1. Появилась обработка ошибок: теперь все ошибки, генерируемые libxml2, транслируются в conditions или warnings (для нефатальных ошибок).
  2. Кроме того, понаводил порядка в исходниках, что вылилось в достаточно заметное изменение их структуры.
  3. В результате выполнения предыдущих двух пунктов вылезло на свет некоторое колличество багов, которые и были исправлены.
Как личное достижение могу отметить то, что на данный момент ознакомился с исходным кодом libxml2 процентов на 30% - документации по библиотеке, я бы сказал, не вполне вменяема, пока код не посмотришь - ничего толком не поймёшь. Так же обнаружил, что в некоторых местах html-документация "не совсем" соответствует комментариям в исходниках, что немного насторожило...

А тем временем, в gentoo-lisp-overlay появилась Xuriella XSLT, а ещё немного ранее уже был добавлен Plexippus XPath. Появись это хотя бы на полгода раньше, то вероятно начинать cl-libxml2 я бы не стал. Однако, теперь забрасывать этот проект не при каких обстоятельствах не собираюсь: полноценная поддержка xml критически важна для меня, а упомянутые проекты ещё сыроваты (им ведь в самом деле приходится писать реализация, а я только обёртку делаю для давно и хорошо известной библиотекой).

четверг, 18 декабря 2008 г.

"Ни дня без строчки" или cl-routes-0.1.5

Выпустил cl-routes версии 0.1.5, в состав пакета включил hunchentoot-routes.asd, который позволяет производить маршрутизацию не только по структуре url, но также по хосту (очень люблю vhost в apache) и методу запроса, типа:
(routes.h:connect-handler *map*
"index.html"
'handler-for-post-query-on-index.html
:host "archimag:8080"
:method :post)
Конечно, routes.asdf всё это тоже поддерживает, но нужно понимать как он работает, что бы этим воспользоваться, а тут всё довольно прозрачно.

На мой взгляд, довольно неплохо для начала.

Тут, правда, возник другой насущный вопрос: где бы мне раздобыть ntlm-аутенфикацию для hunchentoot? Пропускать его (hunchentoot) через apache не хочу. Что, опять писать самому?

вторник, 16 декабря 2008 г.

wget and sed всех победят!

Я вот не понимаю, зачем люди выкладывают книги в веб в html и при этом не дают возможности скачать архив? Что бы отнять у заинтересовавшегося пять минут времени? Захотел вот книжку скачать, Practical PostgreSQL, а архива нет, по крайней мере, не нашёл.

Ну да впрочем, искал я недолго:
wget -m -np http://www.commandprompt.com/ppbook/
Отлично, открываю - а там все ссылки абсолютные, типа /ppbook/p206. Нет думаю, нас так просто не возьмёшь:
sed -i -e "s/\/ppbook\///" *[[:digit:]]**
(такая маска нужна, что бы каталог images пропустить, а так там всё с цифрами)

Докачал css-файлы и изменил ссылки на них.

Кроме того, мне не понравились , что верхние части страниц занимает всякий мусор с http://www.commandprompt.com/, там ссылки на Home, About, поиск какой-то, короче, мне совершенно не нужные вещи. Решил победить:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:html="http://www.w3.org/1999/xhtml"
version="1.0">

<xsl:output method="html" public="-//W3C//DTD XHTML 1.0 Transitional//EN" system="DTD/xhtml1-transitional.dtd">

<xsl:template match="/">
<xsl:copy>
<xsl:copy-of select="@*">
<xsl:apply-templates select="*">
</xsl:copy>
</xsl:template>

<xsl:template match="div[@id='widetop']">
<xsl:template match="ul[@id='greymenu_wide']">

<xsl:template match="*|text()">
<xsl:copy>
<xsl:copy-of select="@*">
<xsl:apply-templates select="*|text()">
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Это xslt-преобразование копирует входящий html документ, вырезая из него блоки <div id="widetop"> и <ul id="greymenu_wide">
Плюс потребовался небольшой скрипт:
for path in $@
do
name=`echo $path | sed -e 's/ppbook\///'`
`xsltproc --html --novalid ppbook.xsl ppbook/$name > ppbook-copy/$name`
echo $name
done
Который был вызван следующим образом:
 ./ppbook.sh ppbook/*[[:digit:]]** 
И всё отлично работает. Но полчаса времени я потерял. Вот и спрашивается, зачем людям жизнь осложнять?

воскресенье, 14 декабря 2008 г.

cl-routes-0.1

Выпустил cl-routes версии 0.1. Оказалось, что использование механизма унификации делает решение проблемы почти тривиальным. Я немного в шоке... В исходниках и на cliki имеется небольшой пример использования совместно с hunchentoot. Конечно, нужно будет ещё много дорабатывать, но это уже после получения опыта практического применения.

четверг, 11 декабря 2008 г.

cl-routes

Начал работу над cl-routes (по ссылке можно не ходить, там ещё ничего интересного)
Routes tackles an interesting problem that comes up frequently in web development, how do you map a URL to your code? While there are many solutions to this problem, that range from using the URL paths as an object publishing hierarchy, to regular expression matching; Routes goes a slightly different way.
(взято отсюда)

Если совсем вкратце, то это (будет) Common Lisp реализация Rails routes system (с этой ссылкой постоянно какие-то проблемы), но поскольку в Ruby, и тем более в Rails, я соображаю чуть менее, чем ничего, то ориентируюсь на Python-реализацию этой идеи.

Правда, упомянутые реализации делают упор на использовании в рамках шаблонна MVC, который (как впрочем и вообще паттерны) я, мягко говоря, недолюбливаю, так что, никаких намёков на MVC в cl-routes не будет.

Основное предназначение cl-routes это имея набор шаблонов типа:
/forum/:chapter/:topic/:message
/forum/archives/:year/:month/:day
и т.д.
из переданного URL, например, /archives/2008/12/11 извлечь информацию о year (2008), month (12) и day (11), а также дополнительную информацию, указанную при регистрации шаблона (например, функцию обработчик, или ещё что).

Реализация routes мне не понравилась (а ведь первой мыслью было просто тупо портировать на CL). Во-первых, слишком много буков. Во-вторых, она основана на регулярных выражениях, что требует в худшем случае полной проверки всех шаблонов и в случае сервера приложений, на котором работает много-много мини-приложений может привести к заметным издержкам. Вообще, разбиением URL на части (например, с помощью puri) данная проблема тривиальным образом сводится к задаче унификации:
(UNIFY ("forum" ?year ?month ?day)
("forum" "2008" "12" "11"))
Это позволяет отказаться от использования регулярных выражений и заметно упростить решение. В голову сразу пришло применить cl-unification. Однако, использование этой библиотеки в авторском виде приводит к необходимости, как и в случае использования регулярных выражений, просматривать все зарегистрированные шаблоны в поисках нужного. Но ведь в большинстве случаев структура сайта образует дерево, а поиск в дереве должен быть гораздо быстрее. Эта дилемма останавливала меня от начала работы: с одной стороны очень хотелось применить унификацию, а с другой, не менее сильно хотелось вести поиск в дереве, а не в линейном списке. Наконец меня осенило: если нельзя сделать дерево из шаблонов, то ведь можно сделать шаблон в виде дерева! Правда, для этого необходимо добавить к cl-unification or-template, который бы давал возможность включать в один шаблон несколько различных вариантов. Например:
#T("forum" #T(or #T("archives" ?year ?mount ?day)
#T(?chapter ?topic ?message)))
Последовательное рекурсивное применение or-template даёт возможность построить дерево произвольной сложности. Кроме того, необходимо добавить ещё несколько других шаблонов, например, concat-template для унификации шаблонов содержащих что-нибудь типа ":{id1}_:{id2}.html".

В итоге я решился пропатчить необходимым образом cl-unification и попробовать уговорить автора принять эти изменения. Начал писать около 12 ночи и около 3 сильно раздражённый сделал перерыв на сон: что-то с этой библиотекой не так... Кроме того, проснувшись я обнаружил, что в некоторых случаях она просто неверно работает, по крайней мере, с точки зрения унификации. Это стало последней каплей, показавшей бесперспективность ориентации на cl-unification. Решил сделать свое решение. Ну не совсем своё. Взял код Питера Норвинга из AIMA, немного разбавил его парой светлых идей из cl-unification (кои там всё же есть) и включил это дело в cl-routes. Попутно обнаружил, что автор cl-unification также пытался "творчески" переработать код Питера Норвинга, но вот получилось у него не очень...

Вот, надеюсь, что первый релиз cl-routes выпущу ещё до Нового Года.

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

вспоминая postgres

Сегодня с утра надо было сделать небольшую базу данных. Давненько ничего подобного не делал... Запустил pgadmin3, потылкался минут 20 - не могу, раздражает, какие-то окошечки, выпадающие списки и прочие "рюшечки". А ведь вроде когда-то под виндой юзал более-менее нормально. Ладно, плюнул, M-x sql-postgres и уже через пять минут почувствовал себя человеком :-) Ну а psql оказалась очень даже вменяемой утилитой. Теперь думаю только так и работать.

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

Могучий, могучий XSLT :-)

Вот уже не первый год активно пишу на XSLT, а до сих пор регулярно обнаруживаю для себя новые возможности. Вот и сегодня, столкнулся с не вполне очевидной проблемой, пусть есть такой документ:
<data>
<item-1>value-1</item-1>
<item-5>value-5></item-5>
<item-3>value-3</item-3>
....
<item-n>value-n</item-n>
</data>
Теперь надо в xslt получать значения этих узлов item-x по номеру (то бишь, по x). На первый взгляд показалось, что без dyn:evaluate из exslt не обойтись, правда такое решение на больших документах (ну там несколько тысяч таких записей), кроме того, ещё и тормозить будет заметно. Этот факт настолько меня растроил, что я тут же придумал решение:
<xsl:key name="item-by-number" match="/data/node()" use="substring(local-name(.), 6)">
и уже в самом коде можно так:
<xsl:value-of select="key('item-by-number', 3)">
Работает... к моему немалому удивлению и восторгу...

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

cl-libxml2 и exslt

Раздумываю над тем, чтобы реализовать exslt с помощью Common Lisp и cl-libxml2, ибо:
  • это даст возможность отладить соответствующие возможности cl-libxml2
  • libexslt не реализует многие полезные функции
Но, есть некоторые сомнения насчёт того, хватит ли мне желания/времени заниматься этим, ведь руки чешутся заняться некоторыми другими проектами, в частности, написать на CL подобие routes (что, в свою очередь, является Python-реализацией Rails routes system): а это последнее, что отделяет меня от непосредственной работы над сервером-приложений, который я уже несколько раз упоминал.

P.S. В последнее время решительно не хватает времени, из-за этого часто трачу его впустую, шарахаясь из стороны в сторону.