Мая обнови решението на 23.11.2011 16:20 (преди почти 13 години)
+class BlockquotesFormatter
+ def initialize(text) #v text sa mahnati nenujnite whitespaces
+ @input = text
+ end
+
+ def to_html
+ lines = []
+ @input.each_line {|line| lines << line}
+ indexes = (0..lines.size-1).find_all {|i| /^\> / =~ lines[i]}
+ parts = change_blockquotes indexes, lines
+ n = lines.size - 1
+ (0..n).each {|i| parts[i] = lines[i].sub("> ", '') unless indexes.include? i}
+ @formatted = parts.join
+ end
+
+ private
+
+ def change_blockquotes(indexes, lines)
+ parts = Array.new(@input.length / 2, '')
+ beginings = indexes.select {|i| not indexes.include? i-1}
+ beginings.each do |i|
+ part = evaluate_part indexes, lines, i
+ parts = add_tags parts, part, i
+ end
+
+ parts
+ end
+
+ def evaluate_part(indexes, lines, i)
+ part = [lines[i].sub("> ", "")]
+ while indexes.include? i+1
+ part << lines[i+1].sub("> ", "")
+ i += 1
+ end
+
+ part
+ end
+
+ def add_tags(parts, part, i)
+ part = ParagraphFormatter.new(part.join).to_html
+ if /\n\Z/ =~ part
+ parts[i] = "<blockquote>" + part.chop + "</blockquote>\n"
+ elsif part == ''
+ parts[i] = part
+ else
+ parts[i] = "<blockquote>" + part + "</blockquote>"
+ end
+
+ parts
+ end
+end
+
+class SpecialSymbolsFormatter
+ def initialize(text)
+ @input = text
+ end
+
+ def to_html
+ @input = @input.gsub("&", "&")
+ @input = @input.gsub("<", "<")
+ @input = change_gt @input
+ @input = @input.gsub("\"", """)
+ @input
+ end
+
+ private
+
+ def change_gt(text)
+ if /^(.+)\>/ =~ text
+ text = text.sub(/^(.+)\>/, $1+">")
+ text = change_gt text
+ end
+ text
+ end
+end
+
+class ShriftFormatter
+ def initialize(line)
+ @input = line
+ end
+
+ def to_html
+ change if /\*\*(.+)\*\*/ =~ @input or /_(.+)_/ =~ @input
+ @input
+ end
+
+ private
+
+ def change
+ /((\*\*)|(_))([^$]+?)\1/ =~ @input
+ if $1 == "**"
+ @input = @input.sub("**", "<strong>").sub("**", "</strong>")
+ change if change_needed?
+ elsif $1 == "_"
+ @input = @input.sub("_", "<em>").sub("_", "</em>")
+ change if change_needed?
+ end
+ end
+
+ def change_needed?
+ if /_(.+)_/ =~ @input and not /\*\*(.*)((\<\/strong\>)|(\<\/em\>))(.*)\*\*/ =~ @input
+ true
+ elsif /\*\*(.+)\*\*/ =~ @input and
+ not /\*\*(.*)((\<\/strong\>)|(\<\/em\>))(.*)\*\*/ =~ @input
+ true
+ else
+ false
+ end
+ end
+end
+
+class UlFormatter
+ def initialize(text)
+ @input = text
+ end
+
+ def to_html
+ lines = []
+ @input.each_line {|line| lines << line}
+ indexes = (0..lines.size-1).find_all {|i| /\A\* / =~ lines[i]}
+ indexes.each {|i| lines = change indexes, lines, i}
+ @formatted = lines.join
+ end
+
+ private
+
+ def change(indexes, lines, i)
+ lines[i] = lines[i].sub(/\A\* /, " <li>").chop + "</li>\n" if /\n/ =~ lines[i]
+ lines[i] = lines[i].sub(/\A\* /, " <li>") + "</li>\n" unless /\n/ =~ lines[i]
+ if (i > 0 and not indexes.include? i-1) or i == 0
+ lines[i] = "<ul>\n" + lines[i]
+ end
+ if (i < lines.size-1 and not /\A\* / =~ lines[i+1]) or i == lines.size-1
+ lines[i] = lines[i] + "</ul>\n" unless i == lines.size-1 and not /\n\Z/ =~ @input
+ lines[i] = lines[i] + "</ul>" if i == lines.size-1 and not /\n\Z/ =~ @input
+ end
+ lines
+ end
+end
+
+class OlFormatter
+ def initialize(text)
+ @input = text
+ end
+
+ def to_html
+ lines = []
+ @input.each_line {|line| lines << line}
+ indexes = (0..lines.size-1).find_all {|i| /\A\d\. / =~ lines[i]}
+ indexes.each {|i| lines = change indexes, lines, i}
+ @formatted = lines.join
+ end
+
+ private
+
+ def change(indexes, lines, i)
+ lines[i] = lines[i].sub(/\A\d\. /, " <li>").chop + "</li>\n" if /\n/ =~ lines[i]
+ lines[i] = lines[i].sub(/\A\d\. /, " <li>") + "</li>\n" unless /\n/ =~ lines[i]
+ if (i > 0 and not indexes.include? i-1) or i == 0
+ lines[i] = "<ol>\n" + lines[i]
+ end
+ if (i < lines.size-1 and not /\A\d\. / =~ lines[i+1]) or i == lines.size-1
+ lines[i] = lines[i] + "</ol>\n" unless i == lines.size-1 and not /\n\Z/ =~ @input
+ lines[i] = lines[i] + "</ol>" if i == lines.size-1 and not /\n\Z/ =~ @input
+ end
+
+ lines
+ end
+end
+
+class LinksFormatter
+ def initialize(line)
+ @input = line
+ end
+
+ def to_html
+ if /\[([^$\]]*)\]\(([^$\)]*)\)/ =~ @input
+ @input = @input.sub("[" + $1 + "](" + $2 + ")",
+ "<a href=\"" + $2 + "\">" + $1 + "</a>")
+ end
+
+ @input
+ end
+end
+
+class CodeFormatter
+ def initialize(text)
+ @input = text
+ end
+
+ def to_html()
+ lines = []
+ @input.each_line {|line| lines << line}
+ indexes = (0..lines.size-1).find_all {|j| /^ / =~ lines[j]}
+ indexes.each {|i| lines = change indexes, lines, i}
+ lines = lines.map {|line| line.sub(' ', '')}
+ @formatted = lines.join
+ end
+
+ private
+
+ def change(indexes, lines, i)
+ lines[0] = lines[0].sub(" ", "<pre><code>") if i == 0
+ if i > 0 and not indexes.include? (i-2)
+ lines[i] = "<pre><code>" + lines[i]
+ end
+ if (i < lines.size-1 and not /^ / =~ lines[i+2]) or i == lines.size-1
+ lines[i] = lines[i] + "</code></pre>" unless /\n/ =~ lines[i]
+ lines[i] = lines[i].chop + "</code></pre>" if /\n/ =~ lines[i]
+ end
+ lines[i] = lines[i].chop if /\n/ =~ lines[i]
+
+ lines
+ end
+end
+
+class HeaderFormatter
+ def initialize(line) #line e red BEZ simvola za nov red nakraq
+ @input, @formatted = line, line
+ end
+
+ def to_html()
+ if /\A([#]{1,4} )([\s]*)([\S]+)/ =~ @input
+ @input = @input.sub($2, "")
+ /\A([#]{1,4} )([\s]*)([\S]+)/ =~ @input
+ exp = $1
+ @formatted = @input.sub(exp, "<h" + exp.count('#').to_s + ">")
+ @formatted += "</h" + exp.count('#').to_s + ">"
+ end
+
+ @formatted
+ end
+end
+
+class ParagraphFormatter
+ def initialize(text)
+ @input = text
+ end
+
+ def to_html()
+ lines = []
+ @input.each_line {|line| lines << line}
+ indexes = (0..lines.size-1).find_all {|i| in_paragraph?(lines, i)}
+ indexes.each {|i| lines = change indexes, lines, i}
+ @formatted = lines.join
+ end
+
+ private
+
+ def change(indexes, lines, i)
+ if i == 0 or (i > 0 and not indexes.include?(i-1))
+ lines[i] = "<p>" + lines[i].strip + "\n"
+ end
+ if i == lines.size-1 or (i < lines.size-1 and not indexes.include?(i+1))
+ lines[i] = lines[i].strip + "</p>\n" if /\n/ =~ lines[i]
+ lines[i] = lines[i].strip + "</p>" unless /\n/ =~ lines[i]
+ end
+
+ lines
+ end
+
+ def in_paragraph?(lines, i)
+ return false if /\A\s*\Z/ =~ lines[i] #ako e prazen red
+ return false if /\A / =~ lines[i] #ako e v blok s kod
+ return false if /\A *\>/ =~ lines[i] #ako e v citat
+ return false if /\A *([#]{1,4}) ([\s]*)([\S]+)/ =~ lines[i] #ako zaglavie
+ return false if /\A *\* ([\S]+)/ =~ lines[i] #ako e spisyk
+ return false if /\A *\d\. ([\S]+)/ =~ lines[i] #ako e spisyk
+ true
+ end
+end
+
+class Formatter
+ def initialize(input)
+ @input, @formatted = input, input
+ end
+
+ def to_html()
+ @formatted = SpecialSymbolsFormatter.new(@formatted).to_html
+ @formatted = ParagraphFormatter.new(@formatted).to_html
+ @formatted = BlockquotesFormatter.new(@formatted).to_html
+ line_formatting
+ @formatted = CodeFormatter.new(@formatted).to_html
+ @formatted = OlFormatter.new(@formatted).to_html
+ @formatted = UlFormatter.new(@formatted).to_html
+ @formatted = @formatted.strip
+ end
+
+ def to_s()
+ to_html()
+ end
+
+ def inspect()
+ @input
+ end
+
+ private
+
+ def line_formatting
+ lines = []
+ @formatted.each_line do |line|
+ unless /^ / =~ line
+ line = LinksFormatter.new(line.strip).to_html
+ line = HeaderFormatter.new(line).to_html
+ line = ShriftFormatter.new(line).to_html
+ end
+ lines << line
+ end
+ @formatted = lines.join("\n")
+ end
+end