rbbcode 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README +46 -0
- data/spec/html_maker_spec.rb +70 -0
- data/spec/node_spec_helper.rb +114 -0
- data/spec/parser_spec.rb +99 -0
- data/spec/schema_spec.rb +98 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/tree_maker_spec.rb +107 -0
- metadata +60 -0
data/README
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
RbbCode is a customizable Ruby library for parsing BB Code.
|
2
|
+
|
3
|
+
RbbCode validates and cleans input. It supports customizable schemas so you can set rules about what tags are allowed where. The default rules are designed to ensure valid HTML output.
|
4
|
+
|
5
|
+
Example usage:
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rbbcode'
|
9
|
+
|
10
|
+
bb_code = 'This is [b]bold[/b] text'
|
11
|
+
parser = RbbCode::Parser.new
|
12
|
+
html = parser.parse(bb_code)
|
13
|
+
# => '<p>This is <strong>bold</strong> text</p>'
|
14
|
+
|
15
|
+
Customizing
|
16
|
+
===========
|
17
|
+
|
18
|
+
You can customize RbbCode by subclassing HtmlMaker and/or by passing configuration directives to a Schema object.
|
19
|
+
|
20
|
+
HtmlMaker can be extended by adding methods like this:
|
21
|
+
|
22
|
+
class MyHtmlMaker < RbbCode::HtmlMaker
|
23
|
+
def html_from_TAGNAME_tag(node)
|
24
|
+
# ...
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
...where TAGNAME should be replaced with the name of the tag. The method should accept an RbbCode::TagNode and return HTML as a string. (See tree_maker.rb for the definition of RbbCode::TagNode.) Anytime the parser encounters the specified tag, it will call your method and insert the returned HTML into the output.
|
29
|
+
|
30
|
+
Now you just have to tell the Parser object to use an instance of your custom subclass instead of the default HtmlMaker:
|
31
|
+
|
32
|
+
my_html_maker = MyHtmlMaker.new
|
33
|
+
parser = RbbCode::Parser.new(:html_maker => my_html_maker)
|
34
|
+
|
35
|
+
RbbCode removes invalid markup by comparing the input against a Schema object. The Schema is much like a DTD in XML. You can set your own rules and change the default ones by calling configuration methods on a Schema instance. Look at Schema#use_defaults in schema.rb for examples.
|
36
|
+
|
37
|
+
Normally, RbbCode instantiates Schema behind the scenes, but if you want to customize it, you'll have to instantiate it yourself and pass the instance to the Parser object:
|
38
|
+
|
39
|
+
schema = RbbCode::Schema.new
|
40
|
+
schema.tag('quote').may_not_be_nested # Or whatever other configuration methods you want to call
|
41
|
+
parser = RbbCode::Parser.new(:schema => schema)
|
42
|
+
|
43
|
+
Unicode Support
|
44
|
+
===============
|
45
|
+
|
46
|
+
UTF-8 compatibility is a high priority for this project. RbbCode aims to be fully compatible with UTF-8, but not with other multibyte encodings. As of the most recent release, UTF-8 support has been tested to a limited extent. It is possible that there are some hidden gotchas. Please report any bugs you may find.
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/node_spec_helper')
|
3
|
+
|
4
|
+
describe RbbCode::HtmlMaker do
|
5
|
+
context '#make_html' do
|
6
|
+
def expect_html(expected_html, &block)
|
7
|
+
@html_maker.make_html(NodeBuilder.build(&block)).should == expected_html
|
8
|
+
end
|
9
|
+
|
10
|
+
before :each do
|
11
|
+
@html_maker = RbbCode::HtmlMaker.new
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should replace simple BB code tags with HTML tags' do
|
15
|
+
expect_html('<p>This is <strong>bold</strong> text</p>') do
|
16
|
+
tag('p') do
|
17
|
+
text 'This is '
|
18
|
+
tag('b') { text 'bold' }
|
19
|
+
text ' text'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should work for nested tags' do
|
25
|
+
expect_html('<p>This is <strong>bold and <u>underlined</u></strong> text</p>') do
|
26
|
+
tag('p') do
|
27
|
+
text 'This is '
|
28
|
+
tag('b') do
|
29
|
+
text 'bold and '
|
30
|
+
tag('u') { text 'underlined' }
|
31
|
+
end
|
32
|
+
text ' text'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should not allow JavaScript in URLs' do
|
38
|
+
urls = {
|
39
|
+
'javascript:alert("foo");' => 'http://javascript%3Aalert("foo");',
|
40
|
+
'j a v a script:alert("foo");' => 'http://j+a+v+a+script%3Aalert("foo");',
|
41
|
+
' javascript:alert("foo");' => 'http://+javascript%3Aalert("foo");',
|
42
|
+
'JavaScript:alert("foo");' => 'http://JavaScript%3Aalert("foo");' ,
|
43
|
+
"java\nscript:alert(\"foo\");" => 'http://java%0Ascript%3Aalert("foo");',
|
44
|
+
"java\rscript:alert(\"foo\");" => 'http://java%0Dscript%3Aalert("foo");'
|
45
|
+
}
|
46
|
+
|
47
|
+
# url tag
|
48
|
+
urls.each do |evil_url, clean_url|
|
49
|
+
expect_html("<p><a href=\"#{clean_url}\">foo</a></p>") do
|
50
|
+
tag('p') do
|
51
|
+
tag('url', evil_url) do
|
52
|
+
text 'foo'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# img tag
|
59
|
+
urls.each do |evil_url, clean_url|
|
60
|
+
expect_html("<p><img src=\"#{clean_url}\" alt=\"\"/></p>") do
|
61
|
+
tag('p') do
|
62
|
+
tag('img') do
|
63
|
+
text evil_url
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module RbbCode
|
2
|
+
class RootNode
|
3
|
+
def == (other_node)
|
4
|
+
self.class == other_node.class and self.children == other_node.children
|
5
|
+
end
|
6
|
+
|
7
|
+
def print_tree(indent = 0)
|
8
|
+
output = ''
|
9
|
+
indent.times { output << " " }
|
10
|
+
output << 'ROOT'
|
11
|
+
children.each do |child|
|
12
|
+
output << "\n" << child.print_tree(indent + 1)
|
13
|
+
end
|
14
|
+
output << "\n/ROOT"
|
15
|
+
output
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class TagNode
|
20
|
+
def == (other_node)
|
21
|
+
self.class == other_node.class and self.tag_name == other_node.tag_name and self.value == other_node.value and self.children == other_node.children
|
22
|
+
end
|
23
|
+
|
24
|
+
def print_tree(indent = 0)
|
25
|
+
output = ''
|
26
|
+
indent.times { output << " " }
|
27
|
+
if value.nil?
|
28
|
+
output << "[#{tag_name}]"
|
29
|
+
else
|
30
|
+
output << "[#{tag_name}=#{value}]"
|
31
|
+
end
|
32
|
+
children.each do |child|
|
33
|
+
output << "\n" << child.print_tree(indent + 1)
|
34
|
+
end
|
35
|
+
output << "\n"
|
36
|
+
indent.times { output << " " }
|
37
|
+
output << "[/#{tag_name}]"
|
38
|
+
output
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class TextNode
|
43
|
+
def == (other_node)
|
44
|
+
self.class == other_node.class and self.text == other_node.text
|
45
|
+
end
|
46
|
+
|
47
|
+
def print_tree(indent = 0)
|
48
|
+
output = ''
|
49
|
+
indent.times { output << " " }
|
50
|
+
output << '"' << text << '"'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class NodeBuilder
|
56
|
+
include RbbCode
|
57
|
+
|
58
|
+
def self.build(&block)
|
59
|
+
builder = new
|
60
|
+
builder.instance_eval(&block)
|
61
|
+
builder.root
|
62
|
+
end
|
63
|
+
|
64
|
+
attr_reader :root
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
def << (node)
|
69
|
+
@current_parent.children << node
|
70
|
+
end
|
71
|
+
|
72
|
+
def initialize
|
73
|
+
@root = RootNode.new
|
74
|
+
@current_parent = @root
|
75
|
+
end
|
76
|
+
|
77
|
+
def text(contents, &block)
|
78
|
+
self << TextNode.new(@current_parent, contents)
|
79
|
+
end
|
80
|
+
|
81
|
+
def tag(tag_name, value = nil, &block)
|
82
|
+
tag_node = TagNode.new(@current_parent, tag_name, value)
|
83
|
+
self << tag_node
|
84
|
+
original_parent = @current_parent
|
85
|
+
@current_parent = tag_node
|
86
|
+
instance_eval(&block)
|
87
|
+
@current_parent = original_parent
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
module NodeMatchers
|
92
|
+
class MatchNode
|
93
|
+
def initialize(expected_tree)
|
94
|
+
@expected_tree = expected_tree
|
95
|
+
end
|
96
|
+
|
97
|
+
def matches?(target)
|
98
|
+
@target = target
|
99
|
+
@target == @expected_tree
|
100
|
+
end
|
101
|
+
|
102
|
+
def failure_message
|
103
|
+
"Expected:\n\n#{@expected_tree.print_tree}\n\nbut got:\n\n#{@target.print_tree}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def negative_failure_message
|
107
|
+
"Expected anything other than:\n\n#{@expected_tree.print_tree}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def match_node(expected_node)
|
112
|
+
MatchNode.new(expected_node)
|
113
|
+
end
|
114
|
+
end
|
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
$KCODE = 'u'
|
2
|
+
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
4
|
+
|
5
|
+
describe RbbCode::Parser do
|
6
|
+
context '#parse' do
|
7
|
+
before :each do
|
8
|
+
@parser = RbbCode::Parser.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should create paragraphs and line breaks' do
|
12
|
+
bb_code = "This is one paragraph.\n\nThis is another paragraph."
|
13
|
+
@parser.parse(bb_code).should == '<p>This is one paragraph.</p><p>This is another paragraph.</p>'
|
14
|
+
bb_code = "This is one line.\nThis is another line."
|
15
|
+
@parser.parse(bb_code).should == '<p>This is one line.<br/>This is another line.</p>'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should turn [b] to <strong>' do
|
19
|
+
@parser.parse('This is [b]bold[/b] text').should == '<p>This is <strong>bold</strong> text</p>'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should turn [i] to <em> by default' do
|
23
|
+
@parser.parse('This is [i]italic[/i] text').should == '<p>This is <em>italic</em> text</p>'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should turn [u] to <u>' do
|
27
|
+
@parser.parse('This is [u]underlined[/u] text').should == '<p>This is <u>underlined</u> text</p>'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should turn [url]http://google.com[/url] to a link' do
|
31
|
+
@parser.parse('Visit [url]http://google.com[/url] now').should == '<p>Visit <a href="http://google.com">http://google.com</a> now</p>'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should turn [url=http://google.com]Google[/url] to a link' do
|
35
|
+
@parser.parse('Visit [url=http://google.com]Google[/url] now').should == '<p>Visit <a href="http://google.com">Google</a> now</p>'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should turn [img] to <img>' do
|
39
|
+
@parser.parse('[img]http://example.com/image.jpg[/img]').should == '<p><img src="http://example.com/image.jpg" alt=""/></p>'
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should turn [code] to <code>' do
|
43
|
+
@parser.parse('Too bad [code]method_missing[/code] is rarely useful').should == '<p>Too bad <code>method_missing</code> is rarely useful</p>'
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should parse nested tags' do
|
47
|
+
@parser.parse('[b][i]This is bold-italic[/i][/b]').should == '<p><strong><em>This is bold-italic</em></strong></p>'
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should not put <p> tags around <ul> tags' do
|
51
|
+
@parser.parse("Text.\n\n[list]\n[*]Foo[/*]\n[*]Bar[/*]\n[/list]\n\nMore text.").should == '<p>Text.</p><ul><li>Foo</li><li>Bar</li></ul><p>More text.</p>'
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should ignore forbidden or unrecognized tags' do
|
55
|
+
@parser.parse('There is [foo]no such thing[/foo] as a foo tag').should == '<p>There is no such thing as a foo tag</p>'
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should recover gracefully from malformed or improperly matched tags' do
|
59
|
+
@parser.parse('This [i/]tag[/i] is malformed').should == '<p>This [i/]tag is malformed</p>'
|
60
|
+
@parser.parse('This [i]]tag[/i] is malformed').should == '<p>This <em>]tag</em> is malformed</p>'
|
61
|
+
@parser.parse('This [i]tag[[/i] is malformed').should == '<p>This <em>tag[</em> is malformed</p>'
|
62
|
+
@parser.parse('This [i]tag[//i] is malformed').should == '<p>This <em>tag[//i] is malformed</em></p>'
|
63
|
+
@parser.parse('This [[i]tag[/i] is malformed').should == '<p>This [<em>tag</em> is malformed</p>'
|
64
|
+
@parser.parse('This [i]tag[/i]] is malformed').should == '<p>This <em>tag</em>] is malformed</p>'
|
65
|
+
@parser.parse('This [i]i tag[i] is not properly matched').should == '<p>This <em>i tag is not properly matched</em></p>'
|
66
|
+
@parser.parse('This i tag[/i] is not properly matched').should == '<p>This i tag is not properly matched</p>'
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should escape < and >' do
|
70
|
+
@parser.parse('This is [i]italic[/i], but this it not <i>italic</i>.').should == '<p>This is <em>italic</em>, but this it not <i>italic</i>.</p>'
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should work when the string begins with a tag' do
|
74
|
+
@parser.parse('[b]This is bold[/b]').should == '<p><strong>This is bold</strong></p>'
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should handle UTF8' do
|
78
|
+
@parser.parse("Here's some UTF-8: [i]א[/i]. And here's some ASCII text.").should == "<p>Here's some UTF-8: <em>א</em>. And here's some ASCII text.</p>"
|
79
|
+
end
|
80
|
+
|
81
|
+
# Bugs reported and fixed:
|
82
|
+
|
83
|
+
it 'should not leave an open <em> tag when parsing "foo [i][/i] bar"' do
|
84
|
+
# Thanks to Vizakenjack for finding this. It creates an empty <em> tag. Browsers don't like this, so we need to replace it.
|
85
|
+
@parser.parse('foo [i][/i] bar').should match(/<p>foo +bar<\/p>/)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should not raise when parsing "Are you a real phan yet?\r\n\r\n[ ] Yes\r\n[X] No"' do
|
89
|
+
# Thanks to sblackstone for finding this.
|
90
|
+
@parser.parse("Are you a real phan yet?\r\n\r\n[ ] Yes\r\n[X] No")
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should support images inside links' do
|
94
|
+
# Thanks to Vizakenjack for finding this.
|
95
|
+
@parser.parse('[url=http://www.google.com][img]http://www.123.com/123.png[/img][/url]').should ==
|
96
|
+
'<p><a href="http://www.google.com"><img src="http://www.123.com/123.png" alt=""/></a></p>'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/spec/schema_spec.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe RbbCode::Schema do
|
4
|
+
before :each do
|
5
|
+
@schema = RbbCode::Schema.new
|
6
|
+
@schema.clear
|
7
|
+
@schema.allow_tags(*RbbCode::DEFAULT_ALLOWED_TAGS)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should allow the default tags at the top level' do
|
11
|
+
schema = RbbCode::Schema.new
|
12
|
+
[
|
13
|
+
'b',
|
14
|
+
'i',
|
15
|
+
'u',
|
16
|
+
'url',
|
17
|
+
'img',
|
18
|
+
'code',
|
19
|
+
'quote',
|
20
|
+
'list'
|
21
|
+
].each do |tag|
|
22
|
+
schema.tag(tag).valid_in_context?().should == true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should not allow unknown tags' do
|
27
|
+
@schema.tag('foo').valid_in_context?().should == false
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should return a new SchemaTag object when tag is called' do
|
31
|
+
@schema.tag('b').should be_a(RbbCode::SchemaTag)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should not allow nesting a tag when may_not_be_nested is called on it' do
|
35
|
+
@schema.tag('b').may_not_be_nested
|
36
|
+
@schema.tag('b').valid_in_context?('b').should == false
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should allow nesting a tag when may_be_nested is called on it' do
|
40
|
+
@schema.tag('b').may_not_be_nested
|
41
|
+
@schema.tag('b').may_be_nested
|
42
|
+
@schema.tag('b').valid_in_context?('b').should == true
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should not allow a tag to descend from another when forbidden by may_not_descend_from' do
|
46
|
+
@schema.tag('b').may_not_descend_from('u')
|
47
|
+
@schema.tag('b').valid_in_context?('u').should == false
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should allow a tag to descend from another when permitted by may_descend_from' do
|
51
|
+
@schema.tag('b').may_not_descend_from('u')
|
52
|
+
@schema.tag('b').may_descend_from('u')
|
53
|
+
@schema.tag('b').valid_in_context?('u').should == true
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should not allow a tag to descend from anything other than the tags specified in must_be_child_of' do
|
57
|
+
@schema.tag('b').must_be_child_of('u', 'quote')
|
58
|
+
@schema.tag('b').valid_in_context?('i').should == false
|
59
|
+
@schema.tag('b').valid_in_context?('u').should == true
|
60
|
+
@schema.tag('b').valid_in_context?('quote').should == true
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should allow a tag to descend from the one specified in must_be_child_of' do
|
64
|
+
@schema.tag('b').may_not_descend_from('u')
|
65
|
+
@schema.tag('b').must_be_child_of('u')
|
66
|
+
@schema.tag('b').valid_in_context?('u').should == true
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should not require a tag to be a child of another when need_not_be_child_of is called' do
|
70
|
+
@schema.tag('b').must_be_child_of('u')
|
71
|
+
@schema.tag('b').need_not_be_child_of('u')
|
72
|
+
@schema.tag('b').valid_in_context?('i').should == true
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should allow only the specified tag as a child when may_only_be_parent_of is called' do
|
76
|
+
@schema.tag('list').may_only_be_parent_of('*')
|
77
|
+
@schema.tag('*').valid_in_context?('list').should == true
|
78
|
+
@schema.tag('u').valid_in_context?('list').should == false
|
79
|
+
@schema.tag('u').valid_in_context?('*', 'list').should == true
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should not allow text inside a tag when may_not_contain_text is called' do
|
83
|
+
@schema.tag('list').may_not_contain_text
|
84
|
+
@schema.text.valid_in_context?('list').should == false
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should allow text inside a tag when may_contain_text is called' do
|
88
|
+
@schema.tag('list').may_not_contain_text
|
89
|
+
@schema.tag('list').may_contain_text
|
90
|
+
@schema.text.valid_in_context?('list').should == true
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should not allow text or children when must_be_empty is called' do
|
94
|
+
@schema.tag('br').must_be_empty
|
95
|
+
@schema.text.valid_in_context?('br').should == false
|
96
|
+
@schema.tag('b').valid_in_context?('br').should == false
|
97
|
+
end
|
98
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/node_spec_helper')
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
describe RbbCode::TreeMaker do
|
6
|
+
include NodeMatchers
|
7
|
+
|
8
|
+
context '#make_tree' do
|
9
|
+
def expect_tree(str, &block)
|
10
|
+
expected = NodeBuilder.build(&block)
|
11
|
+
@tree_maker.make_tree(str).should match_node(expected)
|
12
|
+
end
|
13
|
+
|
14
|
+
before :each do
|
15
|
+
@schema = RbbCode::Schema.new
|
16
|
+
@tree_maker = RbbCode::TreeMaker.new(@schema)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should make a tree from a string with one tag' do
|
20
|
+
str = 'This is [b]bold[/b] text'
|
21
|
+
|
22
|
+
expect_tree(str) do
|
23
|
+
tag('p') do
|
24
|
+
text 'This is '
|
25
|
+
tag('b') { text 'bold' }
|
26
|
+
text ' text'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should ignore tags that are invalid in their context' do
|
32
|
+
@schema.tag('u').may_not_descend_from('b')
|
33
|
+
|
34
|
+
str = 'This is [b]bold and [u]underlined[/u][/b] text'
|
35
|
+
|
36
|
+
expect_tree(str) do
|
37
|
+
tag('p') do
|
38
|
+
text 'This is '
|
39
|
+
tag('b') do
|
40
|
+
text 'bold and '
|
41
|
+
text 'underlined'
|
42
|
+
end
|
43
|
+
text ' text'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should create paragraph tags' do
|
49
|
+
str = "This is a paragraph.\n\nThis is another."
|
50
|
+
|
51
|
+
expect_tree(str) do
|
52
|
+
tag('p') do
|
53
|
+
text 'This is a paragraph.'
|
54
|
+
end
|
55
|
+
tag('p') do
|
56
|
+
text 'This is another.'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should not put block-level elements inside paragraph tags' do
|
62
|
+
str = "This is a list:\n\n[list]\n\n[*]Foo[/i]\n\n[/list]\n\nwith some text after it"
|
63
|
+
|
64
|
+
expect_tree(str) do
|
65
|
+
tag('p') do
|
66
|
+
text 'This is a list:'
|
67
|
+
end
|
68
|
+
tag('list') do
|
69
|
+
tag('*') { text 'Foo' }
|
70
|
+
end
|
71
|
+
tag('p') do
|
72
|
+
text 'with some text after it'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should not insert br tags in the midst of block-level elements' do
|
78
|
+
str = "List:\n[list]\n[*]Foo[/*]\n[*]Bar[/*]\n[/list]\nText after list"
|
79
|
+
|
80
|
+
expect_tree(str) do
|
81
|
+
tag('p') do
|
82
|
+
text 'List:'
|
83
|
+
end
|
84
|
+
tag('list') do
|
85
|
+
tag('*') { text 'Foo' }
|
86
|
+
tag('*') { text 'Bar' }
|
87
|
+
end
|
88
|
+
tag('p') do
|
89
|
+
text 'Text after list'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should store tag values' do
|
95
|
+
str = 'This is a [url=http://google.com]link[/url]'
|
96
|
+
|
97
|
+
expect_tree(str) do
|
98
|
+
tag('p') do
|
99
|
+
text 'This is a '
|
100
|
+
tag('url', 'http://google.com') do
|
101
|
+
text 'link'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
metadata
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rbbcode
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jarrett Colby
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-09 00:00:00 -06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: RbbCode is a customizable Ruby library for parsing BB Code. RbbCode validates and cleans input. It supports customizable schemas so you can set rules about what tags are allowed where. The default rules are designed to ensure valid HTML output.
|
17
|
+
email: jarrett@jarrettcolby.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
has_rdoc: true
|
27
|
+
homepage: http://github.com/jarrett/rbbcode
|
28
|
+
licenses: []
|
29
|
+
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options:
|
32
|
+
- --charset=UTF-8
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: "0"
|
40
|
+
version:
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
requirements: []
|
48
|
+
|
49
|
+
rubyforge_project:
|
50
|
+
rubygems_version: 1.3.5
|
51
|
+
signing_key:
|
52
|
+
specification_version: 3
|
53
|
+
summary: Ruby BB Code parser
|
54
|
+
test_files:
|
55
|
+
- spec/html_maker_spec.rb
|
56
|
+
- spec/node_spec_helper.rb
|
57
|
+
- spec/parser_spec.rb
|
58
|
+
- spec/schema_spec.rb
|
59
|
+
- spec/spec_helper.rb
|
60
|
+
- spec/tree_maker_spec.rb
|