Решение на Пета задача от Ангел Лазаров

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

Към профила на Ангел Лазаров

Резултати

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

Код

module Parser
def self.parse(text)
parser_classes = [SpecialChars, Paragraph, Header, Code, List, BlockQuote]
parser_classes.each do |parser_class|
text = (parser_class.new text).to_html
end
text.strip
end
#inner content parsing is not used in code blocks, only special chars replacing
def self.inner_parse(content)
[ItalicBold, Links].each do |inner_parser_class|
content = (inner_parser_class.new content).to_html
end
content
end
class Header
REGEX = /^[ \t]{,3}(\#{1,4})(?:[ \t]+)(\S.+)$/u
def initialize(text)
@text = text
end
def to_html
@text.gsub(REGEX) do
tag = "h#{$1.size}"
"<%s>%s</%s>" % [tag, Parser.inner_parse($2.strip), tag]
end
end
def self.identifization_pattern
'[ \t]{,3}\#{1,4}[ \t]+\S'
end
end
class Links
REGEX = /\[(?<text>[^\]\[\n]+)\]\((?<href>[^\)\n]+)\)/u
def initialize(text)
@text = text
end
def to_html
@text.gsub REGEX, '<a href="\k<href>">\k<text></a>'
end
end
class Code
REGEX = /^(([ \t]{4}.*\n?)+)/u
def initialize(text)
@text = text
end
def to_html
@text.gsub(REGEX) do |match|
"<pre><code>" + format(match).chomp + "</code></pre>\n"
end
end
def format(code_block)
''.tap { |output| code_block.lines { |line| output << line[4..-1] } }
end
def self.identifization_pattern
'[ \t]{4,}'
end
end
class List
REGEX = /^((([ \t]{,3}\*|\d+\.)[ \t]+(.+)\n?)+)/u
TAGS = {"*" => 'ul'}
def initialize(text)
@text = text
end
def to_html
@text.gsub(REGEX) do |match|
tag = TAGS.fetch($3, "ol")
"<%s>\n%s</%s>\n" % [tag, format(match), tag]
end
end
def format(list_items)
formatted = ""
list_items.lines do |item|
item = Parser.inner_parse(item)
formatted << item.sub(/(([ \t]{,3}\*|\d+\.)[ \t]+)/, " <li>").chomp + "</li>\n"
end
formatted
end
def self.identifization_pattern
'(?:[ \t]{,3}\*|\d+\.)[ \t]+'
end
end
class ItalicBold
REGEX = /(\*{2}|_)([^\/\n]+?)\1/u
TAGS = {'**' => 'strong', '_' => 'em'}
def initialize(text)
@text = text
end
def to_html
output_text = @text
while output_text =~ REGEX
output_text = output_text.sub REGEX, '<%s>\2</%s>' % ([TAGS[$1]] * 2)
end
output_text
end
end
class SpecialChars
REGEX = /((?!^)>|<|&|")/
ESCAPES = {'&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;'}
def initialize(text)
@text = text
end
def to_html
@text.gsub(REGEX) { ESCAPES[$1] }
end
end
class BlockQuote
REGEX = /^(([ \t]{,3}>[ \t]+)(.*?)(\n|$))+/u
def initialize(text)
@text = text
end
def to_html
tag = 'blockquote'
@text.gsub(REGEX) do |match|
content = Paragraph.new(format(match).chomp).to_html.chomp
"<%s>%s</%s>\n" % [tag, content, tag]
end
end
def format(quote_block)
formatted = ""
quote_block.lines do |line|
formatted << line.sub(/[ \t]{,3}>[ \t]+/, "").rstrip + "\n"
end
formatted
end
def self.identifization_pattern
'[ \t]{,3}>[ \t]+'
end
end
class Paragraph
HEADER = Header.identifization_pattern
CODE = Code.identifization_pattern
BLOCKQUOTE = BlockQuote.identifization_pattern
LIST = List.identifization_pattern
REGEX = /(^(?!#{[HEADER, CODE, BLOCKQUOTE, LIST].join('|')})(.+)(\n|$))+/u
def initialize(text)
@text = text
end
def to_html
@text.gsub(REGEX) { |match| "<p>" + Parser.inner_parse(match.strip) + "</p>\n" }
end
end
end
class Formatter
def initialize(text)
@text = text
end
def to_html
Parser.parse(@text)
end
def to_s
to_html
end
def inspect
@text
end
end

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

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

Finished in 0.60827 seconds
57 examples, 0 failures

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

Ангел обнови решението на 23.11.2011 18:55 (преди над 12 години)

+module Parser
+ def self.parse(text)
+ parser_classes = [SpecialChars, Paragraph, Header, Code, List, BlockQuote]
+ parser_classes.each do |parser_class|
+ text = (parser_class.new text).to_html
+ end
+ text.strip
+ end
+
+ #inner content parsing is not used in code blocks, only special chars replacing
+ def self.inner_parse(content)
+ [ItalicBold, Links].each do |inner_parser_class|
+ content = (inner_parser_class.new content).to_html
+ end
+ content
+ end
+
+ class Header
+ REGEX = /^[ \t]{,3}(\#{1,4})(?:[ \t]+)(\S.+)$/u
+
+ def initialize(text)
+ @text = text
+ end
+
+ def to_html
+ @text.gsub(REGEX) do
+ tag = "h#{$1.size}"
+ "<%s>%s</%s>" % [tag, Parser.inner_parse($2.strip), tag]
+ end
+ end
+
+ def self.identifization_pattern
+ '[ \t]{,3}\#{1,4}[ \t]+\S'
+ end
+ end
+
+ class Links
+ REGEX = /\[(?<text>[^\]\[\n]+)\]\((?<href>[^\)\n]+)\)/u
+
+ def initialize(text)
+ @text = text
+ end
+
+ def to_html
+ @text.gsub REGEX, '<a href="\k<href>">\k<text></a>'
+ end
+ end
+
+ class Code
+ REGEX = /^(([ \t]{4}.*\n?)+)/u
+
+ def initialize(text)
+ @text = text
+ end
+
+ def to_html
+ @text.gsub(REGEX) do |match|
+ "<pre><code>" + format(match).chomp + "</code></pre>\n"
+ end
+ end
+
+ def format(code_block)
+ ''.tap { |output| code_block.lines { |line| output << line[4..-1] } }
+ end
+
+ def self.identifization_pattern
+ '[ \t]{4,}'
+ end
+ end
+
+ class List
+ REGEX = /^((([ \t]{,3}\*|\d+\.)[ \t]+(.+)\n?)+)/u
+ TAGS = {"*" => 'ul'}
+
+ def initialize(text)
+ @text = text
+ end
+
+ def to_html
+ @text.gsub(REGEX) do |match|
+ tag = TAGS.fetch($3, "ol")
+ "<%s>\n%s</%s>\n" % [tag, format(match), tag]
+ end
+ end
+
+ def format(list_items)
+ formatted = ""
+ list_items.lines do |item|
+ item = Parser.inner_parse(item)
+ formatted << item.sub(/(([ \t]{,3}\*|\d+\.)[ \t]+)/, " <li>").chomp + "</li>\n"
+ end
+ formatted
+ end
+
+ def self.identifization_pattern
+ '(?:[ \t]{,3}\*|\d+\.)[ \t]+'
+ end
+ end
+
+ class ItalicBold
+ REGEX = /(\*{2}|_)([^\/\n]+?)\1/u
+ TAGS = {'**' => 'strong', '_' => 'em'}
+
+ def initialize(text)
+ @text = text
+ end
+
+ def to_html
+ output_text = @text
+ while output_text =~ REGEX
+ output_text = output_text.sub REGEX, '<%s>\2</%s>' % ([TAGS[$1]] * 2)
+ end
+ output_text
+ end
+ end
+
+ class SpecialChars
+ REGEX = /((?!^)>|<|&|")/
+ ESCAPES = {'&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;'}
+
+ def initialize(text)
+ @text = text
+ end
+
+ def to_html
+ @text.gsub(REGEX) { ESCAPES[$1] }
+ end
+ end
+
+ class BlockQuote
+ REGEX = /^(([ \t]{,3}>[ \t]+)(.*?)(\n|$))+/u
+
+ def initialize(text)
+ @text = text
+ end
+
+ def to_html
+ tag = 'blockquote'
+ @text.gsub(REGEX) do |match|
+ content = Paragraph.new(format(match).chomp).to_html.chomp
+ "<%s>%s</%s>\n" % [tag, content, tag]
+ end
+ end
+
+ def format(quote_block)
+ formatted = ""
+ quote_block.lines do |line|
+ formatted << line.sub(/[ \t]{,3}>[ \t]+/, "").rstrip + "\n"
+ end
+ formatted
+ end
+
+ def self.identifization_pattern
+ '[ \t]{,3}>[ \t]+'
+ end
+ end
+
+ class Paragraph
+ HEADER = Header.identifization_pattern
+ CODE = Code.identifization_pattern
+ BLOCKQUOTE = BlockQuote.identifization_pattern
+ LIST = List.identifization_pattern
+
+ REGEX = /(^(?!#{[HEADER, CODE, BLOCKQUOTE, LIST].join('|')})(.+)(\n|$))+/u
+
+ def initialize(text)
+ @text = text
+ end
+
+ def to_html
+ @text.gsub(REGEX) { |match| "<p>" + Parser.inner_parse(match.strip) + "</p>\n" }
+ end
+ end
+end
+
+class Formatter
+ def initialize(text)
+ @text = text
+ end
+
+ def to_html
+ Parser.parse(@text)
+ end
+
+ def to_s
+ to_html
+ end
+
+ def inspect
+ @text
+ end
+end