sitemap_generator_ftbpro 5.0.4
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/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/adapters.rb +0 -0
- data/lib/sitemap_generator/application.rb +49 -0
- data/lib/sitemap_generator/builder/sitemap_file.rb +171 -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/builder.rb +8 -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/core_ext.rb +3 -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 +665 -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/sitemap_generator.rb +82 -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,192 @@
|
|
1
|
+
require 'sitemap_generator/helpers/number_helper'
|
2
|
+
|
3
|
+
module SitemapGenerator
|
4
|
+
# A class for determining the exact location at which to write sitemap data.
|
5
|
+
# Handles reserving filenames from namers, constructing paths and sending
|
6
|
+
# data to the adapter to be written out.
|
7
|
+
class SitemapLocation < Hash
|
8
|
+
include SitemapGenerator::Helpers::NumberHelper
|
9
|
+
|
10
|
+
PATH_OUTPUT_WIDTH = 47 # Character width of the path in the summary lines
|
11
|
+
|
12
|
+
[:host, :adapter].each do |method|
|
13
|
+
define_method(method) do
|
14
|
+
raise SitemapGenerator::SitemapError, "No value set for #{method}" unless self[method]
|
15
|
+
self[method]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
[:public_path, :sitemaps_path].each do |method|
|
20
|
+
define_method(method) do
|
21
|
+
Pathname.new(SitemapGenerator::Utilities.append_slash(self[method]))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# If no +filename+ or +namer+ is provided, the default namer is used, which
|
26
|
+
# generates names like <tt>sitemap.xml.gz</tt>, <tt>sitemap1.xml.gz</tt>, <tt>sitemap2.xml.gz</tt> and so on.
|
27
|
+
#
|
28
|
+
# === Options
|
29
|
+
# * <tt>:adapter</tt> - SitemapGenerator::Adapter subclass
|
30
|
+
# * <tt>:filename</tt> - full name of the file e.g. <tt>'sitemap1.xml.gz'<tt>
|
31
|
+
# * <tt>:host</tt> - host name for URLs. The full URL to the file is then constructed from
|
32
|
+
# the <tt>host</tt>, <tt>sitemaps_path</tt> and <tt>filename</tt>
|
33
|
+
# * <tt>:namer</tt> - a SitemapGenerator::SimpleNamer instance for generating file names.
|
34
|
+
# Should be passed if no +filename+ is provided.
|
35
|
+
# * <tt>:public_path</tt> - path to the "public" directory, or the directory you want to
|
36
|
+
# write sitemaps in. Default is a directory <tt>public/</tt>
|
37
|
+
# in the current working directory, or relative to the Rails root
|
38
|
+
# directory if running under Rails.
|
39
|
+
# * <tt>:sitemaps_path</tt> - gives the path relative to the <tt>public_path</tt> in which to
|
40
|
+
# write sitemaps e.g. <tt>sitemaps/</tt>.
|
41
|
+
# * <tt>:verbose</tt> - whether to output summary into to STDOUT. Default +false+.
|
42
|
+
# * <tt>:create_index</tt> - whether to create a sitemap index. Default `:auto`. See <tt>LinkSet::create_index=</tt>
|
43
|
+
# for possible values. Only applies to the SitemapIndexLocation object.
|
44
|
+
# * <tt>compress</tt> - The LinkSet compress setting. Default: true. If `false` any `.gz` extension is
|
45
|
+
# stripped from the filename. If `:all_but_first`, only the `.gz` extension of the first
|
46
|
+
# filename is stripped off. If `true` the extensions are left unchanged.
|
47
|
+
def initialize(opts={})
|
48
|
+
SitemapGenerator::Utilities.assert_valid_keys(opts, [:adapter, :public_path, :sitemaps_path, :host, :filename, :namer, :verbose, :create_index, :compress])
|
49
|
+
opts[:adapter] ||= SitemapGenerator::FileAdapter.new
|
50
|
+
opts[:public_path] ||= SitemapGenerator.app.root + 'public/'
|
51
|
+
# This is a bit of a hack to make the SimpleNamer act like the old SitemapNamer.
|
52
|
+
# It doesn't really make sense to create a default namer like this because the
|
53
|
+
# namer instance should be shared by the location objects of the sitemaps and
|
54
|
+
# sitemap index files. However, this greatly eases testing, so I'm leaving it in
|
55
|
+
# for now.
|
56
|
+
if !opts[:filename] && !opts[:namer]
|
57
|
+
opts[:namer] = SitemapGenerator::SimpleNamer.new(:sitemap, :start => 2, :zero => 1)
|
58
|
+
end
|
59
|
+
opts[:verbose] = !!opts[:verbose]
|
60
|
+
self.merge!(opts)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Return a new Location instance with the given options merged in
|
64
|
+
def with(opts={})
|
65
|
+
self.merge(opts)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Full path to the directory of the file.
|
69
|
+
def directory
|
70
|
+
(public_path + sitemaps_path).expand_path.to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
# Full path of the file including the filename.
|
74
|
+
def path
|
75
|
+
(public_path + sitemaps_path + filename).expand_path.to_s
|
76
|
+
end
|
77
|
+
|
78
|
+
# Relative path of the file (including the filename) relative to <tt>public_path</tt>
|
79
|
+
def path_in_public
|
80
|
+
(sitemaps_path + filename).to_s
|
81
|
+
end
|
82
|
+
|
83
|
+
# Full URL of the file.
|
84
|
+
def url
|
85
|
+
URI.join(host, sitemaps_path.to_s, filename.to_s).to_s
|
86
|
+
end
|
87
|
+
|
88
|
+
# Return the size of the file at <tt>path</tt>
|
89
|
+
def filesize
|
90
|
+
File.size?(path)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Return the filename. Raises an exception if no filename or namer is set.
|
94
|
+
# If using a namer once the filename has been retrieved from the namer its
|
95
|
+
# value is locked so that it is unaffected by further changes to the namer.
|
96
|
+
def filename
|
97
|
+
raise SitemapGenerator::SitemapError, "No filename or namer set" unless self[:filename] || self[:namer]
|
98
|
+
unless self[:filename]
|
99
|
+
self.send(:[]=, :filename, self[:namer].to_s, :super => true)
|
100
|
+
|
101
|
+
# Post-process the filename for our compression settings.
|
102
|
+
# Strip the `.gz` from the extension if we aren't compressing this file.
|
103
|
+
# If you're setting the filename manually, :all_but_first won't work as
|
104
|
+
# expected. Ultimately I should force using a namer in all circumstances.
|
105
|
+
# Changing the filename here will affect how the FileAdapter writes out the file.
|
106
|
+
if self[:compress] == false ||
|
107
|
+
(self[:namer] && self[:namer].start? && self[:compress] == :all_but_first)
|
108
|
+
self[:filename].gsub!(/\.gz$/, '')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
self[:filename]
|
112
|
+
end
|
113
|
+
|
114
|
+
# If a namer is set, reserve the filename and increment the namer.
|
115
|
+
# Returns the reserved name.
|
116
|
+
def reserve_name
|
117
|
+
if self[:namer]
|
118
|
+
filename
|
119
|
+
self[:namer].next
|
120
|
+
end
|
121
|
+
self[:filename]
|
122
|
+
end
|
123
|
+
|
124
|
+
# Return true if this location has a fixed filename. If no name has been
|
125
|
+
# reserved from the namer, for instance, returns false.
|
126
|
+
def reserved_name?
|
127
|
+
!!self[:filename]
|
128
|
+
end
|
129
|
+
|
130
|
+
def namer
|
131
|
+
self[:namer]
|
132
|
+
end
|
133
|
+
|
134
|
+
def verbose?
|
135
|
+
self[:verbose]
|
136
|
+
end
|
137
|
+
|
138
|
+
# If you set the filename, clear the namer and vice versa.
|
139
|
+
def []=(key, value, opts={})
|
140
|
+
if !opts[:super]
|
141
|
+
case key
|
142
|
+
when :namer
|
143
|
+
super(:filename, nil)
|
144
|
+
when :filename
|
145
|
+
super(:namer, nil)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
super(key, value)
|
149
|
+
end
|
150
|
+
|
151
|
+
# Write `data` out to a file.
|
152
|
+
# Output a summary line if verbose is true.
|
153
|
+
def write(data, link_count)
|
154
|
+
adapter.write(self, data)
|
155
|
+
puts summary(link_count) if verbose?
|
156
|
+
end
|
157
|
+
|
158
|
+
# Return a summary string
|
159
|
+
def summary(link_count)
|
160
|
+
filesize = number_to_human_size(self.filesize)
|
161
|
+
width = self.class::PATH_OUTPUT_WIDTH
|
162
|
+
path = SitemapGenerator::Utilities.ellipsis(self.path_in_public, width)
|
163
|
+
"+ #{('%-'+width.to_s+'s') % path} #{'%10s' % link_count} links / #{'%10s' % filesize}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class SitemapIndexLocation < SitemapLocation
|
168
|
+
def initialize(opts={})
|
169
|
+
if !opts[:filename] && !opts[:namer]
|
170
|
+
opts[:namer] = SitemapGenerator::SimpleNamer.new(:sitemap)
|
171
|
+
end
|
172
|
+
super(opts)
|
173
|
+
end
|
174
|
+
|
175
|
+
# Whether to create a sitemap index. Default `:auto`. See <tt>LinkSet::create_index=</tt>
|
176
|
+
# for possible values.
|
177
|
+
#
|
178
|
+
# A placeholder for an option which should really go into some
|
179
|
+
# kind of options class.
|
180
|
+
def create_index
|
181
|
+
self[:create_index]
|
182
|
+
end
|
183
|
+
|
184
|
+
# Return a summary string
|
185
|
+
def summary(link_count)
|
186
|
+
filesize = number_to_human_size(self.filesize)
|
187
|
+
width = self.class::PATH_OUTPUT_WIDTH - 3
|
188
|
+
path = SitemapGenerator::Utilities.ellipsis(self.path_in_public, width)
|
189
|
+
"+ #{('%-'+width.to_s+'s') % path} #{'%10s' % link_count} sitemaps / #{'%10s' % filesize}"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module SitemapGenerator
|
2
|
+
# A class for generating sitemap filenames.
|
3
|
+
#
|
4
|
+
# The SimpleNamer uses the same namer instance for the sitemap index and the sitemaps.
|
5
|
+
# If no index is needed, the first sitemap gets the first name. However, if
|
6
|
+
# an index is needed, the index gets the first name.
|
7
|
+
#
|
8
|
+
# A typical sequence would looks like this:
|
9
|
+
# * sitemap.xml.gz
|
10
|
+
# * sitemap1.xml.gz
|
11
|
+
# * sitemap2.xml.gz
|
12
|
+
# * sitemap3.xml.gz
|
13
|
+
# * ...
|
14
|
+
#
|
15
|
+
# Arguments:
|
16
|
+
# base - string or symbol that forms the base of the generated filename e.g.
|
17
|
+
# if `:geo` files are generated like `geo.xml.gz`, `geo1.xml.gz`, `geo2.xml.gz` etc.
|
18
|
+
#
|
19
|
+
# Options:
|
20
|
+
# :extension - Default: '.xml.gz'. File extension to append.
|
21
|
+
# :start - Default: 1. Numerical index at which to start counting.
|
22
|
+
# :zero - Default: nil. A string or number that is appended to +base+
|
23
|
+
# to create the first name in the sequence. So setting this
|
24
|
+
# to '_index' would produce 'sitemap_index.xml.gz' as
|
25
|
+
# the first name. Thereafter, the numerical index defined by +start+
|
26
|
+
# is used, and subsequent names would be 'sitemap1.xml.gz', 'sitemap2.xml.gz', etc.
|
27
|
+
# In these examples the `base` string is assumed to be 'sitemap'.
|
28
|
+
class SimpleNamer
|
29
|
+
def initialize(base, options={})
|
30
|
+
@options = SitemapGenerator::Utilities.reverse_merge(options,
|
31
|
+
:zero => nil, # identifies the marker for the start of the series
|
32
|
+
:extension => '.xml.gz',
|
33
|
+
:start => 1
|
34
|
+
)
|
35
|
+
@base = base
|
36
|
+
reset
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
extension = @options[:extension]
|
41
|
+
"#{@base}#{@count}#{extension}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Reset to the first name
|
45
|
+
def reset
|
46
|
+
@count = @options[:zero]
|
47
|
+
end
|
48
|
+
|
49
|
+
# True if on the first name
|
50
|
+
def start?
|
51
|
+
@count == @options[:zero]
|
52
|
+
end
|
53
|
+
|
54
|
+
# Return this instance set to the next name
|
55
|
+
def next
|
56
|
+
if start?
|
57
|
+
@count = @options[:start]
|
58
|
+
else
|
59
|
+
@count += 1
|
60
|
+
end
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
# Return this instance set to the previous name
|
65
|
+
def previous
|
66
|
+
raise NameError, "Already at the start of the series" if start?
|
67
|
+
if @count <= @options[:start]
|
68
|
+
@count = @options[:zero]
|
69
|
+
else
|
70
|
+
@count -= 1
|
71
|
+
end
|
72
|
+
self
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# require this file to load the tasks
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
# Require sitemap_generator at runtime. If we don't do this the ActionView helpers are included
|
5
|
+
# before the Rails environment can be loaded by other Rake tasks, which causes problems
|
6
|
+
# for those tasks when rendering using ActionView.
|
7
|
+
namespace :sitemap do
|
8
|
+
# Require sitemap_generator only. When installed as a plugin the require will fail, so in
|
9
|
+
# that case, load the environment first.
|
10
|
+
task :require do
|
11
|
+
begin
|
12
|
+
require 'sitemap_generator'
|
13
|
+
rescue LoadError => e
|
14
|
+
if defined?(Rails)
|
15
|
+
Rake::Task['sitemap:require_environment'].invoke
|
16
|
+
else
|
17
|
+
raise e
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Require sitemap_generator after loading the Rails environment. We still need the require
|
23
|
+
# in case we are installed as a gem and are setup to not automatically be required.
|
24
|
+
task :require_environment do
|
25
|
+
if defined?(Rails)
|
26
|
+
Rake::Task['environment'].invoke
|
27
|
+
end
|
28
|
+
require 'sitemap_generator'
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "Install a default config/sitemap.rb file"
|
32
|
+
task :install => ['sitemap:require'] do
|
33
|
+
SitemapGenerator::Utilities.install_sitemap_rb(verbose)
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "Delete all Sitemap files in public/ directory"
|
37
|
+
task :clean => ['sitemap:require'] do
|
38
|
+
SitemapGenerator::Utilities.clean_files
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "Generate sitemaps and ping search engines."
|
42
|
+
task :refresh => ['sitemap:create'] do
|
43
|
+
SitemapGenerator::Sitemap.ping_search_engines
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Generate sitemaps but don't ping search engines."
|
47
|
+
task 'refresh:no_ping' => ['sitemap:create']
|
48
|
+
|
49
|
+
desc "Generate sitemaps but don't ping search engines. Alias for refresh:no_ping."
|
50
|
+
task :create => ['sitemap:require_environment'] do
|
51
|
+
SitemapGenerator::Interpreter.run(:config_file => ENV["CONFIG_FILE"], :verbose => verbose)
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module SitemapGenerator
|
2
|
+
# Provide convenient access to template files. E.g.
|
3
|
+
#
|
4
|
+
# SitemapGenerator.templates.sitemap_index
|
5
|
+
#
|
6
|
+
# Lazy-load and cache for efficient access.
|
7
|
+
# Define an accessor method for each template file.
|
8
|
+
class Templates
|
9
|
+
FILES = {
|
10
|
+
:sitemap_sample => 'sitemap.rb',
|
11
|
+
}
|
12
|
+
|
13
|
+
# Dynamically define accessors for each key defined in <tt>FILES</tt>
|
14
|
+
attr_accessor *FILES.keys
|
15
|
+
FILES.keys.each do |name|
|
16
|
+
eval <<-END
|
17
|
+
define_method(:#{name}) do
|
18
|
+
@#{name} ||= read_template(:#{name})
|
19
|
+
end
|
20
|
+
END
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(root = SitemapGenerator.root)
|
24
|
+
@root = root
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return the full path to a template.
|
28
|
+
#
|
29
|
+
# <tt>file</tt> template symbol e.g. <tt>:sitemap_sample</tt>
|
30
|
+
def template_path(template)
|
31
|
+
File.join(@root, 'templates', self.class::FILES[template])
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
# Read the template file and return its contents.
|
37
|
+
def read_template(template)
|
38
|
+
File.read(template_path(template))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
module SitemapGenerator
|
2
|
+
module Utilities
|
3
|
+
extend self
|
4
|
+
|
5
|
+
# Copy templates/sitemap.rb to config if not there yet.
|
6
|
+
def install_sitemap_rb(verbose=false)
|
7
|
+
if File.exist?(SitemapGenerator.app.root + 'config/sitemap.rb')
|
8
|
+
puts "already exists: config/sitemap.rb, file not copied" if verbose
|
9
|
+
else
|
10
|
+
FileUtils.cp(
|
11
|
+
SitemapGenerator.templates.template_path(:sitemap_sample),
|
12
|
+
SitemapGenerator.app.root + 'config/sitemap.rb')
|
13
|
+
puts "created: config/sitemap.rb" if verbose
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Remove config/sitemap.rb if exists.
|
18
|
+
def uninstall_sitemap_rb
|
19
|
+
if File.exist?(SitemapGenerator.app.root + 'config/sitemap.rb')
|
20
|
+
File.rm(SitemapGenerator.app.root + 'config/sitemap.rb')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Clean sitemap files in output directory.
|
25
|
+
def clean_files
|
26
|
+
FileUtils.rm(Dir[SitemapGenerator.app.root + 'public/sitemap*.xml.gz'])
|
27
|
+
end
|
28
|
+
|
29
|
+
# Validate all keys in a hash match *valid keys, raising ArgumentError on a
|
30
|
+
# mismatch. Note that keys are NOT treated indifferently, meaning if you use
|
31
|
+
# strings for keys but assert symbols as keys, this will fail.
|
32
|
+
def assert_valid_keys(hash, *valid_keys)
|
33
|
+
unknown_keys = hash.keys - [valid_keys].flatten
|
34
|
+
raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
|
35
|
+
end
|
36
|
+
|
37
|
+
# Return a new hash with all keys converted to symbols, as long as
|
38
|
+
# they respond to +to_sym+.
|
39
|
+
def symbolize_keys(hash)
|
40
|
+
symbolize_keys!(hash.dup)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Destructively convert all keys to symbols, as long as they respond
|
44
|
+
# to +to_sym+.
|
45
|
+
def symbolize_keys!(hash)
|
46
|
+
hash.keys.each do |key|
|
47
|
+
hash[(key.to_sym rescue key) || key] = hash.delete(key)
|
48
|
+
end
|
49
|
+
hash
|
50
|
+
end
|
51
|
+
|
52
|
+
# Make a list of `value` if it is not a list already. If `value` is
|
53
|
+
# nil, an empty list is returned. If `value` is already a list, return it unchanged.
|
54
|
+
def as_array(value)
|
55
|
+
if value.nil?
|
56
|
+
[]
|
57
|
+
elsif value.is_a?(Array)
|
58
|
+
value
|
59
|
+
else
|
60
|
+
[value]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Rounds the float with the specified precision.
|
65
|
+
#
|
66
|
+
# x = 1.337
|
67
|
+
# x.round # => 1
|
68
|
+
# x.round(1) # => 1.3
|
69
|
+
# x.round(2) # => 1.34
|
70
|
+
def round(float, precision = nil)
|
71
|
+
if precision
|
72
|
+
magnitude = 10.0 ** precision
|
73
|
+
(float * magnitude).round / magnitude
|
74
|
+
else
|
75
|
+
float.round
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Allows for reverse merging two hashes where the keys in the calling hash take precedence over those
|
80
|
+
# in the <tt>other_hash</tt>. This is particularly useful for initializing an option hash with default values:
|
81
|
+
#
|
82
|
+
# def setup(options = {})
|
83
|
+
# options.reverse_merge! :size => 25, :velocity => 10
|
84
|
+
# end
|
85
|
+
#
|
86
|
+
# Using <tt>merge</tt>, the above example would look as follows:
|
87
|
+
#
|
88
|
+
# def setup(options = {})
|
89
|
+
# { :size => 25, :velocity => 10 }.merge(options)
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# The default <tt>:size</tt> and <tt>:velocity</tt> are only set if the +options+ hash passed in doesn't already
|
93
|
+
# have the respective key.
|
94
|
+
def reverse_merge(hash, other_hash)
|
95
|
+
other_hash.merge(hash)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Performs the opposite of <tt>merge</tt>, with the keys and values from the first hash taking precedence over the second.
|
99
|
+
# Modifies the receiver in place.
|
100
|
+
def reverse_merge!(hash, other_hash)
|
101
|
+
hash.merge!( other_hash ){|k,o,n| o }
|
102
|
+
end
|
103
|
+
|
104
|
+
# An object is blank if it's false, empty, or a whitespace string.
|
105
|
+
# For example, "", " ", +nil+, [], and {} are blank.
|
106
|
+
#
|
107
|
+
# This simplifies:
|
108
|
+
#
|
109
|
+
# if !address.nil? && !address.empty?
|
110
|
+
#
|
111
|
+
# ...to:
|
112
|
+
#
|
113
|
+
# if !address.blank?
|
114
|
+
def blank?(object)
|
115
|
+
case object
|
116
|
+
when NilClass, FalseClass
|
117
|
+
true
|
118
|
+
when TrueClass, Numeric
|
119
|
+
false
|
120
|
+
when String
|
121
|
+
object !~ /\S/
|
122
|
+
when Hash, Array
|
123
|
+
object.empty?
|
124
|
+
when Object
|
125
|
+
object.respond_to?(:empty?) ? object.empty? : !object
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# An object is present if it's not blank.
|
130
|
+
def present?(object)
|
131
|
+
!blank?(object)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Sets $VERBOSE for the duration of the block and back to its original value afterwards.
|
135
|
+
def with_warnings(flag)
|
136
|
+
old_verbose, $VERBOSE = $VERBOSE, flag
|
137
|
+
yield
|
138
|
+
ensure
|
139
|
+
$VERBOSE = old_verbose
|
140
|
+
end
|
141
|
+
|
142
|
+
def titleize(string)
|
143
|
+
string.gsub!(/_/, ' ')
|
144
|
+
string.split(/(\W)/).map(&:capitalize).join
|
145
|
+
end
|
146
|
+
|
147
|
+
def truthy?(value)
|
148
|
+
['1', 1, 't', 'true', true].include?(value)
|
149
|
+
end
|
150
|
+
|
151
|
+
def falsy?(value)
|
152
|
+
['0', 0, 'f', 'false', false].include?(value)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Append a slash to `path` if it does not already end in a slash.
|
156
|
+
# Returns a string. Expects a string or Pathname object.
|
157
|
+
def append_slash(path)
|
158
|
+
strpath = path.to_s
|
159
|
+
if strpath[-1] != nil && strpath[-1].chr != '/'
|
160
|
+
strpath + '/'
|
161
|
+
else
|
162
|
+
strpath
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Replace the last 3 characters of string with ... if the string is as big
|
167
|
+
# or bigger than max.
|
168
|
+
def ellipsis(string, max)
|
169
|
+
if string.size > max
|
170
|
+
(string[0, max - 3] || '') + '...'
|
171
|
+
else
|
172
|
+
string
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Return the bytesize length of the string. Ruby 1.8.6 compatible.
|
177
|
+
def bytesize(string)
|
178
|
+
string.respond_to?(:bytesize) ? string.bytesize : string.length
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'sitemap_generator/sitemap_namer'
|
2
|
+
require 'sitemap_generator/builder'
|
3
|
+
require 'sitemap_generator/link_set'
|
4
|
+
require 'sitemap_generator/templates'
|
5
|
+
require 'sitemap_generator/utilities'
|
6
|
+
require 'sitemap_generator/application'
|
7
|
+
require 'sitemap_generator/adapters'
|
8
|
+
require 'sitemap_generator/sitemap_location'
|
9
|
+
|
10
|
+
module SitemapGenerator
|
11
|
+
autoload(:Interpreter, 'sitemap_generator/interpreter')
|
12
|
+
autoload(:FileAdapter, 'sitemap_generator/adapters/file_adapter')
|
13
|
+
autoload(:S3Adapter, 'sitemap_generator/adapters/s3_adapter')
|
14
|
+
autoload(:WaveAdapter, 'sitemap_generator/adapters/wave_adapter')
|
15
|
+
autoload(:FogAdapter, 'sitemap_generator/adapters/fog_adapter')
|
16
|
+
autoload(:BigDecimal, 'sitemap_generator/core_ext/big_decimal')
|
17
|
+
autoload(:Numeric, 'sitemap_generator/core_ext/numeric')
|
18
|
+
|
19
|
+
SitemapError = Class.new(StandardError)
|
20
|
+
SitemapFullError = Class.new(SitemapError)
|
21
|
+
SitemapFinalizedError = Class.new(SitemapError)
|
22
|
+
|
23
|
+
Utilities.with_warnings(nil) do
|
24
|
+
VERSION = File.read(File.dirname(__FILE__) + "/../VERSION").strip
|
25
|
+
MAX_SITEMAP_FILES = 50_000 # max sitemap links per index file
|
26
|
+
MAX_SITEMAP_LINKS = 50_000 # max links per sitemap
|
27
|
+
MAX_SITEMAP_IMAGES = 1_000 # max images per url
|
28
|
+
MAX_SITEMAP_NEWS = 1_000 # max news sitemap per index_file
|
29
|
+
MAX_SITEMAP_FILESIZE = 10_000_000 # bytes
|
30
|
+
SCHEMAS = {
|
31
|
+
'geo' => 'http://www.google.com/geo/schemas/sitemap/1.0',
|
32
|
+
'image' => 'http://www.google.com/schemas/sitemap-image/1.1',
|
33
|
+
'mobile' => 'http://www.google.com/schemas/sitemap-mobile/1.0',
|
34
|
+
'news' => 'http://www.google.com/schemas/sitemap-news/0.9',
|
35
|
+
'pagemap' => 'http://www.google.com/schemas/sitemap-pagemap/1.0',
|
36
|
+
'video' => 'http://www.google.com/schemas/sitemap-video/1.1'
|
37
|
+
}
|
38
|
+
|
39
|
+
# Lazy-initialize the LinkSet instance
|
40
|
+
Sitemap = (Class.new do
|
41
|
+
def method_missing(*args, &block)
|
42
|
+
(@link_set ||= reset!).send(*args, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Use a new LinkSet instance
|
46
|
+
def reset!
|
47
|
+
@link_set = LinkSet.new
|
48
|
+
end
|
49
|
+
end).new
|
50
|
+
end
|
51
|
+
|
52
|
+
class << self
|
53
|
+
attr_accessor :root, :app, :templates
|
54
|
+
attr_writer :yield_sitemap, :verbose
|
55
|
+
end
|
56
|
+
|
57
|
+
# Global default for the verbose setting.
|
58
|
+
def self.verbose
|
59
|
+
if @verbose.nil?
|
60
|
+
@verbose = if SitemapGenerator::Utilities.truthy?(ENV['VERBOSE'])
|
61
|
+
true
|
62
|
+
elsif SitemapGenerator::Utilities.falsy?(ENV['VERBOSE'])
|
63
|
+
false
|
64
|
+
else
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
else
|
68
|
+
@verbose
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns true if we should yield the sitemap instance to the block, false otherwise.
|
73
|
+
def self.yield_sitemap?
|
74
|
+
!!@yield_sitemap
|
75
|
+
end
|
76
|
+
|
77
|
+
self.root = File.expand_path(File.join(File.dirname(__FILE__), '../')) # Root of the install dir, not the Rails app
|
78
|
+
self.templates = SitemapGenerator::Templates.new(self.root)
|
79
|
+
self.app = SitemapGenerator::Application.new
|
80
|
+
end
|
81
|
+
|
82
|
+
require 'sitemap_generator/railtie' if SitemapGenerator.app.rails3?
|
@@ -0,0 +1 @@
|
|
1
|
+
load(File.expand_path(File.join(File.dirname(__FILE__), '../sitemap_generator/tasks.rb')))
|
data/rails/install.rb
ADDED
data/rails/uninstall.rb
ADDED
data/spec/blueprint.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
SitemapGenerator::Sitemap.default_host = "http://www.example.com"
|
2
|
+
|
3
|
+
SitemapGenerator::Sitemap.create do
|
4
|
+
add '/contents', :priority => 0.7, :changefreq => 'daily'
|
5
|
+
|
6
|
+
# add all individual articles
|
7
|
+
(1..10).each do |i|
|
8
|
+
add "/content/#{i}"
|
9
|
+
end
|
10
|
+
|
11
|
+
add "/merchant_path", :host => "https://www.example.com"
|
12
|
+
end
|