meta-tags 2.22.3 → 2.24.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.
@@ -1,14 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MetaTags
4
- # This class is used by MetaTags gems to render HTML meta tags into page.
4
+ # This class is used by the MetaTags gem to render HTML meta tags on a page.
5
5
  class Renderer
6
6
  attr_reader :meta_tags, :normalized_meta_tags
7
7
 
8
- # Initialized a new instance of Renderer.
9
- #
10
- # @param [MetaTagsCollection] meta_tags meta tags object to render.
8
+ # Initializes a new instance of Renderer.
11
9
  #
10
+ # @param meta_tags [MetaTagsCollection] meta tags object to render.
12
11
  def initialize(meta_tags)
13
12
  @meta_tags = meta_tags
14
13
  @normalized_meta_tags = {}
@@ -16,7 +15,7 @@ module MetaTags
16
15
 
17
16
  # Renders meta tags on the page.
18
17
  #
19
- # @param [ActionView::Base] view Rails view object.
18
+ # @param view [ActionView::Base] Rails view object.
20
19
  def render(view)
21
20
  tags = [] # : Array[Tag]
22
21
 
@@ -43,8 +42,7 @@ module MetaTags
43
42
 
44
43
  # Renders charset tag.
45
44
  #
46
- # @param [Array<Tag>] tags a buffer object to store tag in.
47
- #
45
+ # @param tags [Array<Tag>] a buffer object to store tags in.
48
46
  def render_charset(tags)
49
47
  charset = meta_tags.extract(:charset)
50
48
  tags << Tag.new(:meta, charset: charset) if charset.present?
@@ -52,8 +50,7 @@ module MetaTags
52
50
 
53
51
  # Renders title tag.
54
52
  #
55
- # @param [Array<Tag>] tags a buffer object to store tag in.
56
- #
53
+ # @param tags [Array<Tag>] a buffer object to store tags in.
57
54
  def render_title(tags)
58
55
  normalized_meta_tags[:title] = meta_tags.page_title
59
56
  normalized_meta_tags[:site] = meta_tags[:site]
@@ -68,8 +65,7 @@ module MetaTags
68
65
 
69
66
  # Renders icon(s) tag.
70
67
  #
71
- # @param [Array<Tag>] tags a buffer object to store tag in.
72
- #
68
+ # @param tags [Array<Tag>] a buffer object to store tags in.
73
69
  def render_icon(tags)
74
70
  icon = meta_tags.extract(:icon)
75
71
  return unless icon
@@ -81,16 +77,16 @@ module MetaTags
81
77
 
82
78
  icon.each do |icon_params|
83
79
  icon_params = {rel: "icon", type: "image/x-icon"}.with_indifferent_access.merge(icon_params)
84
- tags << Tag.new(:link, icon_params)
80
+ tags << Tag.new(:link, icon_params) if icon_params[:href].present?
85
81
  end
86
82
  end
87
83
 
88
84
  # Renders meta tag with normalization (should have a corresponding normalize_
89
85
  # method in TextNormalizer).
90
86
  #
91
- # @param [Array<Tag>] tags a buffer object to store tag in.
87
+ # @param tags [Array<Tag>] a buffer object to store tags in.
88
+ # @param name [Symbol] meta tag name to normalize and render.
92
89
  # @see TextNormalizer
93
- #
94
90
  def render_with_normalization(tags, name)
95
91
  value = TextNormalizer.public_send(:"normalize_#{name}", meta_tags.extract(name))
96
92
  normalized_meta_tags[name] = value
@@ -99,8 +95,7 @@ module MetaTags
99
95
 
100
96
  # Renders noindex and nofollow meta tags.
101
97
  #
102
- # @param [Array<Tag>] tags a buffer object to store tag in.
103
- #
98
+ # @param tags [Array<Tag>] a buffer object to store tags in.
104
99
  def render_noindex(tags)
105
100
  meta_tags.extract_robots.each do |name, content|
106
101
  tags << Tag.new(:meta, name: name, content: content) if content.present?
@@ -109,8 +104,7 @@ module MetaTags
109
104
 
110
105
  # Renders refresh meta tag.
111
106
  #
112
- # @param [Array<Tag>] tags a buffer object to store tag in.
113
- #
107
+ # @param tags [Array<Tag>] a buffer object to store tags in.
114
108
  def render_refresh(tags)
115
109
  refresh = meta_tags.extract(:refresh)
116
110
  tags << Tag.new(:meta, "http-equiv" => "refresh", :content => refresh.to_s) if refresh.present?
@@ -118,8 +112,7 @@ module MetaTags
118
112
 
119
113
  # Renders alternate link tags.
120
114
  #
121
- # @param [Array<Tag>] tags a buffer object to store tag in.
122
- #
115
+ # @param tags [Array<Tag>] a buffer object to store tags in.
123
116
  def render_alternate(tags)
124
117
  alternate = meta_tags.extract(:alternate)
125
118
  return unless alternate
@@ -130,15 +123,15 @@ module MetaTags
130
123
  end
131
124
  elsif alternate.is_a?(Array)
132
125
  alternate.each do |link_params|
133
- tags << Tag.new(:link, {rel: "alternate"}.with_indifferent_access.merge(link_params))
126
+ link_params = {rel: "alternate"}.with_indifferent_access.merge(link_params)
127
+ tags << Tag.new(:link, link_params) if link_params[:href].present?
134
128
  end
135
129
  end
136
130
  end
137
131
 
138
- # Renders open_search link tag.
139
- #
140
- # @param [Array<Tag>] tags a buffer object to store tag in.
132
+ # Renders the OpenSearch link tag.
141
133
  #
134
+ # @param tags [Array<Tag>] a buffer object to store tags in.
142
135
  def render_open_search(tags)
143
136
  open_search = meta_tags.extract(:open_search)
144
137
  return unless open_search
@@ -152,8 +145,7 @@ module MetaTags
152
145
 
153
146
  # Renders links.
154
147
  #
155
- # @param [Array<Tag>] tags a buffer object to store tag in.
156
- #
148
+ # @param tags [Array<Tag>] a buffer object to store tags in.
157
149
  def render_links(tags)
158
150
  [:amphtml, :prev, :next, :image_src, :manifest].each do |tag_name|
159
151
  href = meta_tags.extract(tag_name)
@@ -164,13 +156,12 @@ module MetaTags
164
156
  end
165
157
  end
166
158
 
167
- # Renders canonical link
168
- #
169
- # @param [Array<Tag>] tags a buffer object to store tag in.
159
+ # Renders the canonical link.
170
160
  #
161
+ # @param tags [Array<Tag>] a buffer object to store tags in.
171
162
  def render_canonical_link(tags)
172
- href = meta_tags.extract(:canonical) # extract, so its not used anywhere else
173
- return if MetaTags.config.skip_canonical_links_on_noindex && meta_tags[:noindex]
163
+ href = meta_tags.extract(:canonical) # extract, so it's not used anywhere else
164
+ return if MetaTags.config.skip_canonical_links_on_noindex && meta_tags.noindex?
174
165
  return if href.blank?
175
166
 
176
167
  @normalized_meta_tags[:canonical] = href
@@ -179,30 +170,28 @@ module MetaTags
179
170
 
180
171
  # Renders complex hash objects.
181
172
  #
182
- # @param [Array<Tag>] tags a buffer object to store tag in.
183
- #
184
- def render_hashes(tags, **opts)
173
+ # @param tags [Array<Tag>] a buffer object to store tags in.
174
+ def render_hashes(tags)
185
175
  meta_tags.meta_tags.each_key do |property|
186
- render_hash(tags, property, **opts)
176
+ render_hash(tags, property)
187
177
  end
188
178
  end
189
179
 
190
180
  # Renders a complex hash object by key.
191
181
  #
192
- # @param [Array<Tag>] tags a buffer object to store tag in.
193
- #
194
- def render_hash(tags, key, **opts)
182
+ # @param tags [Array<Tag>] a buffer object to store tags in.
183
+ # @param key [String, Symbol] top-level meta tag key.
184
+ def render_hash(tags, key)
195
185
  data = meta_tags.meta_tags[key]
196
186
  return unless data.is_a?(Hash)
197
187
 
198
- process_hash(tags, key, data, **opts)
188
+ process_hash(tags, key, data)
199
189
  meta_tags.extract(key)
200
190
  end
201
191
 
202
192
  # Renders custom meta tags.
203
193
  #
204
- # @param [Array<Tag>] tags a buffer object to store tag in.
205
- #
194
+ # @param tags [Array<Tag>] a buffer object to store tags in.
206
195
  def render_custom(tags)
207
196
  meta_tags.meta_tags.each do |name, data|
208
197
  Array(data).each do |val|
@@ -212,85 +201,136 @@ module MetaTags
212
201
  end
213
202
  end
214
203
 
215
- # Recursive method to process all the hashes and arrays on meta tags
216
- #
217
- # @param [Array<Tag>] tags a buffer object to store tag in.
218
- # @param [String, Symbol] property a Hash or a String to render as meta tag.
219
- # @param [Hash, Array, String, Symbol] content text content or a symbol reference to
220
- # top-level meta tag.
204
+ # Recursive method to process all hashes and arrays in meta tags.
221
205
  #
222
- def process_tree(tags, property, content, itemprop: nil, **opts)
223
- method = case content
206
+ # @param tags [Array<Tag>] a buffer object to store tags in.
207
+ # @param property [String, Symbol] the meta tag property name.
208
+ # @param content [Hash, Array, String, Symbol] text content or a symbol
209
+ # reference to a top-level meta tag.
210
+ # @param itemprop [String, Symbol, nil] value of the itemprop attribute.
211
+ def process_tree(tags, property, content, itemprop: nil)
212
+ case content
224
213
  when Hash
225
- :process_hash
214
+ process_hash(tags, property, content, itemprop: itemprop)
226
215
  when Array
227
- :process_array
216
+ process_array(tags, property, content, itemprop: itemprop)
228
217
  else
229
- iprop = itemprop
230
- :render_tag
218
+ if content.is_a?(Symbol) && MetaTags.config.resolve_symbolic_references_in_arrays
219
+ process_reference(tags, property, content, itemprop: itemprop)
220
+ else
221
+ render_tag(tags, property, content, itemprop: itemprop)
222
+ end
231
223
  end
232
- __send__(method, tags, property, content, itemprop: iprop, **opts)
233
224
  end
234
225
 
235
- # Recursive method to process a hash with meta tags
226
+ # Recursive method to process a hash of meta tags.
236
227
  #
237
- # @param [Array<Tag>] tags a buffer object to store tag in.
238
- # @param [String, Symbol] property a Hash or a String to render as meta tag.
239
- # @param [Hash] content nested meta tag attributes.
240
- #
241
- def process_hash(tags, property, content, **opts)
242
- itemprop = content.delete(:itemprop)
228
+ # @param tags [Array<Tag>] a buffer object to store tags in.
229
+ # @param property [String, Symbol] the meta tag property name.
230
+ # @param content [Hash] nested meta tag attributes.
231
+ # @param itemprop [String, Symbol, nil] inherited itemprop value.
232
+ def process_hash(tags, property, content, itemprop: nil)
233
+ itemprop_key = content.key?(:itemprop) ? :itemprop : "itemprop"
234
+ current_itemprop = content.key?(itemprop_key) ? content[itemprop_key] : itemprop
235
+
243
236
  content.each do |key, value|
237
+ next if key.to_s == "itemprop"
238
+
244
239
  if key.to_s == "_"
245
- iprop = itemprop
246
240
  key = property
241
+ next_itemprop = current_itemprop
247
242
  else
248
243
  key = "#{property}:#{key}"
244
+ next_itemprop = nil
249
245
  end
250
246
 
251
- normalized_value = if value.is_a?(Symbol)
252
- normalized_meta_tags[value]
247
+ if value.is_a?(Symbol)
248
+ process_reference(tags, key, value, itemprop: next_itemprop)
253
249
  else
254
- value
250
+ process_tree(tags, key, value, itemprop: next_itemprop)
255
251
  end
256
- process_tree(tags, key, normalized_value, **opts.merge(itemprop: iprop))
257
252
  end
258
253
  end
259
254
 
260
- # Recursive method to process a hash with meta tags
261
- #
262
- # @param [Array<Tag>] tags a buffer object to store tag in.
263
- # @param [String, Symbol] property a Hash or a String to render as meta tag.
264
- # @param [Array] content array of nested meta tag attributes or values.
265
- #
266
- def process_array(tags, property, content, **opts)
267
- content.each { |v| process_tree(tags, property, v, **opts) }
255
+ # Recursive method to process an array of meta tags.
256
+ #
257
+ # @param tags [Array<Tag>] a buffer object to store tags in.
258
+ # @param property [String, Symbol] the meta tag property name.
259
+ # @param content [Array] array of nested meta tag attributes or values.
260
+ # @param itemprop [String, Symbol, nil] value of the itemprop attribute.
261
+ def process_array(tags, property, content, itemprop: nil)
262
+ unless MetaTags.config.resolve_symbolic_references_in_arrays
263
+ symbol_reference = content.find { |value| value.is_a?(Symbol) }
264
+ if symbol_reference
265
+ MetaTags.deprecator.warn(
266
+ "Passing #{symbol_reference.inspect} directly inside a nested meta tag Array is deprecated. " \
267
+ "It is rendered literally in MetaTags 2.x but will be interpreted as a mirrored reference in MetaTags 3.0. " \
268
+ "Set MetaTags.config.resolve_symbolic_references_in_arrays = true to opt in now; this behavior will " \
269
+ "become the default in MetaTags 3.0. Use a String to keep a literal value."
270
+ )
271
+ end
272
+ end
273
+
274
+ content.each { |value| process_tree(tags, property, value, itemprop: itemprop) }
268
275
  end
269
276
 
270
- # Recursive method to process a hash with meta tags
277
+ # Resolves a Symbol reference and processes its normalized value once.
271
278
  #
272
- # @param [Array<Tag>] tags a buffer object to store tag in.
273
- # @param [String, Symbol] name a Hash or a String to render as meta tag.
274
- # @param [String, Symbol] value text content or a symbol reference to
275
- # top-level meta tag.
276
- # @param [String, Symbol] itemprop value of the itemprop attribute.
279
+ # @param tags [Array<Tag>] a buffer object to store tags in.
280
+ # @param property [String, Symbol] the meta tag property name.
281
+ # @param reference [Symbol] normalized top-level meta tag reference.
282
+ # @param itemprop [String, Symbol, nil] value of the itemprop attribute.
283
+ def process_reference(tags, property, reference, itemprop: nil)
284
+ content = normalized_meta_tags[reference]
285
+ case content
286
+ when Hash
287
+ process_hash(tags, property, content, itemprop: itemprop)
288
+ when Array
289
+ process_array(tags, property, content, itemprop: itemprop)
290
+ else
291
+ render_tag(tags, property, content, itemprop: itemprop)
292
+ end
293
+ end
294
+
295
+ # Renders a single meta tag.
277
296
  #
297
+ # @param tags [Array<Tag>] a buffer object to store tags in.
298
+ # @param name [String, Symbol] the meta tag name.
299
+ # @param value [String, Symbol] text content or a symbol reference to a
300
+ # top-level meta tag.
301
+ # @param itemprop [String, Symbol, nil] value of the itemprop attribute.
278
302
  def render_tag(tags, name, value, itemprop: nil)
279
303
  name_key ||= configured_name_key(name)
280
304
  tags << Tag.new(:meta, name_key => name.to_s, :content => value, :itemprop => itemprop) if value.present?
281
305
  end
282
306
 
283
- # Returns meta tag property name for a give meta tag based on the
307
+ # Returns the meta tag property name for a given meta tag based on the
284
308
  # configured list of property tags in MetaTags::Configuration#property_tags.
285
309
  #
286
- # @param [String, Symbol] name tag key.
310
+ # @param name [String, Symbol] tag key.
287
311
  # @return [Symbol] meta tag attribute name (:property or :name).
288
- #
289
312
  def configured_name_key(name)
313
+ name = name.to_s
290
314
  is_property_tag = MetaTags.config.property_tags.any? do |tag_name|
291
- name.to_s.match(/^#{Regexp.escape(tag_name.to_s)}\b/)
315
+ property_tag?(name, tag_name.to_s)
292
316
  end
293
317
  is_property_tag ? :property : :name
294
318
  end
319
+
320
+ # Returns true when a configured property tag matches the exact meta tag
321
+ # name or the start of a colon-delimited namespace.
322
+ #
323
+ # @param name [String] rendered meta tag name.
324
+ # @param tag_name [String] configured property tag name or namespace prefix.
325
+ # @return [Boolean]
326
+ def property_tag?(name, tag_name)
327
+ return false unless name.start_with?(tag_name)
328
+
329
+ tag_name_length = tag_name.bytesize
330
+ return true if name.bytesize == tag_name_length
331
+ return true if tag_name.getbyte(tag_name_length - 1) == 58
332
+
333
+ name.getbyte(tag_name_length) == 58
334
+ end
295
335
  end
296
336
  end
data/lib/meta_tags/tag.rb CHANGED
@@ -7,26 +7,28 @@ module MetaTags
7
7
 
8
8
  # Initializes a new instance of Tag class.
9
9
  #
10
- # @param [String, Symbol] name HTML tag name
11
- # @param [Hash] attributes list of HTML tag attributes
12
- #
10
+ # @param name [String, Symbol] HTML tag name.
11
+ # @param attributes [Hash] list of HTML tag attributes.
13
12
  def initialize(name, attributes = {})
14
13
  @name = name.to_s
15
14
  @attributes = attributes
16
15
  end
17
16
 
18
- # Render tag into a Rails view.
17
+ # Renders the tag in a Rails view.
19
18
  #
20
- # @param [ActionView::Base] view instance of a Rails view.
19
+ # @param view [ActionView::Base] instance of a Rails view.
21
20
  # @return [String] HTML string for the tag.
22
- #
23
21
  def render(view)
24
- view.tag(name, prepare_attributes(attributes), MetaTags.config.open_meta_tags?)
22
+ view.tag(name, serialize_iso8601_attributes(attributes), MetaTags.config.open_meta_tags?)
25
23
  end
26
24
 
27
25
  protected
28
26
 
29
- def prepare_attributes(attributes)
27
+ # Serializes attribute values that support ISO 8601 formatting.
28
+ #
29
+ # @param attributes [Hash] HTML tag attributes.
30
+ # @return [Hash] normalized HTML tag attributes.
31
+ def serialize_iso8601_attributes(attributes)
30
32
  attributes.each do |key, value|
31
33
  attributes[key] = value.iso8601 if value.respond_to?(:iso8601)
32
34
  end
@@ -1,18 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MetaTags
4
- # Module contains helpers that normalize text meta tag values.
4
+ # This module contains helpers that normalize text meta tag values.
5
5
  module TextNormalizer
6
6
  extend self
7
7
 
8
8
  # Normalize title value.
9
9
  #
10
- # @param [String] site_title site title.
11
- # @param [Array<String>] title title string.
12
- # @param [String] separator a string to join title parts with.
13
- # @param [true,false] reverse whether title should be reversed.
10
+ # @param site_title [String] site title.
11
+ # @param title [Array<String>] title segments.
12
+ # @param separator [String] a string to join title parts with.
13
+ # @param reverse [Boolean] whether title should be reversed.
14
14
  # @return [String] title with HTML tags removed.
15
- #
16
15
  def normalize_title(site_title, title, separator, reverse = false)
17
16
  clean_title = cleanup_strings(title)
18
17
  clean_title.reverse! if reverse
@@ -35,13 +34,12 @@ module MetaTags
35
34
 
36
35
  # Normalize description value.
37
36
  #
38
- # @param [String] description description string.
39
- # @return [String] text with tags removed, squashed spaces, truncated
40
- # to 200 characters.
41
- #
37
+ # @param description [String] description string.
38
+ # @return [String] text with tags removed, squashed spaces, and truncated
39
+ # to the configured description limit.
42
40
  def normalize_description(description)
43
41
  # description could be another object not a string, but since it probably
44
- # serves the same purpose we could just as it to convert itself to str
42
+ # serves the same purpose, we can ask it to convert itself to a string
45
43
  # and continue from there
46
44
  description = cleanup_string(description)
47
45
  return "" if description.blank?
@@ -51,9 +49,8 @@ module MetaTags
51
49
 
52
50
  # Normalize keywords value.
53
51
  #
54
- # @param [String, Array<String>] keywords list of keywords as a string or Array.
52
+ # @param keywords [String, Array<String>] list of keywords as a string or Array.
55
53
  # @return [String] list of keywords joined with comma, with tags removed.
56
- #
57
54
  def normalize_keywords(keywords)
58
55
  keywords = cleanup_strings(keywords)
59
56
  return "" if keywords.blank?
@@ -68,16 +65,14 @@ module MetaTags
68
65
  # Easy way to get access to Rails helpers.
69
66
  #
70
67
  # @return [ActionView::Base] proxy object to access Rails helpers.
71
- #
72
68
  def helpers
73
69
  ActionController::Base.helpers
74
70
  end
75
71
 
76
- # Strips all HTML tags from the +html+, including comments.
77
- #
78
- # @param [String] string HTML string.
79
- # @return [String] html_safe string with no HTML tags.
72
+ # Strips all HTML tags from +string+, including comments.
80
73
  #
74
+ # @param string [String] HTML string.
75
+ # @return [String] HTML-safe string with no HTML tags.
81
76
  def strip_tags(string)
82
77
  if defined?(Loofah)
83
78
  # Instead of strip_tags we will use Loofah to strip tags from now on
@@ -87,25 +82,24 @@ module MetaTags
87
82
  end
88
83
  end
89
84
 
90
- # This method returns a html safe string similar to what <tt>Array#join</tt>
85
+ # This method returns an HTML-safe string similar to what <tt>Array#join</tt>
91
86
  # would return. All items in the array, including the supplied separator, are
92
- # html escaped unless they are html safe, and the returned string is marked
93
- # as html safe.
87
+ # HTML-escaped unless they are HTML-safe, and the returned string is marked
88
+ # as HTML-safe.
94
89
  #
95
- # @param [Array<String>] array list of strings to join.
96
- # @param [String] sep separator to join strings with.
90
+ # @param array [Array<String>] list of strings to join.
91
+ # @param sep [String] separator to join strings with.
97
92
  # @return [String] input strings joined together using a given separator.
98
- #
99
93
  def safe_join(array, sep = $OFS)
100
94
  helpers.safe_join(array, sep)
101
95
  end
102
96
 
103
97
  # Removes HTML tags and squashes down all the spaces.
104
98
  #
105
- # @param [String, nil] string input string.
106
- # @return [String] input string with no HTML tags and consequent white
107
- # space characters squashed into a single space.
108
- #
99
+ # @param string [String, nil] input string.
100
+ # @param strip [Boolean] whether to trim leading and trailing whitespace.
101
+ # @return [String] input string with no HTML tags and consecutive
102
+ # whitespace characters squashed into a single space.
109
103
  def cleanup_string(string, strip: true)
110
104
  return "" if string.nil?
111
105
  raise ArgumentError, "Expected a string or an object that implements #to_str" unless string.respond_to?(:to_str)
@@ -118,24 +112,24 @@ module MetaTags
118
112
  s
119
113
  end
120
114
 
121
- # Cleans multiple strings up.
115
+ # Cleans up multiple strings.
122
116
  #
123
- # @param [String, Array<String>] strings input string(s).
117
+ # @param strings [String, Array<String>] input string(s).
118
+ # @param strip [Boolean] whether to trim leading and trailing whitespace.
124
119
  # @return [Array<String>] clean strings.
125
120
  # @see cleanup_string
126
- #
127
121
  def cleanup_strings(strings, strip: true)
128
122
  strings = Array(strings).flatten.map! { |s| cleanup_string(s, strip: strip) }
129
123
  strings.reject!(&:blank?)
130
124
  strings
131
125
  end
132
126
 
133
- # Truncates a string to a specific limit. Return string without truncation when limit 0 or nil
127
+ # Truncates a string to a specific limit. Returns the string without
128
+ # truncation when the limit is 0 or nil.
134
129
  #
135
- # @param [String] string input strings.
136
- # @param [Integer,nil] limit characters number to truncate to.
130
+ # @param string [String] input string.
131
+ # @param limit [Integer, nil] number of characters to truncate to.
137
132
  # @return [String] truncated string.
138
- #
139
133
  def truncate(string, limit = nil)
140
134
  return string if limit.to_i == 0
141
135
 
@@ -150,22 +144,22 @@ module MetaTags
150
144
 
151
145
  # Truncates an array of strings to a specific limit.
152
146
  #
153
- # @param [Array<String>] string_array input strings.
154
- # @param [Integer,nil] limit characters number to truncate to.
155
- # @param [String] separator separator that will be used to join array later.
147
+ # @param string_array [Array<String>] input strings.
148
+ # @param limit [Integer, nil] number of characters to truncate to.
149
+ # @param separator [String] separator that will be used to join the array later.
156
150
  # @return [Array<String>] truncated array of strings.
157
- #
158
151
  def truncate_array(string_array, limit = nil, separator = "")
159
152
  return string_array if limit.nil? || limit <= 0
160
153
 
161
154
  length = 0
155
+ preserve_items = string_array.size > 1 && MetaTags.config.truncate_array_items_at_boundaries
162
156
  result = [] # : Array[String]
163
157
 
164
158
  string_array.each do |string|
165
159
  limit_left = calculate_limit_left(limit, length, result, separator)
166
160
 
167
161
  if string.length > limit_left
168
- result << truncate(string, limit_left)
162
+ result << truncate(string, limit_left) if !preserve_items || result.empty?
169
163
  break string_array
170
164
  end
171
165
 
@@ -181,10 +175,23 @@ module MetaTags
181
175
 
182
176
  private
183
177
 
178
+ # Calculates how many characters are left for the next segment.
179
+ #
180
+ # @param limit [Integer] total truncation limit.
181
+ # @param length [Integer] current accumulated length.
182
+ # @param result [Array<String>] accumulated string segments.
183
+ # @param separator [String] separator inserted between segments.
184
+ # @return [Integer] remaining number of characters.
184
185
  def calculate_limit_left(limit, length, result, separator)
185
186
  limit - length - (result.any? ? separator.length : 0)
186
187
  end
187
188
 
189
+ # Truncates the site title and page title segments to the configured limit.
190
+ #
191
+ # @param site_title [String] site title.
192
+ # @param title [Array<String>] page title segments.
193
+ # @param separator [String] separator used between segments.
194
+ # @return [Array] truncated site title and title segments.
188
195
  def truncate_title(site_title, title, separator)
189
196
  global_limit = MetaTags.config.title_limit.to_i
190
197
  if global_limit > 0
@@ -199,6 +206,13 @@ module MetaTags
199
206
  [site_title, title]
200
207
  end
201
208
 
209
+ # Calculates the title length limits for the site title and page title.
210
+ #
211
+ # @param site_title [String] site title.
212
+ # @param title [Array<String>] page title segments.
213
+ # @param separator [String] separator used between segments.
214
+ # @param global_limit [Integer] total allowed title length.
215
+ # @return [Array<Integer>] site title limit and page title limit.
202
216
  def calculate_title_limits(site_title, title, separator, global_limit)
203
217
  # What should we truncate first: site title or page title?
204
218
  main_title = MetaTags.config.truncate_site_title_first ? title : [site_title]
@@ -2,6 +2,6 @@
2
2
 
3
3
  module MetaTags
4
4
  # Gem version.
5
- VERSION = "2.22.3"
5
+ VERSION = "2.24.0"
6
6
  public_constant :VERSION
7
7
  end