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.
@@ -1,58 +1,112 @@
1
1
  module DynamicSitemaps
2
2
  class Generator
3
- class << self
4
- def generate
5
- instance_eval open(DynamicSitemaps.config_path).read
6
- generate_index
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
- def generate_index
10
- IndexGenerator.new(sitemaps).generate
11
- end
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
- def sitemap(*args, &block)
14
- args << {} unless args.last.is_a?(Hash)
15
- args.last[:host] ||= host
16
- args.last[:folder] ||= folder
17
- sitemap = Sitemap.new(*args, &block)
18
- sitemaps << SitemapGenerator.new(sitemap).generate
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
- def sitemap_for(collection, options = {}, &block)
22
- raise "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)
42
+ def ping_search_engines
43
+ Pinger.ping_search_engines_with ping_urls
44
+ end
23
45
 
24
- name = options.delete(:name) || collection.model_name.underscore.pluralize.to_sym
25
- options[:collection] = collection
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
- sitemap(name, options, &block)
28
- end
52
+ ensure_valid_sitemap_name! sitemap
53
+ sitemap_names[sitemap.folder] << sitemap.name
29
54
 
30
- # Array of SitemapResult
31
- def sitemaps
32
- @sitemaps ||= []
33
- end
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
- def host(*args)
36
- if args.any?
37
- @host = args.first
38
- Rails.application.routes.default_url_options[:host] = @host
39
- else
40
- @host
41
- end
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
- def folder(*args)
45
- if args.any?
46
- @folder = args.first
47
- raise ArgumentError, "Folder can't be blank." if @folder.blank?
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
- FileUtils.rm_rf Dir.glob("#{DynamicSitemaps.path}/#{folder}/*")
50
- else
51
- # Ensure that the default folder is set and cleaned.
52
- folder DynamicSitemaps.folder if @folder.blank?
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
- @folder
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.path}/#{folder}/#{DynamicSitemaps.index_file_name}"
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.path}/#{folder}/#{sitemaps.first.files.first}"
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 ping_search_engines
5
- sitemap_urls = DynamicSitemaps.sitemap_ping_urls
6
- if sitemap_urls.any?
7
- puts "Pinging search engines..."
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
- puts "Done pinging search engines."
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
- puts "Pinging #{url} ..."
27
+ Logger.info "Pinging #{url} ..."
27
28
  begin
28
29
  Net::HTTP.get(URI.parse(url))
29
30
  rescue Exception => e
30
- puts "Failed to ping #{url} : #{e}"
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::DEFAULT_PER_PAGE
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.path}/#{folder}"
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
- puts "Generating sitemap..."
4
+ DynamicSitemaps::Logger.info "Generating sitemap..."
5
5
  DynamicSitemaps.generate_sitemap
6
- puts "Done generating sitemap in #{Time.now - start_time} seconds."
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
@@ -1,3 +1,3 @@
1
1
  module DynamicSitemaps
2
- VERSION = "2.0.0.beta"
2
+ VERSION = "2.0.0.beta2"
3
3
  end
@@ -3,5 +3,8 @@ host "www.example.com"
3
3
  sitemap :site do
4
4
  url root_url, last_mod: Time.now, change_freq: "daily", priority: 1.0
5
5
 
6
+ # Ping search engines after sitemap generation
7
+ # ping_with "http://#{host}/sitemap.xml"
8
+
6
9
  # TODO: Add examples
7
10
  end
@@ -1,3 +1,7 @@
1
1
  class Product < ActiveRecord::Base
2
- attr_accessible :name, :slug
2
+ attr_accessible :slug, :featured
3
+
4
+ def to_param
5
+ slug || id.to_s
6
+ end
3
7
  end
@@ -1,58 +1,7 @@
1
1
  Dummy::Application.routes.draw do
2
- # The priority is based upon order of creation:
3
- # first created -> highest priority.
2
+ root to: "home#index"
4
3
 
5
- # Sample of regular route:
6
- # match 'products/:id' => 'catalog#view'
7
- # Keep in mind you can assign values other than :controller and :action
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
@@ -0,0 +1,5 @@
1
+ host "www.mytest.com"
2
+
3
+ sitemap :site do
4
+ url root_url, last_mod: Time.now, change_freq: "daily", priority: 1.0
5
+ end
@@ -1,12 +1,10 @@
1
1
  class CreateProducts < ActiveRecord::Migration
2
2
  def change
3
3
  create_table :products do |t|
4
- t.string :name
4
+ t.boolean :featured, default: false
5
5
  t.string :slug
6
6
 
7
7
  t.timestamps
8
8
  end
9
-
10
- add_index :products, :slug
11
9
  end
12
10
  end
@@ -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.string "name"
17
+ t.boolean "featured", :default => false
18
18
  t.string "slug"
19
- t.datetime "created_at", :null => false
20
- t.datetime "updated_at", :null => false
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
- test "truth" do
5
- assert_kind_of Module, DynamicSitemaps
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