sitemap_generator 7.0.3 → 7.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 +4 -4
- data/CHANGES.md +73 -64
- data/README.md +142 -143
- data/VERSION +1 -1
- data/lib/capistrano/sitemap_generator.rb +2 -0
- data/lib/sitemap_generator/adapters/active_storage_adapter.rb +15 -10
- data/lib/sitemap_generator/adapters/aws_sdk_adapter.rb +13 -12
- data/lib/sitemap_generator/adapters/file_adapter.rb +10 -13
- data/lib/sitemap_generator/adapters/fog_adapter.rb +2 -2
- data/lib/sitemap_generator/adapters/google_storage_adapter.rb +5 -4
- data/lib/sitemap_generator/adapters/s3_adapter.rb +15 -14
- data/lib/sitemap_generator/adapters/wave_adapter.rb +5 -5
- data/lib/sitemap_generator/application.rb +5 -3
- data/lib/sitemap_generator/builder/sitemap_file.rb +17 -14
- data/lib/sitemap_generator/builder/sitemap_index_file.rb +20 -18
- data/lib/sitemap_generator/builder/sitemap_index_url.rb +5 -6
- data/lib/sitemap_generator/builder/sitemap_url.rb +58 -34
- data/lib/sitemap_generator/builder.rb +4 -2
- data/lib/sitemap_generator/core_ext/big_decimal.rb +38 -33
- data/lib/sitemap_generator/core_ext/numeric.rb +50 -46
- data/lib/sitemap_generator/helpers/number_helper.rb +52 -46
- data/lib/sitemap_generator/interpreter.rb +11 -15
- data/lib/sitemap_generator/link_set.rb +63 -65
- data/lib/sitemap_generator/railtie.rb +1 -0
- data/lib/sitemap_generator/simple_namer.rb +3 -4
- data/lib/sitemap_generator/sitemap_location.rb +44 -36
- data/lib/sitemap_generator/tasks.rb +1 -1
- data/lib/sitemap_generator/templates.rb +6 -7
- data/lib/sitemap_generator/utilities.rb +25 -17
- data/lib/sitemap_generator.rb +22 -14
- 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 +2 -0
- metadata +2 -2
|
@@ -10,23 +10,26 @@ module SitemapGenerator
|
|
|
10
10
|
# compressed prior to being written out. Otherwise the data will be written out
|
|
11
11
|
# unchanged.
|
|
12
12
|
# @param raw_data - data to write to the file.
|
|
13
|
-
def write(location, raw_data)
|
|
13
|
+
def write(location, raw_data) # rubocop:disable Metrics/MethodLength
|
|
14
14
|
# Ensure that the directory exists
|
|
15
15
|
dir = location.directory
|
|
16
16
|
if !File.exist?(dir)
|
|
17
17
|
FileUtils.mkdir_p(dir)
|
|
18
18
|
elsif !File.directory?(dir)
|
|
19
|
-
raise SitemapError
|
|
19
|
+
raise SitemapError, "#{dir} should be a directory!"
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
File.open(location.path, 'wb') do |stream|
|
|
23
|
+
if location.gzip?
|
|
24
|
+
gzip(stream, raw_data)
|
|
25
|
+
else
|
|
26
|
+
stream.write raw_data
|
|
27
|
+
end
|
|
27
28
|
end
|
|
28
29
|
end
|
|
29
30
|
|
|
31
|
+
private
|
|
32
|
+
|
|
30
33
|
# Write `data` to a stream, passing the data through a GzipWriter
|
|
31
34
|
# to compress it.
|
|
32
35
|
def gzip(stream, data)
|
|
@@ -34,11 +37,5 @@ module SitemapGenerator
|
|
|
34
37
|
gz.write data
|
|
35
38
|
gz.close
|
|
36
39
|
end
|
|
37
|
-
|
|
38
|
-
# Write `data` to a stream as is.
|
|
39
|
-
def plain(stream, data)
|
|
40
|
-
stream.write data
|
|
41
|
-
stream.close
|
|
42
|
-
end
|
|
43
40
|
end
|
|
44
41
|
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
unless defined?(Fog::Storage)
|
|
4
4
|
raise LoadError, "Error: `Fog::Storage` is not defined.\n\n" \
|
|
5
|
-
|
|
5
|
+
"Please `require 'fog'` - or another library that defines this class."
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
module SitemapGenerator
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
unless defined?(Google::Cloud::Storage)
|
|
4
4
|
raise LoadError, "Error: `Google::Cloud::Storage` is not defined.\n\n" \
|
|
5
|
-
|
|
5
|
+
"Please `require 'google/cloud/storage'` - or another library that defines this class."
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
module SitemapGenerator
|
|
@@ -12,7 +12,8 @@ module SitemapGenerator
|
|
|
12
12
|
#
|
|
13
13
|
# @param [Hash] opts Google::Cloud::Storage configuration options.
|
|
14
14
|
# @option :bucket [String] Required. Name of Google Storage Bucket where the file is to be uploaded.
|
|
15
|
-
# @option :acl [String] Optional. Access control which is applied to the uploaded file(s).
|
|
15
|
+
# @option :acl [String] Optional. Access control which is applied to the uploaded file(s).
|
|
16
|
+
# Default value is 'public'.
|
|
16
17
|
#
|
|
17
18
|
# All options other than the `:bucket` and `:acl` options are passed to the `Google::Cloud::Storage.new`
|
|
18
19
|
# initializer. See https://googleapis.dev/ruby/google-cloud-storage/latest/file.AUTHENTICATION.html
|
|
@@ -25,7 +26,7 @@ module SitemapGenerator
|
|
|
25
26
|
def initialize(opts = {})
|
|
26
27
|
opts = opts.clone
|
|
27
28
|
@bucket = opts.delete(:bucket)
|
|
28
|
-
@acl = opts.
|
|
29
|
+
@acl = opts.key?(:acl) ? opts.delete(:acl) : 'public'
|
|
29
30
|
@storage_options = opts
|
|
30
31
|
end
|
|
31
32
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
unless defined?(Fog::Storage)
|
|
4
4
|
raise LoadError, "Error: `Fog::Storage` is not defined.\n\n" \
|
|
5
|
-
|
|
5
|
+
"Please `require 'fog-aws'` - or another library that defines this class."
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
module SitemapGenerator
|
|
@@ -22,21 +22,21 @@ module SitemapGenerator
|
|
|
22
22
|
#
|
|
23
23
|
# Alternatively you can use an environment variable to configure each option (except `fog_storage_options`).
|
|
24
24
|
# The environment variables have the same name but capitalized, e.g. `FOG_PATH_STYLE`.
|
|
25
|
-
def initialize(opts = {})
|
|
26
|
-
@aws_access_key_id = opts[:aws_access_key_id] || ENV
|
|
27
|
-
@aws_secret_access_key = opts[:aws_secret_access_key] || ENV
|
|
28
|
-
@aws_session_token = opts[:aws_session_token] || ENV
|
|
29
|
-
@fog_provider = opts[:fog_provider] || ENV
|
|
30
|
-
@fog_directory = opts[:fog_directory] || ENV
|
|
31
|
-
@fog_region = opts[:fog_region] || ENV
|
|
32
|
-
@fog_path_style = opts[:fog_path_style] || ENV
|
|
25
|
+
def initialize(opts = {}) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
26
|
+
@aws_access_key_id = opts[:aws_access_key_id] || ENV.fetch('AWS_ACCESS_KEY_ID', nil)
|
|
27
|
+
@aws_secret_access_key = opts[:aws_secret_access_key] || ENV.fetch('AWS_SECRET_ACCESS_KEY', nil)
|
|
28
|
+
@aws_session_token = opts[:aws_session_token] || ENV.fetch('AWS_SESSION_TOKEN', nil)
|
|
29
|
+
@fog_provider = opts[:fog_provider] || ENV.fetch('FOG_PROVIDER', nil)
|
|
30
|
+
@fog_directory = opts[:fog_directory] || ENV.fetch('FOG_DIRECTORY', nil)
|
|
31
|
+
@fog_region = opts[:fog_region] || ENV.fetch('FOG_REGION', nil)
|
|
32
|
+
@fog_path_style = opts[:fog_path_style] || ENV.fetch('FOG_PATH_STYLE', nil)
|
|
33
33
|
@fog_storage_options = opts[:fog_storage_options] || {}
|
|
34
|
-
fog_public = opts[:fog_public].nil? ? ENV
|
|
35
|
-
@fog_public = SitemapGenerator::Utilities.falsy?(fog_public)
|
|
34
|
+
fog_public = opts[:fog_public].nil? ? ENV.fetch('FOG_PUBLIC', nil) : opts[:fog_public]
|
|
35
|
+
@fog_public = !SitemapGenerator::Utilities.falsy?(fog_public)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
# Call with a SitemapLocation and string data
|
|
39
|
-
def write(location, raw_data)
|
|
39
|
+
def write(location, raw_data) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
40
40
|
SitemapGenerator::FileAdapter.new.write(location, raw_data)
|
|
41
41
|
|
|
42
42
|
credentials = { provider: @fog_provider }
|
|
@@ -57,7 +57,8 @@ module SitemapGenerator
|
|
|
57
57
|
directory.files.create(
|
|
58
58
|
key: location.path_in_public,
|
|
59
59
|
body: File.open(location.path),
|
|
60
|
-
public: @fog_public
|
|
60
|
+
public: @fog_public,
|
|
61
|
+
content_type: location.content_type
|
|
61
62
|
)
|
|
62
63
|
end
|
|
63
64
|
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
unless defined?(CarrierWave::Uploader::Base)
|
|
4
4
|
raise LoadError, "Error: `CarrierWave::Uploader::Base` is not defined.\n\n" \
|
|
5
|
-
|
|
5
|
+
"Please `require 'carrierwave'` - or another library that defines this class."
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
module SitemapGenerator
|
|
@@ -14,10 +14,10 @@ module SitemapGenerator
|
|
|
14
14
|
def write(location, raw_data)
|
|
15
15
|
SitemapGenerator::FileAdapter.new.write(location, raw_data)
|
|
16
16
|
directory = File.dirname(location.path_in_public)
|
|
17
|
-
if directory != '.'
|
|
18
|
-
|
|
17
|
+
self.store_dir = directory if directory != '.'
|
|
18
|
+
File.open(location.path, 'rb') do |io|
|
|
19
|
+
store!(io)
|
|
19
20
|
end
|
|
20
|
-
store!(open(location.path, 'rb'))
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
end
|
|
@@ -3,17 +3,19 @@
|
|
|
3
3
|
require 'pathname'
|
|
4
4
|
|
|
5
5
|
module SitemapGenerator
|
|
6
|
+
# Thin abstraction over the host application environment.
|
|
7
|
+
# Provides the app +root+ path and Rails version detection.
|
|
6
8
|
class Application
|
|
7
|
-
def is_rails?
|
|
9
|
+
def is_rails? # rubocop:disable Naming/PredicatePrefix
|
|
8
10
|
!!defined?(Rails::VERSION)
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
# Returns a boolean indicating whether this environment is Rails 3
|
|
12
14
|
#
|
|
13
15
|
# @return [Boolean]
|
|
14
|
-
def is_at_least_rails3?
|
|
16
|
+
def is_at_least_rails3? # rubocop:disable Naming/PredicatePrefix
|
|
15
17
|
is_rails? && Rails.version.to_f >= 3
|
|
16
|
-
rescue
|
|
18
|
+
rescue StandardError
|
|
17
19
|
false # Rails.version defined in 2.1.0
|
|
18
20
|
end
|
|
19
21
|
|
|
@@ -11,10 +11,12 @@ module SitemapGenerator
|
|
|
11
11
|
#
|
|
12
12
|
# sitemap = SitemapFile.new(:location => SitemapLocation.new(...))
|
|
13
13
|
# sitemap.add('/', { ... }) <- add a link to the sitemap
|
|
14
|
-
# sitemap.finalize! <- write the sitemap file and freeze the object
|
|
14
|
+
# sitemap.finalize! <- write the sitemap file and freeze the object
|
|
15
|
+
# to protect it from further modification
|
|
15
16
|
#
|
|
16
17
|
class SitemapFile
|
|
17
18
|
include SitemapGenerator::Helpers::NumberHelper
|
|
19
|
+
|
|
18
20
|
attr_reader :link_count, :filesize, :location, :news_count
|
|
19
21
|
|
|
20
22
|
# === Options
|
|
@@ -22,7 +24,7 @@ module SitemapGenerator
|
|
|
22
24
|
# * <tt>location</tt> - a SitemapGenerator::SitemapLocation instance or a Hash of options
|
|
23
25
|
# from which a SitemapLocation will be created for you. See `SitemapGenerator::SitemapLocation` for
|
|
24
26
|
# the supported list of options.
|
|
25
|
-
def initialize(opts = {})
|
|
27
|
+
def initialize(opts = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
26
28
|
@location = opts.is_a?(Hash) ? SitemapGenerator::SitemapLocation.new(opts) : opts
|
|
27
29
|
@link_count = 0
|
|
28
30
|
@news_count = 0
|
|
@@ -46,7 +48,8 @@ module SitemapGenerator
|
|
|
46
48
|
HTML
|
|
47
49
|
@xml_wrapper_start.gsub!(/\s+/, ' ').gsub!(/ *> */, '>').strip!
|
|
48
50
|
@xml_wrapper_end = '</urlset>'
|
|
49
|
-
@filesize = SitemapGenerator::Utilities.bytesize(@xml_wrapper_start) +
|
|
51
|
+
@filesize = SitemapGenerator::Utilities.bytesize(@xml_wrapper_start) +
|
|
52
|
+
SitemapGenerator::Utilities.bytesize(@xml_wrapper_end)
|
|
50
53
|
@xml_content = @xml_wrapper_start
|
|
51
54
|
@written = false
|
|
52
55
|
@reserved_name = nil # holds the name reserved from the namer
|
|
@@ -59,20 +62,22 @@ module SitemapGenerator
|
|
|
59
62
|
# mess up the name-assignment sequence.
|
|
60
63
|
def lastmod
|
|
61
64
|
File.mtime(location.path) if location.reserved_name?
|
|
62
|
-
rescue
|
|
65
|
+
rescue StandardError
|
|
63
66
|
nil
|
|
64
67
|
end
|
|
65
68
|
|
|
66
69
|
def empty?
|
|
67
|
-
@link_count
|
|
70
|
+
@link_count.zero?
|
|
68
71
|
end
|
|
69
72
|
|
|
70
73
|
# Return a boolean indicating whether the sitemap file can fit another link
|
|
71
74
|
# of <tt>bytes</tt> bytes in size. You can also pass a string and the
|
|
72
75
|
# bytesize will be calculated for you.
|
|
73
76
|
def file_can_fit?(bytes)
|
|
74
|
-
bytes =
|
|
75
|
-
(@filesize + bytes) < SitemapGenerator::MAX_SITEMAP_FILESIZE &&
|
|
77
|
+
bytes = SitemapGenerator::Utilities.bytesize(bytes) if bytes.is_a?(String)
|
|
78
|
+
(@filesize + bytes) < SitemapGenerator::MAX_SITEMAP_FILESIZE &&
|
|
79
|
+
@link_count < max_sitemap_links &&
|
|
80
|
+
@news_count < SitemapGenerator::MAX_SITEMAP_NEWS
|
|
76
81
|
end
|
|
77
82
|
|
|
78
83
|
# Add a link to the sitemap file.
|
|
@@ -94,7 +99,7 @@ module SitemapGenerator
|
|
|
94
99
|
#
|
|
95
100
|
# The link added to the sitemap will use the host from its location object
|
|
96
101
|
# if no host has been specified.
|
|
97
|
-
def add(link, options = {})
|
|
102
|
+
def add(link, options = {}) # rubocop:disable Metrics/MethodLength
|
|
98
103
|
raise SitemapGenerator::SitemapFinalizedError if finalized?
|
|
99
104
|
|
|
100
105
|
sitemap_url =
|
|
@@ -106,11 +111,9 @@ module SitemapGenerator
|
|
|
106
111
|
end
|
|
107
112
|
|
|
108
113
|
xml = sitemap_url.to_xml
|
|
109
|
-
raise SitemapGenerator::SitemapFullError
|
|
114
|
+
raise SitemapGenerator::SitemapFullError unless file_can_fit?(xml)
|
|
110
115
|
|
|
111
|
-
if sitemap_url.news?
|
|
112
|
-
@news_count += 1
|
|
113
|
-
end
|
|
116
|
+
@news_count += 1 if sitemap_url.news?
|
|
114
117
|
|
|
115
118
|
# Add the XML to the sitemap
|
|
116
119
|
@xml_content << xml
|
|
@@ -140,7 +143,7 @@ module SitemapGenerator
|
|
|
140
143
|
# A SitemapGenerator::SitemapError exception is raised if the file has
|
|
141
144
|
# already been written.
|
|
142
145
|
def write
|
|
143
|
-
raise SitemapGenerator::SitemapError
|
|
146
|
+
raise SitemapGenerator::SitemapError, 'Sitemap already written!' if written?
|
|
144
147
|
|
|
145
148
|
finalize! unless finalized?
|
|
146
149
|
reserve_name
|
|
@@ -158,7 +161,7 @@ module SitemapGenerator
|
|
|
158
161
|
# Reserve a name from the namer unless one has already been reserved.
|
|
159
162
|
# Safe to call more than once.
|
|
160
163
|
def reserve_name
|
|
161
|
-
@reserved_name ||= @location.reserve_name
|
|
164
|
+
@reserved_name ||= @location.reserve_name # rubocop:disable Naming/MemoizedInstanceVariableName
|
|
162
165
|
end
|
|
163
166
|
|
|
164
167
|
# Return a boolean indicating whether a name has been reserved
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
module SitemapGenerator
|
|
4
4
|
module Builder
|
|
5
|
+
# Builds the sitemap index XML file, listing all sitemap files.
|
|
6
|
+
# Manages deferred naming (waits for a second sitemap before reserving the index name)
|
|
7
|
+
# and controls whether an index is written at all via +create_index+.
|
|
5
8
|
class SitemapIndexFile < SitemapFile
|
|
6
|
-
|
|
7
9
|
# === Options
|
|
8
10
|
#
|
|
9
11
|
# * <tt>location</tt> - a SitemapGenerator::SitemapIndexLocation instance or a Hash of options
|
|
10
12
|
# from which a SitemapLocation will be created for you.
|
|
11
|
-
def initialize(opts = {})
|
|
13
|
+
def initialize(opts = {}) # rubocop:disable Lint/MissingSuper, Metrics/MethodLength
|
|
12
14
|
@location = opts.is_a?(Hash) ? SitemapGenerator::SitemapIndexLocation.new(opts) : opts
|
|
13
15
|
@link_count = 0
|
|
14
16
|
@sitemaps_link_count = 0
|
|
@@ -49,9 +51,9 @@ module SitemapGenerator
|
|
|
49
51
|
# If a link is being added to the index manually as a string, then we
|
|
50
52
|
# can assume that the index is required (unless create_index is false of course).
|
|
51
53
|
# This seems like the logical thing to do.
|
|
52
|
-
|
|
53
|
-
def add(link, options = {})
|
|
54
|
-
if file = link.is_a?(SitemapFile) && link
|
|
54
|
+
alias super_add add
|
|
55
|
+
def add(link, options = {}) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
56
|
+
if (file = link.is_a?(SitemapFile) && link)
|
|
55
57
|
@sitemaps_link_count += file.link_count
|
|
56
58
|
file.finalize! unless file.finalized?
|
|
57
59
|
|
|
@@ -62,7 +64,7 @@ module SitemapGenerator
|
|
|
62
64
|
# first name (the index, or the sitemap). If the item is not a SitemapFile,
|
|
63
65
|
# then it has been manually added and we can be sure that the user intends
|
|
64
66
|
# for there to be an index.
|
|
65
|
-
if @link_count
|
|
67
|
+
if @link_count.zero?
|
|
66
68
|
@first_sitemap = SitemapGenerator::Builder::LinkHolder.new(file, options)
|
|
67
69
|
@link_count += 1 # pretend it's added, but don't add it yet
|
|
68
70
|
else
|
|
@@ -90,7 +92,7 @@ module SitemapGenerator
|
|
|
90
92
|
# of <tt>bytes</tt> bytes in size. You can also pass a string and the
|
|
91
93
|
# bytesize will be calculated for you.
|
|
92
94
|
def file_can_fit?(bytes)
|
|
93
|
-
bytes =
|
|
95
|
+
bytes = SitemapGenerator::Utilities.bytesize(bytes) if bytes.is_a?(String)
|
|
94
96
|
(@filesize + bytes) < SitemapGenerator::MAX_SITEMAP_FILESIZE && @link_count < SitemapGenerator::MAX_SITEMAP_FILES
|
|
95
97
|
end
|
|
96
98
|
|
|
@@ -101,7 +103,7 @@ module SitemapGenerator
|
|
|
101
103
|
|
|
102
104
|
def stats_summary(opts = {})
|
|
103
105
|
str = "Sitemap stats: #{number_with_delimiter(@sitemaps_link_count)} links / #{@link_count} sitemaps"
|
|
104
|
-
str
|
|
106
|
+
str + format(' / %dm%02ds', *opts[:time_taken].divmod(60)) if opts[:time_taken] # rubocop:disable Style/FormatStringToken
|
|
105
107
|
end
|
|
106
108
|
|
|
107
109
|
def finalize!
|
|
@@ -122,7 +124,7 @@ module SitemapGenerator
|
|
|
122
124
|
# If a link is added manually and create_index is not false, we force index
|
|
123
125
|
# creation because they obviously intend for there to be an index. False otherwise.
|
|
124
126
|
def create_index?
|
|
125
|
-
@create_index || @location.create_index == true || @location.create_index == :auto && @link_count > 1
|
|
127
|
+
@create_index || @location.create_index == true || (@location.create_index == :auto && @link_count > 1)
|
|
126
128
|
end
|
|
127
129
|
|
|
128
130
|
# Return the index file URL. If create_index is true, this is the URL
|
|
@@ -141,15 +143,15 @@ module SitemapGenerator
|
|
|
141
143
|
|
|
142
144
|
# Make sure the first sitemap has been written out and added to the index
|
|
143
145
|
def write_first_sitemap
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
146
|
+
return unless @first_sitemap
|
|
147
|
+
|
|
148
|
+
@first_sitemap.link.write unless @first_sitemap.link.written?
|
|
149
|
+
super_add(SitemapGenerator::Builder::SitemapIndexUrl.new(@first_sitemap.link, @first_sitemap.options))
|
|
150
|
+
@link_count -= 1 # we already counted it, don't count it twice
|
|
151
|
+
# Store the URL because if create_index is false, this is the
|
|
152
|
+
# "index" URL
|
|
153
|
+
@first_sitemap_url = @first_sitemap.link.location.url
|
|
154
|
+
@first_sitemap = nil
|
|
153
155
|
end
|
|
154
156
|
end
|
|
155
157
|
end
|
|
@@ -4,16 +4,15 @@ require 'builder'
|
|
|
4
4
|
|
|
5
5
|
module SitemapGenerator
|
|
6
6
|
module Builder
|
|
7
|
+
# Wraps a sitemap file reference as a +<sitemap>+ XML entry for use in a sitemap index.
|
|
7
8
|
class SitemapIndexUrl < SitemapUrl
|
|
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: Time.now,
|
|
10
|
+
if (index = path.is_a?(SitemapGenerator::Builder::SitemapIndexFile) && path)
|
|
11
|
+
options = SitemapGenerator::Utilities.reverse_merge(options, host: index.location.host, lastmod: Time.now,
|
|
12
|
+
priority: 1.0)
|
|
12
13
|
path = index.location.path_in_public
|
|
13
|
-
super(path, options)
|
|
14
|
-
else
|
|
15
|
-
super
|
|
16
14
|
end
|
|
15
|
+
super
|
|
17
16
|
end
|
|
18
17
|
|
|
19
18
|
# Return the URL as XML
|
|
@@ -9,8 +9,7 @@ module SitemapGenerator
|
|
|
9
9
|
module Builder
|
|
10
10
|
# A Hash-like class for holding information about a sitemap URL and
|
|
11
11
|
# generating an XML <url> element suitable for sitemaps.
|
|
12
|
-
class SitemapUrl < Hash
|
|
13
|
-
|
|
12
|
+
class SitemapUrl < Hash # rubocop:disable Metrics/ClassLength
|
|
14
13
|
# Return a new instance with options configured on it.
|
|
15
14
|
#
|
|
16
15
|
# == Arguments
|
|
@@ -31,9 +30,10 @@ module SitemapGenerator
|
|
|
31
30
|
# * +mobile+
|
|
32
31
|
# * +alternate+/+alternates+
|
|
33
32
|
# * +pagemap+
|
|
34
|
-
def initialize(path, options = {})
|
|
33
|
+
def initialize(path, options = {}) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
34
|
+
super()
|
|
35
35
|
options = SitemapGenerator::Utilities.symbolize_keys(options)
|
|
36
|
-
if sitemap = path.is_a?(SitemapGenerator::Builder::SitemapFile) && path
|
|
36
|
+
if (sitemap = path.is_a?(SitemapGenerator::Builder::SitemapFile) && path)
|
|
37
37
|
SitemapGenerator::Utilities.reverse_merge!(
|
|
38
38
|
options,
|
|
39
39
|
host: sitemap.location.host,
|
|
@@ -44,7 +44,9 @@ module SitemapGenerator
|
|
|
44
44
|
|
|
45
45
|
SitemapGenerator::Utilities.assert_valid_keys(
|
|
46
46
|
options,
|
|
47
|
-
:priority, :changefreq, :lastmod, :expires, :host,
|
|
47
|
+
:priority, :changefreq, :lastmod, :expires, :host,
|
|
48
|
+
:images, :video, :news, :videos, :mobile,
|
|
49
|
+
:alternate, :alternates, :pagemap
|
|
48
50
|
)
|
|
49
51
|
SitemapGenerator::Utilities.reverse_merge!(
|
|
50
52
|
options,
|
|
@@ -59,16 +61,17 @@ module SitemapGenerator
|
|
|
59
61
|
)
|
|
60
62
|
raise 'Cannot generate a url without a host' unless SitemapGenerator::Utilities.present?(options[:host])
|
|
61
63
|
|
|
62
|
-
if video = options.delete(:video)
|
|
64
|
+
if (video = options.delete(:video))
|
|
63
65
|
options[:videos] = video.is_a?(Array) ? options[:videos].concat(video) : options[:videos] << video
|
|
64
66
|
end
|
|
65
|
-
if alternate = options.delete(:alternate)
|
|
66
|
-
options[:alternates] =
|
|
67
|
+
if (alternate = options.delete(:alternate))
|
|
68
|
+
options[:alternates] =
|
|
69
|
+
alternate.is_a?(Array) ? options[:alternates].concat(alternate) : options[:alternates] << alternate
|
|
67
70
|
end
|
|
68
71
|
|
|
69
|
-
path = path.to_s.sub(
|
|
70
|
-
loc = path.empty? ? options[:host] :
|
|
71
|
-
|
|
72
|
+
path = path.to_s.sub(%r{^/}, '')
|
|
73
|
+
loc = path.empty? ? options[:host] : "#{options[:host].to_s.sub(%r{/$}, '')}/#{path}"
|
|
74
|
+
merge!(
|
|
72
75
|
priority: options[:priority],
|
|
73
76
|
changefreq: options[:changefreq],
|
|
74
77
|
lastmod: options[:lastmod],
|
|
@@ -85,9 +88,9 @@ module SitemapGenerator
|
|
|
85
88
|
end
|
|
86
89
|
|
|
87
90
|
# Return the URL as XML
|
|
88
|
-
def to_xml(builder = nil)
|
|
91
|
+
def to_xml(builder = nil) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
89
92
|
builder = ::Builder::XmlMarkup.new if builder.nil?
|
|
90
|
-
builder.url do
|
|
93
|
+
builder.url do # rubocop:disable Metrics/BlockLength
|
|
91
94
|
builder.loc self[:loc]
|
|
92
95
|
builder.lastmod w3c_date(self[:lastmod]) if self[:lastmod]
|
|
93
96
|
builder.expires w3c_date(self[:expires]) if self[:expires]
|
|
@@ -121,15 +124,17 @@ module SitemapGenerator
|
|
|
121
124
|
end
|
|
122
125
|
end
|
|
123
126
|
|
|
124
|
-
self[:videos].each do |video|
|
|
125
|
-
builder.video :video do
|
|
127
|
+
self[:videos].each do |video| # rubocop:disable Metrics/BlockLength
|
|
128
|
+
builder.video :video do # rubocop:disable Metrics/BlockLength
|
|
126
129
|
builder.video :thumbnail_loc, video[:thumbnail_loc].to_s
|
|
127
130
|
builder.video :title, video[:title].to_s
|
|
128
131
|
builder.video :description, video[:description].to_s
|
|
129
132
|
builder.video :content_loc, video[:content_loc].to_s if video[:content_loc]
|
|
130
133
|
if video[:player_loc]
|
|
131
134
|
loc_attributes = { allow_embed: yes_or_no_with_default(video[:allow_embed], true) }
|
|
132
|
-
|
|
135
|
+
if SitemapGenerator::Utilities.present?(video[:autoplay])
|
|
136
|
+
loc_attributes[:autoplay] = video[:autoplay].to_s
|
|
137
|
+
end
|
|
133
138
|
builder.video :player_loc, video[:player_loc].to_s, loc_attributes
|
|
134
139
|
end
|
|
135
140
|
builder.video :duration, video[:duration].to_s if video[:duration]
|
|
@@ -137,17 +142,30 @@ module SitemapGenerator
|
|
|
137
142
|
builder.video :rating, format_float(video[:rating]) if video[:rating]
|
|
138
143
|
builder.video :view_count, video[:view_count].to_s if video[:view_count]
|
|
139
144
|
builder.video :publication_date, w3c_date(video[:publication_date]) if video[:publication_date]
|
|
140
|
-
video[:tags]
|
|
145
|
+
video[:tags]&.each { |tag| builder.video :tag, tag.to_s }
|
|
141
146
|
builder.video :tag, video[:tag].to_s if video[:tag]
|
|
142
147
|
builder.video :category, video[:category].to_s if video[:category]
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
|
146
159
|
if video[:uploader]
|
|
147
|
-
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)
|
|
148
168
|
end
|
|
149
|
-
builder.video :live, yes_or_no_with_default(video[:live], true) if video.has_key?(:live)
|
|
150
|
-
builder.video :requires_subscription, yes_or_no_with_default(video[:requires_subscription], true) if video.has_key?(:requires_subscription)
|
|
151
169
|
end
|
|
152
170
|
end
|
|
153
171
|
|
|
@@ -159,9 +177,7 @@ module SitemapGenerator
|
|
|
159
177
|
builder.xhtml :link, attributes
|
|
160
178
|
end
|
|
161
179
|
|
|
162
|
-
unless SitemapGenerator::Utilities.blank?(self[:mobile])
|
|
163
|
-
builder.mobile :mobile
|
|
164
|
-
end
|
|
180
|
+
builder.mobile :mobile unless SitemapGenerator::Utilities.blank?(self[:mobile])
|
|
165
181
|
|
|
166
182
|
unless SitemapGenerator::Utilities.blank?(self[:pagemap])
|
|
167
183
|
builder.pagemap :PageMap do
|
|
@@ -188,18 +204,26 @@ module SitemapGenerator
|
|
|
188
204
|
attribs = {}
|
|
189
205
|
attribs[:currency] = video[:price_currency].to_s # required
|
|
190
206
|
attribs[:type] = video[:price_type] if SitemapGenerator::Utilities.present?(video[:price_type])
|
|
191
|
-
|
|
207
|
+
if SitemapGenerator::Utilities.present?(video[:price_resolution])
|
|
208
|
+
attribs[:resolution] = video[:price_resolution]
|
|
209
|
+
end
|
|
192
210
|
attribs
|
|
193
211
|
end
|
|
194
212
|
|
|
195
213
|
def prepare_news(news)
|
|
196
|
-
|
|
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
|
|
197
221
|
news
|
|
198
222
|
end
|
|
199
223
|
|
|
200
224
|
# Return an Array of image option Hashes suitable to be parsed by SitemapGenerator::Builder::SitemapFile
|
|
201
225
|
def prepare_images(images, host)
|
|
202
|
-
images.delete_if { |key,
|
|
226
|
+
images.delete_if { |key, _value| key[:loc].nil? }
|
|
203
227
|
images.each do |r|
|
|
204
228
|
SitemapGenerator::Utilities.assert_valid_keys(r, :loc, :caption, :geo_location, :title, :license)
|
|
205
229
|
r[:loc] = URI.join(host, r[:loc]).to_s
|
|
@@ -207,7 +231,7 @@ module SitemapGenerator
|
|
|
207
231
|
images[0..(SitemapGenerator::MAX_SITEMAP_IMAGES - 1)]
|
|
208
232
|
end
|
|
209
233
|
|
|
210
|
-
def w3c_date(date)
|
|
234
|
+
def w3c_date(date) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
211
235
|
if date.is_a?(String)
|
|
212
236
|
date
|
|
213
237
|
elsif date.respond_to?(:iso8601)
|
|
@@ -222,8 +246,6 @@ module SitemapGenerator
|
|
|
222
246
|
date.utc
|
|
223
247
|
elsif date.is_a?(Integer)
|
|
224
248
|
Time.at(date).utc
|
|
225
|
-
else
|
|
226
|
-
nil
|
|
227
249
|
end
|
|
228
250
|
|
|
229
251
|
if zulutime
|
|
@@ -239,7 +261,9 @@ module SitemapGenerator
|
|
|
239
261
|
# value must be 'yes' or 'no'. Pass the default value as a boolean using `default`.
|
|
240
262
|
def yes_or_no(value)
|
|
241
263
|
if value.is_a?(String)
|
|
242
|
-
|
|
264
|
+
unless /^(yes|no)$/i.match?(value)
|
|
265
|
+
raise ArgumentError, "Unrecognized value for yes/no field: #{value.inspect}"
|
|
266
|
+
end
|
|
243
267
|
|
|
244
268
|
value.downcase
|
|
245
269
|
else
|
|
@@ -256,7 +280,7 @@ module SitemapGenerator
|
|
|
256
280
|
# Format a float to to one decimal precision.
|
|
257
281
|
# TODO: Use rounding with precision once merged with framework_agnostic.
|
|
258
282
|
def format_float(value)
|
|
259
|
-
value.is_a?(String) ? value : ('%0.1f'
|
|
283
|
+
value.is_a?(String) ? value : format('%0.1f', value)
|
|
260
284
|
end
|
|
261
285
|
end
|
|
262
286
|
end
|
|
@@ -5,6 +5,8 @@ require 'sitemap_generator/builder/sitemap_index_file'
|
|
|
5
5
|
require 'sitemap_generator/builder/sitemap_url'
|
|
6
6
|
require 'sitemap_generator/builder/sitemap_index_url'
|
|
7
7
|
|
|
8
|
-
module SitemapGenerator
|
|
9
|
-
|
|
8
|
+
module SitemapGenerator
|
|
9
|
+
module Builder
|
|
10
|
+
LinkHolder = Struct.new(:link, :options)
|
|
11
|
+
end
|
|
10
12
|
end
|