diff --git a/bbsandbox.rb b/bbsandbox.rb index f1cdcbe..ee213f5 100644 --- a/bbsandbox.rb +++ b/bbsandbox.rb @@ -3,8 +3,9 @@ require 'slim' require 'digest/sha1' require 'bb-ruby' require 'ruby-bbcode' +require './bristlecode.rb' -@@engines = ['bb-ruby', 'ruby-bbcode', 'raw'] +@@engines = ['bb-ruby', 'ruby-bbcode', 'bristle', 'raw'] get '/' do @posts = list_posts @@ -35,6 +36,8 @@ def exec_bbcode(engine, body) BBRuby.to_html body when "ruby-bbcode" RubyBBCode.to_html body + when "bristle" + Bristlecode::to_html body when "raw" body else diff --git a/bristlecode.rb b/bristlecode.rb new file mode 100644 index 0000000..c668e5e --- /dev/null +++ b/bristlecode.rb @@ -0,0 +1,109 @@ +require 'parslet' + +module Bristlecode + + def Bristlecode.to_html(text) + parser = Bristlecode::Parser.new + parse_tree = parser.parse(text) + tree = Bristlecode::Transform.new.apply(parse_tree) + tree.to_html + end + + class Parser < Parslet::Parser + rule(:space) { match('\s').repeat(1) } + rule(:space?) { space.maybe } + + rule(:bold_open) { + (str('[b]') | str('[B]')) + } + rule(:bold_close) { + (str('[/b]') | str('[/B]')) + } + rule(:bold) { + (bold_open >> children.as(:bold) >> bold_close) + } + + rule(:italic_open) { + (str('[i]') | str('[I]')) + } + rule(:italic_close) { + (str('[/i]') | str('[/I]')) + } + rule(:italic) { + (italic_open >> children.as(:italic) >> italic_close) + } + + rule(:eof) { any.absent? } + rule(:tag) { (bold | italic) } + rule(:elem) { text | tag } + rule(:tag_open) { bold_open | italic_open } + rule(:tag_close) { bold_close | italic_close } + rule(:tag_delim) { tag_open | tag_close } + + rule(:text) { (tag_delim.absent? >> any).repeat(1).as(:text) } + rule(:children) { + space? >> elem.repeat(1) + } + rule(:doc) { + space? >> elem.repeat(1).as(:doc) + } + root(:doc) + end + + class Transform < Parslet::Transform + rule(bold: sequence(:children)) { Bold.new(children) } + rule(italic: sequence(:children)) { Italic.new(children) } + rule(text: simple(:text)) { Text.new(text) } + rule(doc: subtree(:doc)) { Doc.new(doc) } + end + + class Doc + def initialize(children) + @children = children + end + + def to_html + s = StringIO.new + @children.each{|child| s << child.to_html } + s.string + end + end + + class Text + def initialize(text) + @text = text + end + + def to_html + @text + end + end + + class Bold + def initialize(children) + @children = children + end + + def to_html + s = StringIO.new + s << "" + @children.each{|child| s << child.to_html } + s << "" + s.string + end + end + + class Italic + def initialize(children) + @children = children + end + + def to_html + s = StringIO.new + s << "" + @children.each{|child| s << child.to_html } + s << "" + s.string + end + end +end