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,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
|