ftbpro_sitemap_generator 5.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|