ftbpro_sitemap_generator 5.0.8
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 +7 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +35 -0
- data/MIT-LICENSE +20 -0
- data/README.md +1139 -0
- data/Rakefile +43 -0
- data/VERSION +1 -0
- data/lib/capistrano/sitemap_generator.rb +1 -0
- data/lib/capistrano/tasks/sitemap_generator.cap +36 -0
- data/lib/sitemap_generator.rb +85 -0
- data/lib/sitemap_generator/adapters.rb +0 -0
- data/lib/sitemap_generator/adapters/file_adapter.rb +43 -0
- data/lib/sitemap_generator/adapters/fog_adapter.rb +28 -0
- data/lib/sitemap_generator/adapters/s3_adapter.rb +41 -0
- data/lib/sitemap_generator/adapters/wave_adapter.rb +21 -0
- data/lib/sitemap_generator/application.rb +49 -0
- data/lib/sitemap_generator/builder.rb +8 -0
- data/lib/sitemap_generator/builder/sitemap_file.rb +172 -0
- data/lib/sitemap_generator/builder/sitemap_index_file.rb +149 -0
- data/lib/sitemap_generator/builder/sitemap_index_url.rb +28 -0
- data/lib/sitemap_generator/builder/sitemap_url.rb +250 -0
- data/lib/sitemap_generator/core_ext.rb +3 -0
- data/lib/sitemap_generator/core_ext/big_decimal.rb +45 -0
- data/lib/sitemap_generator/core_ext/numeric.rb +48 -0
- data/lib/sitemap_generator/helpers/number_helper.rb +237 -0
- data/lib/sitemap_generator/interpreter.rb +80 -0
- data/lib/sitemap_generator/link_set.rb +677 -0
- data/lib/sitemap_generator/railtie.rb +7 -0
- data/lib/sitemap_generator/sitemap_location.rb +192 -0
- data/lib/sitemap_generator/sitemap_namer.rb +75 -0
- data/lib/sitemap_generator/tasks.rb +53 -0
- data/lib/sitemap_generator/templates.rb +41 -0
- data/lib/sitemap_generator/utilities.rb +181 -0
- data/lib/tasks/sitemap_generator_tasks.rake +1 -0
- data/rails/install.rb +2 -0
- data/rails/uninstall.rb +2 -0
- data/spec/blueprint.rb +15 -0
- data/spec/files/sitemap.create.rb +12 -0
- data/spec/files/sitemap.groups.rb +49 -0
- data/spec/sitemap_generator/adapters/s3_adapter_spec.rb +23 -0
- data/spec/sitemap_generator/alternate_sitemap_spec.rb +79 -0
- data/spec/sitemap_generator/application_spec.rb +69 -0
- data/spec/sitemap_generator/builder/sitemap_file_spec.rb +110 -0
- data/spec/sitemap_generator/builder/sitemap_index_file_spec.rb +124 -0
- data/spec/sitemap_generator/builder/sitemap_index_url_spec.rb +28 -0
- data/spec/sitemap_generator/builder/sitemap_url_spec.rb +186 -0
- data/spec/sitemap_generator/core_ext/bigdecimal_spec.rb +20 -0
- data/spec/sitemap_generator/core_ext/numeric_spec.rb +43 -0
- data/spec/sitemap_generator/file_adaptor_spec.rb +20 -0
- data/spec/sitemap_generator/geo_sitemap_spec.rb +30 -0
- data/spec/sitemap_generator/helpers/number_helper_spec.rb +196 -0
- data/spec/sitemap_generator/interpreter_spec.rb +90 -0
- data/spec/sitemap_generator/link_set_spec.rb +864 -0
- data/spec/sitemap_generator/mobile_sitemap_spec.rb +27 -0
- data/spec/sitemap_generator/news_sitemap_spec.rb +42 -0
- data/spec/sitemap_generator/pagemap_sitemap_spec.rb +57 -0
- data/spec/sitemap_generator/sitemap_generator_spec.rb +582 -0
- data/spec/sitemap_generator/sitemap_groups_spec.rb +144 -0
- data/spec/sitemap_generator/sitemap_location_spec.rb +210 -0
- data/spec/sitemap_generator/sitemap_namer_spec.rb +96 -0
- data/spec/sitemap_generator/templates_spec.rb +24 -0
- data/spec/sitemap_generator/utilities/existence_spec.rb +26 -0
- data/spec/sitemap_generator/utilities/hash_spec.rb +57 -0
- data/spec/sitemap_generator/utilities/rounding_spec.rb +31 -0
- data/spec/sitemap_generator/utilities_spec.rb +101 -0
- data/spec/sitemap_generator/video_sitemap_spec.rb +117 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/file_macros.rb +39 -0
- data/spec/support/schemas/siteindex.xsd +73 -0
- data/spec/support/schemas/sitemap-geo.xsd +41 -0
- data/spec/support/schemas/sitemap-mobile.xsd +32 -0
- data/spec/support/schemas/sitemap-news.xsd +159 -0
- data/spec/support/schemas/sitemap-pagemap.xsd +97 -0
- data/spec/support/schemas/sitemap-video.xsd +643 -0
- data/spec/support/schemas/sitemap.xsd +115 -0
- data/spec/support/xml_macros.rb +67 -0
- data/templates/sitemap.rb +27 -0
- metadata +226 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
class SitemapGenerator::Numeric
|
2
|
+
KILOBYTE = 1024
|
3
|
+
MEGABYTE = KILOBYTE * 1024
|
4
|
+
GIGABYTE = MEGABYTE * 1024
|
5
|
+
TERABYTE = GIGABYTE * 1024
|
6
|
+
PETABYTE = TERABYTE * 1024
|
7
|
+
EXABYTE = PETABYTE * 1024
|
8
|
+
|
9
|
+
def initialize(number)
|
10
|
+
@number = number
|
11
|
+
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
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
# require "sitemap_generator/core_ext/big_decimal/conversions"
|
2
|
+
require "sitemap_generator/utilities"
|
3
|
+
|
4
|
+
module SitemapGenerator
|
5
|
+
# = SitemapGenerator Number Helpers
|
6
|
+
module Helpers #:nodoc:
|
7
|
+
|
8
|
+
# Provides methods for converting numbers into formatted strings.
|
9
|
+
# Methods are provided for precision, positional notation and file size
|
10
|
+
# and pretty printing.
|
11
|
+
#
|
12
|
+
# Most methods expect a +number+ argument, and will return it
|
13
|
+
# unchanged if can't be converted into a valid number.
|
14
|
+
module NumberHelper
|
15
|
+
|
16
|
+
# Raised when argument +number+ param given to the helpers is invalid and
|
17
|
+
# the option :raise is set to +true+.
|
18
|
+
class InvalidNumberError < StandardError
|
19
|
+
attr_accessor :number
|
20
|
+
def initialize(number)
|
21
|
+
@number = number
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Formats a +number+ with grouped thousands using +delimiter+ (e.g., 12,324). You can
|
26
|
+
# customize the format in the +options+ hash.
|
27
|
+
#
|
28
|
+
# ==== Options
|
29
|
+
# * <tt>:locale</tt> - Sets the locale to be used for formatting (defaults to current locale).
|
30
|
+
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ",").
|
31
|
+
# * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to ".").
|
32
|
+
#
|
33
|
+
# ==== Examples
|
34
|
+
# number_with_delimiter(12345678) # => 12,345,678
|
35
|
+
# number_with_delimiter(12345678.05) # => 12,345,678.05
|
36
|
+
# number_with_delimiter(12345678, :delimiter => ".") # => 12.345.678
|
37
|
+
# number_with_delimiter(12345678, :separator => ",") # => 12,345,678
|
38
|
+
# number_with_delimiter(12345678.05, :locale => :fr) # => 12 345 678,05
|
39
|
+
# number_with_delimiter(98765432.98, :delimiter => " ", :separator => ",")
|
40
|
+
# # => 98 765 432,98
|
41
|
+
def number_with_delimiter(number, options = {})
|
42
|
+
SitemapGenerator::Utilities.symbolize_keys!(options)
|
43
|
+
|
44
|
+
begin
|
45
|
+
Float(number)
|
46
|
+
rescue ArgumentError, TypeError
|
47
|
+
if options[:raise]
|
48
|
+
raise InvalidNumberError, number
|
49
|
+
else
|
50
|
+
return number
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
defaults = {
|
55
|
+
:separator => ".",
|
56
|
+
:delimiter => ",",
|
57
|
+
:precision => 3,
|
58
|
+
:significant => false,
|
59
|
+
:strip_insignificant_zeros => false
|
60
|
+
}
|
61
|
+
options = SitemapGenerator::Utilities.reverse_merge(options, defaults)
|
62
|
+
|
63
|
+
parts = number.to_s.to_str.split('.')
|
64
|
+
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
|
65
|
+
parts.join(options[:separator])
|
66
|
+
end
|
67
|
+
|
68
|
+
# Formats a +number+ with the specified level of <tt>:precision</tt> (e.g., 112.32 has a precision
|
69
|
+
# of 2 if +:significant+ is +false+, and 5 if +:significant+ is +true+).
|
70
|
+
# You can customize the format in the +options+ hash.
|
71
|
+
#
|
72
|
+
# ==== Options
|
73
|
+
# * <tt>:locale</tt> - Sets the locale to be used for formatting (defaults to current locale).
|
74
|
+
# * <tt>:precision</tt> - Sets the precision of the number (defaults to 3).
|
75
|
+
# * <tt>:significant</tt> - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +false+)
|
76
|
+
# * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to ".").
|
77
|
+
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
|
78
|
+
# * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator (defaults to +false+)
|
79
|
+
#
|
80
|
+
# ==== Examples
|
81
|
+
# number_with_precision(111.2345) # => 111.235
|
82
|
+
# number_with_precision(111.2345, :precision => 2) # => 111.23
|
83
|
+
# number_with_precision(13, :precision => 5) # => 13.00000
|
84
|
+
# number_with_precision(389.32314, :precision => 0) # => 389
|
85
|
+
# number_with_precision(111.2345, :significant => true) # => 111
|
86
|
+
# number_with_precision(111.2345, :precision => 1, :significant => true) # => 100
|
87
|
+
# number_with_precision(13, :precision => 5, :significant => true) # => 13.000
|
88
|
+
# number_with_precision(111.234, :locale => :fr) # => 111,234
|
89
|
+
# number_with_precision(13, :precision => 5, :significant => true, strip_insignificant_zeros => true)
|
90
|
+
# # => 13
|
91
|
+
# number_with_precision(389.32314, :precision => 4, :significant => true) # => 389.3
|
92
|
+
# number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.')
|
93
|
+
# # => 1.111,23
|
94
|
+
def number_with_precision(number, options = {})
|
95
|
+
SitemapGenerator::Utilities.symbolize_keys!(options)
|
96
|
+
|
97
|
+
number = begin
|
98
|
+
Float(number)
|
99
|
+
rescue ArgumentError, TypeError
|
100
|
+
if options[:raise]
|
101
|
+
raise InvalidNumberError, number
|
102
|
+
else
|
103
|
+
return number
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
defaults = {
|
108
|
+
:separator => ".",
|
109
|
+
:delimiter => ",",
|
110
|
+
:precision => 3,
|
111
|
+
:significant => false,
|
112
|
+
:strip_insignificant_zeros => false
|
113
|
+
}
|
114
|
+
precision_defaults = {
|
115
|
+
:delimiter => ""
|
116
|
+
}
|
117
|
+
defaults = defaults.merge(precision_defaults)
|
118
|
+
|
119
|
+
options = SitemapGenerator::Utilities.reverse_merge(options, defaults) # Allow the user to unset default values: Eg.: :significant => false
|
120
|
+
precision = options.delete :precision
|
121
|
+
significant = options.delete :significant
|
122
|
+
strip_insignificant_zeros = options.delete :strip_insignificant_zeros
|
123
|
+
|
124
|
+
if significant and precision > 0
|
125
|
+
if number == 0
|
126
|
+
digits, rounded_number = 1, 0
|
127
|
+
else
|
128
|
+
digits = (Math.log10(number.abs) + 1).floor
|
129
|
+
rounded_number = (SitemapGenerator::BigDecimal.new(number.to_s) / SitemapGenerator::BigDecimal.new((10 ** (digits - precision)).to_f.to_s)).round.to_f * 10 ** (digits - precision)
|
130
|
+
digits = (Math.log10(rounded_number.abs) + 1).floor # After rounding, the number of digits may have changed
|
131
|
+
end
|
132
|
+
precision = precision - digits
|
133
|
+
precision = precision > 0 ? precision : 0 #don't let it be negative
|
134
|
+
else
|
135
|
+
rounded_number = SitemapGenerator::Utilities.round(SitemapGenerator::BigDecimal.new(number.to_s), precision).to_f
|
136
|
+
end
|
137
|
+
formatted_number = number_with_delimiter("%01.#{precision}f" % rounded_number, options)
|
138
|
+
if strip_insignificant_zeros
|
139
|
+
escaped_separator = Regexp.escape(options[:separator])
|
140
|
+
formatted_number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
|
141
|
+
else
|
142
|
+
formatted_number
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze
|
148
|
+
DECIMAL_UNITS = {0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion,
|
149
|
+
-1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto}.freeze
|
150
|
+
|
151
|
+
# Formats the bytes in +number+ into a more understandable representation
|
152
|
+
# (e.g., giving it 1500 yields 1.5 KB). This method is useful for
|
153
|
+
# reporting file sizes to users. You can customize the
|
154
|
+
# format in the +options+ hash.
|
155
|
+
#
|
156
|
+
# See <tt>number_to_human</tt> if you want to pretty-print a generic number.
|
157
|
+
#
|
158
|
+
# ==== Options
|
159
|
+
# * <tt>:locale</tt> - Sets the locale to be used for formatting (defaults to current locale).
|
160
|
+
# * <tt>:precision</tt> - Sets the precision of the number (defaults to 3).
|
161
|
+
# * <tt>:significant</tt> - If +true+, precision will be the # of significant_digits. If +false+, the # of fractional digits (defaults to +true+)
|
162
|
+
# * <tt>:separator</tt> - Sets the separator between the fractional and integer digits (defaults to ".").
|
163
|
+
# * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
|
164
|
+
# * <tt>:strip_insignificant_zeros</tt> - If +true+ removes insignificant zeros after the decimal separator (defaults to +true+)
|
165
|
+
# ==== Examples
|
166
|
+
# number_to_human_size(123) # => 123 Bytes
|
167
|
+
# number_to_human_size(1234) # => 1.21 KB
|
168
|
+
# number_to_human_size(12345) # => 12.1 KB
|
169
|
+
# number_to_human_size(1234567) # => 1.18 MB
|
170
|
+
# number_to_human_size(1234567890) # => 1.15 GB
|
171
|
+
# number_to_human_size(1234567890123) # => 1.12 TB
|
172
|
+
# number_to_human_size(1234567, :precision => 2) # => 1.2 MB
|
173
|
+
# number_to_human_size(483989, :precision => 2) # => 470 KB
|
174
|
+
# number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,2 MB
|
175
|
+
#
|
176
|
+
# Non-significant zeros after the fractional separator are stripped out by default (set
|
177
|
+
# <tt>:strip_insignificant_zeros</tt> to +false+ to change that):
|
178
|
+
# number_to_human_size(1234567890123, :precision => 5) # => "1.1229 TB"
|
179
|
+
# number_to_human_size(524288000, :precision=>5) # => "500 MB"
|
180
|
+
def number_to_human_size(number, options = {})
|
181
|
+
SitemapGenerator::Utilities.symbolize_keys!(options)
|
182
|
+
|
183
|
+
number = begin
|
184
|
+
Float(number)
|
185
|
+
rescue ArgumentError, TypeError
|
186
|
+
if options[:raise]
|
187
|
+
raise InvalidNumberError, number
|
188
|
+
else
|
189
|
+
return number
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
defaults = {
|
194
|
+
:separator => ".",
|
195
|
+
:delimiter => ",",
|
196
|
+
:precision => 3,
|
197
|
+
:significant => false,
|
198
|
+
:strip_insignificant_zeros => false
|
199
|
+
}
|
200
|
+
human = {
|
201
|
+
:delimiter => "",
|
202
|
+
:precision => 3,
|
203
|
+
:significant => true,
|
204
|
+
:strip_insignificant_zeros => true
|
205
|
+
}
|
206
|
+
defaults = defaults.merge(human)
|
207
|
+
options = SitemapGenerator::Utilities.reverse_merge(options, defaults)
|
208
|
+
#for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
|
209
|
+
options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
|
210
|
+
|
211
|
+
storage_units_format = "%n %u"
|
212
|
+
|
213
|
+
if number.to_i < 1024
|
214
|
+
unit = number.to_i > 1 || number.to_i == 0 ? 'Bytes' : 'Byte'
|
215
|
+
storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit)
|
216
|
+
else
|
217
|
+
max_exp = STORAGE_UNITS.size - 1
|
218
|
+
exponent = (Math.log(number) / Math.log(1024)).to_i # Convert to base 1024
|
219
|
+
exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
|
220
|
+
number /= 1024 ** exponent
|
221
|
+
|
222
|
+
unit_key = STORAGE_UNITS[exponent]
|
223
|
+
units = {
|
224
|
+
:byte => "Bytes",
|
225
|
+
:kb => "KB",
|
226
|
+
:mb => "MB",
|
227
|
+
:gb => "GB",
|
228
|
+
:tb => "TB"
|
229
|
+
}
|
230
|
+
unit = units[unit_key]
|
231
|
+
formatted_number = number_with_precision(number, options)
|
232
|
+
storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'sitemap_generator'
|
2
|
+
|
3
|
+
module SitemapGenerator
|
4
|
+
|
5
|
+
# Provide a class for evaluating blocks, making the URL helpers from the framework
|
6
|
+
# and API methods available to it.
|
7
|
+
class Interpreter
|
8
|
+
|
9
|
+
if SitemapGenerator.app.rails3?
|
10
|
+
include ::Rails.application.routes.url_helpers
|
11
|
+
elsif SitemapGenerator.app.rails?
|
12
|
+
require 'action_controller'
|
13
|
+
include ActionController::UrlWriter
|
14
|
+
end
|
15
|
+
|
16
|
+
# Call with a block to evaluate a dynamic config. The only method exposed for you is
|
17
|
+
# `add` to add a link to the sitemap object attached to this interpreter.
|
18
|
+
#
|
19
|
+
# === Options
|
20
|
+
# * <tt>link_set</tt> - a LinkSet instance to use. Default is SitemapGenerator::Sitemap.
|
21
|
+
#
|
22
|
+
# All other options are passed to the LinkSet by setting them using accessor methods.
|
23
|
+
def initialize(opts={}, &block)
|
24
|
+
opts = SitemapGenerator::Utilities.reverse_merge(opts, :link_set => SitemapGenerator::Sitemap)
|
25
|
+
@linkset = opts.delete :link_set
|
26
|
+
@linkset.send(:set_options, opts)
|
27
|
+
eval(&block) if block_given?
|
28
|
+
end
|
29
|
+
|
30
|
+
def add(*args)
|
31
|
+
@linkset.add(*args)
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_to_index(*args)
|
35
|
+
@linkset.add_to_index(*args)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Start a new group of sitemaps. Any of the options to SitemapGenerator.new may
|
39
|
+
# be passed. Pass a block with calls to +add+ to add links to the sitemaps.
|
40
|
+
#
|
41
|
+
# All groups use the same sitemap index.
|
42
|
+
def group(*args, &block)
|
43
|
+
@linkset.group(*args, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Return the LinkSet instance so that you can access it from within the `create` block
|
47
|
+
# without having to use the yield_sitemap option.
|
48
|
+
def sitemap
|
49
|
+
@linkset
|
50
|
+
end
|
51
|
+
|
52
|
+
# Evaluate the block in the interpreter. Pass :yield_sitemap => true to
|
53
|
+
# yield the Interpreter instance to the block...for old-style calling.
|
54
|
+
def eval(opts={}, &block)
|
55
|
+
if block_given?
|
56
|
+
if opts[:yield_sitemap]
|
57
|
+
yield @linkset
|
58
|
+
else
|
59
|
+
instance_eval(&block)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Run the interpreter on a config file using
|
65
|
+
# the default <tt>SitemapGenerator::Sitemap</tt> sitemap object.
|
66
|
+
#
|
67
|
+
# === Options
|
68
|
+
# * <tt>:config_file</tt> - full path to the config file to evaluate.
|
69
|
+
# Default is config/sitemap.rb in your application's root directory.
|
70
|
+
# All other options are passed to +new+.
|
71
|
+
def self.run(opts={}, &block)
|
72
|
+
opts = opts.dup
|
73
|
+
config_file = opts.delete(:config_file)
|
74
|
+
config_file ||= SitemapGenerator.app.root + 'config/sitemap.rb'
|
75
|
+
interpreter = self.new(opts)
|
76
|
+
interpreter.instance_eval(File.read(config_file), config_file.to_s)
|
77
|
+
interpreter
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,677 @@
|
|
1
|
+
require 'builder'
|
2
|
+
|
3
|
+
# A LinkSet provisions a bunch of links to sitemap files. It also writes the index file
|
4
|
+
# which lists all the sitemap files written.
|
5
|
+
module SitemapGenerator
|
6
|
+
class LinkSet
|
7
|
+
@@requires_finalization_opts = [:filename, :sitemaps_path, :sitemaps_host, :namer]
|
8
|
+
@@new_location_opts = [:filename, :sitemaps_path, :namer]
|
9
|
+
|
10
|
+
attr_reader :default_host, :sitemaps_path, :filename, :create_index
|
11
|
+
attr_accessor :include_root, :include_index, :adapter, :yield_sitemap
|
12
|
+
attr_writer :verbose
|
13
|
+
|
14
|
+
# Create a new sitemap index and sitemap files. Pass a block with calls to the following
|
15
|
+
# methods:
|
16
|
+
# * +add+ - Add a link to the current sitemap
|
17
|
+
# * +group+ - Start a new group of sitemaps
|
18
|
+
#
|
19
|
+
# == Options
|
20
|
+
#
|
21
|
+
# Any option supported by +new+ can be passed. The options will be
|
22
|
+
# set on the instance using the accessor methods. This is provided mostly
|
23
|
+
# as a convenience.
|
24
|
+
#
|
25
|
+
# In addition to the options to +new+, the following options are supported:
|
26
|
+
# * <tt>:finalize</tt> - The sitemaps are written as they get full and at the end
|
27
|
+
# of the block. Pass +false+ as the value to prevent the sitemap or sitemap index
|
28
|
+
# from being finalized. Default is +true+.
|
29
|
+
#
|
30
|
+
# If you are calling +create+ more than once in your sitemap configuration file,
|
31
|
+
# make sure that you set a different +sitemaps_path+ or +filename+ for each call otherwise
|
32
|
+
# the sitemaps may be overwritten.
|
33
|
+
def create(opts={}, &block)
|
34
|
+
reset!
|
35
|
+
set_customized_schemas(opts)
|
36
|
+
set_options(opts)
|
37
|
+
if verbose
|
38
|
+
start_time = Time.now
|
39
|
+
puts "In '#{sitemap_index.location.public_path}':"
|
40
|
+
end
|
41
|
+
interpreter.eval(:yield_sitemap => yield_sitemap?, &block)
|
42
|
+
finalize!
|
43
|
+
end_time = Time.now if verbose
|
44
|
+
output(sitemap_index.stats_summary(:time_taken => end_time - start_time)) if verbose
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
# Constructor
|
49
|
+
#
|
50
|
+
# == Options:
|
51
|
+
# * <tt>:adapter</tt> - instance of a class with a write method which takes a SitemapGenerator::Location
|
52
|
+
# and raw XML data and persists it. The default adapter is a SitemapGenerator::FileAdapter
|
53
|
+
# which simply writes files to the filesystem. You can use a SitemapGenerator::WaveAdapter
|
54
|
+
# for uploading sitemaps to remote servers - useful for read-only hosts such as Heroku. Or
|
55
|
+
# you can provide an instance of your own class to provide custom behavior.
|
56
|
+
#
|
57
|
+
# * <tt>:default_host</tt> - host including protocol to use in all sitemap links
|
58
|
+
# e.g. http://en.google.ca
|
59
|
+
#
|
60
|
+
# * <tt>:public_path</tt> - Full or relative path to the directory to write sitemaps into.
|
61
|
+
# Defaults to the <tt>public/</tt> directory in your application root directory or
|
62
|
+
# the current working directory.
|
63
|
+
#
|
64
|
+
# * <tt>:sitemaps_host</tt> - String. <b>Host including protocol</b> to use when generating
|
65
|
+
# a link to a sitemap file i.e. the hostname of the server where the sitemaps are hosted.
|
66
|
+
# The value will differ from the hostname in your sitemap links.
|
67
|
+
# For example: `'http://amazon.aws.com/'`.
|
68
|
+
#
|
69
|
+
# Note that `include_index` is automatically turned off when the `sitemaps_host` does
|
70
|
+
# not match `default_host`. Because the link to the sitemap index file that would
|
71
|
+
# otherwise be added would point to a different host than the rest of the links in
|
72
|
+
# the sitemap. Something that the sitemap rules forbid.
|
73
|
+
#
|
74
|
+
# * <tt>:sitemaps_path</tt> - path fragment within public to write sitemaps
|
75
|
+
# to e.g. 'en/'. Sitemaps are written to <tt>public_path</tt> + <tt>sitemaps_path</tt>
|
76
|
+
#
|
77
|
+
# * <tt>:filename</tt> - symbol giving the base name for files (default <tt>:sitemap</tt>).
|
78
|
+
# The names are generated like "#{filename}.xml.gz", "#{filename}1.xml.gz", "#{filename}2.xml.gz"
|
79
|
+
# with the first file being the index if you have more than one sitemap file.
|
80
|
+
#
|
81
|
+
# * <tt>:include_index</tt> - Boolean. Whether to <b>add a link pointing to the sitemap index<b>
|
82
|
+
# to the current sitemap. This points search engines to your Sitemap Index to
|
83
|
+
# include it in the indexing of your site. Default is `false`. Turned off when
|
84
|
+
# `sitemaps_host` is set or within a `group()` block. Turned off because Google can complain
|
85
|
+
# about nested indexing and because if a robot is already reading your sitemap, they
|
86
|
+
# probably know about the index.
|
87
|
+
#
|
88
|
+
# * <tt>:include_root</tt> - Boolean. Whether to **add the root** url i.e. '/' to the
|
89
|
+
# current sitemap. Default is `true`. Turned off within a `group()` block.
|
90
|
+
#
|
91
|
+
# * <tt>:search_engines</tt> - Hash. A hash of search engine names mapped to
|
92
|
+
# ping URLs. See ping_search_engines.
|
93
|
+
#
|
94
|
+
# * <tt>:verbose</tt> - If +true+, output a summary line for each sitemap and sitemap
|
95
|
+
# index that is created. Default is +false+.
|
96
|
+
#
|
97
|
+
# * <tt>:create_index</tt> - Supported values: `true`, `false`, `:auto`. Default: `:auto`.
|
98
|
+
# Whether to create a sitemap index file. If `true` an index file is always created,
|
99
|
+
# regardless of how many links are in your sitemap. If `false` an index file is never
|
100
|
+
# created. If `:auto` an index file is created only if your sitemap has more than
|
101
|
+
# one sitemap file.
|
102
|
+
#
|
103
|
+
# * <tt>:namer</tt> - A <tt>SitemapGenerator::SimpleNamer</tt> instance for generating the sitemap
|
104
|
+
# and index file names. See <tt>:filename</tt> if you don't need to do anything fancy, and can
|
105
|
+
# accept the default naming conventions.
|
106
|
+
#
|
107
|
+
# * <tt>:compress</tt> - Specifies which files to compress with gzip. Default is `true`. Accepted values:
|
108
|
+
# * `true` - Boolean; compress all files.
|
109
|
+
# * `false` - Boolean; write out only uncompressed files.
|
110
|
+
# * `:all_but_first` - Symbol; leave the first file uncompressed but compress any remaining files.
|
111
|
+
#
|
112
|
+
# The compression setting applies to groups too. So :all_but_first will have the same effect (the first
|
113
|
+
# file in the group will not be compressed, the rest will). So if you require different behaviour for your
|
114
|
+
# groups, pass in a `:compress` option e.g. <tt>group(:compress => false) { add('/link') }</tt>
|
115
|
+
#
|
116
|
+
# KJV: When adding a new option be sure to include it in `options_for_group()` if
|
117
|
+
# the option should be inherited by groups.
|
118
|
+
def initialize(options={})
|
119
|
+
options = SitemapGenerator::Utilities.reverse_merge(options,
|
120
|
+
:include_root => true,
|
121
|
+
:include_index => false,
|
122
|
+
:filename => :sitemap,
|
123
|
+
:search_engines => {
|
124
|
+
:google => "http://www.google.com/webmasters/tools/ping?sitemap=%s",
|
125
|
+
:bing => "http://www.bing.com/webmaster/ping.aspx?siteMap=%s"
|
126
|
+
},
|
127
|
+
:create_index => :auto,
|
128
|
+
:compress => true
|
129
|
+
)
|
130
|
+
options.each_pair { |k, v| instance_variable_set("@#{k}".to_sym, v) }
|
131
|
+
|
132
|
+
# If an index is passed in, protect it from modification.
|
133
|
+
# Sitemaps can be added to the index but nothing else can be changed.
|
134
|
+
if options[:sitemap_index]
|
135
|
+
@protect_index = true
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Add a link to a Sitemap. If a new Sitemap is required, one will be created for
|
140
|
+
# you.
|
141
|
+
#
|
142
|
+
# link - string link e.g. '/merchant', '/article/1' or whatever.
|
143
|
+
# options - see README.
|
144
|
+
# host - host for the link, defaults to your <tt>default_host</tt>.
|
145
|
+
def add(link, options={})
|
146
|
+
add_default_links if !@added_default_links
|
147
|
+
sitemap.add(link, SitemapGenerator::Utilities.reverse_merge(options, :host => @default_host))
|
148
|
+
rescue SitemapGenerator::SitemapFullError
|
149
|
+
finalize_sitemap!
|
150
|
+
retry
|
151
|
+
rescue SitemapGenerator::SitemapFinalizedError
|
152
|
+
@sitemap = sitemap.new
|
153
|
+
retry
|
154
|
+
end
|
155
|
+
|
156
|
+
# Add a link to the Sitemap Index.
|
157
|
+
# * link - A string link e.g. '/sitemaps/sitemap1.xml.gz' or a SitemapFile instance.
|
158
|
+
# * options - A hash of options including `:lastmod`, ':priority`, ':changefreq` and `:host`
|
159
|
+
#
|
160
|
+
# The `:host` option defaults to the value of `sitemaps_host` which is the host where your
|
161
|
+
# sitemaps reside. If no `sitemaps_host` is set, the `default_host` is used.
|
162
|
+
def add_to_index(link, options={})
|
163
|
+
sitemap_index.add(link, SitemapGenerator::Utilities.reverse_merge(options, :host => sitemaps_host))
|
164
|
+
end
|
165
|
+
|
166
|
+
# Create a new group of sitemap files.
|
167
|
+
#
|
168
|
+
# Returns a new LinkSet instance with the options passed in set on it. All groups
|
169
|
+
# share the sitemap index, which is not affected by any of the options passed here.
|
170
|
+
#
|
171
|
+
# === Options
|
172
|
+
# Any of the options to LinkSet.new. Except for <tt>:public_path</tt> which is shared
|
173
|
+
# by all groups.
|
174
|
+
#
|
175
|
+
# The current options are inherited by the new group of sitemaps. The only exceptions
|
176
|
+
# being <tt>:include_index</tt> and <tt>:include_root</tt> which default to +false+.
|
177
|
+
#
|
178
|
+
# Pass a block to add links to the new LinkSet. If you pass a block the sitemaps will
|
179
|
+
# be finalized when the block returns.
|
180
|
+
#
|
181
|
+
# If you are not changing any of the location settings like <tt>filename<tt>,
|
182
|
+
# <tt>sitemaps_path</tt>, <tt>sitemaps_host</tt> or <tt>namer</tt>,
|
183
|
+
# links you add within the group will be added to the current sitemap.
|
184
|
+
# Otherwise the current sitemap file is finalized and a new sitemap file started,
|
185
|
+
# using the options you specified.
|
186
|
+
#
|
187
|
+
# Most commonly, you'll want to give the group's files a distinct name using
|
188
|
+
# the <tt>filename</tt> option.
|
189
|
+
#
|
190
|
+
# Options like <tt>:default_host</tt> can be used and it will only affect the links
|
191
|
+
# within the group. Links added outside of the group will revert to the previous
|
192
|
+
# +default_host+.
|
193
|
+
def group(opts={}, &block)
|
194
|
+
@created_group = true
|
195
|
+
original_opts = opts.dup
|
196
|
+
|
197
|
+
if (@@requires_finalization_opts & original_opts.keys).empty?
|
198
|
+
# If no new filename or path is specified reuse the default sitemap file.
|
199
|
+
# A new location object will be set on it for the duration of the group.
|
200
|
+
original_opts[:sitemap] = sitemap
|
201
|
+
elsif original_opts.key?(:sitemaps_host) && (@@new_location_opts & original_opts.keys).empty?
|
202
|
+
# If no location options are provided we are creating the next sitemap in the
|
203
|
+
# current series, so finalize and inherit the namer.
|
204
|
+
finalize_sitemap!
|
205
|
+
original_opts[:namer] = namer
|
206
|
+
end
|
207
|
+
|
208
|
+
opts = options_for_group(original_opts)
|
209
|
+
@group = SitemapGenerator::LinkSet.new(opts)
|
210
|
+
if opts.key?(:sitemap)
|
211
|
+
# If the group is sharing the current sitemap, set the
|
212
|
+
# new location options on the location object.
|
213
|
+
@original_location = @sitemap.location.dup
|
214
|
+
@sitemap.location.merge!(@group.sitemap_location)
|
215
|
+
if block_given?
|
216
|
+
@group.interpreter.eval(:yield_sitemap => @yield_sitemap || SitemapGenerator.yield_sitemap?, &block)
|
217
|
+
@sitemap.location.merge!(@original_location)
|
218
|
+
end
|
219
|
+
else
|
220
|
+
# Handle the case where a user only has one group, and it's being written
|
221
|
+
# to a new sitemap file. They would expect there to be an index. So force
|
222
|
+
# index creation. If there is more than one group, we would have an index anyways,
|
223
|
+
# so it's safe to force index creation in these other cases. In the case that
|
224
|
+
# the groups reuse the current sitemap, don't force index creation because
|
225
|
+
# we want the default behaviour i.e. only an index if more than one sitemap file.
|
226
|
+
# Don't force index creation if the user specifically requested no index. This
|
227
|
+
# unfortunately means that if they set it to :auto they may be getting an index
|
228
|
+
# when they didn't expect one, but you shouldn't be using groups if you only have
|
229
|
+
# one sitemap and don't want an index. Rather, just add the links directly in the create()
|
230
|
+
# block.
|
231
|
+
@group.send(:create_index=, true, true) if @group.create_index != false
|
232
|
+
|
233
|
+
if block_given?
|
234
|
+
@group.interpreter.eval(:yield_sitemap => @yield_sitemap || SitemapGenerator.yield_sitemap?, &block)
|
235
|
+
@group.finalize_sitemap!
|
236
|
+
end
|
237
|
+
end
|
238
|
+
@group
|
239
|
+
end
|
240
|
+
|
241
|
+
# Ping search engines to notify them of updated sitemaps.
|
242
|
+
#
|
243
|
+
# Search engines are already notified for you if you run `rake sitemap:refresh`.
|
244
|
+
# If you want to ping search engines separately to your sitemap generation, run
|
245
|
+
# `rake sitemap:refresh:no_ping` and then run a rake task or script
|
246
|
+
# which calls this method as in the example below.
|
247
|
+
#
|
248
|
+
# == Arguments
|
249
|
+
# * sitemap_index_url - The full URL to your sitemap index file.
|
250
|
+
# If not provided the location is based on the `host` you have
|
251
|
+
# set and any other options like your `sitemaps_path`. The URL
|
252
|
+
# will be CGI escaped for you when included as part of the
|
253
|
+
# search engine ping URL.
|
254
|
+
#
|
255
|
+
# == Options
|
256
|
+
# A hash of one or more search engines to ping in addition to the
|
257
|
+
# default search engines. The key is the name of the search engine
|
258
|
+
# as a string or symbol and the value is the full URL to ping with
|
259
|
+
# a string interpolation that will be replaced by the CGI escaped sitemap
|
260
|
+
# index URL. If you have any literal percent characters in your URL you
|
261
|
+
# need to escape them with `%%`. For example if your sitemap index URL
|
262
|
+
# is `http://example.com/sitemap.xml.gz` and your
|
263
|
+
# ping url is `http://example.com/100%%/ping?url=%s`
|
264
|
+
# then the final URL that is pinged will be `http://example.com/100%/ping?url=http%3A%2F%2Fexample.com%2Fsitemap.xml.gz`
|
265
|
+
#
|
266
|
+
# == Examples
|
267
|
+
#
|
268
|
+
# Both of these examples will ping the default search engines in addition to `http://superengine.com/ping?url=http%3A%2F%2Fexample.com%2Fsitemap.xml.gz`
|
269
|
+
#
|
270
|
+
# SitemapGenerator::Sitemap.host('http://example.com/')
|
271
|
+
# SitemapGenerator::Sitemap.ping_search_engines(:super_engine => 'http://superengine.com/ping?url=%s')
|
272
|
+
#
|
273
|
+
# Is equivalent to:
|
274
|
+
#
|
275
|
+
# SitemapGenerator::Sitemap.ping_search_engines('http://example.com/sitemap.xml.gz', :super_engine => 'http://superengine.com/ping?url=%s')
|
276
|
+
def ping_search_engines(*args)
|
277
|
+
require 'cgi/session'
|
278
|
+
require 'open-uri'
|
279
|
+
require 'timeout'
|
280
|
+
|
281
|
+
engines = args.last.is_a?(Hash) ? args.pop : {}
|
282
|
+
unescaped_url = args.shift || sitemap_index_url
|
283
|
+
index_url = CGI.escape(unescaped_url)
|
284
|
+
|
285
|
+
output("\n")
|
286
|
+
output("Pinging with URL '#{unescaped_url}':")
|
287
|
+
search_engines.merge(engines).each do |engine, link|
|
288
|
+
link = link % index_url
|
289
|
+
name = Utilities.titleize(engine.to_s)
|
290
|
+
begin
|
291
|
+
Timeout::timeout(10) {
|
292
|
+
open(link)
|
293
|
+
}
|
294
|
+
output(" Successful ping of #{name}")
|
295
|
+
rescue Timeout::Error, StandardError => e
|
296
|
+
output("Ping failed for #{name}: #{e.inspect} (URL #{link})")
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
# Return a count of the total number of links in all sitemaps
|
302
|
+
def link_count
|
303
|
+
sitemap_index.total_link_count
|
304
|
+
end
|
305
|
+
|
306
|
+
# Return the host to use in links to the sitemap files. This defaults to your
|
307
|
+
# +default_host+.
|
308
|
+
def sitemaps_host
|
309
|
+
@sitemaps_host || @default_host
|
310
|
+
end
|
311
|
+
|
312
|
+
# Lazy-initialize a sitemap instance and return it.
|
313
|
+
def sitemap
|
314
|
+
@sitemap ||= SitemapGenerator::Builder::SitemapFile.new(sitemap_location,
|
315
|
+
schemas,
|
316
|
+
schema_location)
|
317
|
+
end
|
318
|
+
|
319
|
+
# Lazy-initialize a sitemap index instance and return it.
|
320
|
+
def sitemap_index
|
321
|
+
@sitemap_index ||= SitemapGenerator::Builder::SitemapIndexFile.new(sitemap_index_location)
|
322
|
+
end
|
323
|
+
|
324
|
+
# Return the full url to the sitemap index file. When `create_index` is `false`
|
325
|
+
# the first sitemap is technically the index, so this will be its URL. It's important
|
326
|
+
# to use this method to get the index url because `sitemap_index.location.url` will
|
327
|
+
# not be correct in such situations.
|
328
|
+
#
|
329
|
+
# KJV: This is somewhat confusing.
|
330
|
+
def sitemap_index_url
|
331
|
+
sitemap_index.index_url
|
332
|
+
end
|
333
|
+
|
334
|
+
# All done. Write out remaining files.
|
335
|
+
def finalize!
|
336
|
+
finalize_sitemap!
|
337
|
+
finalize_sitemap_index!
|
338
|
+
end
|
339
|
+
|
340
|
+
# Return a boolean indicating hether to add a link to the sitemap index file
|
341
|
+
# to the current sitemap. This points search engines to your Sitemap Index so
|
342
|
+
# they include it in the indexing of your site, but is not strictly neccessary.
|
343
|
+
# Default is `true`. Turned off when `sitemaps_host` is set or within a `group()` block.
|
344
|
+
def include_index?
|
345
|
+
if default_host && sitemaps_host && sitemaps_host != default_host
|
346
|
+
false
|
347
|
+
else
|
348
|
+
@include_index
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
# Return a boolean indicating whether to automatically add the root url i.e. '/' to the
|
353
|
+
# current sitemap. Default is `true`. Turned off within a `group()` block.
|
354
|
+
def include_root?
|
355
|
+
!!@include_root
|
356
|
+
end
|
357
|
+
|
358
|
+
# Set verbose on the instance or by setting ENV['VERBOSE'] to true or false.
|
359
|
+
# By default verbose is true. When running rake tasks, pass the <tt>-s</tt>
|
360
|
+
# option to rake to turn verbose off.
|
361
|
+
def verbose
|
362
|
+
if @verbose.nil?
|
363
|
+
@verbose = SitemapGenerator.verbose.nil? ? true : SitemapGenerator.verbose
|
364
|
+
end
|
365
|
+
@verbose
|
366
|
+
end
|
367
|
+
|
368
|
+
def schemas
|
369
|
+
@schemas || SCHEMAS
|
370
|
+
end
|
371
|
+
|
372
|
+
def schema_location
|
373
|
+
@schema_location || SCHEMA_LOCATION
|
374
|
+
end
|
375
|
+
|
376
|
+
# Return a boolean indicating whether or not to yield the sitemap.
|
377
|
+
def yield_sitemap?
|
378
|
+
@yield_sitemap.nil? ? SitemapGenerator.yield_sitemap? : !!@yield_sitemap
|
379
|
+
end
|
380
|
+
|
381
|
+
protected
|
382
|
+
|
383
|
+
def set_customized_schemas(opts)
|
384
|
+
exclude_keys = opts.delete(:exclude_keys) || []
|
385
|
+
@schemas= SitemapGenerator::SCHEMAS.reject{ |k, v| exclude_keys.include? k }
|
386
|
+
@schema_location = [SitemapGenerator::SCHEMA_LOCATION,
|
387
|
+
opts.delete(:schema_location).to_s].join(" ").strip()
|
388
|
+
end
|
389
|
+
|
390
|
+
# Set each option on this instance using accessor methods. This will affect
|
391
|
+
# both the sitemap and the sitemap index.
|
392
|
+
#
|
393
|
+
# If both `filename` and `namer` are passed, set filename first so it
|
394
|
+
# doesn't override the latter.
|
395
|
+
def set_options(opts={})
|
396
|
+
opts = opts.dup
|
397
|
+
%w(filename namer).each do |key|
|
398
|
+
if value = opts.delete(key.to_sym)
|
399
|
+
send("#{key}=", value)
|
400
|
+
end
|
401
|
+
end
|
402
|
+
opts.each_pair do |key, value|
|
403
|
+
send("#{key}=", value)
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
# Given +opts+, modify it and return it prepped for creating a new group from this LinkSet.
|
408
|
+
# If <tt>:public_path</tt> is present in +opts+ it is removed because groups cannot
|
409
|
+
# change the public path.
|
410
|
+
def options_for_group(opts)
|
411
|
+
opts = SitemapGenerator::Utilities.reverse_merge(opts,
|
412
|
+
:include_index => false,
|
413
|
+
:include_root => false,
|
414
|
+
:sitemap_index => sitemap_index
|
415
|
+
)
|
416
|
+
opts.delete(:public_path)
|
417
|
+
|
418
|
+
# Reverse merge the current settings
|
419
|
+
# KJV: This hash could be a problem because it needs to be maintained
|
420
|
+
# when new options are added, but can easily be missed. We really could
|
421
|
+
# do with a separate SitemapOptions class.
|
422
|
+
current_settings = [
|
423
|
+
:include_root,
|
424
|
+
:include_index,
|
425
|
+
:sitemaps_path,
|
426
|
+
:public_path,
|
427
|
+
:sitemaps_host,
|
428
|
+
:verbose,
|
429
|
+
:default_host,
|
430
|
+
:adapter,
|
431
|
+
:create_index,
|
432
|
+
:compress,
|
433
|
+
:schemas,
|
434
|
+
:schema_location
|
435
|
+
].inject({}) do |hash, key|
|
436
|
+
if !(value = instance_variable_get(:"@#{key}")).nil?
|
437
|
+
hash[key] = value
|
438
|
+
end
|
439
|
+
hash
|
440
|
+
end
|
441
|
+
SitemapGenerator::Utilities.reverse_merge!(opts, current_settings)
|
442
|
+
opts
|
443
|
+
end
|
444
|
+
|
445
|
+
# Add default links if those options are turned on. Record the fact that we have done so
|
446
|
+
# in an instance variable.
|
447
|
+
def add_default_links
|
448
|
+
if include_root?
|
449
|
+
sitemap.add('/', :lastmod => Time.now, :changefreq => 'always', :priority => 1.0, :host => @default_host)
|
450
|
+
end
|
451
|
+
if include_index?
|
452
|
+
sitemap.add(sitemap_index, :lastmod => Time.now, :changefreq => 'always', :priority => 1.0)
|
453
|
+
end
|
454
|
+
@added_default_links = true
|
455
|
+
end
|
456
|
+
|
457
|
+
# Finalize a sitemap by including it in the index and outputting a summary line.
|
458
|
+
# Do nothing if it has already been finalized.
|
459
|
+
#
|
460
|
+
# Don't finalize if the sitemap is empty.
|
461
|
+
#
|
462
|
+
# Add the default links if they have not been added yet and no groups have been created.
|
463
|
+
# If the default links haven't been added we know that the sitemap is empty,
|
464
|
+
# because they are added on the first call to add(). This ensure that if the
|
465
|
+
# block passed to create() is empty the default links are still included in the
|
466
|
+
# sitemap.
|
467
|
+
def finalize_sitemap!
|
468
|
+
return if sitemap.finalized? || sitemap.empty? && @created_group
|
469
|
+
add_default_links if !@added_default_links && !@created_group
|
470
|
+
# This will finalize it. We add to the index even if not creating an index because
|
471
|
+
# the index keeps track of how many links are in our sitemaps and we need this info
|
472
|
+
# for the summary line. Also the index determines which file gets the first name
|
473
|
+
# so everything has to go via the index.
|
474
|
+
add_to_index(sitemap) unless sitemap.empty?
|
475
|
+
end
|
476
|
+
|
477
|
+
# Finalize a sitemap index and output a summary line. Do nothing if it has already
|
478
|
+
# been finalized.
|
479
|
+
def finalize_sitemap_index!
|
480
|
+
return if @protect_index || sitemap_index.finalized?
|
481
|
+
sitemap_index.finalize!
|
482
|
+
sitemap_index.write
|
483
|
+
end
|
484
|
+
|
485
|
+
# Return the interpreter linked to this instance.
|
486
|
+
def interpreter
|
487
|
+
require 'sitemap_generator/interpreter'
|
488
|
+
@interpreter ||= SitemapGenerator::Interpreter.new(:link_set => self)
|
489
|
+
end
|
490
|
+
|
491
|
+
# Reset this instance. Keep the same options, but return to the same state
|
492
|
+
# as before any sitemaps were created.
|
493
|
+
def reset!
|
494
|
+
@sitemap_index = nil if @sitemap_index && @sitemap_index.finalized? && !@protect_index
|
495
|
+
@sitemap = nil if @sitemap && @sitemap.finalized?
|
496
|
+
self.namer.reset
|
497
|
+
@added_default_links = false
|
498
|
+
end
|
499
|
+
|
500
|
+
# Write the given string to STDOUT. Used so that the sitemap config can be
|
501
|
+
# evaluated and some info output to STDOUT in a lazy fasion.
|
502
|
+
def output(string)
|
503
|
+
return unless verbose
|
504
|
+
puts string
|
505
|
+
end
|
506
|
+
|
507
|
+
module LocationHelpers
|
508
|
+
public
|
509
|
+
|
510
|
+
# Set the host name, including protocol, that will be used by default on each
|
511
|
+
# of your sitemap links. You can pass a different host in your options to `add`
|
512
|
+
# if you need to change it on a per-link basis.
|
513
|
+
def default_host=(value)
|
514
|
+
@default_host = value
|
515
|
+
update_location_info(:host, value)
|
516
|
+
end
|
517
|
+
|
518
|
+
# Set the public_path. This path gives the location of your public directory.
|
519
|
+
# The default is the public/ directory in your Rails root. Or if Rails is not
|
520
|
+
# found, it defaults to public/ in the current directory (of the process).
|
521
|
+
#
|
522
|
+
# Example: 'tmp/' if you don't want to generate in public for some reason.
|
523
|
+
#
|
524
|
+
# Set to nil to use the current directory.
|
525
|
+
def public_path=(value)
|
526
|
+
@public_path = Pathname.new(SitemapGenerator::Utilities.append_slash(value))
|
527
|
+
if @public_path.relative?
|
528
|
+
@public_path = SitemapGenerator.app.root + @public_path
|
529
|
+
end
|
530
|
+
update_location_info(:public_path, @public_path)
|
531
|
+
@public_path
|
532
|
+
end
|
533
|
+
|
534
|
+
# Return a Pathname with the full path to the public directory
|
535
|
+
def public_path
|
536
|
+
@public_path ||= self.send(:public_path=, 'public/')
|
537
|
+
end
|
538
|
+
|
539
|
+
# Set the sitemaps_path. This path gives the location to write sitemaps to
|
540
|
+
# relative to your public_path.
|
541
|
+
# Example: 'sitemaps/' to generate your sitemaps in 'public/sitemaps/'.
|
542
|
+
def sitemaps_path=(value)
|
543
|
+
@sitemaps_path = value
|
544
|
+
update_location_info(:sitemaps_path, value)
|
545
|
+
end
|
546
|
+
|
547
|
+
# Set the host name, including protocol, that will be used on all links to your sitemap
|
548
|
+
# files. Useful when the server that hosts the sitemaps is not on the same host as
|
549
|
+
# the links in the sitemap.
|
550
|
+
#
|
551
|
+
# Note that `include_index` will be turned off to avoid adding a link to a sitemap with
|
552
|
+
# a different host than the other links.
|
553
|
+
def sitemaps_host=(value)
|
554
|
+
@sitemaps_host = value
|
555
|
+
update_location_info(:host, value)
|
556
|
+
end
|
557
|
+
|
558
|
+
# Set the filename base to use when generating sitemaps (and the sitemap index).
|
559
|
+
#
|
560
|
+
# === Example
|
561
|
+
# <tt>filename = :sitemap</tt>
|
562
|
+
#
|
563
|
+
# === Generates
|
564
|
+
# <tt>sitemap.xml.gz, sitemap1.xml.gz, sitemap2.xml.gz, ...</tt>
|
565
|
+
def filename=(value)
|
566
|
+
@filename = value
|
567
|
+
self.namer = SitemapGenerator::SimpleNamer.new(@filename)
|
568
|
+
end
|
569
|
+
|
570
|
+
# Set the search engines hash to a new hash of search engine names mapped to
|
571
|
+
# ping URLs (see ping_search_engines). If the value is nil it is converted
|
572
|
+
# to an empty hash.
|
573
|
+
# === Example
|
574
|
+
# <tt>search_engines = { :google => "http://www.google.com/webmasters/sitemaps/ping?sitemap=%s" }</tt>
|
575
|
+
def search_engines=(value)
|
576
|
+
@search_engines = value || {}
|
577
|
+
end
|
578
|
+
|
579
|
+
# Return the hash of search engines.
|
580
|
+
def search_engines
|
581
|
+
@search_engines || {}
|
582
|
+
end
|
583
|
+
|
584
|
+
# Return a new +SitemapLocation+ instance with the current options included
|
585
|
+
def sitemap_location
|
586
|
+
SitemapGenerator::SitemapLocation.new(
|
587
|
+
:host => sitemaps_host,
|
588
|
+
:namer => namer,
|
589
|
+
:public_path => public_path,
|
590
|
+
:sitemaps_path => @sitemaps_path,
|
591
|
+
:adapter => @adapter,
|
592
|
+
:verbose => verbose,
|
593
|
+
:compress => @compress
|
594
|
+
)
|
595
|
+
end
|
596
|
+
|
597
|
+
# Return a new +SitemapIndexLocation+ instance with the current options included
|
598
|
+
def sitemap_index_location
|
599
|
+
SitemapGenerator::SitemapLocation.new(
|
600
|
+
:host => sitemaps_host,
|
601
|
+
:namer => namer,
|
602
|
+
:public_path => public_path,
|
603
|
+
:sitemaps_path => @sitemaps_path,
|
604
|
+
:adapter => @adapter,
|
605
|
+
:verbose => verbose,
|
606
|
+
:create_index => @create_index,
|
607
|
+
:compress => @compress
|
608
|
+
)
|
609
|
+
end
|
610
|
+
|
611
|
+
# Set the value of +create_index+ on the SitemapIndexLocation object of the
|
612
|
+
# SitemapIndexFile.
|
613
|
+
#
|
614
|
+
# Whether to create a sitemap index file. Supported values: `true`, `false`, `:auto`.
|
615
|
+
# If `true` an index file is always created, regardless of how many links
|
616
|
+
# are in your sitemap. If `false` an index file is never created.
|
617
|
+
# If `:auto` an index file is created only if your sitemap has more than
|
618
|
+
# one sitemap file.
|
619
|
+
def create_index=(value, force=false)
|
620
|
+
@create_index = value
|
621
|
+
# Allow overriding the protected status of the index when we are creating a group.
|
622
|
+
# Because sometimes we need to force an index in that case. But generally we don't
|
623
|
+
# want to allow people to mess with this value if the index is protected.
|
624
|
+
@sitemap_index.location[:create_index] = value if @sitemap_index && ((!@sitemap_index.finalized? && !@protect_index) || force)
|
625
|
+
end
|
626
|
+
|
627
|
+
# Set the namer to use to generate the sitemap (and index) file names.
|
628
|
+
# This should be an instance of <tt>SitemapGenerator::SimpleNamer</tt>
|
629
|
+
def namer=(value)
|
630
|
+
@namer = value
|
631
|
+
@sitemap.location[:namer] = value if @sitemap && !@sitemap.finalized?
|
632
|
+
@sitemap_index.location[:namer] = value if @sitemap_index && !@sitemap_index.finalized? && !@protect_index
|
633
|
+
end
|
634
|
+
|
635
|
+
# Return the namer object. If it is not set, looks for it on
|
636
|
+
# the current sitemap and if there is no sitemap, creates a new one using
|
637
|
+
# the current filename.
|
638
|
+
def namer
|
639
|
+
@namer ||= @sitemap && @sitemap.location.namer || SitemapGenerator::SimpleNamer.new(@filename)
|
640
|
+
end
|
641
|
+
|
642
|
+
# Set the value of the compress setting.
|
643
|
+
#
|
644
|
+
# Values:
|
645
|
+
# * `true` - Boolean; compress all files
|
646
|
+
# * `false` - Boolean; write out only uncompressed files
|
647
|
+
# * `:all_but_first` - Symbol; leave the first file uncompressed but compress any remaining files.
|
648
|
+
#
|
649
|
+
# The compression setting applies to groups too. So :all_but_first will have the same effect (the first
|
650
|
+
# file in the group will not be compressed, the rest will). So if you require different behaviour for your
|
651
|
+
# groups, pass in a `:compress` option e.g. <tt>group(:compress => false) { add('/link') }</tt>
|
652
|
+
def compress=(value)
|
653
|
+
@compress = value
|
654
|
+
@sitemap_index.location[:compress] = @compress if @sitemap_index
|
655
|
+
@sitemap.location[:compress] = @compress if @sitemap
|
656
|
+
end
|
657
|
+
|
658
|
+
# Return the current compression setting. Its value determines which files will be gzip'ed.
|
659
|
+
# See the setter for documentation of its values.
|
660
|
+
def compress
|
661
|
+
@compress
|
662
|
+
end
|
663
|
+
|
664
|
+
protected
|
665
|
+
|
666
|
+
# Update the given attribute on the current sitemap index and sitemap file location objects.
|
667
|
+
# But don't create the index or sitemap files yet if they are not already created.
|
668
|
+
def update_location_info(attribute, value, opts={})
|
669
|
+
opts = SitemapGenerator::Utilities.reverse_merge(opts, :include_index => !@protect_index)
|
670
|
+
@sitemap_index.location[attribute] = value if opts[:include_index] && @sitemap_index && !@sitemap_index.finalized?
|
671
|
+
@sitemap.location[attribute] = value if @sitemap && !@sitemap.finalized?
|
672
|
+
end
|
673
|
+
end
|
674
|
+
include LocationHelpers
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|