bbcode-rails 0.7.0 → 0.8.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.
- checksums.yaml +4 -4
- data/README.md +12 -2
- data/lib/bbcode-rails.rb +146 -13
- data/lib/bbcode-rails/tag.rb +54 -14
- data/lib/bbcode-rails/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e3a03c9829b29ae970341a6869350c6d81a63e6
|
4
|
+
data.tar.gz: 1075e5565218f39b55b224764911b19b419f30da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a8313ca29126829b91a2338647b00adf318223ef4de44f7649dba819198070b5045ec211cf977094aa8024da3bf2b1bbfe66c24ae4dbcf1e28ad8d9a4cdfcde
|
7
|
+
data.tar.gz: f5cc8b2ae3c5dcc509c8275599b8d4c1a366c7b6a476773f300492fd1137a7860801b43e0d43ebb172ac5cf2d4138d9b48335ec660bece20045cef174f6ccdc7
|
data/README.md
CHANGED
@@ -55,7 +55,7 @@ This will create `app/bbcode/user_tag.rb`.
|
|
55
55
|
#app/bbcode/user.rb
|
56
56
|
|
57
57
|
class UserTag < BBCode::Tag
|
58
|
-
|
58
|
+
block_name :user
|
59
59
|
on_layout do |args|
|
60
60
|
"TODO: Implement user tag"
|
61
61
|
end
|
@@ -68,7 +68,7 @@ You could now add something like:
|
|
68
68
|
#app/bbcode/user.rb
|
69
69
|
|
70
70
|
class UserTag < BBCode::Tag
|
71
|
-
|
71
|
+
block_name :user, :argument, :no_closing_tag
|
72
72
|
on_layout do |args|
|
73
73
|
user = User.find_by_id(args[1])
|
74
74
|
render partial: 'shared/userquote', locals: { user: user }
|
@@ -78,6 +78,16 @@ end
|
|
78
78
|
|
79
79
|
Of course, the limitations are your knowledge in ruby and rails :)
|
80
80
|
|
81
|
+
### Transforming a BBCode string into HTML
|
82
|
+
|
83
|
+
Just call `bbcode_to_html` on any string.
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
#> User.all.first.bio
|
87
|
+
"[i]Hello [b]Everyone[/b][/i]"
|
88
|
+
#> User.all.first.bio.bbcode_to_html
|
89
|
+
=> "<em>Hello <strong>Everyone</strong></em>"
|
90
|
+
```
|
81
91
|
|
82
92
|
## Contributing
|
83
93
|
|
data/lib/bbcode-rails.rb
CHANGED
@@ -1,12 +1,25 @@
|
|
1
1
|
require "bbcode-rails/version"
|
2
2
|
|
3
3
|
module BBCode
|
4
|
-
|
4
|
+
class ParseError < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
@tags = {}
|
5
8
|
def self.tags
|
6
|
-
|
9
|
+
@tags
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.get_tag_by_name name
|
13
|
+
if defined?(Rails) && Rails.env.development?
|
14
|
+
begin
|
15
|
+
"#{p}_tag".camelize.constantize
|
16
|
+
rescue NameError
|
17
|
+
end
|
18
|
+
end
|
19
|
+
@tags["#{name.to_s.downcase}tag"]
|
7
20
|
end
|
8
21
|
|
9
|
-
def self.parse str
|
22
|
+
def self.parse str, raise_error=false
|
10
23
|
str = str.dup
|
11
24
|
|
12
25
|
str.gsub!( '&', '&' )
|
@@ -15,20 +28,140 @@ module BBCode
|
|
15
28
|
str.gsub!( '"', '"' )
|
16
29
|
str.gsub!( "'", ''' )
|
17
30
|
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
31
|
+
# Let's iterate over the pieces to build a tree
|
32
|
+
# It works like this:
|
33
|
+
# For each object you have two things:
|
34
|
+
# 1. It is a tag name a la [img]
|
35
|
+
# 2. It is a simple string, something like 'Hello'
|
36
|
+
#
|
37
|
+
# Now, we want a tree that looks like this
|
38
|
+
#
|
39
|
+
# -> |
|
40
|
+
# | ImgTag src: http://adada
|
41
|
+
# | String This cat
|
42
|
+
# | BTag is -> |
|
43
|
+
# | ITag funny!
|
44
|
+
# In the end we just recursively append
|
45
|
+
|
46
|
+
result = []
|
47
|
+
|
48
|
+
tag_open = /\[/
|
49
|
+
tag_close = /\]/
|
50
|
+
tag_close_prefix = /\//
|
51
|
+
tag_arg = /=/
|
52
|
+
tag_arg_delim = /"/
|
53
|
+
tag_name = /[-_a-z0-9]/
|
54
|
+
|
55
|
+
current_state = :text
|
56
|
+
current_tag = result
|
57
|
+
|
58
|
+
begin
|
59
|
+
pos = 0
|
60
|
+
while pos < str.length
|
61
|
+
case current_state
|
62
|
+
when :text
|
63
|
+
tmp = ""
|
64
|
+
# We iterate through the string either until the end or if we find a [
|
65
|
+
while not str[pos] =~ tag_open and pos < str.length
|
66
|
+
tmp << str[pos]
|
67
|
+
pos = pos.next
|
68
|
+
end
|
69
|
+
current_tag << tmp
|
70
|
+
current_state = :tag_name if pos < str.length # Okay, we have found the beginning of a possible tag!
|
71
|
+
pos = pos.next
|
72
|
+
when :tag_name
|
73
|
+
name = ""
|
74
|
+
if str[pos-1] =~ tag_open and str[pos] =~ tag_close_prefix
|
75
|
+
# It's a closing tag!
|
76
|
+
# Let's check if it applies to our current tag..
|
77
|
+
|
78
|
+
broke_out = false
|
79
|
+
tag = current_tag
|
80
|
+
until tag.is_a? Array
|
81
|
+
len = tag.name.length
|
82
|
+
if str[pos+1,len] == tag.name and str[pos+len+1] =~ tag_close
|
83
|
+
# If it's the current one?
|
84
|
+
if current_tag == tag
|
85
|
+
current_tag = tag.parent
|
86
|
+
pos += len+1
|
87
|
+
broke_out = true
|
88
|
+
break
|
89
|
+
else
|
90
|
+
# It's not the current one! Invalid construct
|
91
|
+
raise BBCode::ParseError, "Invalid nested tags"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
tag = tag.parent
|
95
|
+
end
|
96
|
+
|
97
|
+
# It's not a closing tag we recognize, so it's text really!
|
98
|
+
# Let's restore this!
|
99
|
+
if not broke_out
|
100
|
+
current_tag << "[/"
|
101
|
+
end
|
102
|
+
current_state = :text
|
103
|
+
pos = pos.next
|
104
|
+
next
|
105
|
+
end
|
106
|
+
while not (str[pos] =~ tag_close and str[pos] =~ tag_arg and pos < str.length) and str[pos] =~ tag_name
|
107
|
+
name << str[pos]
|
108
|
+
pos = pos.next
|
109
|
+
end
|
110
|
+
|
111
|
+
if str[pos] =~ tag_arg or str[pos] =~ tag_close
|
112
|
+
if self.get_tag_by_name(name)
|
113
|
+
new_tag = self.get_tag_by_name(name).new(current_tag)
|
114
|
+
current_tag << new_tag
|
115
|
+
if new_tag.has_option(:content) or new_tag.has_option(:argument)
|
116
|
+
current_tag = new_tag
|
117
|
+
end
|
118
|
+
if str[pos] =~ tag_arg
|
119
|
+
if new_tag.has_option :argument
|
120
|
+
current_state = :tag_arg
|
121
|
+
else
|
122
|
+
raise BBCode::ParseError
|
123
|
+
end
|
124
|
+
else
|
125
|
+
current_state = :text
|
126
|
+
end
|
127
|
+
pos = pos.next
|
128
|
+
else
|
129
|
+
current_tag << "[#{name}"
|
130
|
+
current_state = :text
|
131
|
+
end
|
132
|
+
next
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
# Did we hit the end? Let's get out
|
137
|
+
current_tag << name
|
138
|
+
current_state = :text
|
139
|
+
when :tag_arg
|
140
|
+
arg = ""
|
141
|
+
while not str[pos] =~ tag_close and pos < str.length
|
142
|
+
arg << str[pos]
|
143
|
+
pos = pos.next
|
144
|
+
end
|
145
|
+
|
146
|
+
current_tag.argument = arg.gsub(/^#{tag_arg_delim}(.*)#{tag_arg_delim}$/, '\1')
|
147
|
+
if not current_tag.has_option(:content)
|
148
|
+
current_tag = current_tag.parent
|
149
|
+
end
|
150
|
+
current_state = :text
|
151
|
+
pos = pos.next
|
152
|
+
else
|
153
|
+
pos = pos.next
|
24
154
|
end
|
25
155
|
end
|
26
|
-
end
|
27
156
|
|
28
|
-
|
29
|
-
|
157
|
+
result.map(&:to_s).join('').strip
|
158
|
+
rescue BBCode::ParseError => e
|
159
|
+
if raise_error
|
160
|
+
raise e
|
161
|
+
else
|
162
|
+
str
|
163
|
+
end
|
30
164
|
end
|
31
|
-
str
|
32
165
|
end
|
33
166
|
|
34
167
|
end
|
data/lib/bbcode-rails/tag.rb
CHANGED
@@ -17,33 +17,73 @@ class BBCode::Tag
|
|
17
17
|
self.view_paths = "app/views"
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
attr_accessor :parent
|
21
|
+
|
22
|
+
def initialize parent
|
23
|
+
@parent = parent
|
24
|
+
@content = []
|
25
|
+
@argument = ""
|
22
26
|
end
|
23
27
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
+
def has_option opt
|
29
|
+
self.class.options.include?(opt)
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_block
|
33
|
+
self.class.block
|
28
34
|
end
|
29
35
|
|
30
|
-
def
|
31
|
-
if
|
32
|
-
|
36
|
+
def argument= arg
|
37
|
+
if !has_option :argument
|
38
|
+
raise BBCode::ParseError, "Tried to assign an argument to a tag which takes none, #{name}"
|
39
|
+
else
|
40
|
+
@argument = arg
|
33
41
|
end
|
34
|
-
|
35
|
-
|
42
|
+
end
|
43
|
+
|
44
|
+
def << c
|
45
|
+
if !has_option :content
|
46
|
+
raise BBCode::ParseError, "Tried to assign content to a tag which takes none, #{name}"
|
36
47
|
else
|
37
|
-
@
|
48
|
+
@content << c
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
if has_option :content
|
54
|
+
result = @content.map(&:to_s).join('')
|
38
55
|
end
|
56
|
+
if has_option(:content) and has_option(:argument)
|
57
|
+
get_block.call(@argument, result)
|
58
|
+
elsif has_option :content
|
59
|
+
get_block.call(result)
|
60
|
+
elsif has_option :argument
|
61
|
+
get_block.call(@argument)
|
62
|
+
else
|
63
|
+
get_block.call
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def name
|
68
|
+
self.class.to_s.downcase.gsub(/tag$/i,'')
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.inherited subclass
|
72
|
+
# In case we autoreload, remove earlier instances
|
73
|
+
BBCode.tags.delete_if {|c| c.to_s == subclass.to_s }
|
74
|
+
BBCode.tags[subclass.to_s.downcase] = subclass
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.block_options *args
|
78
|
+
@options = args
|
39
79
|
end
|
40
80
|
|
41
81
|
def self.on_layout &b
|
42
82
|
@block = b
|
43
83
|
end
|
44
84
|
|
45
|
-
def self.
|
46
|
-
@
|
85
|
+
def self.options
|
86
|
+
@options ||= []
|
47
87
|
end
|
48
88
|
|
49
89
|
def self.block
|
data/lib/bbcode-rails/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bbcode-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcel Müller
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|