ruby-bbcode 2.0.0 → 2.1.1

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.
@@ -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)
@@ -8,10 +8,10 @@ module RubyBBCode
8
8
  attr_reader :bbtree, :errors
9
9
 
10
10
  def initialize(text_to_parse, dictionary, escape_html = true)
11
- @text = escape_html ? text_to_parse.gsub('<', '&lt;').gsub('>', '&gt;').gsub('"', "&quot;") : text_to_parse
11
+ @text = escape_html ? text_to_parse.gsub('<', '&lt;').gsub('>', '&gt;').gsub('"', '&quot;') : text_to_parse
12
12
 
13
13
  @dictionary = dictionary # dictionary containing all allowed/defined tags
14
- @bbtree = BBTree.new({:nodes => TagCollection.new})
14
+ @bbtree = BBTree.new(nodes: TagCollection.new)
15
15
  @ti = nil
16
16
  @errors = []
17
17
  end
@@ -25,34 +25,33 @@ module RubyBBCode
25
25
  # once this tree is built, the to_html method can be invoked where the tree is finally
26
26
  # converted into HTML syntax.
27
27
  def process_text
28
- regex_string = '((\[ (\/)? ( \* | (\w+)) ((=[^\[\]]+) | (\s\w+=\w+)* | ([^\]]*))? \]) | ([^\[]+))'
29
- @text.scan(/#{regex_string}/ix) do |tag_info|
28
+ @text.scan(TagInfo::REGEX) do |tag_info|
30
29
  @ti = TagInfo.new(tag_info, @dictionary)
31
30
 
32
- # if the tag isn't in the @dictionary list, then treat it as text
33
- @ti.handle_tag_as_text if @ti.element_is_tag? and !@ti.tag_in_dictionary?
34
-
35
31
  validate_element
36
32
 
37
33
  case @ti.type
38
34
  when :opening_tag
39
- element = {:is_tag => true, :tag => @ti[:tag], :definition => @ti.definition, :errors => @ti[:errors], :nodes => TagCollection.new }
35
+ element = { is_tag: true, tag: @ti[:tag], definition: @ti.definition, opening_whitespace: @ti.whitespace, errors: @ti[:errors], nodes: TagCollection.new }
40
36
  element[:invalid_quick_param] = true if @ti.invalid_quick_param?
41
37
  element[:params] = get_formatted_element_params
42
38
 
43
- @bbtree.retrogress_bbtree if self_closing_tag_reached_a_closer?
39
+ if self_closing_tag_reached_a_closer?
40
+ transfer_whitespace_to_closing_tag
41
+ @bbtree.retrogress_bbtree
42
+ end
44
43
 
45
44
  @bbtree.build_up_new_tag(element)
46
45
 
47
46
  @bbtree.escalate_bbtree(element)
48
47
  when :text
49
48
  tag_def = @bbtree.current_node.definition
50
- if tag_def and tag_def[:multi_tag] == true
49
+ if tag_def && (tag_def[:multi_tag] == true)
51
50
  set_multi_tag_to_actual_tag
52
51
  tag_def = @bbtree.current_node.definition
53
52
  end
54
53
 
55
- if within_open_tag? and tag_def[:require_between]
54
+ if within_open_tag? && tag_def[:require_between]
56
55
  between = get_formatted_between
57
56
  @bbtree.current_node[:between] = between
58
57
  if use_text_as_parameter?
@@ -63,7 +62,7 @@ module RubyBBCode
63
62
  add_element = true
64
63
 
65
64
  # ...and clear between, as this would result in two 'between' texts
66
- @bbtree.current_node[:between] = ""
65
+ @bbtree.current_node[:between] = ''
67
66
  end
68
67
  else
69
68
  # Between text can be used as (first) parameter
@@ -76,16 +75,20 @@ module RubyBBCode
76
75
 
77
76
  create_text_element
78
77
  when :closing_tag
78
+ @bbtree.current_node[:closing_whitespace] = @ti.whitespace
79
79
  if @ti[:wrong_closing]
80
80
  # Convert into text, so it
81
81
  @ti.handle_tag_as_text
82
82
  create_text_element
83
83
  else
84
- @bbtree.retrogress_bbtree if parent_of_self_closing_tag? and within_open_tag?
84
+ if parent_of_self_closing_tag? && within_open_tag?
85
+ transfer_whitespace_to_closing_tag
86
+ @bbtree.retrogress_bbtree
87
+ end
85
88
  @bbtree.retrogress_bbtree
86
89
  end
87
90
  end
88
- end # end of scan loop
91
+ end
89
92
 
90
93
  validate_all_tags_closed_off
91
94
  validate_stack_level_too_deep_potential
@@ -93,6 +96,25 @@ module RubyBBCode
93
96
 
94
97
  private
95
98
 
99
+ def transfer_whitespace_to_closing_tag
100
+ last_text_node = node_last_text(parent_tag)
101
+ unless last_text_node.nil?
102
+ last_text_node[:text].scan(/(\s+)$/) do |result|
103
+ parent_tag[:closing_whitespace] = result[0]
104
+ last_text_node[:text] = last_text_node[:text][0..-result[0].length - 1]
105
+ end
106
+ end
107
+ end
108
+
109
+ # Return the node that holds the last piece of text for the given node (self or child)
110
+ def node_last_text(node)
111
+ return node if node.type == :text
112
+ return node_last_text(node.children[-1]) unless node.children.empty?
113
+
114
+ # node does not hold text
115
+ nil
116
+ end
117
+
96
118
  def set_multi_tag_to_actual_tag
97
119
  # Try to find the actual tag
98
120
  tag = get_actual_tag
@@ -121,7 +143,7 @@ module RubyBBCode
121
143
  end
122
144
 
123
145
  def create_text_element
124
- element = {:is_tag => false, :text => @ti.text, :errors => @ti[:errors] }
146
+ element = { is_tag: false, text: @ti.text, errors: @ti[:errors] }
125
147
  @bbtree.build_up_new_tag(element)
126
148
  end
127
149
 
@@ -132,26 +154,26 @@ module RubyBBCode
132
154
  # perform special formatting for certain tags
133
155
  params[:url] = match_url_id(params[:url], @ti.definition[:url_matches])
134
156
  end
135
- return params
157
+ params
136
158
  end
137
159
 
138
160
  # Get 'between tag' for tag
139
161
  def get_formatted_between
140
162
  between = @ti[:text]
141
- # perform special formatting for cenrtain tags
163
+ # perform special formatting for certain tags
142
164
  between = match_url_id(between, @bbtree.current_node.definition[:url_matches]) if @bbtree.current_node.definition[:url_matches]
143
- return between
165
+ between
144
166
  end
145
167
 
146
168
  def match_url_id(url, regex_matches)
147
169
  regex_matches.each do |regex|
148
170
  if url =~ regex
149
- id = $1
171
+ id = Regexp.last_match(1)
150
172
  return id
151
173
  end
152
174
  end
153
175
 
154
- return url # if we couldn't find a match, then just return the url, hopefully it's a valid ID...
176
+ url # if we couldn't find a match, then just return the url, hopefully it's a valid ID...
155
177
  end
156
178
 
157
179
  # Validates the element
@@ -162,7 +184,7 @@ module RubyBBCode
162
184
  end
163
185
 
164
186
  def valid_text_or_opening_element?
165
- if @ti.element_is_text? or @ti.element_is_opening_tag?
187
+ if @ti.element_is_text? || @ti.element_is_opening_tag?
166
188
  return false unless valid_opening_tag?
167
189
  return false unless valid_constraints_on_child?
168
190
  end
@@ -171,7 +193,7 @@ module RubyBBCode
171
193
 
172
194
  def valid_opening_tag?
173
195
  if @ti.element_is_opening_tag?
174
- if @ti.only_allowed_in_parent_tags? and (!within_open_tag? or !@ti.allowed_in? parent_tag[:tag]) and !self_closing_tag_reached_a_closer?
196
+ if @ti.only_allowed_in_parent_tags? && (!within_open_tag? || !@ti.allowed_in?(parent_tag[:tag])) && !self_closing_tag_reached_a_closer?
175
197
  # Tag doesn't belong in the last opened tag
176
198
  throw_child_requires_specific_parent_error
177
199
  return false
@@ -183,19 +205,15 @@ module RubyBBCode
183
205
  end
184
206
 
185
207
  # Note that if allow_between_as_param is true, other checks already test the (correctness of the) 'between parameter'
186
- unless @ti.definition[:param_tokens].nil? or @ti.definition[:allow_between_as_param] == true
208
+ unless @ti.definition[:param_tokens].nil? || (@ti.definition[:allow_between_as_param] == true)
187
209
  # Check if all required parameters are added
188
210
  @ti.definition[:param_tokens].each do |token|
189
- if @ti[:params][token[:token]].nil? and token[:optional].nil?
190
- add_tag_error "Tag [#{@ti[:tag]}] must have '#{token[:token]}' parameter"
191
- end
211
+ add_tag_error "Tag [#{@ti[:tag]}] must have '#{token[:token]}' parameter" if @ti[:params][token[:token]].nil? && token[:optional].nil?
192
212
  end
193
213
 
194
214
  # Check if no 'custom parameters' are added
195
215
  @ti[:params].keys.each do |token|
196
- if @ti.definition[:param_tokens].find {|param_token| param_token[:token]==token}.nil?
197
- add_tag_error "Tag [#{@ti[:tag]}] doesn't have a '#{token}' parameter"
198
- end
216
+ add_tag_error "Tag [#{@ti[:tag]}] doesn't have a '#{token}' parameter" if @ti.definition[:param_tokens].find { |param_token| param_token[:token] == token }.nil?
199
217
  end
200
218
  end
201
219
  end
@@ -203,15 +221,15 @@ module RubyBBCode
203
221
  end
204
222
 
205
223
  def self_closing_tag_reached_a_closer?
206
- @ti.definition[:self_closable] and @bbtree.current_node[:tag] == @ti[:tag]
224
+ @ti.definition[:self_closable] && (@bbtree.current_node[:tag] == @ti[:tag])
207
225
  end
208
226
 
209
227
  def valid_constraints_on_child?
210
- if within_open_tag? and parent_has_constraints_on_children?
228
+ if within_open_tag? && parent_has_constraints_on_children?
211
229
  # Check if the found tag is allowed
212
230
  last_tag_def = parent_tag[:definition]
213
231
  allowed_tags = last_tag_def[:only_allow]
214
- if (!@ti[:is_tag] and last_tag_def[:require_between] != true and @ti[:text].lstrip != "") or (@ti[:is_tag] and (allowed_tags.include?(@ti[:tag]) == false)) # TODO: refactor this, it's just too long
232
+ if (!@ti.element_is_tag? && (last_tag_def[:require_between] != true) && (@ti[:text].lstrip != '')) || (@ti.element_is_tag? && (allowed_tags.include?(@ti[:tag]) == false)) # TODO: refactor this, it's just too long
215
233
  # Last opened tag does not allow tag
216
234
  throw_parent_prohibits_this_child_error
217
235
  return false
@@ -221,7 +239,6 @@ module RubyBBCode
221
239
  end
222
240
 
223
241
  def valid_closing_element?
224
-
225
242
  if @ti.element_is_closing_tag?
226
243
 
227
244
  if parent_tag.nil?
@@ -230,9 +247,9 @@ module RubyBBCode
230
247
  return false
231
248
  end
232
249
 
233
- if parent_tag[:tag] != @ti[:tag] and !parent_of_self_closing_tag?
250
+ if (parent_tag[:tag] != @ti[:tag]) && !parent_of_self_closing_tag?
234
251
  # Make an exception for 'supported tags'
235
- if @ti.definition[:supported_tags].nil? or ! @ti.definition[:supported_tags].include? parent_tag[:tag]
252
+ if @ti.definition[:supported_tags].nil? || !@ti.definition[:supported_tags].include?(parent_tag[:tag])
236
253
  add_tag_error "Closing tag [/#{@ti[:tag]}] doesn't match [#{parent_tag[:tag]}]"
237
254
  @ti[:wrong_closing] = true
238
255
  return false
@@ -240,7 +257,7 @@ module RubyBBCode
240
257
  end
241
258
 
242
259
  tag_def = @bbtree.current_node.definition
243
- if tag_def[:require_between] and @bbtree.current_node[:between].nil?
260
+ if tag_def[:require_between] && @bbtree.current_node[:between].nil? && @bbtree.current_node[:nodes].empty?
244
261
  err = "No text between [#{@ti[:tag]}] and [/#{@ti[:tag]}] tags."
245
262
  err = "Cannot determine multi-tag type: #{err}" if tag_def[:multi_tag]
246
263
  add_tag_error err, @bbtree.current_node
@@ -251,17 +268,16 @@ module RubyBBCode
251
268
  end
252
269
 
253
270
  def parent_of_self_closing_tag?
254
- tag_being_parsed = @ti.definition
255
271
  was_last_tag_self_closable = @bbtree.current_node[:definition][:self_closable] unless @bbtree.current_node[:definition].nil?
256
272
 
257
- was_last_tag_self_closable and last_tag_fit_in_this_tag?
273
+ was_last_tag_self_closable && last_tag_fit_in_this_tag?
258
274
  end
259
275
 
260
276
  def last_tag_fit_in_this_tag?
261
- @ti.definition[:only_allow].each do |tag|
277
+ @ti.definition[:only_allow]&.each do |tag|
262
278
  return true if tag == @bbtree.current_node[:tag]
263
- end unless @ti.definition[:only_allow].nil?
264
- return false
279
+ end
280
+ false
265
281
  end
266
282
 
267
283
  # This validation is for text elements with between text
@@ -271,8 +287,13 @@ module RubyBBCode
271
287
  def valid_param_supplied_as_text?
272
288
  tag_def = @bbtree.current_node.definition
273
289
 
290
+ if within_open_tag? && use_text_as_parameter? && @ti.element_is_tag? && has_no_text_node?
291
+ add_tag_error 'between parameter must be plain text'
292
+ return false
293
+ end
294
+
274
295
  # this conditional ensures whether the validation is apropriate to this tag type
275
- if @ti.element_is_text? and within_open_tag? and tag_def[:require_between] and use_text_as_parameter? and not tag_def[:quick_param_format].nil?
296
+ if @ti.element_is_text? && within_open_tag? && tag_def[:require_between] && use_text_as_parameter? && !tag_def[:quick_param_format].nil?
276
297
 
277
298
  # check if valid
278
299
  if @ti[:text].match(tag_def[:quick_param_format]).nil?
@@ -284,19 +305,17 @@ module RubyBBCode
284
305
  end
285
306
 
286
307
  def validate_all_tags_closed_off
308
+ return unless expecting_a_closing_tag?
309
+
287
310
  # if we're still expecting a closing tag and we've come to the end of the string... throw error(s)
288
- if expecting_a_closing_tag?
289
- @bbtree.tags_list.each do |tag|
290
- add_tag_error "[#{tag[:tag]}] not closed", tag
291
- tag[:closed] = false
292
- end
311
+ @bbtree.tags_list.each do |tag|
312
+ add_tag_error "[#{tag[:tag]}] not closed", tag
313
+ tag[:closed] = false
293
314
  end
294
315
  end
295
316
 
296
317
  def validate_stack_level_too_deep_potential
297
- if @bbtree.nodes.count > 2200
298
- throw_stack_level_will_be_too_deep_error
299
- end
318
+ throw_stack_level_will_be_too_deep_error if @bbtree.nodes.count > 2200
300
319
  end
301
320
 
302
321
  def throw_child_requires_specific_parent_error
@@ -312,20 +331,24 @@ module RubyBBCode
312
331
  def throw_parent_prohibits_this_child_error
313
332
  allowed_tags = parent_tag[:definition][:only_allow]
314
333
  err = "[#{parent_tag[:tag]}] can only contain [#{allowed_tags.to_sentence(to_sentence_bbcode_tags)}] tags, so "
315
- err += "[#{@ti[:tag]}]" if @ti[:is_tag]
316
- err += "\"#{@ti[:text]}\"" unless @ti[:is_tag]
334
+ err += "[#{@ti[:tag]}]" if @ti.element_is_tag?
335
+ err += "\"#{@ti[:text]}\"" unless @ti.element_is_tag?
317
336
  err += ' is not allowed'
318
337
  add_tag_error err
319
338
  end
320
339
 
321
340
  def throw_stack_level_will_be_too_deep_error
322
- @errors << "Stack level would go too deep. You must be trying to process a text containing thousands of BBTree nodes at once. (limit around 2300 tags containing 2,300 strings). Check RubyBBCode::TagCollection#to_html to see why this validation is needed."
341
+ @errors << 'Stack level would go too deep. You must be trying to process a text containing thousands of BBTree nodes at once. (limit around 2300 tags containing 2,300 strings). Check RubyBBCode::TagCollection#to_html to see why this validation is needed.'
323
342
  end
324
343
 
325
344
  def to_sentence_bbcode_tags
326
- {:words_connector => "], [",
327
- :two_words_connector => "] and [",
328
- :last_word_connector => "] and ["}
345
+ { words_connector: '], [',
346
+ two_words_connector: '] and [',
347
+ last_word_connector: '] and [' }
348
+ end
349
+
350
+ def has_no_text_node?
351
+ @bbtree.current_node[:nodes].blank? || @bbtree.current_node[:nodes][0][:text].nil?
329
352
  end
330
353
 
331
354
  def expecting_a_closing_tag?
@@ -338,7 +361,7 @@ module RubyBBCode
338
361
 
339
362
  def use_text_as_parameter?
340
363
  tag = @bbtree.current_node
341
- tag.definition[:allow_between_as_param] and tag.params_not_set? and !tag.invalid_quick_param?
364
+ tag.definition[:allow_between_as_param] && tag.params_not_set? && !tag.invalid_quick_param?
342
365
  end
343
366
 
344
367
  def parent_tag
@@ -14,16 +14,15 @@ module RubyBBCode::Templates
14
14
  def initialize(node)
15
15
  @node = node
16
16
  @tag_definition = node.definition # tag_definition
17
- @opening_part = "[#{node[:tag]}#{node.allow_params? ? '%param%' : ''}]"
18
- unless @node[:errors].empty?
19
- @opening_part = "<span class='bbcode_error' #{BBCodeErrorsTemplate.error_attribute(@node[:errors])}>#{@opening_part}</span>"
20
- end
21
- @closing_part = "[/#{node[:tag]}]"
17
+ @opening_part = "[#{node[:tag]}#{node.allow_params? ? '%param%' : ''}]" + add_whitespace(node[:opening_whitespace])
18
+ @opening_part = "<span class='bbcode_error' #{BBCodeErrorsTemplate.error_attribute(@node[:errors])}>#{@opening_part}</span>" unless @node[:errors].empty?
19
+ @closing_part = "[/#{node[:tag]}]" + add_whitespace(node[:closing_whitespace])
22
20
  end
23
21
 
24
- def self.convert_text(node)
22
+ def self.convert_text(node, _parent_node)
25
23
  # Keep the text as it was
26
24
  return "<span class='bbcode_error' #{error_attribute(node[:errors])}>#{node[:text]}</span>" unless node[:errors].empty?
25
+
27
26
  node[:text]
28
27
  end
29
28
 
@@ -41,8 +40,7 @@ module RubyBBCode::Templates
41
40
  end
42
41
  end
43
42
 
44
- def inlay_closing_part!
45
- end
43
+ def inlay_closing_part!; end
46
44
 
47
45
  def remove_unused_tokens!
48
46
  @opening_part.gsub!('%param%', '')
@@ -54,15 +52,20 @@ module RubyBBCode::Templates
54
52
 
55
53
  private
56
54
 
57
- def get_between
58
- return @node[:between] if @tag_definition[:require_between] and @node[:between]
59
- ''
60
- end
55
+ def add_whitespace(whitespace)
56
+ whitespace || ''
57
+ end
61
58
 
62
- def self.error_attribute(errors)
63
- # Escape (double) quotes so the JSON can be generated properly (and parsed properly by JavaScript)
64
- escapedErrors = errors.map { |error| error.gsub("\"","&quot;").gsub("'", "&#39;")}
65
- "data-bbcode-errors='#{JSON.fast_generate(escapedErrors)}'"
66
- end
59
+ def get_between
60
+ return @node[:between] if @tag_definition[:require_between] && @node[:between]
61
+
62
+ ''
63
+ end
64
+
65
+ def self.error_attribute(errors)
66
+ # Escape (double) quotes so the JSON can be generated properly (and parsed properly by JavaScript)
67
+ escapedErrors = errors.map { |error| error.gsub('"', '&quot;').gsub("'", '&#39;') }
68
+ "data-bbcode-errors='#{JSON.fast_generate(escapedErrors)}'"
69
+ end
67
70
  end
68
71
  end
@@ -10,20 +10,30 @@ module RubyBBCode::Templates
10
10
 
11
11
  def initialize(node)
12
12
  @node = node
13
- @tag_definition = node.definition # tag_definition
14
- @opening_part = node.definition[:html_open].dup
15
- @closing_part = node.definition[:html_close].dup
13
+ @tag_definition = node.definition
14
+ @opening_part = node.definition[:html_open] + add_whitespace(:opening_whitespace)
15
+ @closing_part = node.definition[:html_close] + add_whitespace(:closing_whitespace)
16
16
  end
17
17
 
18
18
  # Newlines are converted to html <br /> syntax before being returned.
19
- def self.convert_text(node)
19
+ def self.convert_text(node, parent_node)
20
20
  return '' if node[:text].nil?
21
- # convert_newlines_to_br
22
- node[:text].gsub("\r\n", "\n").gsub("\n", "<br />\n")
21
+
22
+ text = node[:text]
23
+ whitespace = ''
24
+
25
+ if !parent_node.nil? && parent_node.definition[:block_tag]
26
+ # Strip EOL whitespace, so it does not get converted
27
+ text.scan(/(\s+)$/) do |result|
28
+ whitespace = result[0]
29
+ text = text[0..-result[0].length - 1]
30
+ end
31
+ end
32
+ convert_newlines(text) + whitespace
23
33
  end
24
34
 
25
35
  def inlay_between_text!
26
- @opening_part.gsub!('%between%', @node[:between]) if between_text_as_param?
36
+ @opening_part.gsub!('%between%', format_between) if between_text_as_param?
27
37
  end
28
38
 
29
39
  def inlay_params!
@@ -31,12 +41,12 @@ module RubyBBCode::Templates
31
41
  @tag_definition[:param_tokens].each do |token|
32
42
  param_value = @node[:params][token[:token]] || token[:default]
33
43
  param_value = CGI.escape(param_value) if token[:uri_escape]
34
- @opening_part.gsub!("%#{token[:token].to_s}%", "#{token[:prefix]}#{param_value}#{token[:postfix]}") unless param_value.nil?
44
+ @opening_part.gsub!("%#{token[:token]}%", "#{token[:prefix]}#{param_value}#{token[:postfix]}") unless param_value.nil?
35
45
  end
36
46
  end
37
47
 
38
48
  def inlay_closing_part!
39
- @closing_part.gsub!('%between%', @node[:between]) if between_text_as_param?
49
+ @closing_part.gsub!('%between%', format_between) if between_text_as_param?
40
50
  end
41
51
 
42
52
  def remove_unused_tokens!
@@ -45,11 +55,27 @@ module RubyBBCode::Templates
45
55
  end
46
56
  end
47
57
 
58
+ def self.convert_newlines(text)
59
+ text.gsub("\r\n", "\n").gsub("\n", "<br />\n")
60
+ end
61
+
48
62
  private
49
63
 
64
+ def add_whitespace(key)
65
+ whitespace = @node[key]
66
+ return '' if whitespace.nil?
67
+
68
+ whitespace = HtmlTemplate.convert_newlines(whitespace) unless @tag_definition[:block_tag]
69
+ whitespace
70
+ end
71
+
50
72
  # Return true if the between text is needed as param
51
73
  def between_text_as_param?
52
74
  @tag_definition[:require_between]
53
75
  end
76
+
77
+ def format_between
78
+ @node[:between] || ''
79
+ end
54
80
  end
55
- end
81
+ end