dynamic_sitemaps 2.0.0.beta → 2.0.0.beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/.travis.yml +8 -0
- data/README.md +230 -55
- data/TODO.md +7 -0
- data/dynamic_sitemaps.gemspec +3 -0
- data/lib/dynamic_sitemaps.rb +44 -19
- data/lib/dynamic_sitemaps/generator.rb +94 -40
- data/lib/dynamic_sitemaps/index_generator.rb +2 -2
- data/lib/dynamic_sitemaps/logger.rb +22 -0
- data/lib/dynamic_sitemaps/pinger.rb +12 -7
- data/lib/dynamic_sitemaps/sitemap.rb +1 -9
- data/lib/dynamic_sitemaps/sitemap_generator.rb +7 -2
- data/lib/dynamic_sitemaps/tasks/sitemap.rake +2 -6
- data/lib/dynamic_sitemaps/version.rb +1 -1
- data/lib/generators/dynamic_sitemaps/templates/config.rb +3 -0
- data/test/dummy/app/models/product.rb +5 -1
- data/test/dummy/config/routes.rb +5 -56
- data/test/dummy/config/sitemap.rb +5 -0
- data/test/dummy/db/migrate/20130211190343_create_products.rb +1 -3
- data/test/dummy/db/schema.rb +3 -5
- data/test/dynamic_sitemaps_test.rb +49 -2
- data/test/generator_test.rb +404 -0
- data/test/pinger_test.rb +73 -0
- data/test/test_helper.rb +1 -0
- metadata +53 -12
- data/test/dummy/app/models/.gitkeep +0 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +0 -902
- data/test/dummy/log/test.log +0 -10
@@ -1,58 +1,112 @@
|
|
1
1
|
module DynamicSitemaps
|
2
2
|
class Generator
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
# Generates the sitemap(s) and index based on the configuration file specified in DynamicSitemaps.config_path.
|
4
|
+
# If you supply a block, that block is evaluated instead of the configuration file.
|
5
|
+
def generate(&block)
|
6
|
+
create_temp_dir
|
7
|
+
if block
|
8
|
+
instance_eval &block
|
9
|
+
else
|
10
|
+
instance_eval open(DynamicSitemaps.config_path).read, DynamicSitemaps.config_path
|
7
11
|
end
|
12
|
+
generate_index
|
13
|
+
move_to_destination
|
14
|
+
ping_search_engines
|
15
|
+
ensure
|
16
|
+
remove_temp_dir
|
17
|
+
end
|
8
18
|
|
9
|
-
|
10
|
-
|
11
|
-
|
19
|
+
def generate_index
|
20
|
+
IndexGenerator.new(sitemaps).generate
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_temp_dir
|
24
|
+
remove_temp_dir
|
25
|
+
FileUtils.mkdir_p DynamicSitemaps.temp_path
|
26
|
+
end
|
27
|
+
|
28
|
+
def remove_temp_dir
|
29
|
+
FileUtils.rm_rf DynamicSitemaps.temp_path
|
30
|
+
end
|
12
31
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
32
|
+
def move_to_destination
|
33
|
+
sitemaps.map(&:folder).uniq.each do |folder|
|
34
|
+
destination = "#{DynamicSitemaps.path}/#{folder}"
|
35
|
+
FileUtils.mkdir_p destination
|
36
|
+
FileUtils.rm_rf Dir.glob("#{destination}/*")
|
37
|
+
FileUtils.mv Dir["#{DynamicSitemaps.temp_path}/#{folder}/*"], destination
|
19
38
|
end
|
39
|
+
remove_temp_dir
|
40
|
+
end
|
20
41
|
|
21
|
-
|
22
|
-
|
42
|
+
def ping_search_engines
|
43
|
+
Pinger.ping_search_engines_with ping_urls
|
44
|
+
end
|
23
45
|
|
24
|
-
|
25
|
-
|
46
|
+
def sitemap(*args, &block)
|
47
|
+
args << {} unless args.last.is_a?(Hash)
|
48
|
+
args.last[:host] ||= host
|
49
|
+
args.last[:folder] ||= folder
|
50
|
+
sitemap = Sitemap.new(*args, &block)
|
26
51
|
|
27
|
-
|
28
|
-
|
52
|
+
ensure_valid_sitemap_name! sitemap
|
53
|
+
sitemap_names[sitemap.folder] << sitemap.name
|
29
54
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
55
|
+
sitemaps << SitemapGenerator.new(sitemap).generate
|
56
|
+
end
|
57
|
+
|
58
|
+
def sitemap_for(collection, options = {}, &block)
|
59
|
+
raise ArgumentError, "The collection given to `sitemap_for` must respond to #find_each. This is for performance. Use `Model.scoped` to get an ActiveRecord relation that responds to #find_each." unless collection.respond_to?(:find_each)
|
34
60
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
61
|
+
name = options.delete(:name) || collection.model_name.underscore.pluralize.to_sym
|
62
|
+
options[:collection] = collection
|
63
|
+
|
64
|
+
sitemap(name, options, &block)
|
65
|
+
end
|
66
|
+
|
67
|
+
def ensure_valid_sitemap_name!(sitemap)
|
68
|
+
raise ArgumentError, "Sitemap name :#{sitemap.name} has already been defined for the folder \"#{sitemap.folder}\". Please use `sitemap :other_name do ... end` or `sitemap_for <relation>, name: :other_name`." if sitemap_names[sitemap.folder].include?(sitemap.name)
|
69
|
+
raise ArgumentError, "Sitemap name :#{sitemap.name} conflicts with the index file name #{DynamicSitemaps.index_file_name}. Please change it using `sitemap :other_name do ... end`." if "#{sitemap.name}.xml" == DynamicSitemaps.index_file_name
|
70
|
+
end
|
71
|
+
|
72
|
+
# Array of SitemapResult
|
73
|
+
def sitemaps
|
74
|
+
@sitemaps ||= []
|
75
|
+
end
|
76
|
+
|
77
|
+
# Generated sitemap names
|
78
|
+
def sitemap_names
|
79
|
+
@sitemap_names ||= Hash.new { |h, k| h[k] = [] }
|
80
|
+
end
|
81
|
+
|
82
|
+
# URLs to ping after generation
|
83
|
+
def ping_urls
|
84
|
+
@ping_urls ||= []
|
85
|
+
end
|
86
|
+
|
87
|
+
def host(*args)
|
88
|
+
if args.any?
|
89
|
+
@host = args.first
|
90
|
+
Rails.application.routes.default_url_options[:host] = @host
|
91
|
+
else
|
92
|
+
@host
|
42
93
|
end
|
94
|
+
end
|
43
95
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
96
|
+
# Adds a sitemap URL to ping search engines with after generation.
|
97
|
+
def ping_with(sitemap_url)
|
98
|
+
ping_urls << sitemap_url
|
99
|
+
end
|
48
100
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
101
|
+
def folder(*args)
|
102
|
+
if args.any?
|
103
|
+
@folder = args.first
|
104
|
+
raise ArgumentError, "Folder can't be blank." if @folder.blank?
|
105
|
+
else
|
106
|
+
# Ensure that the default folder is set and cleaned.
|
107
|
+
folder DynamicSitemaps.folder if @folder.blank?
|
53
108
|
|
54
|
-
|
55
|
-
end
|
109
|
+
@folder
|
56
110
|
end
|
57
111
|
end
|
58
112
|
end
|
@@ -9,10 +9,10 @@ module DynamicSitemaps
|
|
9
9
|
|
10
10
|
def generate
|
11
11
|
sitemaps.group_by(&:folder).each do |folder, sitemaps|
|
12
|
-
index_path = "#{DynamicSitemaps.
|
12
|
+
index_path = "#{DynamicSitemaps.temp_path}/#{folder}/#{DynamicSitemaps.index_file_name}"
|
13
13
|
|
14
14
|
if !DynamicSitemaps.always_generate_index && sitemaps.count == 1 && sitemaps.first.files.count == 1
|
15
|
-
file_path = "#{DynamicSitemaps.
|
15
|
+
file_path = "#{DynamicSitemaps.temp_path}/#{folder}/#{sitemaps.first.files.first}"
|
16
16
|
FileUtils.copy file_path, index_path
|
17
17
|
File.delete file_path
|
18
18
|
else
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module DynamicSitemaps
|
2
|
+
class Logger
|
3
|
+
class << self
|
4
|
+
def info(message)
|
5
|
+
show message
|
6
|
+
Rails.logger.info message
|
7
|
+
end
|
8
|
+
|
9
|
+
def warn(message)
|
10
|
+
show message
|
11
|
+
Rails.logger.warn message
|
12
|
+
end
|
13
|
+
|
14
|
+
# Shows the message using puts unless testing.
|
15
|
+
def show(message)
|
16
|
+
unless Rails.env.test?
|
17
|
+
puts message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,16 +1,17 @@
|
|
1
1
|
module DynamicSitemaps
|
2
2
|
class Pinger
|
3
3
|
class << self
|
4
|
-
def
|
5
|
-
sitemap_urls =
|
6
|
-
|
7
|
-
|
4
|
+
def ping_search_engines_with(sitemap_urls)
|
5
|
+
sitemap_urls = [sitemap_urls] unless sitemap_urls.is_a?(Array)
|
6
|
+
|
7
|
+
if sitemap_urls.any? && ping_for_environment?(Rails.env)
|
8
|
+
Logger.info "Pinging search engines..."
|
8
9
|
|
9
10
|
sitemap_urls.each do |url|
|
10
11
|
ping_search_engines_with_sitemap_url url
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
+
Logger.info "Done pinging search engines."
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
@@ -23,13 +24,17 @@ module DynamicSitemaps
|
|
23
24
|
end
|
24
25
|
|
25
26
|
def ping(url)
|
26
|
-
|
27
|
+
Logger.info "Pinging #{url} ..."
|
27
28
|
begin
|
28
29
|
Net::HTTP.get(URI.parse(url))
|
29
30
|
rescue Exception => e
|
30
|
-
|
31
|
+
Logger.warn "Failed to ping #{url} : #{e}"
|
31
32
|
end
|
32
33
|
end
|
34
|
+
|
35
|
+
def ping_for_environment?(env)
|
36
|
+
DynamicSitemaps.ping_environments.map(&:to_s).include?(env.to_s)
|
37
|
+
end
|
33
38
|
end
|
34
39
|
end
|
35
40
|
end
|
@@ -7,14 +7,6 @@ module DynamicSitemaps
|
|
7
7
|
# Sitemap.new(:site) do
|
8
8
|
# url root_url
|
9
9
|
# end
|
10
|
-
#
|
11
|
-
# Using an ActiveRecord relation:
|
12
|
-
#
|
13
|
-
# Sitemap.new(:site, Product.visible) do |product|
|
14
|
-
# url product
|
15
|
-
# url product_editions_path(product)
|
16
|
-
# end
|
17
|
-
|
18
10
|
def initialize(*args, &block)
|
19
11
|
if args.first.is_a?(Symbol)
|
20
12
|
@name = args.shift
|
@@ -36,7 +28,7 @@ module DynamicSitemaps
|
|
36
28
|
end
|
37
29
|
|
38
30
|
def per_page
|
39
|
-
@per_page ||= DynamicSitemaps
|
31
|
+
@per_page ||= DynamicSitemaps.per_page
|
40
32
|
end
|
41
33
|
|
42
34
|
# Generates sitemap XML files based on this sitemap
|
@@ -11,6 +11,7 @@ module DynamicSitemaps
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def generate
|
14
|
+
ensure_host!
|
14
15
|
write_beginning
|
15
16
|
write_urls
|
16
17
|
write_end
|
@@ -95,7 +96,7 @@ module DynamicSitemaps
|
|
95
96
|
end
|
96
97
|
|
97
98
|
def folder_path
|
98
|
-
"#{DynamicSitemaps.
|
99
|
+
"#{DynamicSitemaps.temp_path}/#{folder}"
|
99
100
|
end
|
100
101
|
|
101
102
|
def path
|
@@ -106,6 +107,10 @@ module DynamicSitemaps
|
|
106
107
|
sitemap.host
|
107
108
|
end
|
108
109
|
|
110
|
+
def ensure_host!
|
111
|
+
raise "No host specified. Please specify a host using `host \"www.mydomain.com\"` at the top of your sitemap configuration file." if sitemap.host.blank?
|
112
|
+
end
|
113
|
+
|
109
114
|
def file
|
110
115
|
@file ||= begin
|
111
116
|
files << file_name
|
@@ -146,7 +151,7 @@ module DynamicSitemaps
|
|
146
151
|
if date.is_a?(Date)
|
147
152
|
date.strftime("%Y-%m-%d")
|
148
153
|
else
|
149
|
-
date.to_datetime.strftime("%Y-%m-%dT%H:%M:%S%:z")
|
154
|
+
date.to_datetime.utc.strftime("%Y-%m-%dT%H:%M:%S%:z")
|
150
155
|
end
|
151
156
|
end
|
152
157
|
end
|
@@ -1,12 +1,8 @@
|
|
1
1
|
namespace :sitemap do
|
2
2
|
task :generate => :environment do
|
3
3
|
start_time = Time.now
|
4
|
-
|
4
|
+
DynamicSitemaps::Logger.info "Generating sitemap..."
|
5
5
|
DynamicSitemaps.generate_sitemap
|
6
|
-
|
7
|
-
|
8
|
-
if Rails.env.production?
|
9
|
-
DynamicSitemaps::Pinger.ping_search_engines
|
10
|
-
end
|
6
|
+
DynamicSitemaps::Logger.info "Done generating sitemap in #{Time.now - start_time} seconds."
|
11
7
|
end
|
12
8
|
end
|
data/test/dummy/config/routes.rb
CHANGED
@@ -1,58 +1,7 @@
|
|
1
1
|
Dummy::Application.routes.draw do
|
2
|
-
|
3
|
-
# first created -> highest priority.
|
2
|
+
root to: "home#index"
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
# Sample of named route:
|
10
|
-
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
|
11
|
-
# This route can be invoked with purchase_url(:id => product.id)
|
12
|
-
|
13
|
-
# Sample resource route (maps HTTP verbs to controller actions automatically):
|
14
|
-
# resources :products
|
15
|
-
|
16
|
-
# Sample resource route with options:
|
17
|
-
# resources :products do
|
18
|
-
# member do
|
19
|
-
# get 'short'
|
20
|
-
# post 'toggle'
|
21
|
-
# end
|
22
|
-
#
|
23
|
-
# collection do
|
24
|
-
# get 'sold'
|
25
|
-
# end
|
26
|
-
# end
|
27
|
-
|
28
|
-
# Sample resource route with sub-resources:
|
29
|
-
# resources :products do
|
30
|
-
# resources :comments, :sales
|
31
|
-
# resource :seller
|
32
|
-
# end
|
33
|
-
|
34
|
-
# Sample resource route with more complex sub-resources
|
35
|
-
# resources :products do
|
36
|
-
# resources :comments
|
37
|
-
# resources :sales do
|
38
|
-
# get 'recent', :on => :collection
|
39
|
-
# end
|
40
|
-
# end
|
41
|
-
|
42
|
-
# Sample resource route within a namespace:
|
43
|
-
# namespace :admin do
|
44
|
-
# # Directs /admin/products/* to Admin::ProductsController
|
45
|
-
# # (app/controllers/admin/products_controller.rb)
|
46
|
-
# resources :products
|
47
|
-
# end
|
48
|
-
|
49
|
-
# You can have the root of your site routed with "root"
|
50
|
-
# just remember to delete public/index.html.
|
51
|
-
# root :to => 'welcome#index'
|
52
|
-
|
53
|
-
# See how all your routes lay out with "rake routes"
|
54
|
-
|
55
|
-
# This is a legacy wild controller route that's not recommended for RESTful applications.
|
56
|
-
# Note: This route will make all actions in every controller accessible via GET requests.
|
57
|
-
# match ':controller(/:action(/:id))(.:format)'
|
58
|
-
end
|
4
|
+
resources :products do
|
5
|
+
resources :comments
|
6
|
+
end
|
7
|
+
end
|
data/test/dummy/db/schema.rb
CHANGED
@@ -14,12 +14,10 @@
|
|
14
14
|
ActiveRecord::Schema.define(:version => 20130211190343) do
|
15
15
|
|
16
16
|
create_table "products", :force => true do |t|
|
17
|
-
t.
|
17
|
+
t.boolean "featured", :default => false
|
18
18
|
t.string "slug"
|
19
|
-
t.datetime "created_at",
|
20
|
-
t.datetime "updated_at",
|
19
|
+
t.datetime "created_at", :null => false
|
20
|
+
t.datetime "updated_at", :null => false
|
21
21
|
end
|
22
22
|
|
23
|
-
add_index "products", ["slug"], :name => "index_products_on_slug"
|
24
|
-
|
25
23
|
end
|
@@ -1,7 +1,54 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class DynamicSitemapsTest < ActiveSupport::TestCase
|
4
|
-
|
5
|
-
|
4
|
+
setup do
|
5
|
+
DynamicSitemaps.reset!
|
6
|
+
end
|
7
|
+
|
8
|
+
test "defaults" do
|
9
|
+
assert_equal Rails.root.join("public").to_s, DynamicSitemaps.path
|
10
|
+
assert_equal "sitemaps", DynamicSitemaps.folder
|
11
|
+
assert_equal "sitemap.xml", DynamicSitemaps.index_file_name
|
12
|
+
assert !DynamicSitemaps.always_generate_index
|
13
|
+
assert_equal Rails.root.join("config", "sitemap.rb").to_s, DynamicSitemaps.config_path
|
14
|
+
assert_equal 50000, DynamicSitemaps.per_page
|
15
|
+
assert_equal ["production"], DynamicSitemaps.ping_environments
|
16
|
+
assert_equal Rails.root.join("tmp", "dynamic_sitemaps").to_s, DynamicSitemaps.temp_path
|
17
|
+
end
|
18
|
+
|
19
|
+
test "configuration block" do
|
20
|
+
DynamicSitemaps.configure do |config|
|
21
|
+
config.folder = "mycustomfolder"
|
22
|
+
config.per_page = 1234
|
23
|
+
end
|
24
|
+
|
25
|
+
assert_equal "mycustomfolder", DynamicSitemaps.folder
|
26
|
+
assert_equal 1234, DynamicSitemaps.per_page
|
27
|
+
end
|
28
|
+
|
29
|
+
test "raises error on blank paths" do
|
30
|
+
assert_nothing_raised do
|
31
|
+
DynamicSitemaps.path = "/my/test/folder"
|
32
|
+
DynamicSitemaps.folder = "my_sitemaps"
|
33
|
+
DynamicSitemaps.config_path = "/my/config.rb"
|
34
|
+
end
|
35
|
+
|
36
|
+
assert_raises ArgumentError do
|
37
|
+
DynamicSitemaps.path = ""
|
38
|
+
end
|
39
|
+
|
40
|
+
assert_raises ArgumentError do
|
41
|
+
DynamicSitemaps.folder = ""
|
42
|
+
end
|
43
|
+
|
44
|
+
assert_raises ArgumentError do
|
45
|
+
DynamicSitemaps.config_path = ""
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
test "raises error when using old sitemap ping urls" do
|
50
|
+
assert_raises RuntimeError do
|
51
|
+
DynamicSitemaps.sitemap_ping_urls = ["http://test.com/sitemap.xml"]
|
52
|
+
end
|
6
53
|
end
|
7
54
|
end
|