sitemap_generator 6.3.0 → 7.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.
- checksums.yaml +4 -4
- data/CHANGES.md +107 -61
- data/README.md +176 -171
- data/VERSION +1 -1
- data/lib/capistrano/sitemap_generator.rb +2 -0
- data/lib/sitemap_generator/adapters/active_storage_adapter.rb +31 -0
- data/lib/sitemap_generator/adapters/aws_sdk_adapter.rb +29 -13
- data/lib/sitemap_generator/adapters/file_adapter.rb +12 -13
- data/lib/sitemap_generator/adapters/fog_adapter.rb +9 -7
- data/lib/sitemap_generator/adapters/google_storage_adapter.rb +8 -5
- data/lib/sitemap_generator/adapters/s3_adapter.rb +23 -18
- data/lib/sitemap_generator/adapters/wave_adapter.rb +8 -6
- data/lib/sitemap_generator/application.rb +9 -3
- data/lib/sitemap_generator/builder/sitemap_file.rb +41 -31
- data/lib/sitemap_generator/builder/sitemap_index_file.rb +31 -23
- data/lib/sitemap_generator/builder/sitemap_index_url.rb +10 -9
- data/lib/sitemap_generator/builder/sitemap_url.rb +130 -80
- data/lib/sitemap_generator/builder.rb +7 -3
- data/lib/sitemap_generator/core_ext/big_decimal.rb +40 -33
- data/lib/sitemap_generator/core_ext/numeric.rb +52 -46
- data/lib/sitemap_generator/core_ext.rb +2 -0
- data/lib/sitemap_generator/helpers/number_helper.rb +84 -76
- data/lib/sitemap_generator/interpreter.rb +22 -18
- data/lib/sitemap_generator/link_set.rb +114 -113
- data/lib/sitemap_generator/railtie.rb +4 -1
- data/lib/sitemap_generator/simple_namer.rb +8 -6
- data/lib/sitemap_generator/sitemap_location.rb +52 -40
- data/lib/sitemap_generator/tasks.rb +16 -26
- data/lib/sitemap_generator/templates.rb +11 -9
- data/lib/sitemap_generator/utilities.rb +46 -24
- data/lib/sitemap_generator.rb +42 -27
- data/lib/tasks/sitemap_generator_tasks.rake +2 -0
- data/rails/install.rb +2 -0
- data/rails/uninstall.rb +2 -0
- data/templates/sitemap.rb +3 -1
- metadata +7 -131
|
@@ -1,25 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'builder'
|
|
2
4
|
|
|
3
5
|
module SitemapGenerator
|
|
4
6
|
module Builder
|
|
7
|
+
# Wraps a sitemap file reference as a +<sitemap>+ XML entry for use in a sitemap index.
|
|
5
8
|
class SitemapIndexUrl < SitemapUrl
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
def initialize(path, options = {})
|
|
10
|
+
if (index = path.is_a?(SitemapGenerator::Builder::SitemapIndexFile) && path)
|
|
11
|
+
options = SitemapGenerator::Utilities.reverse_merge(options, host: index.location.host, lastmod: SitemapGenerator::Utilities.current_time,
|
|
12
|
+
priority: 1.0)
|
|
10
13
|
path = index.location.path_in_public
|
|
11
|
-
super(path, options)
|
|
12
|
-
else
|
|
13
|
-
super
|
|
14
14
|
end
|
|
15
|
+
super
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
# Return the URL as XML
|
|
18
|
-
def to_xml(builder=nil)
|
|
19
|
+
def to_xml(builder = nil)
|
|
19
20
|
builder = ::Builder::XmlMarkup.new if builder.nil?
|
|
20
21
|
builder.sitemap do
|
|
21
22
|
builder.loc self[:loc]
|
|
22
|
-
builder.lastmod w3c_date(self[:lastmod])
|
|
23
|
+
builder.lastmod w3c_date(self[:lastmod]) if self[:lastmod]
|
|
23
24
|
end
|
|
24
25
|
builder << '' # force to string
|
|
25
26
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'builder'
|
|
2
4
|
require 'uri'
|
|
3
5
|
require 'time'
|
|
@@ -7,8 +9,7 @@ module SitemapGenerator
|
|
|
7
9
|
module Builder
|
|
8
10
|
# A Hash-like class for holding information about a sitemap URL and
|
|
9
11
|
# generating an XML <url> element suitable for sitemaps.
|
|
10
|
-
class SitemapUrl < Hash
|
|
11
|
-
|
|
12
|
+
class SitemapUrl < Hash # rubocop:disable Metrics/ClassLength
|
|
12
13
|
# Return a new instance with options configured on it.
|
|
13
14
|
#
|
|
14
15
|
# == Arguments
|
|
@@ -29,63 +30,67 @@ module SitemapGenerator
|
|
|
29
30
|
# * +mobile+
|
|
30
31
|
# * +alternate+/+alternates+
|
|
31
32
|
# * +pagemap+
|
|
32
|
-
def initialize(path, options={})
|
|
33
|
+
def initialize(path, options = {}) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
34
|
+
super()
|
|
33
35
|
options = SitemapGenerator::Utilities.symbolize_keys(options)
|
|
34
|
-
if sitemap = path.is_a?(SitemapGenerator::Builder::SitemapFile) && path
|
|
36
|
+
if (sitemap = path.is_a?(SitemapGenerator::Builder::SitemapFile) && path)
|
|
35
37
|
SitemapGenerator::Utilities.reverse_merge!(
|
|
36
38
|
options,
|
|
37
|
-
:
|
|
38
|
-
:
|
|
39
|
+
host: sitemap.location.host,
|
|
40
|
+
lastmod: sitemap.lastmod
|
|
39
41
|
)
|
|
40
42
|
path = sitemap.location.path_in_public
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
SitemapGenerator::Utilities.assert_valid_keys(
|
|
44
46
|
options,
|
|
45
|
-
:priority, :changefreq, :lastmod, :expires, :host,
|
|
47
|
+
:priority, :changefreq, :lastmod, :expires, :host,
|
|
48
|
+
:images, :video, :news, :videos, :mobile,
|
|
49
|
+
:alternate, :alternates, :pagemap
|
|
46
50
|
)
|
|
47
51
|
SitemapGenerator::Utilities.reverse_merge!(
|
|
48
52
|
options,
|
|
49
|
-
:
|
|
50
|
-
:
|
|
51
|
-
:
|
|
52
|
-
:
|
|
53
|
-
:
|
|
54
|
-
:
|
|
55
|
-
:
|
|
56
|
-
:
|
|
53
|
+
priority: 0.5,
|
|
54
|
+
changefreq: 'weekly',
|
|
55
|
+
lastmod: SitemapGenerator::Utilities.current_time,
|
|
56
|
+
images: [],
|
|
57
|
+
news: {},
|
|
58
|
+
videos: [],
|
|
59
|
+
mobile: false,
|
|
60
|
+
alternates: []
|
|
57
61
|
)
|
|
58
|
-
raise
|
|
62
|
+
raise 'Cannot generate a url without a host' unless SitemapGenerator::Utilities.present?(options[:host])
|
|
59
63
|
|
|
60
|
-
if video = options.delete(:video)
|
|
64
|
+
if (video = options.delete(:video))
|
|
61
65
|
options[:videos] = video.is_a?(Array) ? options[:videos].concat(video) : options[:videos] << video
|
|
62
66
|
end
|
|
63
|
-
if alternate = options.delete(:alternate)
|
|
64
|
-
options[:alternates] =
|
|
67
|
+
if (alternate = options.delete(:alternate))
|
|
68
|
+
options[:alternates] =
|
|
69
|
+
alternate.is_a?(Array) ? options[:alternates].concat(alternate) : options[:alternates] << alternate
|
|
65
70
|
end
|
|
66
71
|
|
|
67
|
-
path = path.to_s.sub(
|
|
68
|
-
loc = path.empty? ? options[:host] :
|
|
69
|
-
|
|
70
|
-
:
|
|
71
|
-
:
|
|
72
|
-
:
|
|
73
|
-
:
|
|
74
|
-
:
|
|
75
|
-
:
|
|
76
|
-
:
|
|
77
|
-
:
|
|
78
|
-
:
|
|
79
|
-
:
|
|
80
|
-
:
|
|
81
|
-
:
|
|
72
|
+
path = encode_non_ascii(path.to_s.sub(%r{^/}, ''))
|
|
73
|
+
loc = path.empty? ? options[:host] : "#{options[:host].to_s.sub(%r{/$}, '')}/#{path}"
|
|
74
|
+
merge!(
|
|
75
|
+
priority: options[:priority],
|
|
76
|
+
changefreq: options[:changefreq],
|
|
77
|
+
lastmod: options[:lastmod],
|
|
78
|
+
expires: options[:expires],
|
|
79
|
+
host: options[:host],
|
|
80
|
+
loc: loc,
|
|
81
|
+
images: prepare_images(options[:images], options[:host]),
|
|
82
|
+
news: prepare_news(options[:news]),
|
|
83
|
+
videos: options[:videos],
|
|
84
|
+
mobile: options[:mobile],
|
|
85
|
+
alternates: prepare_alternates(options[:alternates], options[:host]),
|
|
86
|
+
pagemap: options[:pagemap]
|
|
82
87
|
)
|
|
83
88
|
end
|
|
84
89
|
|
|
85
90
|
# Return the URL as XML
|
|
86
|
-
def to_xml(builder=nil)
|
|
91
|
+
def to_xml(builder = nil) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
87
92
|
builder = ::Builder::XmlMarkup.new if builder.nil?
|
|
88
|
-
builder.url do
|
|
93
|
+
builder.url do # rubocop:disable Metrics/BlockLength
|
|
89
94
|
builder.loc self[:loc]
|
|
90
95
|
builder.lastmod w3c_date(self[:lastmod]) if self[:lastmod]
|
|
91
96
|
builder.expires w3c_date(self[:expires]) if self[:expires]
|
|
@@ -94,8 +99,8 @@ module SitemapGenerator
|
|
|
94
99
|
|
|
95
100
|
unless SitemapGenerator::Utilities.blank?(self[:news])
|
|
96
101
|
news_data = self[:news]
|
|
97
|
-
builder.news:news do
|
|
98
|
-
builder.news:publication do
|
|
102
|
+
builder.news :news do
|
|
103
|
+
builder.news :publication do
|
|
99
104
|
builder.news :name, news_data[:publication_name].to_s if news_data[:publication_name]
|
|
100
105
|
builder.news :language, news_data[:publication_language].to_s if news_data[:publication_language]
|
|
101
106
|
end
|
|
@@ -110,7 +115,7 @@ module SitemapGenerator
|
|
|
110
115
|
end
|
|
111
116
|
|
|
112
117
|
self[:images].each do |image|
|
|
113
|
-
builder.image:image do
|
|
118
|
+
builder.image :image do
|
|
114
119
|
builder.image :loc, image[:loc]
|
|
115
120
|
builder.image :caption, image[:caption].to_s if image[:caption]
|
|
116
121
|
builder.image :geo_location, image[:geo_location].to_s if image[:geo_location]
|
|
@@ -119,54 +124,67 @@ module SitemapGenerator
|
|
|
119
124
|
end
|
|
120
125
|
end
|
|
121
126
|
|
|
122
|
-
self[:videos].each do |video|
|
|
123
|
-
builder.video :video do
|
|
127
|
+
self[:videos].each do |video| # rubocop:disable Metrics/BlockLength
|
|
128
|
+
builder.video :video do # rubocop:disable Metrics/BlockLength
|
|
124
129
|
builder.video :thumbnail_loc, video[:thumbnail_loc].to_s
|
|
125
130
|
builder.video :title, video[:title].to_s
|
|
126
131
|
builder.video :description, video[:description].to_s
|
|
127
|
-
builder.video :content_loc, video[:content_loc].to_s
|
|
132
|
+
builder.video :content_loc, video[:content_loc].to_s if video[:content_loc]
|
|
128
133
|
if video[:player_loc]
|
|
129
|
-
loc_attributes = { :
|
|
130
|
-
|
|
134
|
+
loc_attributes = { allow_embed: yes_or_no_with_default(video[:allow_embed], true) }
|
|
135
|
+
if SitemapGenerator::Utilities.present?(video[:autoplay])
|
|
136
|
+
loc_attributes[:autoplay] = video[:autoplay].to_s
|
|
137
|
+
end
|
|
131
138
|
builder.video :player_loc, video[:player_loc].to_s, loc_attributes
|
|
132
139
|
end
|
|
133
|
-
builder.video :duration, video[:duration].to_s
|
|
134
|
-
builder.video :expiration_date,
|
|
135
|
-
builder.video :rating, format_float(video[:rating])
|
|
136
|
-
builder.video :view_count, video[:view_count].to_s
|
|
140
|
+
builder.video :duration, video[:duration].to_s if video[:duration]
|
|
141
|
+
builder.video :expiration_date, w3c_date(video[:expiration_date]) if video[:expiration_date]
|
|
142
|
+
builder.video :rating, format_float(video[:rating]) if video[:rating]
|
|
143
|
+
builder.video :view_count, video[:view_count].to_s if video[:view_count]
|
|
137
144
|
builder.video :publication_date, w3c_date(video[:publication_date]) if video[:publication_date]
|
|
138
|
-
video[:tags]
|
|
145
|
+
video[:tags]&.each { |tag| builder.video :tag, tag.to_s }
|
|
139
146
|
builder.video :tag, video[:tag].to_s if video[:tag]
|
|
140
147
|
builder.video :category, video[:category].to_s if video[:category]
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
148
|
+
if video.key?(:family_friendly)
|
|
149
|
+
builder.video :family_friendly,
|
|
150
|
+
yes_or_no_with_default(video[:family_friendly], true)
|
|
151
|
+
end
|
|
152
|
+
if video[:gallery_loc]
|
|
153
|
+
builder.video :gallery_loc, video[:gallery_loc].to_s,
|
|
154
|
+
title: video[:gallery_title].to_s
|
|
155
|
+
end
|
|
156
|
+
if SitemapGenerator::Utilities.present?(video[:price])
|
|
157
|
+
builder.video :price, video[:price].to_s, prepare_video_price_attribs(video)
|
|
158
|
+
end
|
|
144
159
|
if video[:uploader]
|
|
145
|
-
builder.video :uploader, video[:uploader].to_s,
|
|
160
|
+
builder.video :uploader, video[:uploader].to_s,
|
|
161
|
+
video[:uploader_info] ? { info: video[:uploader_info].to_s } : {}
|
|
162
|
+
end
|
|
163
|
+
builder.video :live, yes_or_no_with_default(video[:live], true) if video.key?(:live)
|
|
164
|
+
if video.key?(:requires_subscription)
|
|
165
|
+
builder.video :requires_subscription,
|
|
166
|
+
yes_or_no_with_default(video[:requires_subscription],
|
|
167
|
+
true)
|
|
146
168
|
end
|
|
147
|
-
builder.video :live, yes_or_no_with_default(video[:live], true) if video.has_key?(:live)
|
|
148
|
-
builder.video :requires_subscription, yes_or_no_with_default(video[:requires_subscription], true) if video.has_key?(:requires_subscription)
|
|
149
169
|
end
|
|
150
170
|
end
|
|
151
171
|
|
|
152
172
|
self[:alternates].each do |alternate|
|
|
153
173
|
rel = alternate[:nofollow] ? 'alternate nofollow' : 'alternate'
|
|
154
|
-
attributes = { :
|
|
174
|
+
attributes = { rel: rel, href: alternate[:href].to_s }
|
|
155
175
|
attributes[:hreflang] = alternate[:lang].to_s if SitemapGenerator::Utilities.present?(alternate[:lang])
|
|
156
176
|
attributes[:media] = alternate[:media].to_s if SitemapGenerator::Utilities.present?(alternate[:media])
|
|
157
177
|
builder.xhtml :link, attributes
|
|
158
178
|
end
|
|
159
179
|
|
|
160
|
-
unless SitemapGenerator::Utilities.blank?(self[:mobile])
|
|
161
|
-
builder.mobile :mobile
|
|
162
|
-
end
|
|
180
|
+
builder.mobile :mobile unless SitemapGenerator::Utilities.blank?(self[:mobile])
|
|
163
181
|
|
|
164
182
|
unless SitemapGenerator::Utilities.blank?(self[:pagemap])
|
|
165
183
|
builder.pagemap :PageMap do
|
|
166
184
|
SitemapGenerator::Utilities.as_array(self[:pagemap][:dataobjects]).each do |dataobject|
|
|
167
|
-
builder.pagemap :DataObject, :
|
|
185
|
+
builder.pagemap :DataObject, type: dataobject[:type].to_s, id: dataobject[:id].to_s do
|
|
168
186
|
SitemapGenerator::Utilities.as_array(dataobject[:attributes]).each do |attribute|
|
|
169
|
-
builder.pagemap :Attribute, attribute[:value].to_s, :
|
|
187
|
+
builder.pagemap :Attribute, attribute[:value].to_s, name: attribute[:name].to_s
|
|
170
188
|
end
|
|
171
189
|
end
|
|
172
190
|
end
|
|
@@ -186,48 +204,69 @@ module SitemapGenerator
|
|
|
186
204
|
attribs = {}
|
|
187
205
|
attribs[:currency] = video[:price_currency].to_s # required
|
|
188
206
|
attribs[:type] = video[:price_type] if SitemapGenerator::Utilities.present?(video[:price_type])
|
|
189
|
-
|
|
207
|
+
if SitemapGenerator::Utilities.present?(video[:price_resolution])
|
|
208
|
+
attribs[:resolution] = video[:price_resolution]
|
|
209
|
+
end
|
|
190
210
|
attribs
|
|
191
211
|
end
|
|
192
212
|
|
|
193
213
|
def prepare_news(news)
|
|
194
|
-
|
|
214
|
+
unless news.empty?
|
|
215
|
+
SitemapGenerator::Utilities.assert_valid_keys(
|
|
216
|
+
news,
|
|
217
|
+
:publication_name, :publication_language, :publication_date,
|
|
218
|
+
:genres, :access, :title, :keywords, :stock_tickers
|
|
219
|
+
)
|
|
220
|
+
end
|
|
195
221
|
news
|
|
196
222
|
end
|
|
197
223
|
|
|
224
|
+
# Return an Array of alternate option Hashes with relative hrefs expanded to absolute URLs.
|
|
225
|
+
def prepare_alternates(alternates, host)
|
|
226
|
+
alternates.map do |alt|
|
|
227
|
+
next alt unless alt.is_a?(Hash)
|
|
228
|
+
|
|
229
|
+
href = alt[:href].to_s
|
|
230
|
+
if href.start_with?('/')
|
|
231
|
+
alt.merge(href: URI.join(host, href).to_s)
|
|
232
|
+
else
|
|
233
|
+
alt
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
198
238
|
# Return an Array of image option Hashes suitable to be parsed by SitemapGenerator::Builder::SitemapFile
|
|
199
239
|
def prepare_images(images, host)
|
|
200
|
-
images.delete_if { |key,
|
|
240
|
+
images.delete_if { |key, _value| key[:loc].nil? }
|
|
201
241
|
images.each do |r|
|
|
202
242
|
SitemapGenerator::Utilities.assert_valid_keys(r, :loc, :caption, :geo_location, :title, :license)
|
|
203
243
|
r[:loc] = URI.join(host, r[:loc]).to_s
|
|
204
244
|
end
|
|
205
|
-
images[0..(SitemapGenerator::MAX_SITEMAP_IMAGES-1)]
|
|
245
|
+
images[0..(SitemapGenerator::MAX_SITEMAP_IMAGES - 1)]
|
|
206
246
|
end
|
|
207
247
|
|
|
208
|
-
def w3c_date(date)
|
|
248
|
+
def w3c_date(date) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
209
249
|
if date.is_a?(String)
|
|
210
250
|
date
|
|
211
251
|
elsif date.respond_to?(:iso8601)
|
|
212
252
|
date.iso8601.sub(/Z$/i, '+00:00')
|
|
213
253
|
elsif date.is_a?(Date) && !date.is_a?(DateTime)
|
|
214
|
-
date.strftime(
|
|
254
|
+
date.strftime('%Y-%m-%d')
|
|
215
255
|
else
|
|
216
|
-
zulutime =
|
|
217
|
-
date.
|
|
218
|
-
|
|
219
|
-
date.utc
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
end
|
|
256
|
+
zulutime =
|
|
257
|
+
if date.is_a?(DateTime)
|
|
258
|
+
date.new_offset(0)
|
|
259
|
+
elsif date.respond_to?(:utc)
|
|
260
|
+
date.utc
|
|
261
|
+
elsif date.is_a?(Integer)
|
|
262
|
+
Time.at(date).utc
|
|
263
|
+
end
|
|
225
264
|
|
|
226
265
|
if zulutime
|
|
227
|
-
zulutime.strftime(
|
|
266
|
+
zulutime.strftime('%Y-%m-%dT%H:%M:%S+00:00')
|
|
228
267
|
else
|
|
229
268
|
zone = date.strftime('%z').insert(-3, ':')
|
|
230
|
-
date.strftime(
|
|
269
|
+
date.strftime('%Y-%m-%dT%H:%M:%S') + zone
|
|
231
270
|
end
|
|
232
271
|
end
|
|
233
272
|
end
|
|
@@ -236,7 +275,10 @@ module SitemapGenerator
|
|
|
236
275
|
# value must be 'yes' or 'no'. Pass the default value as a boolean using `default`.
|
|
237
276
|
def yes_or_no(value)
|
|
238
277
|
if value.is_a?(String)
|
|
239
|
-
|
|
278
|
+
unless /^(yes|no)$/i.match?(value)
|
|
279
|
+
raise ArgumentError, "Unrecognized value for yes/no field: #{value.inspect}"
|
|
280
|
+
end
|
|
281
|
+
|
|
240
282
|
value.downcase
|
|
241
283
|
else
|
|
242
284
|
value ? 'yes' : 'no'
|
|
@@ -252,7 +294,15 @@ module SitemapGenerator
|
|
|
252
294
|
# Format a float to to one decimal precision.
|
|
253
295
|
# TODO: Use rounding with precision once merged with framework_agnostic.
|
|
254
296
|
def format_float(value)
|
|
255
|
-
value.is_a?(String) ? value : ('%0.1f'
|
|
297
|
+
value.is_a?(String) ? value : format('%0.1f', value)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
private
|
|
301
|
+
|
|
302
|
+
# Percent-encode non-ASCII bytes in a path segment, leaving already-encoded %XX sequences untouched.
|
|
303
|
+
# Applied to paths only — not the host — IDN hostnames require punycode, not percent-encoding.
|
|
304
|
+
def encode_non_ascii(str)
|
|
305
|
+
str.gsub(/[^\x00-\x7F]/) { |c| c.bytes.map { |b| format('%%%02X', b) }.join }
|
|
256
306
|
end
|
|
257
307
|
end
|
|
258
308
|
end
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'sitemap_generator/builder/sitemap_file'
|
|
2
4
|
require 'sitemap_generator/builder/sitemap_index_file'
|
|
3
5
|
require 'sitemap_generator/builder/sitemap_url'
|
|
4
6
|
require 'sitemap_generator/builder/sitemap_index_url'
|
|
5
7
|
|
|
6
|
-
module SitemapGenerator
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
module SitemapGenerator
|
|
9
|
+
module Builder
|
|
10
|
+
LinkHolder = Struct.new(:link, :options)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -1,55 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'bigdecimal'
|
|
2
4
|
|
|
3
5
|
begin
|
|
4
6
|
require 'psych'
|
|
5
7
|
rescue LoadError
|
|
8
|
+
# psych is optional; fall back gracefully if unavailable
|
|
6
9
|
end
|
|
7
10
|
|
|
8
11
|
require 'yaml'
|
|
9
12
|
|
|
10
13
|
# Define our own class rather than modify the global class
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
module SitemapGenerator
|
|
15
|
+
# Scoped BigDecimal wrapper that serializes to YAML without scientific notation.
|
|
16
|
+
# Defined here rather than reopening the global BigDecimal class.
|
|
17
|
+
class BigDecimal
|
|
18
|
+
YAML_TAG = 'tag:yaml.org,2002:float'
|
|
19
|
+
YAML_MAPPING = { 'Infinity' => '.Inf', '-Infinity' => '-.Inf', 'NaN' => '.NaN' }.freeze
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
yaml_tag YAML_TAG
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
def initialize(num)
|
|
24
|
+
@value = BigDecimal(num)
|
|
25
|
+
end
|
|
20
26
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
def *(other)
|
|
28
|
+
other * @value
|
|
29
|
+
end
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
def /(other)
|
|
32
|
+
other.is_a?(SitemapGenerator::BigDecimal) ? @value / other.instance_variable_get(:@value) : @value / other
|
|
33
|
+
end
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
# This emits the number without any scientific notation.
|
|
36
|
+
# This is better than self.to_f.to_s since it doesn't lose precision.
|
|
37
|
+
#
|
|
38
|
+
# Note that reconstituting YAML floats to native floats may lose precision.
|
|
39
|
+
def to_yaml(opts = {})
|
|
40
|
+
return super unless defined?(YAML::ENGINE) && YAML::ENGINE.syck?
|
|
41
|
+
|
|
42
|
+
YAML.quick_emit(nil, opts) do |out|
|
|
43
|
+
string = to_s
|
|
44
|
+
out.scalar(YAML_TAG, YAML_MAPPING[string] || string, :plain)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
35
47
|
|
|
36
|
-
|
|
48
|
+
def encode_with(coder)
|
|
37
49
|
string = to_s
|
|
38
|
-
|
|
50
|
+
coder.represent_scalar(nil, YAML_MAPPING[string] || string)
|
|
39
51
|
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def encode_with(coder)
|
|
43
|
-
string = to_s
|
|
44
|
-
coder.represent_scalar(nil, YAML_MAPPING[string] || string)
|
|
45
|
-
end
|
|
46
52
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
def to_d
|
|
54
|
+
self
|
|
55
|
+
end
|
|
50
56
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
DEFAULT_STRING_FORMAT = 'F'
|
|
58
|
+
def to_s(format = DEFAULT_STRING_FORMAT)
|
|
59
|
+
@value.to_s(format)
|
|
60
|
+
end
|
|
54
61
|
end
|
|
55
62
|
end
|
|
@@ -1,48 +1,54 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SitemapGenerator
|
|
4
|
+
# Scoped Numeric wrapper providing byte-unit helpers (+kilobytes+, +megabytes+, etc.).
|
|
5
|
+
# Defined here rather than reopening the global Numeric class.
|
|
6
|
+
class Numeric
|
|
7
|
+
KILOBYTE = 1024
|
|
8
|
+
MEGABYTE = KILOBYTE * 1024
|
|
9
|
+
GIGABYTE = MEGABYTE * 1024
|
|
10
|
+
TERABYTE = GIGABYTE * 1024
|
|
11
|
+
PETABYTE = TERABYTE * 1024
|
|
12
|
+
EXABYTE = PETABYTE * 1024
|
|
13
|
+
|
|
14
|
+
def initialize(number)
|
|
15
|
+
@number = number
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Enables the use of byte calculations and declarations, like 45.bytes + 2.6.megabytes
|
|
19
|
+
def bytes
|
|
20
|
+
@number
|
|
21
|
+
end
|
|
22
|
+
alias byte bytes
|
|
23
|
+
|
|
24
|
+
def kilobytes
|
|
25
|
+
@number * KILOBYTE
|
|
26
|
+
end
|
|
27
|
+
alias kilobyte kilobytes
|
|
28
|
+
|
|
29
|
+
def megabytes
|
|
30
|
+
@number * MEGABYTE
|
|
31
|
+
end
|
|
32
|
+
alias megabyte megabytes
|
|
33
|
+
|
|
34
|
+
def gigabytes
|
|
35
|
+
@number * GIGABYTE
|
|
36
|
+
end
|
|
37
|
+
alias gigabyte gigabytes
|
|
38
|
+
|
|
39
|
+
def terabytes
|
|
40
|
+
@number * TERABYTE
|
|
41
|
+
end
|
|
42
|
+
alias terabyte terabytes
|
|
43
|
+
|
|
44
|
+
def petabytes
|
|
45
|
+
@number * PETABYTE
|
|
46
|
+
end
|
|
47
|
+
alias petabyte petabytes
|
|
48
|
+
|
|
49
|
+
def exabytes
|
|
50
|
+
@number * EXABYTE
|
|
51
|
+
end
|
|
52
|
+
alias exabyte exabytes
|
|
11
53
|
end
|
|
12
|
-
|
|
13
|
-
# Enables the use of byte calculations and declarations, like 45.bytes + 2.6.megabytes
|
|
14
|
-
def bytes
|
|
15
|
-
@number
|
|
16
|
-
end
|
|
17
|
-
alias :byte :bytes
|
|
18
|
-
|
|
19
|
-
def kilobytes
|
|
20
|
-
@number * KILOBYTE
|
|
21
|
-
end
|
|
22
|
-
alias :kilobyte :kilobytes
|
|
23
|
-
|
|
24
|
-
def megabytes
|
|
25
|
-
@number * MEGABYTE
|
|
26
|
-
end
|
|
27
|
-
alias :megabyte :megabytes
|
|
28
|
-
|
|
29
|
-
def gigabytes
|
|
30
|
-
@number * GIGABYTE
|
|
31
|
-
end
|
|
32
|
-
alias :gigabyte :gigabytes
|
|
33
|
-
|
|
34
|
-
def terabytes
|
|
35
|
-
@number * TERABYTE
|
|
36
|
-
end
|
|
37
|
-
alias :terabyte :terabytes
|
|
38
|
-
|
|
39
|
-
def petabytes
|
|
40
|
-
@number * PETABYTE
|
|
41
|
-
end
|
|
42
|
-
alias :petabyte :petabytes
|
|
43
|
-
|
|
44
|
-
def exabytes
|
|
45
|
-
@number * EXABYTE
|
|
46
|
-
end
|
|
47
|
-
alias :exabyte :exabytes
|
|
48
54
|
end
|