rbbcode 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 05a9ae1e74abb5b265316ce91cefd13b76e6f484040e37b10c7f39a86e44695f
4
+ data.tar.gz: 40a4650b699a0bd33dd35d285eb5f9ef2f3962b0628601be3702362495217bb7
5
+ SHA512:
6
+ metadata.gz: defb74848c8d0632853ea9e3437188a1411978e523079778f29cd73826b3544937e14a36dde7144329d96d2886ca7275afd214af3bf5c8ba9c34da246a628743
7
+ data.tar.gz: a67405feba360b5c719bb1b0f958d2187efe8b217eb52e2635b8b41f3fbc66cd47b3c83c48ea53cae18d63298260bb2e4cd1691e0026b9c0a70e1d631d433ced
@@ -1,50 +1,64 @@
1
- # Uncomment this when developing:
2
- #$:.unshift './lib'
3
-
4
- require 'erb'
5
- require 'rubygems'
6
- require 'treetop'
7
- require 'sanitize'
8
- require 'rbbcode/node_extensions'
9
- require 'rbbcode/sanitize'
10
-
11
- class RbbCode
12
- def self.parser_class
13
- if !@grammar_loaded
14
- Treetop.load_from_string(
15
- ERB.new(
16
- File.read(
17
- File.join(
18
- File.dirname(__FILE__),
19
- 'rbbcode/rbbcode_grammar.treetop'
20
- )
21
- )
22
- ).result
23
- )
24
- @grammar_loaded = true
25
- end
26
- RbbCodeGrammarParser
27
- end
28
-
29
- def initialize(options = {})
30
- @options = {
31
- :sanitize => true,
32
- :sanitize_config => RbbCode::DEFAULT_SANITIZE_CONFIG
33
- }.merge(options)
34
- end
35
-
36
- def convert(bb_code)
37
- html = self.class.parser_class.new.parse("\n\n" + bb_code + "\n\n").to_html
38
- if @options[:emoticons]
39
- @options[:emoticons].each do |emoticon, url|
40
- html.gsub!(emoticon, '<img src="' + url + '" alt="Emoticon"/>')
41
- end
42
- end
43
- html
44
- if @options[:sanitize]
45
- Sanitize.clean(html, @options[:sanitize_config])
46
- else
47
- html
48
- end
49
- end
1
+ # Uncomment this when developing:
2
+ #$:.unshift './lib'
3
+
4
+ require 'erb'
5
+ require 'rubygems'
6
+ require 'treetop'
7
+ require 'sanitize'
8
+ require 'rbbcode/node_extensions'
9
+ require 'rbbcode/sanitize'
10
+
11
+ class RbbCode
12
+ def self.parser_class
13
+ if !instance_variable_defined?(:@grammar_loaded) or !@grammar_loaded
14
+ Treetop.load_from_string(
15
+ ERB.new(
16
+ File.read(
17
+ File.join(
18
+ File.dirname(__FILE__),
19
+ 'rbbcode/rbbcode_grammar.treetop'
20
+ )
21
+ )
22
+ ).result
23
+ )
24
+ @grammar_loaded = true
25
+ end
26
+ RbbCodeGrammarParser
27
+ end
28
+
29
+ def initialize(options = {})
30
+ @options = {
31
+ :output_format => :html,
32
+ :sanitize => true,
33
+ :sanitize_config => RbbCode::DEFAULT_SANITIZE_CONFIG
34
+ }.merge(options)
35
+ end
36
+
37
+ def convert(bb_code)
38
+ # Collapse CRLFs to LFs. Then replace any solitary CRs with LFs.
39
+ bb_code = bb_code.gsub("\r\n", "\n").gsub("\r", "\n")
40
+ # Add linebreaks before and after so that paragraphs etc. can be recognized.
41
+ bb_code = "\n\n" + bb_code + "\n\n"
42
+ output = self.class.parser_class.new.parse(bb_code).send("to_#{@options[:output_format]}")
43
+ if @options[:emoticons]
44
+ output = convert_emoticons(output)
45
+ end
46
+ # Sanitization works for HTML only.
47
+ if @options[:output_format] == :html and @options[:sanitize]
48
+ Sanitize.clean(output, @options[:sanitize_config])
49
+ else
50
+ output
51
+ end
52
+ end
53
+
54
+ def convert_emoticons(output)
55
+ @options[:emoticons].each do |emoticon, url|
56
+ output.gsub!(emoticon, '<img src="' + url + '" alt="Emoticon"/>')
57
+ end
58
+ output
59
+ end
60
+
61
+ def output_format
62
+ @options[:output_format]
63
+ end
50
64
  end
@@ -1,141 +1,286 @@
1
- class RbbCode
2
- module Attributes
3
- # Strips any number of double quotes from the beginning and end of the string
4
- def strip_quotes(str)
5
- str.sub(/^"+/, '').sub(/"+$/, '')
6
- end
7
- end
8
-
9
- module RecursiveConversion
10
- def recursively_convert(node, depth = 0)
11
- if node.terminal?
12
- if node.respond_to?(:to_html)
13
- node.to_html
14
- else
15
- node.text_value.match(/^[\r\n\t]+$/) ? '' : node.text_value
16
- end
17
- else
18
- if node.respond_to?(:to_html)
19
- node.to_html
20
- else
21
- node.elements.collect do |sub_node|
22
- recursively_convert(sub_node, depth + 1)
23
- end.join
24
- end
25
- end
26
- end
27
- end
28
-
29
- module DocumentNode
30
- def to_html
31
- contents.elements.collect { |p| p.to_html }.join
32
- end
33
- end
34
-
35
- module ParagraphNode
36
- include RecursiveConversion
37
-
38
- def to_html
39
- html = elements.collect do |node|
40
- recursively_convert(node)
41
- end.join
42
- "\n<p>" + html + "</p>\n"
43
- end
44
- end
45
-
46
- module BlockquoteNode
47
- include RecursiveConversion
48
-
49
- def to_html
50
- "\n<blockquote>" + recursively_convert(contents) + "</blockquote>\n"
51
- end
52
- end
53
-
54
- module ListNode
55
- include RecursiveConversion
56
-
57
- def to_html
58
- "\n<ul>" + recursively_convert(contents) + "</ul>\n"
59
- end
60
- end
61
-
62
- module ListItemNode
63
- include RecursiveConversion
64
-
65
- def to_html
66
- "\n<li>" + recursively_convert(contents) + "</li>\n"
67
- end
68
- end
69
-
70
- module URLTagNode
71
- include Attributes
72
-
73
- def url_to_html
74
- if respond_to?(:url) and respond_to?(:text)
75
- # A URL tag formatted like [url=http://example.com]Example[/url]
76
- '<a href="' + strip_quotes(url.text_value) + '">' + text.text_value + '</a>'
77
- else
78
- # A URL tag formatted like [url]http://example.com[/url]
79
- '<a href="' + inner_bbcode + '">' + inner_bbcode + '</a>'
80
- end
81
- end
82
- end
83
-
84
- module ImgTagNode
85
- def img_to_html
86
- '<img src="' + inner_bbcode + '" alt="Image"/>'
87
- end
88
- end
89
-
90
- module TagNode
91
- include RecursiveConversion
92
-
93
- TAG_MAPPINGS = {'b' => 'strong', 'i' => 'em', 'u' => 'u', 'url' => URLTagNode, 'img' => ImgTagNode}
94
-
95
- def contents
96
- # The first element is the opening tag, the second is everything inside,
97
- # and the third is the closing tag.
98
- elements[1]
99
- end
100
-
101
- def tag_name
102
- elements.first.text_value.slice(1..-2).downcase
103
- end
104
-
105
- def inner_bbcode
106
- contents.elements.collect { |e| e.text_value }.join
107
- end
108
-
109
- def inner_html
110
- contents.elements.collect do |node|
111
- recursively_convert(node)
112
- end.join
113
- end
114
-
115
- def to_html
116
- t = TAG_MAPPINGS[tag_name]
117
- if t.nil?
118
- raise "No tag mapping found for #{tag_name}"
119
- elsif t.is_a?(Module)
120
- extend(t)
121
- send(tag_name + '_to_html')
122
- # Thus, if our tag_name is"url, and TAG_MAPPINGS points us to URLTagNode,
123
- # that module must define url_to_html.
124
- else
125
- "<#{t}>" + inner_html + "</#{t}>"
126
- end
127
- end
128
- end
129
-
130
- module SingleBreakNode
131
- def to_html
132
- '<br/>'
133
- end
134
- end
135
-
136
- module LiteralTextNode
137
- def to_html
138
- text_value
139
- end
140
- end
1
+ class RbbCode
2
+ module Attributes
3
+ # Strips any number of double quotes from the beginning and end of the string.
4
+ def strip_quotes(str)
5
+ str.sub(/^"+/, '').sub(/"+$/, '')
6
+ end
7
+ end
8
+
9
+ module RecursiveConversion
10
+ def recursively_convert(node, output_method, depth = 0)
11
+ if node.terminal?
12
+ if node.respond_to?(output_method)
13
+ # This is a terminal node with a custom implementation of the output
14
+ # method (e.g. #to_html).
15
+ node.send(output_method)
16
+ else
17
+ # This is a terminal node without a custom implementation of the
18
+ # output method. If the node consists solely of whitespace, emit the
19
+ # empty string. Otherwise, emit the node's text value.
20
+ node.text_value.match(/\A[\n\t]+\Z/) ? '' : node.text_value
21
+ end
22
+ else
23
+ if node.respond_to?(output_method)
24
+ # This is a non-terminal node with a custom implementation of the
25
+ # output method.
26
+ node.send(output_method)
27
+ else
28
+ # This is a non-terminal node without a custom implementation of the
29
+ # output method. Convert all its child nodes and concatenate the results.
30
+ node.elements.collect do |sub_node|
31
+ recursively_convert(sub_node, output_method, depth + 1)
32
+ end.join
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ module DocumentNode
39
+ def to_html
40
+ contents.elements.collect { |p| p.to_html }.join
41
+ end
42
+
43
+ def to_markdown
44
+ contents.elements.collect { |p| p.to_markdown }.join
45
+ end
46
+ end
47
+
48
+ module ParagraphNode
49
+ include RecursiveConversion
50
+
51
+ def to_html
52
+ # Convert all child nodes, concatenate the results,
53
+ # and wrap the concatenated HTML in <p> tags.
54
+ html = elements.collect do |node|
55
+ recursively_convert(node, :to_html)
56
+ end.join
57
+ "\n<p>" + html + "</p>\n"
58
+ end
59
+
60
+ def to_markdown
61
+ # Convert all child nodes, concatenate the results,
62
+ # and append newline characters.
63
+ markdown = elements.collect do |node|
64
+ recursively_convert(node, :to_markdown)
65
+ end.join
66
+ markdown + "\n\n"
67
+ end
68
+ end
69
+
70
+ module BlockquoteNode
71
+ include RecursiveConversion
72
+
73
+ def to_html
74
+ # Detect paragraph breaks and wrap the result in <blockquote> tags.
75
+ paragraphs = []
76
+ cur_para = ''
77
+ lines.elements.each do |line|
78
+ inner = recursively_convert(line, :to_html)
79
+ unless inner.blank?
80
+ cur_para << inner
81
+ if line.post_breaks == 1
82
+ cur_para << ' '
83
+ elsif line.post_breaks >= 2
84
+ paragraphs << cur_para
85
+ cur_para = ''
86
+ end
87
+ end
88
+ end
89
+ unless cur_para.blank?
90
+ paragraphs << cur_para
91
+ end
92
+ inner = paragraphs.map { |str| "<p>#{str}</p>" }.join("\n")
93
+ "\n<blockquote>" + inner + "</blockquote>\n"
94
+ end
95
+
96
+ def to_markdown
97
+ # Add a > character per line, preserving linebreaks as they are in the source.
98
+ # Then append two newlines.
99
+ '> ' + lines.elements.inject('') do |output, line|
100
+ inner_markdown = recursively_convert(line.contents, :to_markdown)
101
+ output + inner_markdown + ("\n> " * line.post_breaks)
102
+ end + "\n\n"
103
+ end
104
+ end
105
+
106
+ module BlockquoteLineNode
107
+ # Returns the number of line breaks after this line. May be zero for the final
108
+ # line, since there doesn't have to be a break before [/quote].
109
+ def post_breaks
110
+ breaks.elements.length
111
+ end
112
+ end
113
+
114
+ module ListNode
115
+ include RecursiveConversion
116
+
117
+ def to_html
118
+ # Convert the :contents child node (defined in the .treetop file)
119
+ # and wrap the result in <ul> tags.
120
+ "\n<ul>" + recursively_convert(items, :to_html) + "</ul>\n"
121
+ end
122
+
123
+ def to_markdown
124
+ # Convert the :contents child node (defined in the .treetop file).
125
+ # (Unlike with HTML, no outer markup needed.) Then append an extra
126
+ # newline, for a total of two at the end.
127
+ recursively_convert(items, :to_markdown) + "\n"
128
+ end
129
+ end
130
+
131
+ module ListItemNode
132
+ include RecursiveConversion
133
+
134
+ def to_html
135
+ # Convert the :contents child node (defined in the .treetop file)
136
+ # and wrap the result in <li> tags.
137
+ "\n<li>" + recursively_convert(contents, :to_html) + "</li>\n"
138
+ end
139
+
140
+ def to_markdown
141
+ # Convert the :contents child node (defined in the .treetop file)
142
+ # and add * characters.
143
+ "* " + recursively_convert(contents, :to_html) + "\n"
144
+ end
145
+ end
146
+
147
+ # You won't find this module in the .treetop file. Instead, it's effectively a specialization
148
+ # of TagNode, which calls to ImgTagNode when processing an img tag. (However, one of the
149
+ # child nodes used here, :url, is indeed defined in the .treetop file.)
150
+ module URLTagNode
151
+ include Attributes
152
+
153
+ def url_to_html
154
+ # The :url child node (defined in the .treetop file) may or may not exist,
155
+ # depending on how the link is formatted in the BBCode source.
156
+ if respond_to?(:url) and respond_to?(:text)
157
+ # This is a URL tag formatted like [url=http://example.com]Example[/url].
158
+ '<a href="' + strip_quotes(url.text_value) + '">' + text.text_value + '</a>'
159
+ else
160
+ # This is a URL tag formatted like [url]http://example.com[/url].
161
+ '<a href="' + inner_bbcode + '">' + inner_bbcode + '</a>'
162
+ end
163
+ end
164
+
165
+ def url_to_markdown
166
+ if respond_to?(:url) and respond_to?(:text)
167
+ # This is a URL tag formatted like [url=http://example.com]Example[/url].
168
+ '[' + text.text_value + '](' + strip_quotes(url.text_value) + ')'
169
+ else
170
+ # This is a URL tag formatted like [url]http://example.com[/url].
171
+ '[' + inner_bbcode + '](' + inner_bbcode + ')'
172
+ end
173
+ end
174
+ end
175
+
176
+ # You won't find this module in the .treetop file. Instead, it's effectively a specialization
177
+ # of TagNode, which calls to ImgTagNode when processing an img tag.
178
+ module ImgTagNode
179
+ def img_to_html
180
+ '<img src="' + inner_bbcode + '" alt="Image"/>'
181
+ end
182
+
183
+ def img_to_markdown
184
+ "![Image](#{inner_bbcode})"
185
+ end
186
+ end
187
+
188
+ module UTagNode
189
+ def u_to_markdown
190
+ # Underlining is unsupported in Markdown. So we just ignore [u] tags.
191
+ inner_bbcode
192
+ end
193
+ end
194
+
195
+ module TagNode
196
+ include RecursiveConversion
197
+
198
+ # For each tag name, we can either: (a) map to a simple HTML tag or Markdown character, or
199
+ # (b) invoke a separate Ruby module for more advanced logic.
200
+ TAG_MAPPINGS = {
201
+ html: {'b' => 'strong', 'i' => 'em', 'u' => 'u', 'url' => URLTagNode, 'img' => ImgTagNode},
202
+ markdown: {'b' => '**', 'i' => '*', 'u' => UTagNode, 'url' => URLTagNode, 'img' => ImgTagNode}
203
+ }
204
+
205
+ def contents
206
+ # The first element is the opening tag, the second is everything inside,
207
+ # and the third is the closing tag.
208
+ elements[1]
209
+ end
210
+
211
+ def tag_name
212
+ elements.first.text_value.slice(1..-2).downcase
213
+ end
214
+
215
+ def inner_bbcode
216
+ contents.elements.collect { |e| e.text_value }.join
217
+ end
218
+
219
+ def inner_html
220
+ contents.elements.collect do |node|
221
+ recursively_convert(node, :to_html)
222
+ end.join
223
+ end
224
+
225
+ def inner_markdown
226
+ contents.elements.collect do |node|
227
+ recursively_convert(node, :to_markdown)
228
+ end.join
229
+ end
230
+
231
+ def wrap_html(t)
232
+ "<#{t}>" + inner_html + "</#{t}>"
233
+ end
234
+
235
+ def wrap_markdown(t)
236
+ t + inner_markdown + t
237
+ end
238
+
239
+ def convert(output_format)
240
+ # Consult TAG_MAPPINGS to decide how to process this type of tag.
241
+ t = TAG_MAPPINGS[output_format][tag_name]
242
+ if t.nil?
243
+ raise "No tag mapping found for #{tag_name}"
244
+ elsif t.is_a?(Module)
245
+ # This type of tag requires more than just a simple mapping from one tag name
246
+ # to another. So we invoke a separate Ruby module.
247
+ extend(t)
248
+ send("#{tag_name}_to_#{output_format}")
249
+ # Thus, if our tag_name is"url, and TAG_MAPPINGS points us to URLTagNode,
250
+ # that module must define url_to_html.
251
+ else
252
+ # For this type of tag, a simple mapping from the tag name to a string (such as
253
+ # <i>) suffices.
254
+ send("wrap_#{output_format}", t)
255
+ end
256
+ end
257
+
258
+ def to_html
259
+ convert :html
260
+ end
261
+
262
+ def to_markdown
263
+ convert :markdown
264
+ end
265
+ end
266
+
267
+ module SingleBreakNode
268
+ def to_html
269
+ '<br/>'
270
+ end
271
+
272
+ def to_markdown
273
+ "\n"
274
+ end
275
+ end
276
+
277
+ module LiteralTextNode
278
+ def to_html
279
+ text_value
280
+ end
281
+
282
+ def to_markdown
283
+ text_value
284
+ end
285
+ end
141
286
  end
@@ -1,113 +1,110 @@
1
- <%
2
- def def_tag(rule_name, tag_name)
3
- "
4
- rule #{rule_name}
5
- ('[#{tag_name.downcase}]'/'[#{tag_name.upcase}]')
6
- (!'[/#{tag_name.downcase}]' !'[/#{tag_name.upcase}]'
7
- (tag <RbbCode::TagNode> / .))+
8
- ('[/#{tag_name.downcase}]' / '[/#{tag_name.upcase}]')
9
- end
10
- "
11
- end
12
- %>
13
-
14
- grammar RbbCodeGrammar
15
- rule document
16
- # Consume the trailing linebreaks, because the paragraph lookahead
17
- # doesn't consume them.
18
- contents:(blockquote <RbbCode::BlockquoteNode> / list <RbbCode::ListNode> / paragraph <RbbCode::ParagraphNode> / . <RbbCode::LiteralTextNode>)* break_ws* <RbbCode::DocumentNode>
19
- end
20
-
21
- rule paragraph
22
- (break_ws 2..)
23
- (
24
- !(break_ws 2..)
25
- paragraph_contents
26
- )+
27
- end
28
-
29
- rule paragraph_contents
30
- (tag <RbbCode::TagNode> / single_break_ws / .)
31
- end
32
-
33
- rule break_ws
34
- # Allow whitespace around the linebreaks
35
- [ \t]* [\r\n] [ \t]*
36
- end
37
-
38
- rule whitespace
39
- # Any whitespace, including linebreaks
40
- [ \t\r\n]
41
- end
42
-
43
- rule single_break_ws
44
- # We don't count linebreaks when they're immediately followed by
45
- # certain keywords. This avoids printing an extra <br/> in some cases.
46
- break_ws !break_ws !(break_ws* ('[/quote]' / '[*]' / '[/list]')) <RbbCode::SingleBreakNode>
47
- end
48
-
49
- rule blockquote
50
- break_ws*
51
- '[quote]'
52
- contents:(
53
- # Possible linebreaks after opening quote tag
54
- break_ws*
55
-
56
- # First paragraph (mandatory)
57
- (blockquote_paragraph <RbbCode::ParagraphNode>)
58
-
59
- # Subsequent paragraphs (optional)
60
- (
61
- (break_ws 2..)
62
- (blockquote_paragraph <RbbCode::ParagraphNode>)
63
- )*
64
-
65
- # Possible linebreaks before closing quote tag
66
- break_ws*
67
- )
68
- '[/quote]'
69
- end
70
-
71
- rule blockquote_paragraph
72
- (!('[/quote]' / (break_ws 2..)) paragraph_contents)+
73
- end
74
-
75
- rule list
76
- break_ws*
77
- '[list]'
78
- contents:(
79
- # Possible linebreaks after opening list tag
80
- whitespace*
81
-
82
- # At least one list item
83
- (
84
- (
85
- '[*]'
86
- contents:(!'[/list]' !'[*]' paragraph_contents)*
87
- <RbbCode::ListItemNode>
88
- )
89
- )+
90
-
91
- # Possible linebreaks before closing list tag
92
- whitespace*
93
- )
94
- '[/list]'
95
- end
96
-
97
- rule tag
98
- # Make sure that anytime you call def_tag, you add it to this list:
99
- bold / italic / underline / simple_url / complex_url / img
100
- end
101
-
102
- <%= def_tag 'bold', 'b' %>
103
- <%= def_tag 'italic', 'i' %>
104
- <%= def_tag 'underline', 'u' %>
105
- <%= def_tag 'simple_url', 'url' %>
106
- <%= def_tag 'img', 'img' %>
107
-
108
- rule complex_url
109
- '[url=' url:[^\]]+ ']'
110
- text:(!'[/url]' .)+
111
- '[/url]'
112
- end
1
+ <%
2
+ def def_tag(rule_name, tag_name)
3
+ "
4
+ rule #{rule_name}
5
+ # Opening tag
6
+ (
7
+ '[#{tag_name.downcase}]' /
8
+ '[#{tag_name.upcase}]'
9
+ )
10
+ # Inner BBCode (which may include nested tags)
11
+ (
12
+ !'[/#{tag_name.downcase}]'
13
+ !'[/#{tag_name.upcase}]'
14
+ (tag / .)
15
+ )+
16
+ # Closing tag
17
+ (
18
+ '[/#{tag_name.downcase}]' /
19
+ '[/#{tag_name.upcase}]'
20
+ )
21
+ end
22
+ "
23
+ end
24
+ %>
25
+
26
+ grammar RbbCodeGrammar
27
+ rule document
28
+ contents:(blockquote / list / paragraph / literal_text)*
29
+ break_ws*
30
+ <RbbCode::DocumentNode>
31
+ end
32
+
33
+ rule literal_text
34
+ [^\n]+ <RbbCode::LiteralTextNode>
35
+ end
36
+
37
+ rule paragraph
38
+ (break_ws 2..)
39
+ (
40
+ !(break_ws 2..)
41
+ (tag / single_break_ws / .)
42
+ )+
43
+ <RbbCode::ParagraphNode>
44
+ end
45
+
46
+ rule break_ws
47
+ # A linebreak, possibly surrounded by whitespace
48
+ [ \t]* "\n" [ \t]*
49
+ end
50
+
51
+ rule single_break_ws
52
+ # We don't count linebreaks when they're immediately followed by
53
+ # certain keywords. This avoids printing an extra <br/> in some cases.
54
+ break_ws !break_ws !(break_ws* ('[/quote]' / '[*]' / '[/list]')) <RbbCode::SingleBreakNode>
55
+ end
56
+
57
+ rule blockquote
58
+ break_ws*
59
+ '[quote]'
60
+ "\n"*
61
+ lines:blockquote_line*
62
+ '[/quote]'
63
+ <RbbCode::BlockquoteNode>
64
+ end
65
+
66
+ rule blockquote_line
67
+ contents:(!('[/quote]' / "\n") (tag / .))+
68
+ [ \t]*
69
+ breaks:break_ws*
70
+ <RbbCode::BlockquoteLineNode>
71
+ end
72
+
73
+ rule list
74
+ break_ws*
75
+ '[list]'
76
+ [ \t\n]*
77
+ items:list_item*
78
+ [ \t\n]*
79
+ '[/list]'
80
+ <RbbCode::ListNode>
81
+ end
82
+
83
+ rule list_item
84
+ '[*]'
85
+ [ \t]*
86
+ contents:(
87
+ !'[/list]' !'[*]'
88
+ (tag / single_break_ws / .)
89
+ )*
90
+ <RbbCode::ListItemNode>
91
+ end
92
+
93
+ rule tag
94
+ # Make sure that anytime you call def_tag, you add it to this list:
95
+ (bold / italic / underline / simple_url / complex_url / img)
96
+ <RbbCode::TagNode>
97
+ end
98
+
99
+ <%= def_tag 'bold', 'b' %>
100
+ <%= def_tag 'italic', 'i' %>
101
+ <%= def_tag 'underline', 'u' %>
102
+ <%= def_tag 'simple_url', 'url' %>
103
+ <%= def_tag 'img', 'img' %>
104
+
105
+ rule complex_url
106
+ '[url=' url:[^\]]+ ']'
107
+ text:(!'[/url]' .)+
108
+ '[/url]'
109
+ end
113
110
  end
@@ -1,13 +1,13 @@
1
- class RbbCode
2
- DEFAULT_SANITIZE_CONFIG = {
3
- :elements => %w[a blockquote br code del em img li p pre strong ul u],
4
- :attributes => {
5
- 'a' => %w[href target],
6
- 'img' => %w[alt src]
7
- },
8
-
9
- :protocols => {
10
- 'a' => {'href' => ['ftp', 'http', 'https', 'mailto', :relative]}
11
- }
12
- }
1
+ class RbbCode
2
+ DEFAULT_SANITIZE_CONFIG = {
3
+ :elements => %w[a blockquote br code del em img li p pre strong ul u],
4
+ :attributes => {
5
+ 'a' => %w[href target],
6
+ 'img' => %w[alt src]
7
+ },
8
+
9
+ :protocols => {
10
+ 'a' => {'href' => ['ftp', 'http', 'https', 'mailto', :relative]}
11
+ }
12
+ }
13
13
  end
metadata CHANGED
@@ -1,62 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbbcode
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
5
- prerelease:
4
+ version: 1.1.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jarrett Colby
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-10-27 00:00:00.000000000 Z
11
+ date: 2020-06-20 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: treetop
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '='
20
18
  - !ruby/object:Gem::Version
21
- version: '0'
19
+ version: 1.5.3
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '='
28
25
  - !ruby/object:Gem::Version
29
- version: '0'
26
+ version: 1.5.3
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: sanitize
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest-reporters
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
44
67
  - !ruby/object:Gem::Version
45
68
  version: '0'
46
69
  - !ruby/object:Gem::Dependency
47
70
  name: lorax
48
71
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
72
  requirements:
51
- - - ! '>='
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 0.3.0.rc2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.3.0.rc2
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
52
88
  - !ruby/object:Gem::Version
53
89
  version: '0'
54
90
  type: :development
55
91
  prerelease: false
56
92
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
93
  requirements:
59
- - - ! '>='
94
+ - - ">="
60
95
  - !ruby/object:Gem::Version
61
96
  version: '0'
62
97
  description: Converts BBCode to HTML. Gracefully handles invalid input.
@@ -65,52 +100,33 @@ executables: []
65
100
  extensions: []
66
101
  extra_rdoc_files: []
67
102
  files:
103
+ - lib/rbbcode.rb
68
104
  - lib/rbbcode/node_extensions.rb
69
105
  - lib/rbbcode/rbbcode_grammar.treetop
70
106
  - lib/rbbcode/sanitize.rb
71
- - lib/rbbcode.rb
72
107
  homepage: https://github.com/jarrett/rbbcode
73
108
  licenses: []
74
- post_install_message: ! '
75
-
76
- Important notice for users of 0.1.11 or lower
77
-
78
- =============================================
79
-
80
-
81
- RbbCode has been updated! The new release (1.x.x)
82
-
83
- is not compatible with the old one (0.1.11). If
84
-
85
- you want to upgrade to 1.x.x, you''ll need to
86
-
87
- adjust any calls to RbbCode in your code to match
88
-
89
- the new API. For more information:
90
-
91
-
92
- https://github.com/jarrett/rbbcode
93
-
94
- '
109
+ metadata: {}
110
+ post_install_message: "\r\nImportant notice for users of 0.1.11 or lower\r\n=============================================\r\n\r\nRbbCode
111
+ has been updated! The new release (1.x.x)\r\nis not compatible with the old one
112
+ (0.1.11). If\r\nyou want to upgrade to 1.x.x, you'll need to\r\nadjust any calls
113
+ to RbbCode in your code to match\r\nthe new API. For more information:\r\n\r\nhttps://github.com/jarrett/rbbcode\r\n"
95
114
  rdoc_options: []
96
115
  require_paths:
97
116
  - lib
98
117
  required_ruby_version: !ruby/object:Gem::Requirement
99
- none: false
100
118
  requirements:
101
- - - ! '>='
119
+ - - ">="
102
120
  - !ruby/object:Gem::Version
103
121
  version: '0'
104
122
  required_rubygems_version: !ruby/object:Gem::Requirement
105
- none: false
106
123
  requirements:
107
- - - ! '>='
124
+ - - ">="
108
125
  - !ruby/object:Gem::Version
109
126
  version: '0'
110
127
  requirements: []
111
- rubyforge_project:
112
- rubygems_version: 1.8.25
128
+ rubygems_version: 3.1.2
113
129
  signing_key:
114
- specification_version: 3
130
+ specification_version: 4
115
131
  summary: RbbCode
116
132
  test_files: []