rbbcode 0.1.11 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile DELETED
@@ -1,35 +0,0 @@
1
- require 'rubygems'
2
- require 'bundler'
3
- begin
4
- Bundler.setup(:default, :development)
5
- rescue Bundler::BundlerError => e
6
- $stderr.puts e.message
7
- $stderr.puts "Run `bundle install` to install missing gems"
8
- exit e.status_code
9
- end
10
- require 'rake'
11
-
12
- require 'jeweler'
13
-
14
- Jeweler::Tasks.new do |gem|
15
- gem.name = 'rbbcode'
16
- gem.homepage = "http://github.com/jarrett/rbbcode"
17
- gem.license = "MIT"
18
- gem.summary = 'Ruby BB Code parser'
19
- gem.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.'
20
- gem.email = "jarrett@jarrettcolby.com, aq1018@gmail.com"
21
- gem.authors = ['Jarrett Colby', "aq1018@gmail.com"]
22
- end
23
- Jeweler::RubygemsDotOrgTasks.new
24
-
25
- require 'rspec/core'
26
- require 'rspec/core/rake_task'
27
- RSpec::Core::RakeTask.new(:spec) do |spec|
28
- spec.pattern = FileList['spec/**/*_spec.rb']
29
- spec.rspec_opts = "--color --format progress"
30
- end
31
-
32
- task :default => :spec
33
-
34
- require 'yard'
35
- YARD::Rake::YardocTask.new
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.1.11
@@ -1,90 +0,0 @@
1
- require 'cgi'
2
- require 'sanitize-url'
3
-
4
- module RbbCode
5
- DEFAULT_TAG_MAPPINGS = {
6
- 'p' => 'p',
7
- 'br' => 'br',
8
- 'b' => 'strong',
9
- 'i' => 'em',
10
- 'u' => 'u',
11
- 'code' => 'code',
12
- 'quote' => 'blockquote',
13
- 'list' => 'ul',
14
- '*' => 'li'
15
- }
16
-
17
- class HtmlMaker
18
- include SanitizeUrl
19
-
20
- def make_html(node)
21
- output = ''
22
- case node
23
- when RbbCode::RootNode
24
- node.children.each do |child|
25
- output << make_html(child)
26
- end
27
- when RbbCode::TagNode
28
- custom_tag_method = "html_from_#{node.tag_name}_tag"
29
- if respond_to?(custom_tag_method)
30
- output << send(custom_tag_method, node)
31
- else
32
- inner_html = ''
33
- node.children.each do |child|
34
- inner_html << make_html(child)
35
- end
36
- to_append = content_tag(map_tag_name(node.tag_name), inner_html)
37
- if node.preformatted?
38
- to_append = content_tag('pre', to_append)
39
- end
40
- output << to_append
41
- #puts output
42
- end
43
- when RbbCode::TextNode
44
- output << node.text
45
- else
46
- raise "Don't know how to make HTML from #{node.class}"
47
- end
48
- output
49
- end
50
-
51
- protected
52
-
53
- def content_tag(tag_name, contents, attributes = {})
54
- output = "<#{tag_name}"
55
- attributes.each do |attr, value|
56
- output << " #{attr}=\"#{value}\""
57
- end
58
- if contents.nil? or contents.empty? and not tag_name == 'code'
59
- output << '/>'
60
- else
61
- output << ">#{contents}</#{tag_name}>"
62
- end
63
- end
64
-
65
- def html_from_img_tag(node)
66
- src = sanitize_url(node.inner_bb_code)
67
- content_tag('img', nil, {'src' => src, 'alt' => ''})
68
- end
69
-
70
- def html_from_url_tag(node)
71
- if node.value.nil?
72
- url = node.inner_bb_code
73
- else
74
- url = node.value
75
- end
76
- url = sanitize_url(url)
77
- inner_html = node.children.inject('') do |output, child|
78
- output + make_html(child)
79
- end
80
- content_tag('a', inner_html, {'href' => url})
81
- end
82
-
83
- def map_tag_name(tag_name)
84
- unless DEFAULT_TAG_MAPPINGS.has_key?(tag_name)
85
- raise "No tag mapping for '#{tag_name}'"
86
- end
87
- DEFAULT_TAG_MAPPINGS[tag_name]
88
- end
89
- end
90
- end
@@ -1,32 +0,0 @@
1
- module RbbCode
2
- class Parser
3
- def initialize(config = {})
4
- config.each_key do |key|
5
- raise(ArgumentError, "Unknown option #{key}") unless known_options.include?(key)
6
- end
7
- @config = config
8
- end
9
-
10
- def parse(str)
11
- str = escape_html_tags(str)
12
-
13
- schema = @config[:schema] || RbbCode::Schema.new
14
-
15
- tree_maker = @config[:tree_maker] || RbbCode::TreeMaker.new(schema)
16
- tree = tree_maker.make_tree(str)
17
-
18
- html_maker = @config[:html_maker] || RbbCode::HtmlMaker.new
19
- html_maker.make_html(tree)
20
- end
21
-
22
- protected
23
-
24
- def escape_html_tags(str)
25
- str.gsub('<', '&lt;').gsub('>', '&gt;')
26
- end
27
-
28
- def known_options
29
- [:schema, :tree_maker, :html_maker]
30
- end
31
- end
32
- end
@@ -1,309 +0,0 @@
1
- module RbbCode
2
- DEFAULT_ALLOWED_TAGS = [
3
- 'p',
4
- 'br',
5
- 'b',
6
- 'i',
7
- 'u',
8
- 'url',
9
- 'img',
10
- 'code',
11
- 'quote',
12
- 'list',
13
- '*'
14
- ]
15
-
16
- DEFAULT_BLOCK_LEVEL_ELEMENTS = [
17
- 'quote',
18
- 'list',
19
- '*'
20
- ]
21
-
22
- class SchemaNode
23
- def initialize(schema)
24
- @schema = schema
25
- end
26
-
27
- protected
28
-
29
- def normalize_ancestors(ancestors)
30
- if ancestors.length == 1 and ancestors[0].is_a?(Array)
31
- ancestors = ancestors[0]
32
- end
33
- ancestors
34
- end
35
- end
36
-
37
- class SchemaTag < SchemaNode
38
- def closes_twins
39
- @schema.close_twins(@name)
40
- self
41
- end
42
-
43
- def does_not_close_twins
44
- @schema.dont_close_twins(@name)
45
- self
46
- end
47
-
48
- def initialize(schema, name)
49
- @schema = schema
50
- @name = name
51
- end
52
-
53
- def is_not_preformatted
54
- @schema.unmark_as_preformatted(@name)
55
- self
56
- end
57
-
58
- def is_preformatted
59
- @schema.mark_as_preformatted(@name)
60
- self
61
- end
62
-
63
- def may_be_nested
64
- @schema.allow_descent(@name, @name)
65
- self
66
- end
67
-
68
- def may_contain_text
69
- @schema.allow_text(@name)
70
- self
71
- end
72
-
73
- def may_not_be_empty
74
- @schema.forbid_emptiness(@name)
75
- end
76
-
77
- def may_not_be_nested
78
- @schema.forbid_descent(@name, @name)
79
- self
80
- end
81
-
82
- def may_descend_from(tag_name)
83
- @schema.allow_descent(tag_name, @name)
84
- self
85
- end
86
-
87
- def may_only_be_parent_of(*tag_names)
88
- @schema.forbid_children_except(@name, tag_names)
89
- self
90
- end
91
-
92
- def may_not_contain_text
93
- @schema.forbid_text(@name)
94
- self
95
- end
96
-
97
- def may_not_descend_from(tag_name)
98
- @schema.forbid_descent(tag_name, @name)
99
- self
100
- end
101
-
102
- def must_be_child_of(*tag_names)
103
- @schema.require_parents(tag_names, @name)
104
- self
105
- end
106
-
107
- def must_be_empty
108
- @schema.forbid_children_except(@name, [])
109
- may_not_contain_text
110
- self
111
- end
112
-
113
- def need_not_be_child_of(tag_name)
114
- @schema.unrequire_parent(tag_name, @name)
115
- self
116
- end
117
-
118
- # Returns true if tag_name is valid in the context defined by its list of ancestors.
119
- # ancestors should be ordered from most recent ancestor to most distant.
120
- def valid_in_context?(*ancestors)
121
- @schema.tag_valid_in_context?(@name, normalize_ancestors(ancestors))
122
- end
123
- end
124
-
125
- class SchemaText < SchemaNode
126
- def valid_in_context?(*ancestors)
127
- @schema.text_valid_in_context?(normalize_ancestors(ancestors))
128
- end
129
- end
130
-
131
- class Schema
132
- def allow_descent(ancestor, descendant) #:nodoc:
133
- if @forbidden_descent.has_key?(descendant.to_s) and @forbidden_descent[descendant.to_s].include?(ancestor.to_s)
134
- @forbidden_descent[descendant.to_s].delete(ancestor.to_s)
135
- end
136
- end
137
-
138
- def allow_emptiness(tag_name)
139
- @never_empty.delete(tag_name.to_s)
140
- end
141
-
142
- def allow_tag(*tag_names)
143
- tag_names.each do |tag_name|
144
- unless @allowed_tags.include?(tag_name.to_s)
145
- @allowed_tags << tag_name.to_s
146
- end
147
- end
148
- end
149
-
150
- def allow_text(tag_name)
151
- @no_text.delete(tag_name.to_s)
152
- end
153
-
154
- def block_level?(tag_name)
155
- DEFAULT_BLOCK_LEVEL_ELEMENTS.include?(tag_name.to_s)
156
- end
157
-
158
- alias_method :allow_tags, :allow_tag
159
-
160
- def clear
161
- @allowed_tags = []
162
- @never_empty = []
163
- @forbidden_descent = {}
164
- @required_parents = {}
165
- @no_text = []
166
- @twin_closers = []
167
- @preformatted = []
168
- end
169
-
170
- def close_twins(tag_name)
171
- @twin_closers << tag_name.to_s unless @twin_closers.include?(tag_name.to_s)
172
- end
173
-
174
- def close_twins?(tag_name)
175
- @twin_closers.include?(tag_name.to_s)
176
- end
177
-
178
- def does_not_close_twins(tag_name)
179
- @twin_closers.delete(tag_name.to_s)
180
- end
181
-
182
- def forbid_children_except(parent, children)
183
- @child_requirements[parent.to_s] = children.collect { |c| c.to_s }
184
- end
185
-
186
- def forbid_descent(ancestor, descendant) #:nodoc:
187
- @forbidden_descent[descendant.to_s] ||= []
188
- unless @forbidden_descent[descendant.to_s].include?(ancestor.to_s)
189
- @forbidden_descent[descendant.to_s] << ancestor.to_s
190
- end
191
- end
192
-
193
- def forbid_emptiness(tag_name)
194
- @never_empty << tag_name.to_s unless @never_empty.include?(tag_name.to_s)
195
- end
196
-
197
- def forbid_tag(name)
198
- @allowed_tags.delete(name.to_s)
199
- end
200
-
201
- def forbid_text(tag_name)
202
- @no_text << tag_name.to_s unless @no_text.include?(tag_name.to_s)
203
- end
204
-
205
- def initialize
206
- @allowed_tags = DEFAULT_ALLOWED_TAGS.dup
207
- @forbidden_descent = {}
208
- @required_parents = {}
209
- @child_requirements = {}
210
- @never_empty = []
211
- @no_text = []
212
- @twin_closers = []
213
- @preformatted = []
214
- use_defaults
215
- end
216
-
217
- def line_break_tag_name
218
- 'br'
219
- end
220
-
221
- def mark_as_preformatted(tag_name)
222
- @preformatted << tag_name.to_s unless @preformatted.include?(tag_name.to_s)
223
- end
224
-
225
- def paragraph_tag_name
226
- 'p'
227
- end
228
-
229
- def preformatted?(tag_name)
230
- @preformatted.include?(tag_name.to_s)
231
- end
232
-
233
- def require_parents(parents, child) #:nodoc:
234
- @required_parents[child.to_s] = parents.collect { |p| p.to_s }
235
- parents.each do |parent|
236
- if @forbidden_descent.has_key?(child.to_s)
237
- @forbidden_descent[child.to_s].delete(parent)
238
- end
239
- end
240
- end
241
-
242
- def tag(name)
243
- SchemaTag.new(self, name)
244
- end
245
-
246
- def tag_may_be_empty?(tag_name)
247
- !@never_empty.include?(tag_name.to_s)
248
- end
249
-
250
- def tag_valid_in_context?(tag_name, ancestors)
251
- return false unless @allowed_tags.include?(tag_name.to_s)
252
- if @required_parents.has_key?(tag_name.to_s) and !@required_parents[tag_name.to_s].include?(ancestors[0].to_s)
253
- return false
254
- end
255
- if @child_requirements.has_key?(ancestors[0].to_s) and !@child_requirements[ancestors[0].to_s].include?(tag_name.to_s)
256
- return false
257
- end
258
- if @forbidden_descent.has_key?(tag_name.to_s)
259
- @forbidden_descent[tag_name.to_s].each do |forbidden_ancestor|
260
- return false if ancestors.include?(forbidden_ancestor)
261
- end
262
- end
263
- return true
264
- end
265
-
266
- def text
267
- SchemaText.new(self)
268
- end
269
-
270
- def text_valid_in_context?(*ancestors)
271
- ancestors.flatten!
272
- if @no_text.include?(ancestors[0].to_s)
273
- return false
274
- end
275
- return true
276
- end
277
-
278
- def unmark_as_preformatted(tag_name)
279
- @preformatted.delete(tag_name.to_s)
280
- end
281
-
282
- def unrequire_parent(parent, child)
283
- @required_parents.delete(child.to_s)
284
- end
285
-
286
- def use_defaults
287
- tag('br').must_be_empty
288
- tag('p').may_not_be_nested
289
- tag('b').may_not_be_nested
290
- tag('b').may_not_be_empty
291
- tag('i').may_not_be_nested
292
- tag('i').may_not_be_empty
293
- tag('u').may_not_be_nested
294
- tag('u').may_not_be_empty
295
- tag('url').may_not_be_nested
296
- tag('img').may_not_be_nested
297
- tag('code').may_not_be_nested
298
- tag('code').is_preformatted
299
- #tag('code').may_not_be_empty
300
- tag('quote').may_not_be_empty
301
- tag('p').may_not_be_nested
302
- tag('*').must_be_child_of('list')
303
- tag('*').closes_twins
304
- tag('list').may_not_descend_from('p')
305
- tag('list').may_only_be_parent_of('*')
306
- tag('list').may_not_contain_text
307
- end
308
- end
309
- end