simple url handling

parslet
Jordan Orelli 9 years ago
parent 59d0e25829
commit df3b9cb7d0

@ -6,3 +6,6 @@ gem "slim"
gem "bb-ruby" gem "bb-ruby"
gem "ruby-bbcode" gem "ruby-bbcode"
gem "rspec", "~> 3.0" gem "rspec", "~> 3.0"
gem "parslet"
gem "guard"
gem "guard-rspec"

@ -8,15 +8,45 @@ GEM
thread_safe (~> 0.3, >= 0.3.4) thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1) tzinfo (~> 1.1)
bb-ruby (1.1.0) bb-ruby (1.1.0)
blankslate (3.1.3)
celluloid (0.15.2)
timers (~> 1.1.0)
coderay (1.1.0)
daemons (1.2.3) daemons (1.2.3)
diff-lcs (1.2.5) diff-lcs (1.2.5)
eventmachine (1.0.8) eventmachine (1.0.8)
ffi (1.9.3)
formatador (0.2.5)
guard (2.6.1)
formatador (>= 0.2.4)
listen (~> 2.7)
lumberjack (~> 1.0)
pry (>= 0.9.12)
thor (>= 0.18.1)
guard-rspec (4.3.1)
guard (~> 2.1)
rspec (>= 2.14, < 4.0)
i18n (0.7.0) i18n (0.7.0)
json (1.8.3) json (1.8.3)
listen (2.7.9)
celluloid (>= 0.15.2)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
lumberjack (1.0.9)
method_source (0.8.2)
minitest (5.8.2) minitest (5.8.2)
parslet (1.7.1)
blankslate (>= 2.0, <= 4.0)
pry (0.10.0)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
rack (1.6.4) rack (1.6.4)
rack-protection (1.5.3) rack-protection (1.5.3)
rack rack
rb-fsevent (0.9.4)
rb-inotify (0.9.5)
ffi (>= 0.5.0)
rspec (3.1.0) rspec (3.1.0)
rspec-core (~> 3.1.0) rspec-core (~> 3.1.0)
rspec-expectations (~> 3.1.0) rspec-expectations (~> 3.1.0)
@ -38,13 +68,16 @@ GEM
slim (3.0.6) slim (3.0.6)
temple (~> 0.7.3) temple (~> 0.7.3)
tilt (>= 1.3.3, < 2.1) tilt (>= 1.3.3, < 2.1)
slop (3.5.0)
temple (0.7.6) temple (0.7.6)
thin (1.6.4) thin (1.6.4)
daemons (~> 1.0, >= 1.0.9) daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4) eventmachine (~> 1.0, >= 1.0.4)
rack (~> 1.0) rack (~> 1.0)
thor (0.19.1)
thread_safe (0.3.5) thread_safe (0.3.5)
tilt (2.0.1) tilt (2.0.1)
timers (1.1.0)
tzinfo (1.2.2) tzinfo (1.2.2)
thread_safe (~> 0.1) thread_safe (~> 0.1)
@ -53,6 +86,9 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
bb-ruby bb-ruby
guard
guard-rspec
parslet
rspec (~> 3.0) rspec (~> 3.0)
ruby-bbcode ruby-bbcode
sinatra sinatra

@ -0,0 +1,4 @@
guard :rspec, cmd: 'bundle exec rspec' do
watch('bristlecode.rb') { "spec" }
watch(%r{^spec/.+(_spec\.rb)$}) { "spec" }
end

@ -21,14 +21,20 @@ module Bristlecode
rule(:italic_close) { str('[/i]') | str('[/I]') | eof } rule(:italic_close) { str('[/i]') | str('[/I]') | eof }
rule(:italic) { italic_open >> children.as(:italic) >> italic_close } rule(:italic) { italic_open >> children.as(:italic) >> italic_close }
rule(:url_open) { str('[url]') }
rule(:url_close) { str('[/url]') | eof }
rule(:simple_href) { (url_close.absent? >> any).repeat }
rule(:simple_url) { url_open >> simple_href.as(:href) >> url_close }
rule(:url) { simple_url.as(:url) }
rule(:eof) { any.absent? } rule(:eof) { any.absent? }
rule(:tag) { bold | italic } rule(:tag) { bold | italic | url }
rule(:elem) { text | tag } rule(:elem) { text.as(:text) | tag }
rule(:tag_open) { bold_open | italic_open } rule(:tag_open) { bold_open | italic_open | url_open }
rule(:tag_close) { bold_close | italic_close } rule(:tag_close) { bold_close | italic_close | url_close }
rule(:tag_delim) { tag_open | tag_close } rule(:tag_delim) { tag_open | tag_close }
rule(:text) { (tag_delim.absent? >> any).repeat(1).as(:text) } rule(:text) { (tag_delim.absent? >> any).repeat(1) }
rule(:children) { space? >> elem.repeat } rule(:children) { space? >> elem.repeat }
rule(:doc) { space? >> elem.repeat.as(:doc) } rule(:doc) { space? >> elem.repeat.as(:doc) }
root(:doc) root(:doc)
@ -39,55 +45,77 @@ module Bristlecode
rule(italic: sequence(:children)) { Italic.new(children) } rule(italic: sequence(:children)) { Italic.new(children) }
rule(text: simple(:text)) { Text.new(text) } rule(text: simple(:text)) { Text.new(text) }
rule(doc: subtree(:doc)) { Doc.new(doc) } rule(doc: subtree(:doc)) { Doc.new(doc) }
rule(url: subtree(:url)) { Url.new(url) }
end end
class Doc class Doc
attr_accessor :children
def initialize(children) def initialize(children)
@children = children self.children = children
end end
def to_html def to_html
s = StringIO.new s = StringIO.new
@children.each{|child| s << child.to_html } children.each{|child| s << child.to_html }
s.string s.string
end end
end end
class Text class Text
attr_accessor :text
def initialize(text) def initialize(text)
@text = text.to_str.strip self.text = text.to_str.strip
end end
def to_html def to_html
@text text
end end
end end
class Bold class Bold
attr_accessor :children
def initialize(children) def initialize(children)
@children = children self.children = children
end end
def to_html def to_html
s = StringIO.new s = StringIO.new
s << "<b>" s << "<b>"
@children.each{|child| s << child.to_html } children.each{|child| s << child.to_html }
s << "</b>" s << "</b>"
s.string s.string
end end
end end
class Italic class Italic
attr_accessor :children
def initialize(children) def initialize(children)
@children = children self.children = children
end end
def to_html def to_html
s = StringIO.new s = StringIO.new
s << "<i>" s << "<i>"
@children.each{|child| s << child.to_html } children.each{|child| s << child.to_html }
s << "</i>" s << "</i>"
s.string s.string
end end
end end
class Url
attr_accessor :href, :title
def initialize(args)
self.href = args[:href].to_str.strip
self.title = args[:title] || href
end
def to_html
"<a href=\"#{href}\">#{title}</a>"
end
end
end end

@ -45,6 +45,22 @@ module Bristlecode
expect(to_html("[b]bold")).to eq("<b>bold</b>") expect(to_html("[b]bold")).to eq("<b>bold</b>")
expect(to_html("[i]italic")).to eq("<i>italic</i>") expect(to_html("[i]italic")).to eq("<i>italic</i>")
end end
it 'can render simple links' do
input = '[url]example.com[/url]'
output = '<a href="example.com">example.com</a>'
expect(to_html(input)).to eq(output)
input = '[url] example.com [/url]'
output = '<a href="example.com">example.com</a>'
expect(to_html(input)).to eq(output)
end
it 'passes simple url contents opaquely' do
input = '[url]x[b]y[/b]z[/url]'
output = '<a href="x[b]y[/b]z">x[b]y[/b]z</a>'
expect(to_html(input)).to eq(output)
end
end end
describe Parser do describe Parser do
@ -133,5 +149,19 @@ module Bristlecode
expect(parser.italic).not_to parse('[italic]fake content[/italic]') expect(parser.italic).not_to parse('[italic]fake content[/italic]')
end end
end end
describe '#url' do
it 'can parse correct urls' do
expect(parser.url).to parse('[url]google.com[/url]')
end
it "doesn't die on elements nested in simple urls" do
expect(parser.url).to parse('[url]goog[b]le.c[/b]om[/url]')
end
it 'fails nested [url] tags' do
expect(parser.url).not_to parse('[url]x[url]y[/url]z[/url]')
end
end
end end
end end

Loading…
Cancel
Save