ruby-bbcode 2.0.3 → 2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0e75772f9527582d10e8c0217244e80c0426c5c861be5ee124e758107349cb2
4
- data.tar.gz: 4c7ef1e08b4d77a7111919cfe9e2d5b9b4d476ab092436264709e20fd04ad199
3
+ metadata.gz: 7b730deba08944b458a3493bbbf22c22332972907a6ee08cdbd6b5fa6ad197f3
4
+ data.tar.gz: f52a6ac0c514718b073bff2480e731b694d17b34420ab3fc8b0d6c3d73321439
5
5
  SHA512:
6
- metadata.gz: 35930032e1756cd925369b1c485c09d4bbe016cb31702a2f89b496d94b5d23f960b5b2f0d7ff7f884f3154ec67a2456c0541dd2ab1d2e955e5e058280f26d36c
7
- data.tar.gz: 1bef1bdbd00a25f3c735824228eb7961c06885bd47b5487030a23a1050d26c1014b1e29d2f108edbf528f7946986c6ca6d166bf3ca5c1e7db491b500e51164be
6
+ metadata.gz: 3fb032ad7763f35eb774a1566c03eaf22fe7ba13f1fae26fc82d05da66eb2163e0a0bbcebe15fa78d7c4345dbb574a03c8a22c5b40d2baf22fc74da7e992e0b8
7
+ data.tar.gz: 6ca73ffcbc1acf6ebd7ba4e3408f9b6448e910193b44e1c3bd29082417089457becd0627c463214aca2bdd14624faa1e3563ffefc3ae8e7cdaebfabd3f38f644
@@ -1,6 +1,14 @@
1
1
  Upcoming
2
2
  --------
3
3
 
4
+ Version 2.1.0 - 30-May-2019
5
+ ---------------------------
6
+
7
+ * Use rubocup and sonargraph and fix minor issues
8
+ * Make behavior of unknown tags configurable ([#33](https://github.com/veger/ruby-bbcode/issues/36))
9
+ * Allow tags inside link tags ([#32](https://github.com/veger/ruby-bbcode/issues/32))
10
+ * Do not convert newlines to HTML br element for 'block tags' ([#31](https://github.com/veger/ruby-bbcode/issues/31))
11
+
4
12
  Version 2.0.3 - 07-Feb-2018
5
13
  ---------------------------
6
14
 
@@ -10,12 +18,12 @@ Version 2.0.3 - 07-Feb-2018
10
18
  Version 2.0.2 - 10-Apr-2017
11
19
  ---------------------------
12
20
 
13
- * Fix error when tags are in self-closing tags (issue #30)
21
+ * Fix error when tags are in self-closing tags ([#30](https://github.com/veger/ruby-bbcode/issues/30))
14
22
 
15
23
  Version 2.0.1 - 15-Jan-2017
16
24
  ---------------------------
17
25
 
18
- * Remove EOL newlines before/after self-closing tags (issue #29)
26
+ * Remove EOL newlines before/after self-closing tags ([#29](https://github.com/veger/ruby-bbcode/issues/29))
19
27
 
20
28
  Version 2.0.0 - 09-Apr-2015
21
29
  ---------------------------
@@ -26,8 +34,8 @@ Version 2.0.0 - 09-Apr-2015
26
34
  * Changed tag description symbols (to become descriptive), **breaks existing custom tag additions!**
27
35
  * Add support to show the BBCode annotated with errors (when there are any)
28
36
  * Add support to escape token value using :uri_escape.
29
- * Recognize uppercase tags (issue #27)
30
- * Support [iframe-API](https://developers.google.com/youtube/iframe_api_reference) for YouTube videos (#18)
37
+ * Recognize uppercase tags ([#27](https://github.com/veger/ruby-bbcode/issues/27))
38
+ * Support [iframe-API](https://developers.google.com/youtube/iframe_api_reference) for YouTube videos ([#18](https://github.com/veger/ruby-bbcode/issues/18))
31
39
  * Support difference between optional and required parameters
32
40
  * Add optional parameters to youtube and vimeo tags to specify the dimensions of the video
33
41
 
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ begin
9
9
  rescue LoadError
10
10
  require 'rdoc/rdoc'
11
11
  require 'rake/rdoctask'
12
- require 'rdoc/task'
12
+ require 'rdoc/task'
13
13
  RDoc::Task = Rake::RDocTask
14
14
  end
15
15
 
@@ -22,8 +22,6 @@ RDoc::Task.new(:rdoc) do |rdoc|
22
22
  rdoc.rdoc_files.include('lib/**/*.rb')
23
23
  end
24
24
 
25
-
26
-
27
25
  Bundler::GemHelper.install_tasks
28
26
 
29
27
  require 'rake/testtask'
@@ -42,4 +40,4 @@ Rake::TestTask.new(:current) do |t|
42
40
  t.verbose = true
43
41
  end
44
42
 
45
- task :default => :test
43
+ task default: :test
@@ -1,4 +1,5 @@
1
1
  require 'tags/tags'
2
+ require 'ruby-bbcode/configuration'
2
3
  require 'ruby-bbcode/tag_info'
3
4
  require 'ruby-bbcode/tag_sifter'
4
5
  require 'ruby-bbcode/tag_node'
@@ -11,6 +12,22 @@ require 'ruby-bbcode/bbtree'
11
12
  module RubyBBCode
12
13
  include ::RubyBBCode::Tags
13
14
 
15
+ class << self
16
+ attr_writer :configuration
17
+ end
18
+
19
+ def self.configuration
20
+ @configuration ||= Configuration.new
21
+ end
22
+
23
+ def self.reset
24
+ @configuration = Configuration.new
25
+ end
26
+
27
+ def self.configure
28
+ yield(configuration)
29
+ end
30
+
14
31
  # This method converts the given text (with BBCode tags) into a HTML representation
15
32
  # The escape_html parameter (default: true) escapes HTML tags that were present in the given text and therefore blocking (mallicious) HTML in the original text
16
33
  # The additional_tags parameter is used to add additional BBCode tags that should be accepted
@@ -43,38 +60,41 @@ module RubyBBCode
43
60
 
44
61
  @tag_sifter.process_text
45
62
  return @tag_sifter.errors unless @tag_sifter.valid?
63
+
46
64
  true
47
65
  end
48
66
 
49
-
50
- protected
51
-
52
- # This method provides the final set of bbcode tags, it merges the default tags with the given additional_tags
53
- # and blacklists(method = :disable) or whitelists the list of tags with the given tags parameter.
54
- def self.determine_applicable_tags(additional_tags, method, *tags)
55
- use_tags = @@tags.merge(additional_tags)
56
- if method == :disable then # if method is set to :disable
57
- tags.each { |t| use_tags.delete(t) } # blacklist (remove) the supplied tags
58
- else # method is not :disable, but has any other value
59
- # Only use the supplied tags (whitelist)
60
- new_use_tags = {}
61
- tags.each { |t| new_use_tags[t] = use_tags[t] if use_tags.key?(t) }
62
- use_tags = new_use_tags
67
+ class << self
68
+ protected
69
+
70
+ # This method provides the final set of bbcode tags, it merges the default tags with the given additional_tags
71
+ # and blacklists(method = :disable) or whitelists the list of tags with the given tags parameter.
72
+ def determine_applicable_tags(additional_tags, method, *tags)
73
+ use_tags = @@tags.merge(additional_tags)
74
+ if method == :disable
75
+ # if method is set to :disable blacklist (remove) the supplied tags
76
+ tags.each { |t| use_tags.delete(t) }
77
+ else
78
+ # only use the supplied tags (whitelist) if method is not :disable
79
+ new_use_tags = {}
80
+ tags.each { |t| new_use_tags[t] = use_tags[t] if use_tags.key?(t) }
81
+ use_tags = new_use_tags
82
+ end
83
+ use_tags
63
84
  end
64
- use_tags
65
- end
66
-
67
- # This method parses the given text (with BBCode tags) into a BBTree representation
68
- # The escape_html parameter (default: true) escapes HTML tags that were present in the given text and therefore blocking (mallicious) HTML in the original text
69
- # The additional_tags parameter is used to add additional BBCode tags that should be accepted
70
- # The method parameter determines whether the tags parameter needs to be used to blacklist (when set to :disable) or whitelist (when not set to :disable) the list of BBCode tags
71
- # The method raises an exception when the text could not be parsed due to errors
72
- def self.parse(text, escape_html = true, additional_tags = {}, method = :disable, *tags)
73
- text = text.clone
74
- use_tags = determine_applicable_tags(additional_tags, method, *tags)
75
85
 
76
- @tag_sifter = TagSifter.new(text, use_tags, escape_html)
77
- @tag_sifter.process_text
86
+ # This method parses the given text (with BBCode tags) into a BBTree representation
87
+ # The escape_html parameter (default: true) escapes HTML tags that were present in the given text and therefore blocking (mallicious) HTML in the original text
88
+ # The additional_tags parameter is used to add additional BBCode tags that should be accepted
89
+ # The method parameter determines whether the tags parameter needs to be used to blacklist (when set to :disable) or whitelist (when not set to :disable) the list of BBCode tags
90
+ # The method raises an exception when the text could not be parsed due to errors
91
+ def parse(text, escape_html = true, additional_tags = {}, method = :disable, *tags)
92
+ text = text.clone
93
+ use_tags = determine_applicable_tags(additional_tags, method, *tags)
94
+
95
+ @tag_sifter = TagSifter.new(text, use_tags, escape_html)
96
+ @tag_sifter.process_text
97
+ end
78
98
  end
79
99
  end
80
100
 
@@ -94,7 +114,7 @@ String.class_eval do
94
114
  # The method parameter determines whether the tags parameter needs to be used to blacklist (when set to :disable) or whitelist (when not set to :disable) the list of BBCode tags
95
115
  # The method raises an exception when the text could not be parsed due to errors
96
116
  def bbcode_to_html!(escape_html = true, additional_tags = {}, method = :disable, *tags)
97
- self.replace(RubyBBCode.to_html(self, escape_html, additional_tags, method, *tags))
117
+ replace(RubyBBCode.to_html(self, escape_html, additional_tags, method, *tags))
98
118
  end
99
119
 
100
120
  # Convert a string with BBCode markup into its corresponding HTML markup
@@ -12,7 +12,7 @@ module RubyBBCode
12
12
  class BBTree
13
13
  attr_accessor :current_node, :tags_list
14
14
 
15
- def initialize(hash = { :nodes => TagCollection.new })
15
+ def initialize(hash = { nodes: TagCollection.new })
16
16
  @bbtree = hash
17
17
  @current_node = TagNode.new(@bbtree)
18
18
  @tags_list = []
@@ -23,13 +23,14 @@ module RubyBBCode
23
23
  end
24
24
 
25
25
  def within_open_tag?
26
- @tags_list.length > 0
26
+ !@tags_list.empty?
27
27
  end
28
- alias :expecting_a_closing_tag? :within_open_tag? # just giving this method multiple names for semantical purposes
28
+ alias expecting_a_closing_tag? within_open_tag? # just giving this method multiple names for semantical purposes
29
29
 
30
30
  # Returns the parent tag, if suitable/available
31
31
  def parent_tag
32
32
  return nil unless within_open_tag?
33
+
33
34
  @tags_list.last
34
35
  end
35
36
 
@@ -49,18 +50,19 @@ module RubyBBCode
49
50
  if @tags_list[-1].definition[:self_closable]
50
51
  # It is possible that the next (self_closable) tag is on the next line
51
52
  # Remove newline of current tag and parent tag as they are (probably) not intented as an actual newline here but as tag separator
52
- @tags_list[-1][:nodes][0][:text].chomp! unless @tags_list[-1][:nodes][0][:text].nil?
53
- @tags_list[-2][:nodes][0][:text].chomp! unless @tags_list.length < 2 or @tags_list[-2][:nodes][0][:text].nil?
53
+ @tags_list[-1][:nodes][0][:text]&.chomp!
54
+ @tags_list[-2][:nodes][0][:text].chomp! unless (@tags_list.length < 2) || @tags_list[-2][:nodes][0][:text].nil?
54
55
  end
55
56
 
56
- @tags_list.pop # remove latest tag in tags_list since it's closed now...
57
+ @tags_list.pop # remove latest tag in tags_list since it's closed now...
57
58
  # The parsed data manifests in @bbtree.current_node.children << TagNode.new(element) which I think is more confusing than needed
58
59
 
59
- if within_open_tag?
60
- @current_node = @tags_list[-1]
61
- else # If we're still at the root of the BBTree or have returned back to the root via encountring closing tags...
62
- @current_node = TagNode.new({:nodes => self.nodes}) # Note: just passing in self works too...
63
- end
60
+ @current_node = if within_open_tag?
61
+ @tags_list[-1]
62
+ else
63
+ # we're still at the root of the BBTree or have returned back to the root via encountering closing tags...
64
+ TagNode.new(nodes: nodes)
65
+ end
64
66
  end
65
67
 
66
68
  # Create a new node and adds it to the current node as a child node
@@ -69,11 +71,11 @@ module RubyBBCode
69
71
  end
70
72
 
71
73
  def to_html(tags = {})
72
- self.nodes.to_html(tags)
74
+ nodes.to_html(tags)
73
75
  end
74
76
 
75
77
  def to_bbcode(tags = {})
76
- self.nodes.to_bbcode(tags)
78
+ nodes.to_bbcode(tags)
77
79
  end
78
80
  end
79
81
  end
@@ -0,0 +1,18 @@
1
+ # Configuration holds RubyBBCode configuration
2
+ class Configuration
3
+ # Defines how to treat unknown tags
4
+ # * :exception throws and exception
5
+ # * :text converts it into a text
6
+ # * :ignore removes it from the output
7
+ attr_reader :ignore_unknown_tags
8
+
9
+ def initialize
10
+ @ignore_unknown_tags = :text
11
+ end
12
+
13
+ def ignore_unknown_tags=(value)
14
+ raise 'ignore_unknown_tags must be either :exception, :text or :ignore' unless %i[exception text ignore].include? value
15
+
16
+ @ignore_unknown_tags = value
17
+ end
18
+ end
@@ -17,9 +17,9 @@ module RubyBBCode
17
17
  # This method is vulnerable to stack-level-too-deep scenarios where >=1,200 tags are being parsed.
18
18
  # But that scenario can be mitigated by splitting up the tags. bbtree = { :nodes => [900tags, 1000tags] }, the work
19
19
  # for that bbtree can be split up into two passes, do the each node one at a time. I'm not coding that though, it's pointless, just a thought though
20
- def to_code(tags, template)
21
- html_string = ""
22
- self.each do |node|
20
+ def to_code(tags, template, parent_node = nil)
21
+ output_string = ''
22
+ each do |node|
23
23
  if node.type == :tag
24
24
  t = template.new node
25
25
 
@@ -30,20 +30,20 @@ module RubyBBCode
30
30
  t.remove_unused_tokens!
31
31
  end
32
32
 
33
- html_string << t.opening_part
33
+ output_string << t.opening_part
34
34
 
35
35
  # invoke "recursive" call if this node contains child nodes
36
- html_string << node.children.to_code(tags, template) if node.has_children? # FIXME: Don't use recursion, it can lead to stack-level-too-deep errors for large volumes?
36
+ output_string << node.children.to_code(tags, template, node) if node.has_children? # FIXME: Don't use recursion, it can lead to stack-level-too-deep errors for large volumes?
37
37
 
38
38
  t.inlay_closing_part!
39
39
 
40
- html_string << t.closing_part
40
+ output_string << t.closing_part
41
41
  elsif node.type == :text
42
- html_string << template.convert_text(node)
42
+ output_string << template.convert_text(node, parent_node)
43
43
  end
44
44
  end
45
45
 
46
- html_string
46
+ output_string
47
47
  end
48
48
  end
49
- end
49
+ end
@@ -3,6 +3,16 @@ module RubyBBCode
3
3
  # This class was made mostly just to keep track of all of the confusing the logic conditions that are checked.
4
4
  #
5
5
  class TagInfo
6
+ REGEX_STRING = '(?:(\[ (\/)? (\* | (?:\w+)) ((?:=[^\[\]]+) | (?:\s\w+=\w+)* | (?:[^\]]*))? \] (\s*)) | ([^\[]+))'.gsub(' ', '').freeze
7
+ REGEX = /#{REGEX_STRING}/i.freeze
8
+
9
+ COMPLETE_MATCH = 0
10
+ CLOSING_MATCH = 1
11
+ TAG_MATCH = 2
12
+ TAG_PARAM_MATCH = 3
13
+ WHITESPACE_AFTER_TAG = 4
14
+ TEXT = 5
15
+
6
16
  def initialize(tag_info, dictionary)
7
17
  @tag_data = find_tag_info(tag_info, dictionary)
8
18
  end
@@ -15,16 +25,19 @@ module RubyBBCode
15
25
  @tag_data[key] = value
16
26
  end
17
27
 
18
- # Returns the definition of this instance (when it represents a tag element)
19
- def definition
20
- @definition
21
- end
28
+ # Definition of this instance (when it represents a tag element)
29
+ attr_reader :definition
22
30
 
23
31
  # Returns the text (when this instance represents a text element)
24
32
  def text
25
33
  @tag_data[:text]
26
34
  end
27
35
 
36
+ # Returns the whitespace that was available directly after the tag definition
37
+ def whitespace
38
+ @tag_data[:whitespace]
39
+ end
40
+
28
41
  # Returns the type of the cuvvrent tag/node, which is either :opening_tag, :closing_tag, or :text
29
42
  def type
30
43
  return :opening_tag if element_is_opening_tag?
@@ -51,12 +64,12 @@ module RubyBBCode
51
64
 
52
65
  # Returns true if this instance represents an opening tag element
53
66
  def element_is_opening_tag?
54
- self[:is_tag] and !self[:closing_tag]
67
+ self[:is_tag] && !self[:closing_tag]
55
68
  end
56
69
 
57
70
  # Returns true if this instance represents a closing tag element
58
71
  def element_is_closing_tag?
59
- self[:is_tag] and self[:closing_tag]
72
+ self[:is_tag] && self[:closing_tag]
60
73
  end
61
74
 
62
75
  # Returns true if this tag element is included in the set of available tags
@@ -71,7 +84,7 @@ module RubyBBCode
71
84
 
72
85
  # Returns true if the tag element is allowed in the provided parent_tag
73
86
  def allowed_in?(parent_tag)
74
- !only_allowed_in_parent_tags? or @definition[:only_in].include?(parent_tag)
87
+ !only_allowed_in_parent_tags? || @definition[:only_in].include?(parent_tag)
75
88
  end
76
89
 
77
90
  # Returns true if this tag has quick parameter support
@@ -86,21 +99,39 @@ module RubyBBCode
86
99
 
87
100
  protected
88
101
 
102
+ # Returns a default info structure used by all tags
103
+ def default_tag_info(tag_info)
104
+ {
105
+ errors: [],
106
+ complete_match: tag_info[COMPLETE_MATCH],
107
+ whitespace: tag_info[WHITESPACE_AFTER_TAG]
108
+ }
109
+ end
110
+
89
111
  # Convert the result of the TagSifter#process_text regex into a more usable hash, that is used by the rest of the parser.
90
112
  # tag_info should a result of the regex of TagSifter#process_text
91
113
  # Returns the tag hash
92
114
  def find_tag_info(tag_info, dictionary)
93
- ti = {}
94
- ti[:errors] = []
95
- ti[:complete_match] = tag_info[0]
96
- ti[:is_tag] = (tag_info[0].start_with? '[')
115
+ ti = default_tag_info(tag_info)
116
+ ti[:is_tag] = (tag_info[COMPLETE_MATCH]&.start_with? '[')
97
117
  if ti[:is_tag]
98
- ti[:closing_tag] = (tag_info[2] == '/')
99
- ti[:tag] = tag_info[3].to_sym.downcase
118
+ ti[:closing_tag] = (tag_info[CLOSING_MATCH] == '/')
119
+ ti[:tag] = tag_info[TAG_MATCH].to_sym.downcase
100
120
  ti[:params] = {}
101
121
  @definition = dictionary[ti[:tag]]
102
- if tag_info[5][0] == ?= and can_have_quick_param?
103
- quick_param = tag_info[5][1..-1]
122
+ if !tag_in_dictionary?
123
+ # Tag is not defined in dictionary, so treat as text
124
+ raise "unknown tag #{ti[:tag]}" if RubyBBCode.configuration.ignore_unknown_tags == :exception
125
+
126
+ ti = default_tag_info(tag_info)
127
+ ti[:is_tag] = false
128
+ ti[:text] = if RubyBBCode.configuration.ignore_unknown_tags == :text
129
+ tag_info[COMPLETE_MATCH]
130
+ else
131
+ ''
132
+ end
133
+ elsif (tag_info[TAG_PARAM_MATCH][0] == '=') && can_have_quick_param?
134
+ quick_param = tag_info[TAG_PARAM_MATCH][1..-1]
104
135
  # Get list of parameter values and add them as (regular) parameters
105
136
  value_array = quick_param.scan(@definition[:quick_param_format])[0]
106
137
  if value_array.nil?
@@ -111,9 +142,9 @@ module RubyBBCode
111
142
  ti[:params][param_tokens[i][:token]] = value
112
143
  end
113
144
  end
114
- elsif tag_info[5][0] == ?\s
145
+ elsif tag_info[TAG_PARAM_MATCH][0] == "\s"
115
146
  regex_string = '((\w+)=([\w#]+)) | ((\w+)="([^"]+)") | ((\w+)=\'([^\']+)\')'
116
- tag_info[5].scan(/#{regex_string}/ix) do |param_info|
147
+ tag_info[TAG_PARAM_MATCH].scan(/#{regex_string}/ix) do |param_info|
117
148
  param = param_info[1] || param_info[4] || param_info[7]
118
149
  value = param_info[2] || param_info[5] || param_info[8]
119
150
  ti[:params][param.to_sym] = value
@@ -121,7 +152,7 @@ module RubyBBCode
121
152
  end
122
153
  else
123
154
  # Plain text
124
- ti[:text] = tag_info[9]
155
+ ti[:text] = tag_info[TEXT]
125
156
  end
126
157
  ti
127
158
  end
@@ -15,7 +15,7 @@ module RubyBBCode
15
15
  # and a tag element has the form of
16
16
  # { :is_tag=>true, :tag=>:i, :nodes => [] }
17
17
  # * +nodes+
18
- def initialize(element, nodes = [])
18
+ def initialize(element)
19
19
  @element = element
20
20
  end
21
21
 
@@ -39,12 +39,12 @@ module RubyBBCode
39
39
 
40
40
  # Returns true if the tag does not have any parameters set.
41
41
  def params_not_set?
42
- @element[:params].length == 0
42
+ @element[:params].empty?
43
43
  end
44
44
 
45
- # Returns true id the node that child nodes
45
+ # Returns true if the node that child nodes
46
46
  def has_children?
47
- type == :tag and children.length > 0
47
+ (type == :tag) && !children.empty?
48
48
  end
49
49
 
50
50
  # Returns true when the quick parameter was invalid (i.e. it did not match the required format)