LE Blog

Инженер с поэтической душой

11.03.2009 firtree_right Использование GEdit для разработки на Ruby и Flex

Сегодня я хочу поделиться своими ресурсами для разработки. В частности, хочу рассказать про IDE. Основную часть рабочего времени я провожу под кубунту. После долгих метаний и проб я остановился на GEdit, как на универсальном средстве разработки.

Установка

Для работы нам понадобятся плагины для GEdit. Они содержат основной набор вкусностей: code snippets, file browser pane, terminal pane и тому подобное. Поэтому устанавливаем:

sudo apt-get install gedit gedit-plugins

Дополнительные файлы, которые понадобятся, находятся в теле поста.

Ruby и Ruby on Rails

Подсветка синтаксиса и сниппеты для ruby уже поставляются из коробки. Единственное, если вы откроете файл со спецификацией подсветки синтаксиса для ruby, то обнаружите там пометку FIXME, касающуюся подсветки интерполяции внутри строки. Это связано с особенностями обработки правил подсветки самим редактором. Эти особенности удалось обойти, присвоив этому правилу измененный цвет фона.

Подсветку синтаксиса Ruby положить в /usr/share/gtksourceview-2.0/language-specs/ Для корректной работы подсветки, потребуется определить стиль для ruby:interpolation. Я использую тему darkmate, в которой определил необходимые дополнительные цвета на свой вкус. Положить следует в /usr/share/gtksourceview-2.0/styles/, а затем выбрать эту тему в установках редактора.

Язык для описания подсветки синтаксиса достаточно прост. Кроме всего прочего он позволяет ссылаться из правил одного языка на правила другого. Что, собственно, нам и понадобится для подсветки языка темплейтов erb. Ведь erb — это по сути html со вставками ruby. Теперь, когда у нас есть оба описания, берём описание для html и вставляем в него ссылку на ruby.

Так же следует определить mime-type для erb. Правила подсветки erb предполагают, что в системе определен mime-type text/erb. В четвертом KDE описать свои типы файлов можно в System->System Settings->Advanced->File Associacions

Мой файл использует цвет erb:background, который так же определен в файле с темой.

Подсмотрев code snippets для других языков, а так же в процессе использования, вполне можно самостоятельно написать пару-тройку полезных выражений.

Flash и Flex

Для работы с flex нам понадобится flex sdk, а так же отладочная версия standalone flash player. Я уж не буду вдаваться в подробности, как там написать компилирующий или запускающий скрипт. А выложу сразу подсветку синтаксиса.

Если определить тип (mime-type) text/x-shockwave, то можно использовать правила для подсветки ActionScript3. Которые следует положить по адресу, указаному выше.

Так же, используя описанное выше знание, легко создать описание подсветки синтаксиса mxml, зная, что это xml, со вставками actionscript. Для корректной работы следует определить mime-type text/mxml.

Заключение

Все файлы, выложенные в посте, можно смело изменять под свои нужды. Если вы используете GEdit, чтобы писать под рельсы или флекс. Я не стал выкладывать сниппеты, потому что на мой взгляд, это вопрос личной привычки. А подсветку синтаксиса, конечно, можно улучшать.

24.02.2009 firtree_right Регулярные выражения: радость победы 2 :)

Ещё один бонус, который я ожидал от этого блога, и который уже успел получить — это обратная связь. После разговора с Лёшей Кукушкиным было решено модифицировать задачу из предыдущего поста так, чтобы стало удобнее.

Задача

  1. Ввести дополнительный тэг для кода
  2. Печатать код внутри тэга так, как он должен выглядеть (прошлый раз пришлось шаманить)
  3. Иметь возможность более ли менее безнаказанно употреблять сами тэги в тексте

Решение

Итак, для кода будем использовать тэг [code]...[/code]. Для того, чтобы не провоцировать преобразование кода там, где не нужно, будет использовать знак «/». (То есть в этом абзаце жирным на самом деле написано «/[code]...[/code]»)

Так же используем стандартный метод rails для приведения в порядок того, что находится внутри тэга [code]. Результат выглядит вот так:

def lonelyelk_format(text)
  res = "<p>" + text.to_s.dup
  codes = []
  res.gsub!(//[^\/]\[code\]([\s\S]+?)\[\/code\]/) do |s|
    codes.push(s.gsub(/(^[^\/]\[code\]|\[\/code\]$)/, ""))
    "#{s[0,1]}[code#{codes.length - 1} /]"
  end
  res.gsub!(/\r\n?/, "\n")
  res.gsub!(/\n*\[h\]\n*/, "</p><h2>")
  res.gsub!(/\n*\[\/h\]\n*/, "</h2><p>")
  res.gsub!(/\n\n+/, "</p><p>")
  res.gsub!(/\n(?=\[code\d+\s\/\])/, "</p><p>")
  res.gsub!(/(\[code\d+\s\/\])\n/, '\1</p><p>')
  res.gsub!("\n", "<br />")
  res += "</p>"
  res.gsub!(/<p>\[code\d+\s\/\]<\/p>/) do |s|
    "<pre><code>#{h codes[s.gsub(/\D+/, '').to_i]}</code></pre>"
  end
  res.gsub!("<p></p>", "")
  res.gsub!("//[", "[")
  res
end

Итоги

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

23.02.2009 firtree_right Регулярные выражения: радость победы

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

Задача

Сделать форматирование текста для блога, чтобы:

  1. Можно было вставлять подзаголовки;
  2. Текст разбивался на параграфы и просто переносы строки;
  3. Со вставками кода ничего не происходило;
  4. Было написано на ruby. Использовать RedCloth не хотелось, а стандартное форматирование не подходило. Поэтому приступим.

Вытащить код

Для того, чтобы не делать лишних проверок, вытаскиваем код из страницы. Код находится внутри тэга <pre>. Первое, что приходит на ум, это выражение типа «<pre> слева, </pre> справа и ни одного </pre> посередине.». Но оказалось, что исключить выражение невозможно (по крайней мере, я не нашёл способа). Выражение типа

/<pre>[^(<\/pre>)]+<\/pre>/

По крайней мере в ruby, интерпретируется как «тэг <pre>, внутри которого не встревается ни "<", ни "p", ни "r"... и т.д.»

Для этого понадобится концепция «жадности». То есть:

/<pre>.+<\/pre>/

Cоответствует куску от первого «<pre>» до последнего «</pre>». А нам нужно жадное:

/<pre>.+?<\/pre>/

То есть до ближайшего.

Теперь про wild card. Оказалось, что точка не включает перенос строки. Поэтому нам понадобится что-то более дикое. Wild, wild card. На эту роль подходит /[\s\S]/: пробельный символ или непробельный.

Итак, вытаскивание кусков кода выглядит так:

codes = []
res.gsub!(/<pre>[\s\S]+?<\/pre>/) do |s|
  codes.push(s)
  "code#{codes.length - 1}"
end

Вокруг кусков кода

Дальше задачи попроще. Приведение переноса строки к единому виду, замена выбранных выражений для заголовков на тэги заголовков, замена двух и более переносов строки на параграф. Это не представляет особых сложностей. Меня интересует, чтобы параграф кончился до кода и начался после, даже если там всего один перенос строки.

Что касается «кончился до», то тут используется lookahead (то есть операция при условии, что впереди есть что-то):

res.gsub!(/\n(?=code\d+)/, "</p><p>")

А чтобы начать параграф после куска кода, нам понадобится lookbehind (то есть операция при условии, что перед совпадением есть что-то), который в ruby не работает (по крайней мере в версии 1.8.7). поэтому здесь мы используем группы. И включим группу в результат:

res.gsub!(/(code\d+)\n/, '\1</p><p>')

Видите, вот этот \1?

Остались мелочи: вставить обратно куски кода. Убрать пустые параграфы и параграфы, окружающие куски кода. И вы видите то, что обрабатывает текст этого сообщения.

application_helper.rb:

...
def lonelyelk_format(text)
  res = "<p>" + text.to_s.dup
  codes = []
  res.gsub!(/<pre>[\s\S]+?<\/pre>/) do |s| # вытаскиваем куски кода
    codes.push(s)
    "code#{codes.length - 1}"
  end
  res.gsub!(/\r\n?/, "\n") # приводим перево каретки к одному виду
  res.gsub!(/\n*\[h\]\n*/, "</p><h2>") # заголовки начало [h]
  res.gsub!(/\n*\[\/h\]\n*/, "</h2><p>") # заголовки конец [/h]
  res.gsub!(/\n\n+/, "</p><p>") # более одного переноса строки - параграф
  res.gsub!(/\n(?=code\d+)/, "</p><p>") # параграф перед кодом
  res.gsub!(/(code\d+)\n/, '\1</p><p>') # параграф после кода
  res.gsub!("\n", "<br />") # единичный перенос строки
  res.gsub!(/(<p>)?code\d+(<\/p>)?/) do |s| # вставляем код обратно
    codes[s[4,1].to_i] # здесь ошибка :)
  end
  res.gsub!("<p></p>", "") # убираем пустые параграфы
  res += "</p>"
end
...

Остается одна проблема. Нельзя написать в тексте поста выражение «сode{цифры}». Но для этого просто можно генерировать случайный маркер, которого точно нет в тексте вместо «code».

Обновление

После того, как я попытался написать данный пост, я обнаружил ещё ряд интересных особенностей поведения кода и браузера. А так же нашёл ошибку. Публикую финальный код без пояснений:

application_helper.rb:

...
def lonelyelk_format(text)
  res = "<p>" + text.to_s.dup
  codes = []
  res.gsub!(/<pre><code>[\s\S]+?<\/code><\/pre>/) do |s|
    codes.push(s.gsub(/(^<pre><code>|<\/code><\/pre>$)/, ""))
    "code#{codes.length - 1}"
  end
  res.gsub!(/\r\n?/, "\n")
  res.gsub!(/\n*\[h\]\n*/, "</p><h2>")
  res.gsub!(/\n*\[\/h\]\n*/, "</h2><p>")
  res.gsub!(/\n\n+/, "</p><p>")
  res.gsub!(/\n(?=code\d+)/, "</p><p>")
  res.gsub!(/(code\d+)\n/, '\1</p><p>')
  res.gsub!("\n", "<br />")
  res.gsub!(/(<p>)?code\d+(<\/p>)?/) do |s|
    "<pre><code>" + codes[s.gsub(/\D/, "").to_i].to_s.gsub("<", "&lt;").gsub(">", "&gt;") + "</code></pre>"
  end
  res.gsub!("<p></p>", "")
  res += "</p>"
end
...

Материалы для изучения

http://www.regular-expressions.info/ http://regexp.ru/