From df3b9cb7d0d8448dc87e2fc8421d03e1b33babdd Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Thu, 5 Nov 2015 15:59:23 -0500 Subject: [PATCH] simple url handling --- Gemfile | 3 ++ Gemfile.lock | 36 ++++++++++++++++++++++ Guardfile | 4 +++ bristlecode.rb | 54 +++++++++++++++++++++++++-------- spec/bristlecode/parser_spec.rb | 30 ++++++++++++++++++ 5 files changed, 114 insertions(+), 13 deletions(-) create mode 100644 Guardfile diff --git a/Gemfile b/Gemfile index 594c90b..d6432c8 100644 --- a/Gemfile +++ b/Gemfile @@ -6,3 +6,6 @@ gem "slim" gem "bb-ruby" gem "ruby-bbcode" gem "rspec", "~> 3.0" +gem "parslet" +gem "guard" +gem "guard-rspec" diff --git a/Gemfile.lock b/Gemfile.lock index 9244ec2..0a1c754 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,15 +8,45 @@ GEM thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) 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) diff-lcs (1.2.5) 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) 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) + 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-protection (1.5.3) rack + rb-fsevent (0.9.4) + rb-inotify (0.9.5) + ffi (>= 0.5.0) rspec (3.1.0) rspec-core (~> 3.1.0) rspec-expectations (~> 3.1.0) @@ -38,13 +68,16 @@ GEM slim (3.0.6) temple (~> 0.7.3) tilt (>= 1.3.3, < 2.1) + slop (3.5.0) temple (0.7.6) thin (1.6.4) daemons (~> 1.0, >= 1.0.9) eventmachine (~> 1.0, >= 1.0.4) rack (~> 1.0) + thor (0.19.1) thread_safe (0.3.5) tilt (2.0.1) + timers (1.1.0) tzinfo (1.2.2) thread_safe (~> 0.1) @@ -53,6 +86,9 @@ PLATFORMS DEPENDENCIES bb-ruby + guard + guard-rspec + parslet rspec (~> 3.0) ruby-bbcode sinatra diff --git a/Guardfile b/Guardfile new file mode 100644 index 0000000..e3ada70 --- /dev/null +++ b/Guardfile @@ -0,0 +1,4 @@ +guard :rspec, cmd: 'bundle exec rspec' do + watch('bristlecode.rb') { "spec" } + watch(%r{^spec/.+(_spec\.rb)$}) { "spec" } +end diff --git a/bristlecode.rb b/bristlecode.rb index 34a7b0a..b8f8a43 100644 --- a/bristlecode.rb +++ b/bristlecode.rb @@ -21,14 +21,20 @@ module Bristlecode rule(:italic_close) { str('[/i]') | str('[/I]') | eof } 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(:tag) { bold | italic } - rule(:elem) { text | tag } - rule(:tag_open) { bold_open | italic_open } - rule(:tag_close) { bold_close | italic_close } + rule(:tag) { bold | italic | url } + rule(:elem) { text.as(:text) | tag } + rule(:tag_open) { bold_open | italic_open | url_open } + rule(:tag_close) { bold_close | italic_close | url_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(:doc) { space? >> elem.repeat.as(:doc) } root(:doc) @@ -39,55 +45,77 @@ module Bristlecode rule(italic: sequence(:children)) { Italic.new(children) } rule(text: simple(:text)) { Text.new(text) } rule(doc: subtree(:doc)) { Doc.new(doc) } + rule(url: subtree(:url)) { Url.new(url) } end class Doc + attr_accessor :children + def initialize(children) - @children = children + self.children = children end def to_html s = StringIO.new - @children.each{|child| s << child.to_html } + children.each{|child| s << child.to_html } s.string end end class Text + attr_accessor :text + def initialize(text) - @text = text.to_str.strip + self.text = text.to_str.strip end def to_html - @text + text end end class Bold + attr_accessor :children + def initialize(children) - @children = children + self.children = children end def to_html s = StringIO.new s << "" - @children.each{|child| s << child.to_html } + children.each{|child| s << child.to_html } s << "" s.string end end class Italic + attr_accessor :children + def initialize(children) - @children = children + self.children = children end def to_html s = StringIO.new s << "" - @children.each{|child| s << child.to_html } + children.each{|child| s << child.to_html } s << "" s.string 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 + "#{title}" + end + end end diff --git a/spec/bristlecode/parser_spec.rb b/spec/bristlecode/parser_spec.rb index 0ddccc9..5e2199d 100644 --- a/spec/bristlecode/parser_spec.rb +++ b/spec/bristlecode/parser_spec.rb @@ -45,6 +45,22 @@ module Bristlecode expect(to_html("[b]bold")).to eq("bold") expect(to_html("[i]italic")).to eq("italic") end + + it 'can render simple links' do + input = '[url]example.com[/url]' + output = 'example.com' + expect(to_html(input)).to eq(output) + + input = '[url] example.com [/url]' + output = 'example.com' + expect(to_html(input)).to eq(output) + end + + it 'passes simple url contents opaquely' do + input = '[url]x[b]y[/b]z[/url]' + output = 'x[b]y[/b]z' + expect(to_html(input)).to eq(output) + end end describe Parser do @@ -133,5 +149,19 @@ module Bristlecode expect(parser.italic).not_to parse('[italic]fake content[/italic]') 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