rubb 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/LICENSE +19 -0
- data/README.rdoc +37 -0
- data/Rakefile +28 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/lib/rubb.rb +22 -0
- data/lib/rubb/node.rb +25 -0
- data/lib/rubb/node/image.rb +25 -0
- data/lib/rubb/node/quote.rb +22 -0
- data/lib/rubb/node/simple.rb +21 -0
- data/lib/rubb/node/styled.rb +28 -0
- data/lib/rubb/node/text.rb +22 -0
- data/lib/rubb/node/url.rb +26 -0
- data/lib/rubb/parser.rb +128 -0
- data/test/test_helper.rb +2 -0
- data/test/test_rubb.rb +187 -0
- metadata +82 -0
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010 Peter Jihoon Kim
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
= RuBB
|
2
|
+
|
3
|
+
BBCode Parser for Ruby.
|
4
|
+
|
5
|
+
RuBB parses BBCode by generating a parse tree, so it is able to handle nested BBCode tags properly.
|
6
|
+
|
7
|
+
== Usage
|
8
|
+
|
9
|
+
RuBB.to_html('[b]hello[/b]')
|
10
|
+
|
11
|
+
'[b]hello[/b]'.to_html
|
12
|
+
|
13
|
+
== BBCode Tags
|
14
|
+
|
15
|
+
RuBB supports the following BBCode tags:
|
16
|
+
|
17
|
+
[b]text[/b]
|
18
|
+
[i]text[/i]
|
19
|
+
[u]text[/u]
|
20
|
+
[s]text[/s]
|
21
|
+
[size=10]text[/size]
|
22
|
+
[color=#ff0000]text[/color]
|
23
|
+
[center]text[/center]
|
24
|
+
[quote]text[/quote]
|
25
|
+
[quote=someone]text[/quote]
|
26
|
+
[url]http://github.com/petejkim/rubb/[/url]
|
27
|
+
[url=http://github.com/petejkim/rubb/]RuBB[/url]
|
28
|
+
[img]http://test.com/test.jpg[/img]
|
29
|
+
[img=640x480]http://test.com/test.jpg[/img]
|
30
|
+
[ul][li]text[/li][/ul]
|
31
|
+
[ol][li]text[/li][/ol]
|
32
|
+
[code]text[/code]
|
33
|
+
[table][tr][th]text[/th][/tr][tr][td]text[/td][/tr][/table]
|
34
|
+
|
35
|
+
== Copyright
|
36
|
+
|
37
|
+
Copyright (c) 2010 Peter Jihoon Kim. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
|
7
|
+
Jeweler::Tasks.new do |s|
|
8
|
+
s.name = "rubb"
|
9
|
+
s.summary = "BBCode Parser for Ruby that supports nested BBCode tags."
|
10
|
+
s.description = s.summary
|
11
|
+
s.homepage = "http://github.com/petejkim/rubb"
|
12
|
+
s.authors = ["Peter Jihoon Kim"]
|
13
|
+
s.email = "raingrove@gmail.com"
|
14
|
+
end
|
15
|
+
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts "Jeweler - or one of its dependencies - is not available. " <<
|
19
|
+
"Install it with: sudo gem install jeweler -s http://gemcutter.org"
|
20
|
+
end
|
21
|
+
|
22
|
+
Rake::TestTask.new do |t|
|
23
|
+
t.libs << 'lib'
|
24
|
+
t.pattern = 'test/**/test_*.rb'
|
25
|
+
t.verbose = true
|
26
|
+
end
|
27
|
+
|
28
|
+
task :default => :test
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.9.0
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rubb'
|
data/lib/rubb.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module RuBB
|
2
|
+
class << self
|
3
|
+
def parse(bbcode)
|
4
|
+
Parser.parse(Parser.escape_html(bbcode), nil)
|
5
|
+
end
|
6
|
+
|
7
|
+
def to_html(bbcode)
|
8
|
+
parse(bbcode).to_html
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class String
|
14
|
+
def bb_to_html
|
15
|
+
RuBB.to_html(self)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
$: << (File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
20
|
+
|
21
|
+
require 'rubb/node'
|
22
|
+
require 'rubb/parser'
|
data/lib/rubb/node.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module RuBB
|
2
|
+
class Node
|
3
|
+
attr_accessor :children
|
4
|
+
attr_accessor :leftover
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
@children = options[:children] || []
|
8
|
+
@leftover = options[:leftover]
|
9
|
+
end
|
10
|
+
|
11
|
+
def <<(child)
|
12
|
+
@children << child
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_html
|
16
|
+
html = ''
|
17
|
+
@children.each do |child|
|
18
|
+
html += child ? child.to_html : ''
|
19
|
+
end
|
20
|
+
html
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'node/*.rb')).each {|f| require f }
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RuBB
|
2
|
+
class Node
|
3
|
+
class Image < Node
|
4
|
+
attr_accessor :width
|
5
|
+
attr_accessor :height
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
super(options)
|
9
|
+
@width = options[:width]
|
10
|
+
@height = options[:height]
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_html
|
14
|
+
if(@width && @height)
|
15
|
+
url = Parser.escape_quotes(@children.map {|c| c ? c.to_html : '' }.join)
|
16
|
+
html = "<img src=\"#{url}\" style=\"width: #{@width}px; height: #{@height}px;\" alt=\"\" />"
|
17
|
+
else
|
18
|
+
url = Parser.escape_quotes(@children.map {|c| c ? c.to_html : '' }.join)
|
19
|
+
html = "<img src=\"#{url}\" alt=\"\" />"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module RuBB
|
2
|
+
class Node
|
3
|
+
class Quote < Node
|
4
|
+
attr_accessor :who
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
super(options)
|
8
|
+
@who = options[:who] || ''
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_html
|
12
|
+
html = '<p class="rubb_quote_header">Quote:</p><blockquote>'
|
13
|
+
html += "<p class=\"rubb_quote_who\">Originally Posted by <strong>#{Parser.escape_quotes(@who)}</strong></p>" unless(@who.empty?)
|
14
|
+
html += '<p class="rubb_quote_content">'
|
15
|
+
@children.each do |child|
|
16
|
+
html += child ? child.to_html : ''
|
17
|
+
end
|
18
|
+
html + '</p></blockquote>'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RuBB
|
2
|
+
class Node
|
3
|
+
class Simple < Node
|
4
|
+
attr_accessor :html_tag_name
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
super(options)
|
8
|
+
@html_tag_name = options[:html_tag_name] || ''
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_html
|
12
|
+
html = "<#{@html_tag_name}>"
|
13
|
+
@children.each do |child|
|
14
|
+
html += child ? child.to_html : ''
|
15
|
+
end
|
16
|
+
html + "</#{@html_tag_name}>"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RuBB
|
2
|
+
class Node
|
3
|
+
class Styled < Node
|
4
|
+
attr_accessor :style_hash
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
super(options)
|
8
|
+
@style_hash = options[:style_hash] || {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_html
|
12
|
+
html = '<span style="'
|
13
|
+
@style_hash.each do |k,v|
|
14
|
+
if(v) # if v is not nil
|
15
|
+
v = v[/\A([^;]*);/,1] if v.include?(';') # ignore semicolons and any trailing text
|
16
|
+
html += "#{k}: #{v};"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
html += '">'
|
20
|
+
@children.each do |child|
|
21
|
+
html += child ? child.to_html : ''
|
22
|
+
end
|
23
|
+
html + "</span>"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module RuBB
|
2
|
+
class Node
|
3
|
+
class Text < Node
|
4
|
+
attr_accessor :text
|
5
|
+
attr_accessor :ignore_whitespace
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
super(options)
|
9
|
+
@text = options[:text] || ''
|
10
|
+
@ignore_whitespace = options[:ignore_whitespace] || false
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_html
|
14
|
+
if(@ignore_whitespace)
|
15
|
+
@text.gsub(/\s/, '')
|
16
|
+
else
|
17
|
+
@text.gsub(/\r\n?/, "\n").gsub(/\n/, '<br />')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RuBB
|
2
|
+
class Node
|
3
|
+
class URL < Node
|
4
|
+
attr_accessor :url
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
super(options)
|
8
|
+
@url = options[:url] || ''
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_html
|
12
|
+
unless(@url.empty?)
|
13
|
+
html = "<a href=\"#{Parser.escape_quotes(@url)}\">"
|
14
|
+
@children.each do |child|
|
15
|
+
html += child ? child.to_html : ''
|
16
|
+
end
|
17
|
+
html + '</a>'
|
18
|
+
else
|
19
|
+
url = Parser.escape_quotes(@children.map {|c| c ? c.to_html : '' }.join)
|
20
|
+
html = "<a href=\"#{url}\">#{url}</a>"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
data/lib/rubb/parser.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
module RuBB
|
2
|
+
class Parser
|
3
|
+
TEXT_REGEXP = /\A([^\[]+)/
|
4
|
+
BB_REGEXP = /\A\[([^\]]*)\]/
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def escape_html(code)
|
8
|
+
code.gsub(/&/,'&').gsub(/</,'<').gsub(/>/,'>')
|
9
|
+
end
|
10
|
+
|
11
|
+
def escape_quotes(code)
|
12
|
+
code.gsub(/"/, "\\\"").gsub(/'/, "\\\\'")
|
13
|
+
end
|
14
|
+
|
15
|
+
def remove_wrapping_quotes(code)
|
16
|
+
if code[0] == "\"" && code[code.length-1] == "\""
|
17
|
+
return code[/\A"(.*)"\z/,1]
|
18
|
+
elsif code[0] == "\'" && code[code.length-1] == "\'"
|
19
|
+
return code[/\A'(.*)'\z/,1]
|
20
|
+
end
|
21
|
+
code
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse(code, current_tag_name, extra_params={})
|
25
|
+
return nil if code.length == 0
|
26
|
+
|
27
|
+
ignore_bbcode_in_children = false
|
28
|
+
|
29
|
+
node = case current_tag_name
|
30
|
+
when 'b'
|
31
|
+
Node::Simple.new(:html_tag_name => 'strong')
|
32
|
+
when 'i'
|
33
|
+
Node::Simple.new(:html_tag_name => 'em')
|
34
|
+
when 'u'
|
35
|
+
Node::Simple.new(:html_tag_name => 'ins')
|
36
|
+
when 's'
|
37
|
+
Node::Simple.new(:html_tag_name => 'del')
|
38
|
+
when 'code'
|
39
|
+
ignore_bbcode_in_children = true
|
40
|
+
Node::Simple.new(:html_tag_name => 'pre')
|
41
|
+
when 'ul', 'ol', 'li', 'table', 'tr', 'th', 'td'
|
42
|
+
Node::Simple.new(:html_tag_name => current_tag_name)
|
43
|
+
when 'size'
|
44
|
+
Node::Styled.new(:style_hash => {'font-size' => (extra_params[:param] ? extra_params[:param].to_f.to_s + 'px' : nil)})
|
45
|
+
when 'color'
|
46
|
+
Node::Styled.new(:style_hash => {'color' => (extra_params[:param] || nil)})
|
47
|
+
when 'center'
|
48
|
+
Node::Styled.new(:style_hash => {'text-align' => 'center'})
|
49
|
+
when 'quote'
|
50
|
+
Node::Quote.new(:who => (extra_params[:param] || ''))
|
51
|
+
when 'url'
|
52
|
+
ignore_bbcode_in_children = true if extra_params[:param].nil?
|
53
|
+
Node::URL.new(:url => (extra_params[:param] || ''))
|
54
|
+
when 'img'
|
55
|
+
ignore_bbcode_in_children = true
|
56
|
+
if(extra_params[:param] && (dimensions = extra_params[:param].split('x')).size >= 2)
|
57
|
+
Node::Image.new(:width => dimensions[0].to_i, :height => dimensions[1].to_i)
|
58
|
+
else
|
59
|
+
Node::Image.new
|
60
|
+
end
|
61
|
+
else
|
62
|
+
Node.new
|
63
|
+
end
|
64
|
+
|
65
|
+
until code.empty?
|
66
|
+
match_data = code.match(TEXT_REGEXP)
|
67
|
+
|
68
|
+
if(match_data)
|
69
|
+
code.replace(match_data.post_match)
|
70
|
+
case current_tag_name
|
71
|
+
when 'ul', 'ol', 'table', 'tr' # ignore orphaned text within these tags
|
72
|
+
# do nothing
|
73
|
+
else
|
74
|
+
node << Node::Text.new(:text => match_data[1], :ignore_whitespace => ignore_bbcode_in_children)
|
75
|
+
end
|
76
|
+
else
|
77
|
+
match_data = code.match(BB_REGEXP)
|
78
|
+
if(match_data)
|
79
|
+
tag = match_data[1].sub(/\s*=\s*/,' = ').split(' ')
|
80
|
+
tag_name = tag.first.downcase
|
81
|
+
|
82
|
+
code.replace(match_data.post_match)
|
83
|
+
if(current_tag_name && tag_name == ('/' + current_tag_name))
|
84
|
+
return node
|
85
|
+
else
|
86
|
+
case current_tag_name
|
87
|
+
when 'ul', 'ol' # if current tag is a list tag, expect only li tag
|
88
|
+
if(tag_name == 'li')
|
89
|
+
node << parse(code, tag_name)
|
90
|
+
end
|
91
|
+
when 'table'
|
92
|
+
if(tag_name == 'tr')
|
93
|
+
node << parse(code, tag_name)
|
94
|
+
end
|
95
|
+
when 'tr'
|
96
|
+
if(tag_name == 'th' || tag_name == 'td')
|
97
|
+
node << parse(code, tag_name)
|
98
|
+
end
|
99
|
+
else # if current tag is not a list tag
|
100
|
+
if(ignore_bbcode_in_children)
|
101
|
+
node << Node::Text.new(:text => match_data[0], :ignore_whitespace => true)
|
102
|
+
else
|
103
|
+
case tag_name
|
104
|
+
when 'b', 'i', 'u', 's', 'code', 'center', 'ul', 'ol', 'table'
|
105
|
+
node << parse(code, tag_name)
|
106
|
+
when 'url', 'img', 'size', 'color', 'quote'
|
107
|
+
if(tag[1] == '=' && tag.size > 2) # param is present
|
108
|
+
param = remove_wrapping_quotes(tag[2..(tag.size)].join(' '))
|
109
|
+
node << parse(code, tag_name, {:param => param})
|
110
|
+
else
|
111
|
+
node << parse(code, tag_name)
|
112
|
+
end
|
113
|
+
else
|
114
|
+
node << Node::Text.new(:text => match_data[0])
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
node
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'parser/*.rb')).each {|f| require f }
|
data/test/test_helper.rb
ADDED
data/test/test_rubb.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
$: << (File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class RuBBTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_escape
|
9
|
+
bb = "<p>tom & jerry kids</p>"
|
10
|
+
html = "<p>tom & jerry kids</p>"
|
11
|
+
assert_equal html, bb.bb_to_html
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_text
|
15
|
+
bb = "hello\nbye"
|
16
|
+
html = "hello<br />bye"
|
17
|
+
assert_equal html, bb.bb_to_html
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_b
|
21
|
+
bb = '[b]hello[/b]'
|
22
|
+
html = '<strong>hello</strong>'
|
23
|
+
assert_equal html, bb.bb_to_html
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_i
|
27
|
+
bb = '[i]hello[/i]'
|
28
|
+
html = '<em>hello</em>'
|
29
|
+
assert_equal html, bb.bb_to_html
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_u
|
33
|
+
bb = '[u]hello[/u]'
|
34
|
+
html = '<ins>hello</ins>'
|
35
|
+
assert_equal html, bb.bb_to_html
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_s
|
39
|
+
bb = '[s]hello[/s]'
|
40
|
+
html = '<del>hello</del>'
|
41
|
+
assert_equal html, bb.bb_to_html
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_code
|
45
|
+
bb = '[code]<p>hi</p>[b]hi[/b][/code]'
|
46
|
+
html = '<pre><p>hi</p>[b]hi[/b]</pre>'
|
47
|
+
assert_equal html, bb.bb_to_html
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_center
|
51
|
+
bb = '[center]hello[/center]'
|
52
|
+
html = '<span style="text-align: center;">hello</span>'
|
53
|
+
assert_equal html, bb.bb_to_html
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_quote
|
57
|
+
bb = '[quote]hello world![/quote]'
|
58
|
+
html = '<p class="rubb_quote_header">Quote:</p><blockquote><p class="rubb_quote_content">hello world!</p></blockquote>'
|
59
|
+
assert_equal html, bb.bb_to_html
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_named_quote
|
63
|
+
bb = '[quote=raingrove]hello world![/quote]'
|
64
|
+
html = '<p class="rubb_quote_header">Quote:</p><blockquote><p class="rubb_quote_who">Originally Posted by <strong>raingrove</strong></p><p class="rubb_quote_content">hello world!</p></blockquote>'
|
65
|
+
assert_equal html, bb.bb_to_html
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_size
|
69
|
+
bb = '[size=16]hello[/size]'
|
70
|
+
html = '<span style="font-size: 16.0px;">hello</span>'
|
71
|
+
assert_equal html, bb.bb_to_html
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_semicolon
|
75
|
+
bb = '[size=16;display: none;]hello[/size]'
|
76
|
+
html = '<span style="font-size: 16.0px;">hello</span>'
|
77
|
+
assert_equal html, bb.bb_to_html
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_color
|
81
|
+
bb = '[color=#ff0000]hello[/color]'
|
82
|
+
html = '<span style="color: #ff0000;">hello</span>'
|
83
|
+
assert_equal html, bb.bb_to_html
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_url_simple
|
87
|
+
bb = '[url]http://test.com/[/url]'
|
88
|
+
html = '<a href="http://test.com/">http://test.com/</a>'
|
89
|
+
assert_equal html, bb.bb_to_html
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_url_named
|
93
|
+
bb = '[url=http://test.com/]Test[/url]'
|
94
|
+
html = '<a href="http://test.com/">Test</a>'
|
95
|
+
assert_equal html, bb.bb_to_html
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_url_named_with_single_quotes
|
99
|
+
bb = "[url=\'http://test.com/\']Test[/url]"
|
100
|
+
html = '<a href="http://test.com/">Test</a>'
|
101
|
+
assert_equal html, bb.bb_to_html
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_url_named_with_double_quotes
|
105
|
+
bb = '[url="http://test.com/"]Test[/url]'
|
106
|
+
html = '<a href="http://test.com/">Test</a>'
|
107
|
+
assert_equal html, bb.bb_to_html
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_escape_quotes
|
111
|
+
bb = "[url=hello\">hello<p class='test'>hi</p><a href=\"]hello[/url]"
|
112
|
+
html = "<a href=\"hello\\\">hello<p class=\\\'test\\\'>hi</p><a href=\\\"\">hello</a>"
|
113
|
+
assert_equal html, bb.bb_to_html
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_img_simple
|
117
|
+
bb = '[img]http://test.com/hello.jpg[/img]'
|
118
|
+
html = '<img src="http://test.com/hello.jpg" alt="" />'
|
119
|
+
assert_equal html, bb.bb_to_html
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_img_with_dimensions
|
123
|
+
bb = '[img=100x200]http://test.com/hello.jpg[/img]'
|
124
|
+
html = '<img src="http://test.com/hello.jpg" style="width: 100px; height: 200px;" alt="" />'
|
125
|
+
assert_equal html, bb.bb_to_html
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_img_with_dimensions_with_quotes
|
129
|
+
bb = '[img="100x200"]http://test.com/hello.jpg[/img]'
|
130
|
+
html = '<img src="http://test.com/hello.jpg" style="width: 100px; height: 200px;" alt="" />'
|
131
|
+
assert_equal html, bb.bb_to_html
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_img_with_invalid_dimensions
|
135
|
+
bb = '[img="100"]http://test.com/hello.jpg[/img]'
|
136
|
+
html = '<img src="http://test.com/hello.jpg" alt="" />'
|
137
|
+
assert_equal html, bb.bb_to_html
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_ul
|
141
|
+
bb = '[ul][li]item1[/li][li]item2[/li][/ul]'
|
142
|
+
html = '<ul><li>item1</li><li>item2</li></ul>'
|
143
|
+
assert_equal html, bb.bb_to_html
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_ol
|
147
|
+
bb = '[ol][li]item1[/li][li]item2[/li][/ol]'
|
148
|
+
html = '<ol><li>item1</li><li>item2</li></ol>'
|
149
|
+
assert_equal html, bb.bb_to_html
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_list_with_extraneous_stuff
|
153
|
+
bb = '[ul]blah[li]item1[/li][li]item2[/li]blah[b]blah[/b]blah[/ul]'
|
154
|
+
html = '<ul><li>item1</li><li>item2</li></ul>'
|
155
|
+
assert_equal html, bb.bb_to_html
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_table
|
159
|
+
bb = '[table][tr][th]col1[/th][th]col2[/th][/tr][tr][td]data1[/td][td]data2[/td][/tr][/table]'
|
160
|
+
html = '<table><tr><th>col1</th><th>col2</th></tr><tr><td>data1</td><td>data2</td></tr></table>'
|
161
|
+
assert_equal html, bb.bb_to_html
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_table_with_extraneous_stuff
|
165
|
+
bb = '[table]blah[tr]blah[th]col1[/th]blah[th]col2[/th]blah[/tr]blah[tr]blah[td]data1[/td]blah[td]data2[/td]blah[/tr]blah[/table]'
|
166
|
+
html = '<table><tr><th>col1</th><th>col2</th></tr><tr><td>data1</td><td>data2</td></tr></table>'
|
167
|
+
assert_equal html, bb.bb_to_html
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_str_around
|
171
|
+
bb = 'aaa[b]bbb[/b]ccc'
|
172
|
+
html = 'aaa<strong>bbb</strong>ccc'
|
173
|
+
assert_equal html, bb.bb_to_html
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_nested
|
177
|
+
bb = '[b]aaa[b]bbb[/b]ccc[/b]'
|
178
|
+
html = '<strong>aaa<strong>bbb</strong>ccc</strong>'
|
179
|
+
assert_equal html, bb.bb_to_html
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_complex
|
183
|
+
bb = "xx[s]aaa[b]bbb[u]eee[/u]ff\nff[/b]ccc[i]ggg[/i]hhh[/s]yy"
|
184
|
+
html = 'xx<del>aaa<strong>bbb<ins>eee</ins>ff<br />ff</strong>ccc<em>ggg</em>hhh</del>yy'
|
185
|
+
assert_equal html, bb.bb_to_html
|
186
|
+
end
|
187
|
+
end
|
metadata
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rubb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 9
|
8
|
+
- 0
|
9
|
+
version: 0.9.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Peter Jihoon Kim
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-07-12 00:00:00 +09:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: BBCode Parser for Ruby that supports nested BBCode tags.
|
22
|
+
email: raingrove@gmail.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- LICENSE
|
29
|
+
- README.rdoc
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- LICENSE
|
33
|
+
- README.rdoc
|
34
|
+
- Rakefile
|
35
|
+
- VERSION
|
36
|
+
- init.rb
|
37
|
+
- lib/rubb.rb
|
38
|
+
- lib/rubb/node.rb
|
39
|
+
- lib/rubb/node/image.rb
|
40
|
+
- lib/rubb/node/quote.rb
|
41
|
+
- lib/rubb/node/simple.rb
|
42
|
+
- lib/rubb/node/styled.rb
|
43
|
+
- lib/rubb/node/text.rb
|
44
|
+
- lib/rubb/node/url.rb
|
45
|
+
- lib/rubb/parser.rb
|
46
|
+
- test/test_helper.rb
|
47
|
+
- test/test_rubb.rb
|
48
|
+
has_rdoc: true
|
49
|
+
homepage: http://github.com/petejkim/rubb
|
50
|
+
licenses: []
|
51
|
+
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options:
|
54
|
+
- --charset=UTF-8
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
version: "0"
|
73
|
+
requirements: []
|
74
|
+
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 1.3.7
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: BBCode Parser for Ruby that supports nested BBCode tags.
|
80
|
+
test_files:
|
81
|
+
- test/test_helper.rb
|
82
|
+
- test/test_rubb.rb
|