Использование Maruku (часть №3)

Расширяй и углубляй

Как я и обещал, сейчас я расскажу вам о возможностях расширения Markdown. Так как есть два способа расширить функциональность, то в этом посте я расскажу про первый, а в следующем про второй.

Первый способ позволяет создавать свои span-подобные теги т.е. теги состоящие из одной строки. Например можно преобразовывать конструкцию вида

( ximg: ruby.jpg : Логотип Ruby : center )

в изображение с подписью. Или например вставлять на место смайликов их изображения, чем мы сейчас и займёмся.

В качестве заготовки для span-расширений можно использовать код приведённый ниже:

RegExp = /<регулярное выражение>/

MaRuKu::In::Markdown::register_span_extension(
:chars => [<символы с которых могут начинаться ваши span-теги>],
:regexp  => RegExp,
:handler => lambda { |doc, src, context|
    # Здесь находиться ваш код который преобразует span-тег в HTML разметку
    # Код возвращает true если тег успешно обработан, иначе возвращает false
  }
)

Этот код используя метод register_span_extension регистрирует обработчик span-тегов.

В аргументе :chars указывается символ или массив символов при встрече которых срабатывает обработчик. Причём символы не должны попадать в диапазон [a-zA-Z].

В аргументе :regexp указывается регулярное выражение которое будет выполнятся при встрече символа указанного в :chars и проверять является ли последовательность символов (начиная с текущего) вашим span-тегом. Не забудьте добавить символы из :chars в начало своего регулярного выражения, я потратил довольно много времени пытаясь понять почему обработчик не срабатывает.

В аргументе :handler в виде лямбда выражения находиться ваш обработчик. Который собственно говоря и занимается преобразованием вашего span-тега в нужную вам разметку. У этого обработчика тоже есть аргументы:

Аргумент doc это экземпляр класса Maruku который вы создали. В него подмешены методы из модуля MaRuKu::Helpers которые позволяют конструировать элементы на основе которых генерируется конечная разметка (понятно что формат мета-информации о том является ли текст курсивом в XHTML, PDF и LaTeX различаются, поэтому эти методы создают промежуточные объекты в которых храниться эта мета-информация, а уже из этих объектов по вашему требованию строится или XHTML или PDF или LaTeX)

Аргумент src предоставляет объект который содержит обрабатываемый текст и методы для его обработки.

Аргумент context предоставляет объект в который ваше расширение складывает результат своей работы (т.е. элемент или элементы полученные с помощью вспомогательных методов аргумента doc и заполненные мета-информацией необходимой для генерации разметки)

Остаётся добавить что если вы успешно обработали свой span-тег, то лямбда выражение должно вернуть true, тогда обработчики идущие за ним не будут вызваны и по окончанию преобразований ваш span-тег будет замещён генерированной в обработчике разметкой. А если вернуть false, то представление вашего span-тега без изменений будет помещено в выходную разметку.

Теперь мы готовы к написанию обработчика span-тегов. Как я уже сказал выше мы будем преобразовывать текстовые смайлики в HTML разметку содержащую изображение смайлика. Так как я суровый программист, то смайликов у меня будет всего лишь два (улыбающийся смайлик - :) или :-) и расстроенный смайлик - :( или :-( )

RegSmiles = /:-?(\(|\))/

MaRuKu::In::Markdown::register_span_extension(
      :chars => [?:],
      :regexp  => RegSmiles,
      :handler => lambda { |doc, src, context|
    attrs = src.read_regexp(RegSmiles).captures
    bracket = attrs[0]

    case bracket
      when ")"
        image = doc.md_im_image([], "/images/smile1.gif", ":-)", {:style => "padding:0;margin:0", :alt => ":-)"})
      when "("
        image = doc.md_im_image([], "/images/smile0.gif", ":-(", {:style => "padding:0;margin:0", :alt => ":-("})
    end

    context.push_element image
    true
  }
)

Вот такой вот код у меня получился. Так как мои смайлики начинаются с :, то аргумент :chars содержит этот символ. Регулярное выражение RegSmiles проверяет наличие смайлика при встречи символа двоеточия, а так же захватывает один символ (символ скобки) который после проверяется в case-е и на его основе формируется элемент на основе которого будет сформировано изображение. Затем этот элемент с помощью метода push_element помещается в контейнер context и лямбда выражение сигнализирует об успешной обработке возвращая true.

Это вот пример строк которые я использовал для тестирования:

Test :)
Тест :(

К сожалению этот код не заработал… не заработал с первого раза. Только для первой строки где содержались латинские символы появился смайлик, в строке же с русскими символами текст остался без изменений. Потратив больше часа на поиски проблемы я нашел решение и даже готовый патч (но ещё не включенный в основную версию). Порадовал меня и тот факт что я нашел то же место, но не стал писать заплатку, а решил отправить баг автору :)

А вот получившаяся разметка:

<p>Test <img src='/images/smile1.gif' alt='' style='padding:0;margin:0' /></p>
<p>Тест <img src='/images/smile0.gif' alt='' style='padding:0;margin:0' /></p>

На всякий случай приведу патч:

*** lib/maruku/input/charsource.rb.bak	2008-03-20 20:06:04.000000000 +0200
--- lib/maruku/input/charsource.rb	2008-03-20 20:28:34.000000000 +0200
***************
*** 88,95 ****
	end

	def next_matches(r)
! 		r2 = /^.{#{@buffer_index}}#{r}/m
! 		md = r2.match @buffer
		return !!md
	end
	
--- 88,94 ----
	end

	def next_matches(r)
!         md = /#{r}/um.match @buffer[@buffer_index, @buffer.size-@buffer_index]
		return !!md
	end

Думаю он потребуется нам и в следующей части. А пока всё.

Тэги: Maruku
Будь всегда в курсе последних новостей блога подписавшись на новости
в формате RSS. Присоединяйся!
* * *

Добавить новый комментарий

Доступные BB теги

*

* (не будет опубликован)

(если есть)

  • Multi CAPTCHA Refresh2
  • *

1. Проверьте комментарий перед отправкой
2. Все комментарии проходят модерацию перед публикацией в блоге