Решение на Пета задача от Пламен Стоев

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

Към профила на Пламен Стоев

Резултати

  • 8 точки от тестове
  • 0 бонус точки
  • 8 точки общо
  • 57 успешни тест(а)
  • 0 неуспешни тест(а)

Код

# -*- coding: utf-8 -*-
module ContentParser
REGEXPS = {
a: /\[([^\]]+)\]\(([^\)]+)\)/,
em: /_(?<text>.*?)_/,
strong: /\*\*(?<text>.*?)\*\*/,
a_split: /(\[[^\]]+\]\([^\)]+\))/,
em_strong: /_.*?_|\*\*.*?\*\*/,
}
ENTITIES = {
'&' => '&amp;',
'<' => '&lt;',
'>' => '&gt;',
'"' => '&quot;',
}
def self.sanitize(text)
text.gsub(/(&|<|>|")/) { |entity| ENTITIES[entity] }
end
class EmStrongParser
def initialize(raw_text)
@head, @text, @tail = raw_text.partition(REGEXPS[:em_strong])
@tail = EmStrongParser.new(@tail).render if @tail != ""
end
def render
@head + wrap + @tail
end
def wrap
result = @text.gsub(REGEXPS[:em], '<em>\k<text></em>')
result.gsub(REGEXPS[:strong], '<strong>\k<text></strong>')
end
end
class LinkParser
def initialize(raw_text)
@text, @href = REGEXPS[:a].match(raw_text).captures
end
def render
"<a href=\"#@href\">#{ EmStrongParser.new(@text).render }</a>"
end
end
def self.parse(raw_text)
strings = sanitize(raw_text).split(REGEXPS[:a_split])
parsers = strings.map do |string|
case string
when REGEXPS[:a] then LinkParser.new(string)
else EmStrongParser.new(string)
end
end
parsers.map { |parser| parser.render }.join
end
end
module StructureParser
class ParagraphParser
def initialize(chunk_data)
chunks = chunk_data.chunk { |line| line.strip != '' }
@paragraphs = chunks.map { |status, array| array }
end
def render
joined_paragraphs = @paragraphs.map do |paragraph|
(paragraph.first != "\n") ? paragraph.join : ""
end
joined_paragraphs.map { |paragraph| wrap(paragraph) }.join("\n")
end
def wrap(p)
(p.strip != "") ? "<p>#{ ContentParser.parse(p.strip) }</p>" : ""
end
end
class HeaderParser
def initialize(chunk_data, h_number)
@h_number = h_number
@header = chunk_data.first.sub(Regexp.new("^\s*#{ '#' * h_number }\s+"), '')
end
def render
"<h#@h_number>#{ ContentParser.parse(@header.strip) }</h#@h_number>"
end
end
class H1Parser < HeaderParser
def initialize(chunk_data)
super(chunk_data, 1)
end
end
class H2Parser < HeaderParser
def initialize(chunk_data)
super(chunk_data, 2)
end
end
class H3Parser < HeaderParser
def initialize(chunk_data)
super(chunk_data, 3)
end
end
class H4Parser < HeaderParser
def initialize(chunk_data)
super(chunk_data, 4)
end
end
class CodeParser
def initialize(chunk_data)
@code = chunk_data.map { |line| line.sub(/^ /, '') }.join
end
def render
"<pre><code>#{ ContentParser.sanitize(@code.chomp("\n")) }</code></pre>"
end
end
class BlockQuoteParser
def initialize(chunk_data)
quote_prefix = chunk_data.first[/^>\s+/]
@quote = chunk_data.map { |line| line.sub(quote_prefix, '') }.join
end
def render
"<blockquote>#{ StructureParser.parse(@quote) }</blockquote>"
end
end
class ListParser
def initialize(chunk_data, label, rgxp)
@items = chunk_data.map { |item| item.sub(rgxp, '') }
@label = label
end
def render
items = @items.map { |item| wrap(item.strip) }.join("\n")
"<#@label>\n#{ items }\n</#@label>"
end
def wrap(li)
(li != '') ? " <li>#{ ContentParser.parse(li) }</li>" : ""
end
end
class UListParser < ListParser
def initialize(chunk_data)
super(chunk_data, 'ul', /^\s*\*\s+/)
end
end
class OListParser < ListParser
def initialize(chunk_data)
super(chunk_data, 'ol', /^\s*(\d+)\.\s+/)
end
end
REGEXPS = {
bquote: /^>\s+.*$/,
code: /^ .*$/,
ulist: /^\s*\*\s+.*$/,
olist: /^\s*(\d)+\.\s+.*$/,
h1: /^\s*#\s+\S.*$/,
h2: /^\s*##\s+\S.*$/,
h3: /^\s*###\s+\S.*$/,
h4: /^\s*####\s+\S.*$/,
}
PARSERS = {
p: ParagraphParser,
bquote: BlockQuoteParser,
code: CodeParser,
ulist: UListParser,
olist: OListParser,
h1: H1Parser,
h2: H2Parser,
h3: H3Parser,
h4: H4Parser,
}
def self.parse(raw_text)
lines = raw_text.lines.chunk do |line|
REGEXPS.keys.find { |code| line =~ REGEXPS[code] } or :p
end
parsed = lines.map { |code, chunk| PARSERS[code].new(chunk) }
parsed.map { |p| p.render }.join("\n").strip
end
end
class Formatter
attr_reader :to_html, :inspect
alias :to_s :to_html
def initialize(raw_text)
@inspect = raw_text
@to_html = StructureParser.parse raw_text
end
end

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

.........................................................

Finished in 0.61798 seconds
57 examples, 0 failures

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

Пламен обнови решението на 21.11.2011 18:14 (преди над 12 години)

+# -*- coding: utf-8 -*-
+
+module ContentParser
+ REGEXPS = {
+ a: /\[([^\]]+)\]\(([^\)]+)\)/,
+ em: /_(?<text>.*?)_/,
+ strong: /\*\*(?<text>.*?)\*\*/,
+ a_split: /(\[[^\]]+\]\([^\)]+\))/,
+ em_strong: /_.*?_|\*\*.*?\*\*/,
+ }
+
+ ENTITIES = {
+ '&' => '&amp;',
+ '<' => '&lt;',
+ '>' => '&gt;',
+ '"' => '&quot;',
+ }
+
+ def self.sanitize(text)
+ text.gsub(/(&|<|>|")/) { |entity| ENTITIES[entity] }
+ end
+
+ class EmStrongParser
+ def initialize(raw_text)
+ @head, @text, @tail = raw_text.partition(REGEXPS[:em_strong])
+ @tail = EmStrongParser.new(@tail).render if @tail != ""
+ end
+
+ def render
+ @head + wrap + @tail
+ end
+
+ def wrap
+ result = @text.gsub(REGEXPS[:em], '<em>\k<text></em>')
+
+ result.gsub(REGEXPS[:strong], '<strong>\k<text></strong>')
+ end
+ end
+
+ class LinkParser
+ def initialize(raw_text)
+ @text, @href = REGEXPS[:a].match(raw_text).captures
+ end
+
+ def render
+ "<a href=\"#@href\">#{ EmStrongParser.new(@text).render }</a>"
+ end
+ end
+
+ def self.parse(raw_text)
+ strings = sanitize(raw_text).split(REGEXPS[:a_split])
+
+ parsers = strings.map do |string|
+ case string
+ when REGEXPS[:a] then LinkParser.new(string)
+ else EmStrongParser.new(string)
+ end
+ end
+
+ parsers.map { |parser| parser.render }.join
+ end
+end
+
+module StructureParser
+ class ParagraphParser
+ def initialize(chunk_data)
+ chunks = chunk_data.chunk { |line| line.strip != '' }
+ @paragraphs = chunks.map { |status, array| array }
+ end
+
+ def render
+ joined_paragraphs = @paragraphs.map do |paragraph|
+ (paragraph.first != "\n") ? paragraph.join : ""
+ end
+
+ joined_paragraphs.map { |paragraph| wrap(paragraph) }.join("\n")
+ end
+
+ def wrap(p)
+ (p.strip != "") ? "<p>#{ ContentParser.parse(p.strip) }</p>" : ""
+ end
+ end
+
+ class HeaderParser
+ def initialize(chunk_data, h_number)
+ @h_number = h_number
+ @header = chunk_data.first.sub(Regexp.new("^\s*#{ '#' * h_number }\s+"), '')
+ end
+
+ def render
+ "<h#@h_number>#{ ContentParser.parse(@header.strip) }</h#@h_number>"
+ end
+ end
+
+ class H1Parser < HeaderParser
+ def initialize(chunk_data)
+ super(chunk_data, 1)
+ end
+ end
+
+ class H2Parser < HeaderParser
+ def initialize(chunk_data)
+ super(chunk_data, 2)
+ end
+ end
+
+ class H3Parser < HeaderParser
+ def initialize(chunk_data)
+ super(chunk_data, 3)
+ end
+ end
+
+ class H4Parser < HeaderParser
+ def initialize(chunk_data)
+ super(chunk_data, 4)
+ end
+ end
+
+ class CodeParser
+ def initialize(chunk_data)
+ @code = chunk_data.map { |line| line.sub(/^ /, '') }.join
+ end
+
+ def render
+ "<pre><code>#{ ContentParser.sanitize(@code.chomp("\n")) }</code></pre>"
+ end
+ end
+
+ class BlockQuoteParser
+ def initialize(chunk_data)
+ quote_prefix = chunk_data.first[/^>\s+/]
+ @quote = chunk_data.map { |line| line.sub(quote_prefix, '') }.join
+ end
+
+ def render
+ "<blockquote>#{ StructureParser.parse(@quote) }</blockquote>"
+ end
+ end
+
+ class ListParser
+ def initialize(chunk_data, label, rgxp)
+ @items = chunk_data.map { |item| item.sub(rgxp, '') }
+ @label = label
+ end
+
+ def render
+ items = @items.map { |item| wrap(item.strip) }.join("\n")
+
+ "<#@label>\n#{ items }\n</#@label>"
+ end
+
+ def wrap(li)
+ (li != '') ? " <li>#{ ContentParser.parse(li) }</li>" : ""
+ end
+ end
+
+ class UListParser < ListParser
+ def initialize(chunk_data)
+ super(chunk_data, 'ul', /^\s*\*\s+/)
+ end
+ end
+
+ class OListParser < ListParser
+ def initialize(chunk_data)
+ super(chunk_data, 'ol', /^\s*(\d+)\.\s+/)
+ end
+ end
+
+ REGEXPS = {
+ bquote: /^>\s+.*$/,
+ code: /^ .*$/,
+ ulist: /^\s*\*\s+.*$/,
+ olist: /^\s*(\d)+\.\s+.*$/,
+ h1: /^\s*#\s+\S.*$/,
+ h2: /^\s*##\s+\S.*$/,
+ h3: /^\s*###\s+\S.*$/,
+ h4: /^\s*####\s+\S.*$/,
+ }
+
+ PARSERS = {
+ p: ParagraphParser,
+ bquote: BlockQuoteParser,
+ code: CodeParser,
+ ulist: UListParser,
+ olist: OListParser,
+ h1: H1Parser,
+ h2: H2Parser,
+ h3: H3Parser,
+ h4: H4Parser,
+ }
+
+ def self.parse(raw_text)
+ lines = raw_text.lines.chunk do |line|
+ REGEXPS.keys.find { |code| line =~ REGEXPS[code] } or :p
+ end
+
+ parsed = lines.map { |code, chunk| PARSERS[code].new(chunk) }
+
+ parsed.map { |p| p.render }.join("\n").strip
+ end
+end
+
+class Formatter
+ attr_reader :to_html, :inspect
+ alias :to_s :to_html
+
+ def initialize(raw_text)
+ @inspect = raw_text
+ @to_html = StructureParser.parse raw_text
+ end
+end