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

Блок

Приближается к концу мой “эпос” посвящённый Maruku :)

В этой части, как и обещал, я расскажу о том как добавить свои собственные блочные элементы. Напомню, что про добавление span-элементов я рассказал в прошлом посте.

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

StartTag = /^<регулярное выражение для начального тега>/
EndTag   = /^<регулярное выражение для конечного тега>/

MaRuKu::In::Markdown::register_block_extension(
	:regexp  => StartTag,
	:handler => lambda { |doc, src, context|
		# Пропускаем первую строку с начальным тегом
		src.shift_line
		# Считываем строки которые находятся внутри блока
		lines = []
		while src.cur_line && !(src.cur_line =~ EndTag)
			lines.push src.shift_line
		end
		# Пропускаем строку с конечным тегом
		src.shift_line
                    
                    # Здесь находиться ваш код который обрабатывает строки внутри блока
                    # и возвращает результат в переменной result
		context.push result
		true
	}
)

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

Мы завели две переменные в которых хранятся регулярные выражения для начального и конечного тега. Как вы понимаете это связано с тем что блок имеет следующий формат:

<начальный тег>
...
<содержимое блока>
...
<конечный тег>

И с помощью этих регулярных выражений мы находим эти теги, а затем “выкусываем” содержимое которое находится между ними и обрабатываем его.

Хорошим тоном думаю будет строить такие регулярные выражения которые будут искать теги начиная с начала строки (я специально указал в шаблоне символ чайки ^) связано это с тем что обработчик не принимает аргумент :chars как было в обработчике для span-тегов, а вместо этого применяет ко всем строкам вашего документа регулярное выражение StartTag чтобы понять содержит ли строка открывающий тег. Думаю понятно что из-за этого могут возникнуть проблемы с производительностью, а символ ^ всего лишь небольшая страховка от этих проблем.

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

Теоретическая часть закончена, переходим к практике :) Создадим блочный элемент в который можно помещать код на Ruby, а на выходе получать результат выполнения этого кода :)

Вот что у меня получилось:

StartTag = /^!ruby/
EndTag   = /^!/

MaRuKu::In::Markdown::register_block_extension(
  :regexp  => StartTag,
  :handler => lambda { |doc, src, context|
    # Пропускаем первую строку с начальным тегом
    src.shift_line
    # Считываем строки которые находятся внутри блока
    lines = []
    while src.cur_line && !(src.cur_line =~ EndTag)
      lines.push src.shift_line
    end
    # Пропускаем строку с конечным тегом
    src.shift_line

    code = lines.join("\n")
    result = get_result(code)
    context.push doc.md_html("<pre><code>#{result}</code></pre>")
    true
  })

class StdOutCapturer
  attr_reader :output

  def initialize
    @output = ""
  end

  def write(s)
    @output += s
  end
end

def get_result(code)
  origin_stdout = $stdout
  $stdout = StdOutCapturer.new

  eval(code)

  result = $stdout.output
  $stdout = origin_stdout

  result
end

И такой вот блок

!ruby
5.times { |i| puts "Hello World #{i}!!!" }
!

конвертируется в следующую разметку

<pre><code>Hello World 0!!!
Hello World 1!!!
Hello World 2!!!
Hello World 3!!!
Hello World 4!!!
</code></pre>

Что ж, я рассказал про все доступные способы расширения Markdown в Maruku. Код правда получился несколько громоздким, если видите способы исправить это - оставляйте комментарии :)

Следующий пост завершит цикл статей о Maruku, в нём я попробую выяснить насколько быстро работает Maruku.

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

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

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

*

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

(если есть)

  • Multi CAPTCHA Refresh2
  • *

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