ruby-bbcode 2.0.3 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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)