Решение на Пета задача от Велина Ташева

Обратно към всички решения

Към профила на Велина Ташева

Резултати

  • 7 точки от тестове
  • 0 бонус точки
  • 7 точки общо
  • 52 успешни тест(а)
  • 5 неуспешни тест(а)

Код

class Formatter
Tuple = Struct.new(:pattern, :replace)
attr_accessor :text
PATTERNS = [
Tuple.new('\r\n', '\n'),
Tuple.new('\r', '\n'),
Tuple.new(/_(.*?)_/, :process_em),
Tuple.new(/\*{2}(.*)\*{2}/, :process_strong),
Tuple.new(/\b_(\w+)_\b/, '<em>\1</em>'),
Tuple.new(/\[(.*)\]\((.*)\)/, '<a href="\2">\1</a>'),
Tuple.new(/(\n*)(^\#{1,4}[ ])(.*)(\n*)/, :process_headers),
Tuple.new(/[ ]{4}.*(\n[ ]{4}.*)*/, :process_code),
Tuple.new(/\n*^>\s+.*(\n>\s+.*)*$/, :process_blockquotes),
Tuple.new(/(\n*)^\d\.\s.*(\n\d\..*)*$/, :process_ordered_lists),
Tuple.new(/\n*^\*.*(\n\*.*)*$/, :process_unordered_lists),
Tuple.new(/(\n{2,})(?!<p>)/, '</p>\1<p>'),
Tuple.new(/<p>(\s*)<\/p>/, '\1'),
Tuple.new(/<p>[ ]{2,}/, '<p>'),
Tuple.new(/[ ]{2,}<\/p>/, '</p>'),
Tuple.new(/<\/p><\/p>/, '</p>'),
Tuple.new(/<p><pre>/, '<pre>'),
Tuple.new(/<\/pre><p>/, '</pre>'),
Tuple.new(/(<h\d>)[ ]{2,}/, '\1'),
Tuple.new(/[ ]{2,}(<\/h\d>)/, '\1'),
Tuple.new(/<pre><code>(.*)<\/code><\/pre>/m, :remove_html_from_code),
]
def initialize(text)
@text = text
end
def to_html
text = escape_special_entries
PATTERNS.each do |tuple|
if (tuple.replace.is_a? String)
text = text.gsub(tuple.pattern, tuple.replace)
else
text = sub_with_lambda(tuple, text)
end
end
if !text.start_with?("<ul>") and !text.start_with?("<blockquote>")
text = (text.include? "\n")? text.sub(/\n/, '').reverse.sub(/\n/, '').reverse : text
end
text.strip
end
def to_s
to_html
end
def inspect
@text
end
private
def sub_with_lambda(tuple, text)
match = tuple.pattern.match(text)
if match
handler = Parser.method(tuple.replace)
args = match[1], match[2], match[3], match[4]
text = text.gsub(tuple.pattern){ |s| handler.call(s, *args )}
end
text
end
def escape_special_entries
text = (@text.start_with?(' ' * 4))? @text : @text.strip
text = text.gsub(/&/,'&amp;')
text = text.gsub(/</,'&lt;')
text = text.gsub(/(?!(^))>/,'&gt;')
text = text.gsub(/"/,'&quot;')
"<p>\n" + text + "\n</p>"
end
end
class Parser
def self.process_headers(data, first_group, second_group, third_group, fourth_group)
h_number = second_group.length - 1
"</p>#{first_group}<h#{h_number}>#{third_group}</h#{h_number}>#{fourth_group}<p>"
end
def self.process_code(data, first_group, *args)
if !data
return ''
end
code = data.lines("\n").map { |s| remove_empty_space(s)}.join
code = "</p><pre><code>" + code + "</code></pre><p>"
end
def self.process_blockquotes(data, *args)
if data
return '</p><blockquote><p>' + data.strip.gsub(/> */, '') + '</p></blockquote><p>'
end
''
end
def self.process_ordered_lists(data, first_group, *args)
if data
beginning = "</p>#{first_group}<ol>\n"
return beginning + data.strip.gsub(/\d\.\s(.*)/, ' <li>\1</li>') + "\n</ol><p>"
end
''
end
def self.process_unordered_lists(data, *args)
if data
return "</p>\n<ul>\n" + data.strip.gsub(/\*\s(.*)/, ' <li>\1</li>') + "\n</ul><p>"
end
''
end
def self.process_em(data, *args)
if ((data.include? '<strong>' and data.include? '</strong>') or
(!data.include? '<strong>' and !data.include? '</strong>'))
return '<em>' + data[1..data.length-2] + '</em>'
end
data
end
def self.process_strong(data, *args)
if ((data.include? '<em>' and data.include? '</em>') or
(!data.include? '<em>' and !data.include? '</em>'))
return '<strong>' + data[2..data.length-3] + '</strong>'
end
data
end
def self.remove_html_from_code(data, *args)
text = data.gsub(/<p>|<\/p>/, '')
text = text.gsub(/<em>|<\/em>/, '_')
text = text.gsub(/<strong>|<\/strong>/, '**')
text = text.gsub(/<h1>/, '# ')
text = text.gsub(/<\/h1>/, '')
text
end
private
def self.remove_empty_space(text)
if text == "\n"
return text
end
if text and text[4..text.length]
return text[4..text.length]
end
''
end
end

Лог от изпълнението

..................F....F.F...........F..................F

Failures:

  1) Formatter blockquotes renders multiple ones
     Failure/Error: Formatter.new(plain).to_html.should eq formatted.strip
       
       expected: "<blockquote><p>First quote.</p></blockquote>\n\n<blockquote><p>Second quote.</p></blockquote>"
            got: "<blockquote><p>First quote.</p></blockquote><blockquote><p>Second quote.</p></blockquote>"
       
       (compared using ==)
       
       Diff:
       @@ -1,4 +1,2 @@
       -<blockquote><p>First quote.</p></blockquote>
       -
       -<blockquote><p>Second quote.</p></blockquote>
       +<blockquote><p>First quote.</p></blockquote><blockquote><p>Second quote.</p></blockquote>
     # /tmp/d20111129-16859-yxgx66/spec.rb:660:in `expect_transformation'
     # /tmp/d20111129-16859-yxgx66/spec.rb:252:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  2) Formatter links allows multiple links on a single line
     Failure/Error: Formatter.new(plain).to_html.should eq formatted.strip
       
       expected: "<p>We have <a href=\"some-url\">a first</a> and <a href=\"another-url\">Second</a>.</p>"
            got: "<p>We have <a href=\"another-url\">a first](some-url) and [Second</a>.</p>"
       
       (compared using ==)
     # /tmp/d20111129-16859-yxgx66/spec.rb:660:in `expect_transformation'
     # /tmp/d20111129-16859-yxgx66/spec.rb:286:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  3) Formatter links does not render them in code blocks
     Failure/Error: Formatter.new(plain).to_html.should eq formatted.strip
       
       expected: "<pre><code>This one [is a link](in-a-code-block) - keep as-is.</code></pre>"
            got: "<pre><code>This one <a href=\"in-a-code-block\">is a link</a> - keep as-is.</code></pre>"
       
       (compared using ==)
     # /tmp/d20111129-16859-yxgx66/spec.rb:660:in `expect_transformation'
     # /tmp/d20111129-16859-yxgx66/spec.rb:299:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  4) Formatter bold and italic text rendering works in blockquotes
     Failure/Error: Formatter.new(plain).to_html.should eq formatted.strip
       
       expected: "<blockquote><p><em>Simplest</em> case</p></blockquote>"
            got: "<blockquote><p><emSimplest</emcase</p></blockquote>"
       
       (compared using ==)
     # /tmp/d20111129-16859-yxgx66/spec.rb:660:in `expect_transformation'
     # /tmp/d20111129-16859-yxgx66/spec.rb:665:in `block in expect_transformations'
     # /tmp/d20111129-16859-yxgx66/spec.rb:664:in `each'
     # /tmp/d20111129-16859-yxgx66/spec.rb:664:in `expect_transformations'
     # /tmp/d20111129-16859-yxgx66/spec.rb:455:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

  5) Formatter mixed, complex input renders properly
     Failure/Error: Formatter.new(plain).to_html.should eq formatted.strip
       
       expected: "<h1>\u0426\u044F\u043B\u043E\u0441\u0442\u0435\u043D \u043F\u0440\u0438\u043C\u0435\u0440</h1>\n<p>\u0422\u0443\u043A \u0449\u0435 \u0434\u0435\u043C\u043E\u043D\u0441\u0442\u0440\u0438\u0440\u0430\u043C\u0435 \u043D\u0430\u043A\u0440\u0430\u0442\u043A\u043E \u0432\u044A\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u0438\u0442\u0435 \u043D\u0430 \u043D\u0430\u0448\u0438\u044F \u043F\u0440\u043E\u0441\u0442 Markdown-\u043F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u0443\u0432\u0430\u0442\u0435\u043B.</p>\n\n<h2><em>\u0424\u0438\u043B\u043E\u0441\u043E\u0444\u0438\u044F</em> \u043D\u0430 <a href=\"http://daringfireball.net/projects/markdown/syntax#philosophy\">Markdown</a></h2>\n\n<p>\u041A\u0440\u0430\u0442\u044A\u043A \u0446\u0438\u0442\u0430\u0442 \u043E\u0442\u043D\u043E\u0441\u043D\u043E \u0444\u0438\u043B\u043E\u0441\u043E\u0444\u0438\u044F\u0442\u0430 \u043D\u0430 Markdown:</p>\n<blockquote><p>Markdown is intended to be as easy-to-read and easy-to-write as is feasible.</p>\n\n<p>Readability, however, is emphasized above all else. A Markdown-formatted document should be publishable as-is, as plain text, without looking like it\u2019s been marked up with tags or formatting instructions.</p></blockquote>\n<p>\u041F\u043E\u0432\u0435\u0447\u0435 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043C\u043E\u0436\u0435 \u0434\u0430 \u043D\u0430\u043C\u0435\u0440\u0438\u0442\u0435 \u043D\u0430 <a href=\"http://daringfireball.net/projects/markdown\">\u0441\u0430\u0439\u0442\u0430 \u043D\u0430 <strong>Markdown</strong></a>.</p>\n\n<h2>\u041F\u0440\u0435\u0434\u0438\u043C\u0441\u0442\u0432\u0430</h2>\n\n<p>\u0421\u044A\u0437\u0434\u0430\u0432\u0430\u043D\u0435\u0442\u043E \u043D\u0430 \u0441\u044A\u0434\u044A\u0440\u0436\u0430\u043D\u0438\u0435 \u0432\u044A\u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0430 Markdown \u0438\u043C\u0430 \u043C\u043D\u043E\u0436\u0435\u0441\u0442\u0432\u043E \u043F\u0440\u0435\u0434\u0438\u043C\u0441\u0442\u0432\u0430.</p>\n\n<p>\u0415\u0442\u043E \u043D\u044F\u043A\u043E\u0438 \u043E\u0442 \u0442\u044F\u0445:</p>\n<ul>\n  <li>\u041B\u0435\u0441\u043D\u043E \u0447\u0435\u0442\u0438\u043C \u0432 <em>\u0441\u0443\u0440\u043E\u0432</em> \u0432\u0438\u0434</li>\n  <li>\u0411\u0435\u0437 &quot;\u0441\u043A\u0440\u0438\u0442\u0438&quot; \u0444\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u0430\u0449\u0438 \u0442\u0430\u0433\u043E\u0432\u0435 \u2014 \u0444\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u0430\u043D\u0435\u0442\u043E \u0432\u0438 \u043D\u0438\u043A\u043E\u0433\u0430 \u043D\u0435 \u0441\u0435 \u0447\u0443\u043F\u0438</li>\n  <li>\u0421\u043B\u0435\u0434 \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u043A\u0430 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0438\u0437\u0433\u043B\u0435\u0436\u0434\u0430 \u043C\u043D\u043E\u0433\u043E \u0434\u043E\u0431\u0440\u0435</li>\n</ul>\n\n<h2>\u041F\u043E\u0434\u0434\u0440\u044A\u0436\u043A\u0430 \u0432 <em>Ruby</em></h2>\n\n<p>\u0412 <strong>Ruby</strong> \u0438\u043C\u0430 \u043C\u043D\u043E\u0436\u0435\u0441\u0442\u0432\u043E Gem-\u043E\u0432\u0435, \u043A\u043E\u0438\u0442\u043E \u043C\u043E\u0433\u0430\u0442 \u0434\u0430 \u0432\u0438 \u043F\u043E\u043C\u043E\u0433\u043D\u0430\u0442 \u0437\u0430 \u0434\u0430 \u043F\u0440\u0435\u0445\u0432\u044A\u0440\u043B\u044F\u0442\u0435 Markdown-\u0441\u044A\u0434\u044A\u0440\u0436\u0430\u043D\u0438\u0435 \u0432 HTML-\u0444\u043E\u0440\u043C\u0430\u0442.\n\u041A\u043E\u0434\u044A\u0442, \u043A\u043E\u0439\u0442\u043E \u0432\u0438\u0435 \u0441\u044A\u0437\u0434\u0430\u0432\u0430\u0442\u0435, \u0441\u044A\u0449\u043E \u043C\u043E\u0436\u0435 \u0434\u0430 \u0432\u044A\u0440\u0448\u0438 \u0442\u043E\u0432\u0430 \u0434\u043E \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u0430 \u0441\u0442\u0435\u043F\u0435\u043D.</p>\n\n<p>\u041F\u0440\u0438\u043C\u0435\u0440 \u0437\u0430 \u0443\u043F\u043E\u0442\u0440\u0435\u0431\u0430 \u043D\u0430 \u0432\u0430\u0448\u0438\u044F \u043A\u043E\u0434:</p>\n\n<pre><code># \u041C\u043D\u043E\u0433\u043E \u043F\u0440\u043E\u0441\u0442\u043E\nformatter = Formatter.new &quot;## My Markdown&quot;\nputs formatter.to_html</code></pre>"
            got: "<h1>\u0426\u044F\u043B\u043E\u0441\u0442\u0435\u043D \u043F\u0440\u0438\u043C\u0435\u0440</h1>\n<p>\u0422\u0443\u043A \u0449\u0435 \u0434\u0435\u043C\u043E\u043D\u0441\u0442\u0440\u0438\u0440\u0430\u043C\u0435 \u043D\u0430\u043A\u0440\u0430\u0442\u043A\u043E \u0432\u044A\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u0438\u0442\u0435 \u043D\u0430 \u043D\u0430\u0448\u0438\u044F \u043F\u0440\u043E\u0441\u0442 Markdown-\u043F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u0443\u0432\u0430\u0442\u0435\u043B.</p>\n<h1>\u0426\u044F\u043B\u043E\u0441\u0442\u0435\u043D \u043F\u0440\u0438\u043C\u0435\u0440</h1>\n<p>\u041A\u0440\u0430\u0442\u044A\u043A \u0446\u0438\u0442\u0430\u0442 \u043E\u0442\u043D\u043E\u0441\u043D\u043E \u0444\u0438\u043B\u043E\u0441\u043E\u0444\u0438\u044F\u0442\u0430 \u043D\u0430 Markdown:</p><blockquote><p>Markdown is intended to be as easy-to-read and easy-to-write as is feasible.</p>\n\n<p>Readability, however, is emphasized above all else. A Markdown-formatted document should be publishable as-is, as plain text, without looking like it\u2019s been marked up with tags or formatting instructions.</p></blockquote><p>\n\u041F\u043E\u0432\u0435\u0447\u0435 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043C\u043E\u0436\u0435 \u0434\u0430 \u043D\u0430\u043C\u0435\u0440\u0438\u0442\u0435 \u043D\u0430 <a href=\"http://daringfireball.net/projects/markdown\">\u0441\u0430\u0439\u0442\u0430 \u043D\u0430 <strong>Markdown</strong></a>.</p>\n<h1>\u0426\u044F\u043B\u043E\u0441\u0442\u0435\u043D \u043F\u0440\u0438\u043C\u0435\u0440</h1>\n<p>\u0421\u044A\u0437\u0434\u0430\u0432\u0430\u043D\u0435\u0442\u043E \u043D\u0430 \u0441\u044A\u0434\u044A\u0440\u0436\u0430\u043D\u0438\u0435 \u0432\u044A\u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0430 Markdown \u0438\u043C\u0430 \u043C\u043D\u043E\u0436\u0435\u0441\u0442\u0432\u043E \u043F\u0440\u0435\u0434\u0438\u043C\u0441\u0442\u0432\u0430.</p>\n\n<p>\u0415\u0442\u043E \u043D\u044F\u043A\u043E\u0438 \u043E\u0442 \u0442\u044F\u0445:</p>\n<ul>\n  <li>\u041B\u0435\u0441\u043D\u043E \u0447\u0435\u0442\u0438\u043C \u0432 <em>\u0441\u0443\u0440\u043E\u0432</em> \u0432\u0438\u0434</li>\n  <li>\u0411\u0435\u0437 &quot;\u0441\u043A\u0440\u0438\u0442\u0438&quot; \u0444\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u0430\u0449\u0438 \u0442\u0430\u0433\u043E\u0432\u0435 \u2014 \u0444\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u0430\u043D\u0435\u0442\u043E \u0432\u0438 \u043D\u0438\u043A\u043E\u0433\u0430 \u043D\u0435 \u0441\u0435 \u0447\u0443\u043F\u0438</li>\n  <li>\u0421\u043B\u0435\u0434 \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u043A\u0430 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0438\u0437\u0433\u043B\u0435\u0436\u0434\u0430 \u043C\u043D\u043E\u0433\u043E \u0434\u043E\u0431\u0440\u0435</p></li>\n</ul><p>\n<h1>\u0426\u044F\u043B\u043E\u0441\u0442\u0435\u043D \u043F\u0440\u0438\u043C\u0435\u0440</h1>\n<p>\u0412 <strong>Ruby</strong> \u0438\u043C\u0430 \u043C\u043D\u043E\u0436\u0435\u0441\u0442\u0432\u043E Gem-\u043E\u0432\u0435, \u043A\u043E\u0438\u0442\u043E \u043C\u043E\u0433\u0430\u0442 \u0434\u0430 \u0432\u0438 \u043F\u043E\u043C\u043E\u0433\u043D\u0430\u0442 \u0437\u0430 \u0434\u0430 \u043F\u0440\u0435\u0445\u0432\u044A\u0440\u043B\u044F\u0442\u0435 Markdown-\u0441\u044A\u0434\u044A\u0440\u0436\u0430\u043D\u0438\u0435 \u0432 HTML-\u0444\u043E\u0440\u043C\u0430\u0442.\n\u041A\u043E\u0434\u044A\u0442, \u043A\u043E\u0439\u0442\u043E \u0432\u0438\u0435 \u0441\u044A\u0437\u0434\u0430\u0432\u0430\u0442\u0435, \u0441\u044A\u0449\u043E \u043C\u043E\u0436\u0435 \u0434\u0430 \u0432\u044A\u0440\u0448\u0438 \u0442\u043E\u0432\u0430 \u0434\u043E \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u0430 \u0441\u0442\u0435\u043F\u0435\u043D.</p>\n\n<p>\u041F\u0440\u0438\u043C\u0435\u0440 \u0437\u0430 \u0443\u043F\u043E\u0442\u0440\u0435\u0431\u0430 \u043D\u0430 \u0432\u0430\u0448\u0438\u044F \u043A\u043E\u0434:</p>\n\n<pre><code># \u041C\u043D\u043E\u0433\u043E \u043F\u0440\u043E\u0441\u0442\u043E\nformatter = Formatter.new &quot;## My Markdown&quot;\nputs formatter.to_html</code></pre>"
       
       (compared using ==)
       
       Diff:
       
       
       @@ -1,27 +1,20 @@
        <h1>Цялостен пример</h1>
        <p>Тук ще демонстрираме накратко възможностите на нашия прост Markdown-преобразувател.</p>
       +<h1>Цялостен пример</h1>
       +<p>Кратък цитат относно философията на Markdown:</p><blockquote><p>Markdown is intended to be as easy-to-read and easy-to-write as is feasible.</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>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>
       +<h1>Цялостен пример</h1>
        <p>Създаването на съдържание във формата Markdown има множество предимства.</p>
        
        <p>Ето някои от тях:</p>
        <ul>
          <li>Лесно четим в <em>суров</em> вид</li>
          <li>Без &quot;скрити&quot; форматиращи тагове — форматирането ви никога не се чупи</li>
       -  <li>След обработка може да изглежда много добре</li>
       -</ul>
       -
       -<h2>Поддръжка в <em>Ruby</em></h2>
       -
       +  <li>След обработка може да изглежда много добре</p></li>
       +</ul><p>
       +<h1>Цялостен пример</h1>
        <p>В <strong>Ruby</strong> има множество Gem-ове, които могат да ви помогнат за да прехвърляте Markdown-съдържание в HTML-формат.
        Кодът, който вие създавате, също може да върши това до известна степен.</p>
        
     # /tmp/d20111129-16859-yxgx66/spec.rb:660:in `expect_transformation'
     # /tmp/d20111129-16859-yxgx66/spec.rb:655:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (3 levels) in <top (required)>'
     # ./lib/homework/run_with_timeout.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.68782 seconds
57 examples, 5 failures

Failed examples:

rspec /tmp/d20111129-16859-yxgx66/spec.rb:239 # Formatter blockquotes renders multiple ones
rspec /tmp/d20111129-16859-yxgx66/spec.rb:285 # Formatter links allows multiple links on a single line
rspec /tmp/d20111129-16859-yxgx66/spec.rb:298 # Formatter links does not render them in code blocks
rspec /tmp/d20111129-16859-yxgx66/spec.rb:450 # Formatter bold and italic text rendering works in blockquotes
rspec /tmp/d20111129-16859-yxgx66/spec.rb:586 # Formatter mixed, complex input renders properly

История (1 версия и 0 коментара)

Велина обнови решението на 21.11.2011 16:53 (преди над 12 години)

+class Formatter
+ Tuple = Struct.new(:pattern, :replace)
+ attr_accessor :text
+ PATTERNS = [
+ Tuple.new('\r\n', '\n'),
+ Tuple.new('\r', '\n'),
+ Tuple.new(/_(.*?)_/, :process_em),
+ Tuple.new(/\*{2}(.*)\*{2}/, :process_strong),
+ Tuple.new(/\b_(\w+)_\b/, '<em>\1</em>'),
+ Tuple.new(/\[(.*)\]\((.*)\)/, '<a href="\2">\1</a>'),
+ Tuple.new(/(\n*)(^\#{1,4}[ ])(.*)(\n*)/, :process_headers),
+ Tuple.new(/[ ]{4}.*(\n[ ]{4}.*)*/, :process_code),
+ Tuple.new(/\n*^>\s+.*(\n>\s+.*)*$/, :process_blockquotes),
+ Tuple.new(/(\n*)^\d\.\s.*(\n\d\..*)*$/, :process_ordered_lists),
+ Tuple.new(/\n*^\*.*(\n\*.*)*$/, :process_unordered_lists),
+ Tuple.new(/(\n{2,})(?!<p>)/, '</p>\1<p>'),
+ Tuple.new(/<p>(\s*)<\/p>/, '\1'),
+ Tuple.new(/<p>[ ]{2,}/, '<p>'),
+ Tuple.new(/[ ]{2,}<\/p>/, '</p>'),
+ Tuple.new(/<\/p><\/p>/, '</p>'),
+ Tuple.new(/<p><pre>/, '<pre>'),
+ Tuple.new(/<\/pre><p>/, '</pre>'),
+ Tuple.new(/(<h\d>)[ ]{2,}/, '\1'),
+ Tuple.new(/[ ]{2,}(<\/h\d>)/, '\1'),
+ Tuple.new(/<pre><code>(.*)<\/code><\/pre>/m, :remove_html_from_code),
+ ]
+
+ def initialize(text)
+ @text = text
+ end
+
+ def to_html
+ text = escape_special_entries
+
+ PATTERNS.each do |tuple|
+ if (tuple.replace.is_a? String)
+ text = text.gsub(tuple.pattern, tuple.replace)
+ else
+ text = sub_with_lambda(tuple, text)
+ end
+ end
+ if !text.start_with?("<ul>") and !text.start_with?("<blockquote>")
+ text = (text.include? "\n")? text.sub(/\n/, '').reverse.sub(/\n/, '').reverse : text
+ end
+ text.strip
+ end
+
+ def to_s
+ to_html
+ end
+
+ def inspect
+ @text
+ end
+
+ private
+
+ def sub_with_lambda(tuple, text)
+ match = tuple.pattern.match(text)
+ if match
+ handler = Parser.method(tuple.replace)
+ args = match[1], match[2], match[3], match[4]
+ text = text.gsub(tuple.pattern){ |s| handler.call(s, *args )}
+ end
+ text
+ end
+
+ def escape_special_entries
+ text = (@text.start_with?(' ' * 4))? @text : @text.strip
+ text = text.gsub(/&/,'&amp;')
+ text = text.gsub(/</,'&lt;')
+ text = text.gsub(/(?!(^))>/,'&gt;')
+ text = text.gsub(/"/,'&quot;')
+ "<p>\n" + text + "\n</p>"
+ end
+end
+
+class Parser
+
+ def self.process_headers(data, first_group, second_group, third_group, fourth_group)
+ h_number = second_group.length - 1
+ "</p>#{first_group}<h#{h_number}>#{third_group}</h#{h_number}>#{fourth_group}<p>"
+ end
+
+ def self.process_code(data, first_group, *args)
+ if !data
+ return ''
+ end
+ code = data.lines("\n").map { |s| remove_empty_space(s)}.join
+ code = "</p><pre><code>" + code + "</code></pre><p>"
+ end
+
+ def self.process_blockquotes(data, *args)
+ if data
+ return '</p><blockquote><p>' + data.strip.gsub(/> */, '') + '</p></blockquote><p>'
+ end
+ ''
+ end
+
+ def self.process_ordered_lists(data, first_group, *args)
+ if data
+ beginning = "</p>#{first_group}<ol>\n"
+ return beginning + data.strip.gsub(/\d\.\s(.*)/, ' <li>\1</li>') + "\n</ol><p>"
+ end
+ ''
+ end
+
+ def self.process_unordered_lists(data, *args)
+ if data
+ return "</p>\n<ul>\n" + data.strip.gsub(/\*\s(.*)/, ' <li>\1</li>') + "\n</ul><p>"
+ end
+ ''
+ end
+
+ def self.process_em(data, *args)
+ if ((data.include? '<strong>' and data.include? '</strong>') or
+ (!data.include? '<strong>' and !data.include? '</strong>'))
+ return '<em>' + data[1..data.length-2] + '</em>'
+ end
+ data
+ end
+
+ def self.process_strong(data, *args)
+ if ((data.include? '<em>' and data.include? '</em>') or
+ (!data.include? '<em>' and !data.include? '</em>'))
+ return '<strong>' + data[2..data.length-3] + '</strong>'
+ end
+ data
+ end
+
+ def self.remove_html_from_code(data, *args)
+ text = data.gsub(/<p>|<\/p>/, '')
+ text = text.gsub(/<em>|<\/em>/, '_')
+ text = text.gsub(/<strong>|<\/strong>/, '**')
+ text = text.gsub(/<h1>/, '# ')
+ text = text.gsub(/<\/h1>/, '')
+ text
+ end
+
+ private
+
+ def self.remove_empty_space(text)
+ if text == "\n"
+ return text
+ end
+ if text and text[4..text.length]
+ return text[4..text.length]
+ end
+ ''
+ end
+end