th-bbcode 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +11 -0
- data/lib/bbcode.rb +28 -0
- data/lib/bbcode/abstract_handler.rb +19 -0
- data/lib/bbcode/base.rb +8 -6
- data/lib/bbcode/handler.rb +1 -1
- data/lib/bbcode/helpers.rb +9 -1
- data/lib/bbcode/parser.rb +7 -9
- data/lib/bbcode/tokenizer.rb +10 -10
- data/lib/bbcode/version.rb +1 -1
- data/spec/lib/bbcode/base_spec.rb +0 -4
- data/spec/lib/bbcode/helpers_spec.rb +2 -2
- data/spec/lib/bbcode/tokenizer_spec.rb +3 -6
- data/spec/spec_helper.rb +12 -0
- metadata +11 -10
data/README.md
CHANGED
@@ -104,6 +104,17 @@ are no longer replaced automatically: You need to escape them in your handler
|
|
104
104
|
callback yourself. Failing to do so might expose your website to XSS
|
105
105
|
vulnerabilities.
|
106
106
|
|
107
|
+
Using another parser or tokenizer:
|
108
|
+
----------------------------------
|
109
|
+
Although this bbcode parser gem was primary designed for converting bbcode to
|
110
|
+
HTML, it is possible to use another parser or tokenizer while still using the
|
111
|
+
same handlers.
|
112
|
+
|
113
|
+
Using another tokenizer allows you to parse anything as if it were to be
|
114
|
+
bbcode. This feature is still in development, but a nice example is my own
|
115
|
+
ycode gem. This gem can be found here:
|
116
|
+
`https://github.com/tobyhinloopen/y-code`
|
117
|
+
|
107
118
|
Todo:
|
108
119
|
-----
|
109
120
|
* An easier way to handle text around bbcode tags to, for example, add smileys
|
data/lib/bbcode.rb
CHANGED
@@ -4,6 +4,7 @@ require 'action_view/helpers/tag_helper'
|
|
4
4
|
require 'cgi'
|
5
5
|
require "bbcode/version"
|
6
6
|
require "bbcode/tokenizer"
|
7
|
+
require "bbcode/abstract_handler"
|
7
8
|
require "bbcode/parser"
|
8
9
|
require "bbcode/handler"
|
9
10
|
require "bbcode/html_handler"
|
@@ -14,4 +15,31 @@ include ActionView::Helpers::TagHelper
|
|
14
15
|
|
15
16
|
module Bbcode
|
16
17
|
String.send :include, Bbcode::Helpers
|
18
|
+
|
19
|
+
def self.handlers
|
20
|
+
@@handlers ||= {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.handler(name)
|
24
|
+
handlers[name]
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.register_handler(name, handler)
|
28
|
+
handlers[name] = handler
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.parsers
|
32
|
+
@@parsers ||= {}
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.parser(name)
|
36
|
+
parser = parsers[name]
|
37
|
+
parser.respond_to?(:call) ? parser.call : parser
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.register_parser(name, parser = nil, &parser_factory)
|
41
|
+
parsers[name] = (parser || parser_factory)
|
42
|
+
end
|
43
|
+
|
44
|
+
register_parser(:bbcode){ Parser.new(Tokenizer.new) }
|
17
45
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Bbcode
|
2
|
+
class AbstractHandler
|
3
|
+
def start_element(tagname, attributes = {}, source = nil); end
|
4
|
+
def end_element(tagname, source = nil); end
|
5
|
+
def text(text); end
|
6
|
+
def interrupt_element(tagname); end
|
7
|
+
def continue_element(tagname); end
|
8
|
+
|
9
|
+
def restart_element(tagname, attributes = {}, source = nil)
|
10
|
+
end_element tagname
|
11
|
+
start_element tagname, attributes, source
|
12
|
+
end
|
13
|
+
|
14
|
+
def void_element(tagname, attributes = {}, source = nil)
|
15
|
+
start_element tagname, attributes, source
|
16
|
+
end_element tagname
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/bbcode/base.rb
CHANGED
@@ -4,22 +4,24 @@ module Bbcode
|
|
4
4
|
|
5
5
|
attr_reader :locals
|
6
6
|
|
7
|
-
def initialize(
|
7
|
+
def initialize(parser, string)
|
8
|
+
@parser = parser
|
8
9
|
@string = string
|
9
10
|
end
|
10
11
|
|
11
|
-
def to(
|
12
|
-
handler =
|
13
|
-
raise "Handler #{handler} isn't registered" if handler.
|
12
|
+
def to(handler_name, locals = {})
|
13
|
+
handler = Bbcode.handler handler_name
|
14
|
+
raise "Handler #{handler} isn't registered." if handler.nil?
|
14
15
|
handler.locals = locals.with_indifferent_access
|
15
|
-
|
16
|
+
@parser.parse @string, handler
|
16
17
|
result = handler.get_document.content.to_s
|
17
18
|
handler.clear
|
18
19
|
result
|
19
20
|
end
|
20
21
|
|
21
22
|
def self.register_handler(name, handler)
|
22
|
-
|
23
|
+
puts "WARNING: Bbcode::Base.register_handler is deprecated. Use Bbcode.register_handler instead."
|
24
|
+
Bbcode.register_handler(name, handler)
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
data/lib/bbcode/handler.rb
CHANGED
data/lib/bbcode/helpers.rb
CHANGED
data/lib/bbcode/parser.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Bbcode
|
2
2
|
# Attempts to pair a stream of tokens created by a tokenizer
|
3
|
-
class Parser
|
3
|
+
class Parser < AbstractHandler
|
4
4
|
attr_accessor :tokenizer
|
5
5
|
|
6
6
|
def initialize( tokenizer = nil )
|
@@ -14,12 +14,12 @@ module Bbcode
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def text( text )
|
17
|
-
@handler.
|
17
|
+
@handler.text text
|
18
18
|
end
|
19
19
|
|
20
20
|
def start_element( tagname, attributes, source )
|
21
21
|
@tags_stack << tagname
|
22
|
-
@handler.
|
22
|
+
@handler.start_element tagname, attributes, source
|
23
23
|
end
|
24
24
|
|
25
25
|
def end_element( tagname, source )
|
@@ -29,22 +29,20 @@ module Bbcode
|
|
29
29
|
@interruption_stack = []
|
30
30
|
while @tags_stack.last != tagname do
|
31
31
|
@interruption_stack << @tags_stack.last
|
32
|
-
@handler.
|
32
|
+
@handler.interrupt_element @tags_stack.pop
|
33
33
|
end
|
34
34
|
|
35
|
-
@handler.
|
35
|
+
@handler.end_element @tags_stack.pop, source
|
36
36
|
|
37
37
|
while !@interruption_stack.empty? do
|
38
38
|
@tags_stack << @interruption_stack.last
|
39
|
-
@handler.
|
39
|
+
@handler.continue_element @interruption_stack.pop
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
def parse( document, handler )
|
44
44
|
@handler = handler
|
45
|
-
@tokenizer.tokenize document
|
46
|
-
self.send *args if [:start_element, :end_element, :text].include?(args.first)
|
47
|
-
end
|
45
|
+
@tokenizer.tokenize document, self
|
48
46
|
end
|
49
47
|
end
|
50
48
|
end
|
data/lib/bbcode/tokenizer.rb
CHANGED
@@ -25,14 +25,14 @@ module Bbcode
|
|
25
25
|
# Parses the document as BBCode-formatted text and calls block with bbcode
|
26
26
|
# events.
|
27
27
|
#
|
28
|
-
# The
|
29
|
-
# -
|
28
|
+
# The handler will have the following methods called:
|
29
|
+
# - .text text
|
30
30
|
# A text-event with an additional parameter containing the actual text.
|
31
|
-
# -
|
31
|
+
# - .start_element element_name, element_arguments
|
32
32
|
# An element-event with 2 additional parameters: The element name as a
|
33
33
|
# symbol and the element attributes as a hash. This events indicate the
|
34
34
|
# start of the element.
|
35
|
-
# -
|
35
|
+
# - .end_element element_name
|
36
36
|
# An element-event indicating the end of an element. Optionally, the
|
37
37
|
# element_name is added as a parameter. If no parameter is present, it is
|
38
38
|
# assumed to be the last started element.
|
@@ -44,12 +44,12 @@ module Bbcode
|
|
44
44
|
# Also note that :text events are not guaranteed to match the whole text.
|
45
45
|
# In some cases, the text might be separated to multiple :text events, even
|
46
46
|
# though there are no nodes in between.
|
47
|
-
def tokenize(
|
47
|
+
def tokenize(document, handler)
|
48
48
|
while !(match = BBCODE_TAG_PATTERN.match(document)).nil?
|
49
49
|
offset = match.begin(0)
|
50
50
|
elem_source = match[0]
|
51
51
|
|
52
|
-
handler.
|
52
|
+
handler.text document[0...offset] unless offset == 0
|
53
53
|
|
54
54
|
elem_is_closing_tag = match[1]=='/'
|
55
55
|
elem_name = (match[2].length > 0 && match[2].to_sym) || nil
|
@@ -57,18 +57,18 @@ module Bbcode
|
|
57
57
|
|
58
58
|
if (elem_is_closing_tag && !elem_attr_string) || (!elem_is_closing_tag && elem_name)
|
59
59
|
if !elem_is_closing_tag
|
60
|
-
handler.
|
60
|
+
handler.start_element elem_name, parse_attributes_string(elem_attr_string), elem_source
|
61
61
|
else
|
62
|
-
handler.
|
62
|
+
handler.end_element elem_name, elem_source
|
63
63
|
end
|
64
64
|
else
|
65
|
-
handler.
|
65
|
+
handler.text elem_source
|
66
66
|
end
|
67
67
|
|
68
68
|
document = document[(offset+elem_source.length)..-1]
|
69
69
|
end
|
70
70
|
|
71
|
-
handler.
|
71
|
+
handler.text document unless document.length == 0
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
data/lib/bbcode/version.rb
CHANGED
@@ -19,8 +19,8 @@ quote_handler.register_element_handlers handler.element_handlers.merge({
|
|
19
19
|
:quote => ->(element){ "[...]" }
|
20
20
|
})
|
21
21
|
|
22
|
-
Bbcode
|
23
|
-
Bbcode
|
22
|
+
Bbcode.register_handler :html, handler
|
23
|
+
Bbcode.register_handler :text, Bbcode::Handler.new
|
24
24
|
|
25
25
|
describe Bbcode::Helpers do
|
26
26
|
it "should enable a string to use a registered helper" do
|
@@ -2,12 +2,9 @@ require 'spec_helper.rb'
|
|
2
2
|
|
3
3
|
def get_tokenizer_results(string, strip_source = true)
|
4
4
|
tokenizer = Bbcode::Tokenizer.new
|
5
|
-
|
6
|
-
tokenizer.tokenize string
|
7
|
-
|
8
|
-
results.push args
|
9
|
-
end
|
10
|
-
results
|
5
|
+
handler = DummyHandler.new strip_source
|
6
|
+
tokenizer.tokenize string, handler
|
7
|
+
handler.stack
|
11
8
|
end
|
12
9
|
|
13
10
|
describe Bbcode::Tokenizer do
|
data/spec/spec_helper.rb
CHANGED
@@ -3,6 +3,18 @@ require 'bundler/setup'
|
|
3
3
|
|
4
4
|
require 'bbcode'
|
5
5
|
|
6
|
+
class DummyHandler
|
7
|
+
attr_accessor :stack
|
8
|
+
|
9
|
+
def initialize(strip_source)
|
10
|
+
@strip_source = strip_source
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(*args)
|
14
|
+
(@stack ||= []) << args.tap{ |args| args.pop if @strip_source && args.first.to_s.end_with?("element") }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
6
18
|
RSpec.configure do |config|
|
7
19
|
# some (optional) config here
|
8
20
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: th-bbcode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-14 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70359577113220 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70359577113220
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activesupport
|
27
|
-
requirement: &
|
27
|
+
requirement: &70359577112800 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70359577112800
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: actionpack
|
38
|
-
requirement: &
|
38
|
+
requirement: &70359577112380 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70359577112380
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: i18n
|
49
|
-
requirement: &
|
49
|
+
requirement: &70359577111960 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70359577111960
|
58
58
|
description: Gem for parsing bbcode-formatted strings to HTML or any other formatting
|
59
59
|
you like (or don't like).
|
60
60
|
email:
|
@@ -69,6 +69,7 @@ files:
|
|
69
69
|
- Rakefile
|
70
70
|
- bbcode.gemspec
|
71
71
|
- lib/bbcode.rb
|
72
|
+
- lib/bbcode/abstract_handler.rb
|
72
73
|
- lib/bbcode/base.rb
|
73
74
|
- lib/bbcode/element.rb
|
74
75
|
- lib/bbcode/handler.rb
|