Пета задача

Предадени решения

Краен срок:
23.11.2011 23:59
Точки:
8

Срокът за предаване на решения е отминал

Прост markup

Из философията на Markdown:

Markdown is intended to be as easy-to-read and easy-to-write as is feasible.

Readability, however, is emphasized above all else. A Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions.

Свободен превод на горното би било нещо от сорта на:

Markdown има за цел да е максимално лесен и за четене, и за писане.

Четимостта, обаче, е на първо място. Документ, форматиран с Markdown трябва да може да се публикува едно към едно, като обикновен текст, без да изглежда така, сякаш е бил форматиран с някакви тагове или други специални инструкции.

Вашата цел в тази задача ще бъде да реализирате прост преобразувател от документи, форматирани с подмножество на Markdown към HTML.

Параграфи (p)

За параграф считаме всяка последователност от един или повече непразни редове текст, които не заглавен елемент, списък, блок с код или цитат. Всяка последователност от два един или повече празни редове се счита за разделител между параграфи. Началото на параграф се маркира с <p>, а краят му с </p>.

Пример:

В този текст ще имаме един параграф.

Резултат:

<p>В този текст ще имаме един параграф.</p>

Втори пример:

Първи, уводен параграф.

Тук ще очакваме да имаме и още един, втори параграф.
Новите редове в параграфите се игнорират.

Резултат:

<p>В този текст ще имаме един параграф.</p>

<p>Тук ще очакваме да имаме и още един, втори параграф.
Новите редове в параграфите се игнорират.</p>

След форматиране, не трябва да има текст, който е извън параграф, заглавен елемент, блок с код, цитат или списък. Не трябва да имате и празни параграфи (от вида <p></p>).

Специални блокови елементи като заглавия, списъци, блокове код и цитати, "прекъсват" параграфа и го разделят на две части. Ще намерите описание на заглавните елементи в следващата секция.

Например:

Първи ред тескт.
### Заглавен елемент
Трети ред текст.

Резултира в:

<p>Първи ред тескт.</p>
<h3>Заглавен елемент</h3>
<p>Трети ред текст.</p>

Забележка: параграфът е най-важната конструкция. Много тестове очакват да сте поставили маркери за параграфи на правилните места и ако не сте, няма да минат и няма да вземете точки.

Заглавни елементи (h1, h2, h3, h4)

Ще разпознаваме четири различни заглавни елемента — от h1 до h4. Въпреки, че HTML-стандартът дефинира заглавни елементи до h7, ние няма да ползваме всички. Ред текст се счита за заглавен елемент, ако започва с един до четири символа #, последвани от един или повече whitespace-символи, последвани от самия текст. Ако символите # са друга бройка, редът не се счита за заглавен. Ако липсва whitespace между символите # и самия текст, редът също не се счита за заглавен. Във форматирания си вид, whitespace-ът, намиращ се между символите # и самия текст трябва да бъде премахнат.

Примери:

# Най-прост h1-елемент

Резултат:

<h1>Най-прост h1-елемент</h1>

Още примери:

### Това е h3
#### Това — h4
##   Валиден h2-елемент   ##

Горното трябва да продуцира:

<h3>Това е h3</h3>
<h4>Това — h4</h4>
<h2>Валиден h2-елемент   ##</h2>

Примери за невалидни заглавни елементи:

##Това е невалиден заглавен елемент

##### Това също не е валидно

Горното резултира в:

<p>##Това е невалиден заглавен елемент</p>

<p>##### Това също не е валидно</p>

Блокове с код (pre)

Всяка непрекъсната последователност от редове в текста, идентирана с точно четири интервала, ще считате за блок от код и ще ограждате в елементи <pre> и <code> (<pre><code>код</code></pre>). В блоковете от код не се прилага никакво друго форматиране. Специални символи в блокове с код се екранират (вж. секция "Специални симовли"). Всеки символ за whitespace след задължителните четири водещи интервала трябва да се запази както си е. Whitespace в края на редовете, които са блокове код, също се запазва без промяна.

Пример:

    // Пример за блок с код.
    // В него всеки ред, дори празните, е предшестван от точно четири интервала.
    include <stdio.h>

    int main(int, char**) {
        // Whitespace след четирите задължителни интервала в началото, се запазва.
        return 42;
    }

Резултат:

<pre><code>// Пример за блок с код.
// В него всеки ред, дори празните, е предшестван от точно четири интервала.
include <stdio.h>

int main(int, char**) {
    // Whitespace след четирите задължителни интервала в началото, се запазва.
    return 42;
}</code></pre>

Блоковете с код са неизменна и много важна част от нашия mini-Markdown стандарт :)

Цитати (blockquotes)

Цитати са всички последователности от един или повече непрекъснати реда, които започват със символа >, последван от един или повече whitespace-символи, последвани от цитирания текст. Whitespace в края на реда трябва да бъде премахван от обработения текст. Елементът от HTML, в който трябва да бъде ограден всеки цитат, е <blockquote>. Текстът в самия цитат трябва да е в параграфи, по съответните правила (вж. секция "Параграфи").

Пример:

> Около 80% от хората вече не проверяват достоверността на цитирана статистика.
> Дадено твърдение се приема на доверие, особено ако в него има число или процент.
> Източник: ИНТЕРНЕТ

Трябва да продуцира следния HTML-код:

<blockquote><p>Около 80% от хората вече не проверяват достоверността на цитирана статистика.
Дадено твърдение се приема на доверие, особено ако в него има число или процент.
Източник: ИНТЕРНЕТ</p></blockquote>

Не забравяйте, че цитатите, както и заглавните елементи, блоковете с код и списъците, "прекъсват" целостта на даден параграф и го разделят на две части (вижте примера в секцията за параграфи).

Линкове (a)

Линковете (хипервръзки) имат много проста структура. Състоят се от точно два елемента — текст на линка и адрес на линка. Линкове в HTML се дефинират по следния начин: <a href="адрес">текст</a>. Линковете могат да се намират в параграфи, заглавни елементи, цитати и елементи от списъци.

Ограничения:

  • Текст на линка не може да съдържа символа ]
  • В текст или адрес на линк не може да се съдържа нов ред
  • Текстът и адресът на линка трябва да са дефинирани на един и същи ред
  • Адресът на линка не може да съдържа символа )
  • Не е необходимо да добавяте протоколи пред адресите — ползвайте ги както са си; указване на съответния протокол ще е грижа на потребителя

Пример:

Не знаете нещо? [Ползвайте Google](http://google.com/).

Трява да резултира в:

<p>Не знаете нещо? <a href="http://google.com/">Ползвайте Google</a>.</p>

Забележете, че около адреса на линка се поставят двойни кавички (") и няма интервали около знака =. Също, кавичките в дефиницията на тага <a> не се екранират. За екраниране на специални символи ще стане дума в следващите секции.

Списъци (ul, ol)

Необходимо е да се разпознават два вида списъци -- наредени (ol, ordered lists) и ненаредени (ul, unordered list). Първите се дефинират по следния начин:

1. Първо
2. Второ
3. Трето...

И продуцират следния резултат:

<ol>
  <li>Първо</li>
  <li>Второ</li>
  <li>Трето...</li>
</ol>

Вторите се дефинират така:

* Едно
* Друго
* Трето...

И след обработка, резултират в:

<ul>
  <li>Едно</li>
  <li>Друго</li>
  <li>Трето...</li>
</ul>

Забележете, че в обработения текст, преди всеки елемент от списък (<li>), има точно два интервала за прегледност на резултата.

Почернен и курсив шрифт (strong, em)

Почернен шрифт или шрифт в курсив можем да дефинираме във всеки параграф, заглавен елемент, елемент от списък, цитат или линк. И двете могат да съществуват само в рамките на един ред.

Почернен шрифт се дефинира по следния начин:

Следната дума е в **почернен** шрифт.
Можем да **удебеляваме и цели изрази в рамките на реда.**

Резултат:

<p>Следната дума е в <strong>почернен</strong> шрифт.
Можем да <strong>удебеляваме и цели изрази в рамките на реда.</strong></p>

На свой ред, шрифт в курсив се дефинира с помощна на един символ _. Например:

Шрифт в _курсив_.
Курсивът _също работи_ за изрази.

Резултира в:

<p>Шрифт в <em>курсив</em>.
Курсивът <em>също работи</em> за изрази.</p>

Забележка: курсив и почернен шрифт могат да се влагат изцяло един в друг, но не могат да се застъпват частично. Например, следното:

Неправилно _влагане на **почернен текст_ в курсив** не трябва да се допуска.

Трябва да продуцира:

<p>Неправилно <em>влагане на **почернен текст</em> в курсив** не трябва да се допуска.</p>

В горния пример се вижда, че почернен шрифт няма, тъй като би довел до частично застъпване с курсив.

Специални символи (&amp; &lt; &gt; ...)

Следните специални символи, ако бъдат срещнати някъде в текста, трябва да бъдат екранирани, т.е. заместени със съответния HTML escape sequence:

& → &amp;
< → &lt;
> → &gt;
" → &quot;

Екранацията трябва да се случва без значение къде в текста се намира специалният символ, със следните изключения — екранация не се прилага над:

  • Специални символи, които имат вече дефиниран смисъл в този документ; например > в началото на ред не се екранира, но за сметка на това се преработва в секция "цитат".
  • Двойните кавички, ограждащи атрибута "адрес" на линк не се екранират; забележете, обаче, че самият адрес и също текст на линка трябва да бъдат с екранирани специални символи.

Пример:

# Игра на "котка & мишка"

Много <забавна> игра!

Резултат:

<h1>Игра на &quot;котка &amp; и мишка&quot;

<p>Много &lt;забавна&gt; игра!</p>

Whitespace

  • Считайте, че новите редове ще са единствено \n.
  • Whitespace в началото или в края на ред трябва да бъде премахван, освен ако в някоя от по-горните секции не е указано друго.
  • Излишен whitespace в началото или в края на текста трябва да бъде премахван, без това да чупи евентуални блокове с код.
  • Всеки друг whitespace, ако не е изрично указано, трябва да се запази както си е.

Цялостен пример

Ако имаме следния примерен текст:

# Цялостен пример
Тук ще демонстрираме накратко възможностите на нашия прост Markdown-интерпретатор.

## _Философия_ на [Markdown](http://daringfireball.net/projects/markdown/syntax#philosophy)

Кратък цитат относно философията на Markdown:
> Markdown is intended to be as easy-to-read and easy-to-write as is feasible.
> 
> Readability, however, is emphasized above all else. A Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions.
Повече информация може да намерите на [сайта на **Markdown**](http://daringfireball.net/projects/markdown).

## Предимства

Създаването на съдържание във формата Markdown има множество предимства.

Ето някои от тях:
* Лесно четим в _суров_ вид
* Без "скрити" форматиращи тагове — форматирането ви никога не се чупи
* След обработка може да изглежда много добре

## Поддръжка в _Ruby_

В **Ruby** има множество Gem-ове, които могат да ви помогнат за да прехвърляте Markdown-съдържание в HTML-формат.
Кодът, който вие създавате, също може да върши това до известна степен.

Пример за употреба на вашия код:

    # Много просто
    formatter = Formatter.new "## My Markdown"
    puts formatter.to_html

Ще се очаква да се получи този резултат:

<h1>Цялостен пример</h1>
<p>Тук ще демонстрираме накратко възможностите на нашия прост Markdown-интерпретатор.</p>

<h2><em>Философия</em> на <a href="http://daringfireball.net/projects/markdown/syntax#philosophy">Markdown</a></h2>

<p>Кратък цитат относно философията на Markdown:</p>
<blockquote><p>Markdown is intended to be as easy-to-read and easy-to-write as is feasible.</p>

<p>Readability, however, is emphasized above all else. A Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions.</p></blockquote>
<p>Повече информация може да намерите на <a href="http://daringfireball.net/projects/markdown">сайта на <strong>Markdown</strong></a>.</p>

<h2>Предимства</h2>

<p>Създаването на съдържание във формата Markdown има множество предимства.</p>

<p>Ето някои от тях:</p>
<ul>
  <li>Лесно четим в <em>суров</em> вид</li>
  <li>Без &quot;скрити&quot; форматиращи тагове — форматирането ви никога не се чупи</li>
  <li>След обработка може да изглежда много добре</li>
</ul>

<h2>Поддръжка в <em>Ruby</em></h2>

<p>В <strong>Ruby</strong> има множество Gem-ове, които могат да ви помогнат за да прехвърляте Markdown-съдържание в HTML-формат.
Кодът, който вие създавате, също може да върши това до известна степен.</p>

<p>Пример за употреба на вашия код:</p>

<pre><code># Много просто
formatter = Formatter.new &quot;## My Markdown&quot;
puts formatter.to_html</code></pre>

Дизайн

Изисквания към публичното ви API:

  • Да имате клас Formatter
  • Конструкторът му да прима един-единтствен аргумент — чистият, неформатиран текст
  • Да имате инстанционен метод Formatter#to_html, който връща резултатния HTML-код на база на неформатирания текст
  • Formatter#to_s, който да връща същото, което връща и #to_html
  • Formatter#inspect, връщащ чистия, неформатиран текст, с който е създаден обектът

Ограничения

Тази задача има следните ограничения:

  • Най-много 90 символа на ред
  • Най-много 8 реда на метод
  • Най-много 2 нива на влагане

Ако искате да проверите дали задачата ви спазва ограниченията, следвайте инструкциите в описанието на хранилището за домашните.

Няма да приемаме решения, които не спазват ограниченията. Изпълнявайте rubocop редовно, докато пишете кода. Ако смятате, че rubocop греши по някакъв начин, пишете ни на fmi@ruby.bg, заедно с прикачен код или линк към такъв като private gist. Ако пуснете кода си публично (например във форумите), ще смятаме това за преписване.