rbbcode 1.0.0 → 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,126 +1,286 @@
1
- class RbbCode
2
- module RecursiveConversion
3
- def recursively_convert(node, depth = 0)
4
- if node.terminal?
5
- if node.respond_to?(:to_html)
6
- node.to_html
7
- else
8
- node.text_value.match(/^[\r\n\t]+$/) ? '' : node.text_value
9
- end
10
- else
11
- if node.respond_to?(:to_html)
12
- node.to_html
13
- else
14
- node.elements.collect do |sub_node|
15
- recursively_convert(sub_node, depth + 1)
16
- end.join
17
- end
18
- end
19
- end
20
- end
21
-
22
- module DocumentNode
23
- def to_html
24
- contents.elements.collect { |p| p.to_html }.join
25
- end
26
- end
27
-
28
- module ParagraphNode
29
- include RecursiveConversion
30
-
31
- def to_html
32
- html = elements.collect do |node|
33
- recursively_convert(node)
34
- end.join
35
- "\n<p>" + html + "</p>\n"
36
- end
37
- end
38
-
39
- module BlockquoteNode
40
- include RecursiveConversion
41
-
42
- def to_html
43
- "\n<blockquote>" + recursively_convert(contents) + "</blockquote>\n"
44
- end
45
- end
46
-
47
- module ListNode
48
- include RecursiveConversion
49
-
50
- def to_html
51
- "\n<ul>" + recursively_convert(contents) + "</ul>\n"
52
- end
53
- end
54
-
55
- module ListItemNode
56
- include RecursiveConversion
57
-
58
- def to_html
59
- "\n<li>" + recursively_convert(contents) + "</li>\n"
60
- end
61
- end
62
-
63
- module URLTagNode
64
- def url_to_html
65
- if respond_to?(:url) and respond_to?(:text)
66
- # A URL tag formatted like [url=http://example.com]Example[/url]
67
- '<a href="' + url.text_value + '">' + text.text_value + '</a>'
68
- else
69
- # A URL tag formatted like [url]http://example.com[/url]
70
- '<a href="' + inner_bbcode + '">' + inner_bbcode + '</a>'
71
- end
72
- end
73
- end
74
-
75
- module ImgTagNode
76
- def img_to_html
77
- '<img src="' + inner_bbcode + '" alt="Image"/>'
78
- end
79
- end
80
-
81
- module TagNode
82
- include RecursiveConversion
83
-
84
- TAG_MAPPINGS = {'b' => 'strong', 'i' => 'em', 'u' => 'u', 'url' => URLTagNode, 'img' => ImgTagNode}
85
-
86
- def contents
87
- # The first element is the opening tag, the second is everything inside,
88
- # and the third is the closing tag.
89
- elements[1]
90
- end
91
-
92
- def tag_name
93
- elements.first.text_value.slice(1..-2).downcase
94
- end
95
-
96
- def inner_bbcode
97
- contents.elements.collect { |e| e.text_value }.join
98
- end
99
-
100
- def inner_html
101
- contents.elements.collect do |node|
102
- recursively_convert(node)
103
- end.join
104
- end
105
-
106
- def to_html
107
- t = TAG_MAPPINGS[tag_name]
108
- if t.nil?
109
- raise "No tag mapping found for #{tag_name}"
110
- elsif t.is_a?(Module)
111
- extend(t)
112
- send(tag_name + '_to_html')
113
- # Thus, if our tag_name is"url, and TAG_MAPPINGS points us to URLTagNode,
114
- # that module must define url_to_html.
115
- else
116
- "<#{t}>" + inner_html + "</#{t}>"
117
- end
118
- end
119
- end
120
-
121
- module SingleBreakNode
122
- def to_html
123
- '<br/>'
124
- end
125
- 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
126
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>)* 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],
4
- :attributes => {
5
- 'a' => %w[href],
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,88 +1,132 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: rbbcode
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 1.0.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
6
5
  platform: ruby
7
- authors:
6
+ authors:
8
7
  - Jarrett Colby
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
-
13
- date: 2012-10-27 00:00:00 -05:00
14
- default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
11
+ date: 2020-06-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
17
14
  name: treetop
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.5.3
20
+ type: :runtime
18
21
  prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
20
- none: false
21
- requirements:
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.5.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: sanitize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
22
31
  - - ">="
23
- - !ruby/object:Gem::Version
24
- version: "0"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
25
34
  type: :runtime
26
- version_requirements: *id001
27
- - !ruby/object:Gem::Dependency
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
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
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
28
70
  name: lorax
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 0.3.0.rc2
76
+ type: :development
29
77
  prerelease: false
30
- requirement: &id002 !ruby/object:Gem::Requirement
31
- none: false
32
- requirements:
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:
33
87
  - - ">="
34
- - !ruby/object:Gem::Version
35
- version: "0"
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
36
90
  type: :development
37
- version_requirements: *id002
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
38
97
  description: Converts BBCode to HTML. Gracefully handles invalid input.
39
98
  email: jarrett@madebyhq.com
40
99
  executables: []
41
-
42
100
  extensions: []
43
-
44
101
  extra_rdoc_files: []
45
-
46
- files:
102
+ files:
103
+ - lib/rbbcode.rb
47
104
  - lib/rbbcode/node_extensions.rb
48
105
  - lib/rbbcode/rbbcode_grammar.treetop
49
106
  - lib/rbbcode/sanitize.rb
50
- - lib/rbbcode.rb
51
- has_rdoc: true
52
107
  homepage: https://github.com/jarrett/rbbcode
53
108
  licenses: []
54
-
55
- post_install_message: "\n\
56
- Important notice for users of 0.1.11 or lower\n\
57
- =============================================\n\n\
58
- RbbCode has been updated! The new release (1.x.x)\n\
59
- is not compatible with the old one (0.1.11). If\n\
60
- you want to upgrade to 1.x.x, you'll need to\n\
61
- adjust any calls to RbbCode in your code to match\n\
62
- the new API. For more information:\n\n\
63
- https://github.com/jarrett/rbbcode\n"
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"
64
114
  rdoc_options: []
65
-
66
- require_paths:
115
+ require_paths:
67
116
  - lib
68
- required_ruby_version: !ruby/object:Gem::Requirement
69
- none: false
70
- requirements:
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
71
119
  - - ">="
72
- - !ruby/object:Gem::Version
73
- version: "0"
74
- required_rubygems_version: !ruby/object:Gem::Requirement
75
- none: false
76
- requirements:
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
77
124
  - - ">="
78
- - !ruby/object:Gem::Version
79
- version: "0"
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
80
127
  requirements: []
81
-
82
- rubyforge_project:
83
- rubygems_version: 1.6.2
128
+ rubygems_version: 3.1.2
84
129
  signing_key:
85
- specification_version: 3
130
+ specification_version: 4
86
131
  summary: RbbCode
87
132
  test_files: []
88
-