sitemap_generator 1.5.2 → 2.0.0

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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.5.2
1
+ 2.0.0
@@ -1,5 +1,5 @@
1
- require 'sitemap_generator/builder'
2
1
  require 'sitemap_generator/sitemap_namer'
2
+ require 'sitemap_generator/builder'
3
3
  require 'sitemap_generator/link_set'
4
4
  require 'sitemap_generator/templates'
5
5
  require 'sitemap_generator/utilities'
@@ -8,6 +8,8 @@ require 'sitemap_generator/sitemap_location'
8
8
  require 'active_support/core_ext/numeric'
9
9
 
10
10
  module SitemapGenerator
11
+ autoload(:Interpreter, 'sitemap_generator/interpreter')
12
+
11
13
  SitemapError = Class.new(StandardError)
12
14
  SitemapFullError = Class.new(SitemapError)
13
15
  SitemapFinalizedError = Class.new(SitemapError)
@@ -22,13 +24,24 @@ module SitemapGenerator
22
24
  # Lazy-initialize the LinkSet instance
23
25
  Sitemap = (Class.new do
24
26
  def method_missing(*args, &block)
25
- (@link_set ||= LinkSet.new).send(*args, &block)
27
+ (@link_set ||= reset!).send(*args, &block)
28
+ end
29
+
30
+ # Use a new LinkSet instance
31
+ def reset!
32
+ @link_set = LinkSet.new
26
33
  end
27
34
  end).new
28
35
  end
29
36
 
30
37
  class << self
31
38
  attr_accessor :root, :app, :templates
39
+ attr_writer :yield_sitemap
40
+ end
41
+
42
+ # Returns true if we should yield the sitemap instance to the block, false otherwise.
43
+ def self.yield_sitemap?
44
+ !!@yeild_sitemap
32
45
  end
33
46
 
34
47
  self.root = File.expand_path(File.join(File.dirname(__FILE__), '../'))
@@ -14,21 +14,14 @@ module SitemapGenerator
14
14
  class SitemapFile
15
15
  include ActionView::Helpers::NumberHelper
16
16
  include ActionView::Helpers::TextHelper # Rails 2.2.2 fails with missing 'pluralize' otherwise
17
- attr_reader :link_count, :filesize, :filename, :location
17
+ attr_reader :link_count, :filesize, :location
18
18
 
19
- # Options:
19
+ # === Options
20
20
  #
21
- # <tt>location</tt> a SitemapGenerator::SitemapLocation instance
22
- #
23
- # <tt>filename</tt> a symbol giving the base of the sitemap fileaname. Default: :sitemap
24
- #
25
- # <tt>namer</tt> (optional) if provided is used to get the next sitemap filename, overriding :filename
21
+ # * <tt>location</tt> - a SitemapGenerator::SitemapLocation instance or a Hash of options
22
+ # from which a SitemapLocation will be created for you.
26
23
  def initialize(opts={})
27
- SitemapGenerator::Utilities.assert_valid_keys(opts, [:location, :filename, :namer])
28
-
29
- @location = opts.delete(:location) || SitemapGenerator::SitemapLocation.new
30
- @namer = opts.delete(:namer) || new_namer(opts.delete(:filename))
31
- @filename = @location[:filename] = @namer.next
24
+ @location = opts.is_a?(Hash) ? SitemapGenerator::SitemapLocation.new(opts) : opts
32
25
  @link_count = 0
33
26
  @xml_content = '' # XML urlset content
34
27
  @xml_wrapper_start = <<-HTML
@@ -102,20 +95,25 @@ module SitemapGenerator
102
95
 
103
96
  # Ensure that the directory exists
104
97
  dir = @location.directory
105
- path = @location.path
106
98
  if !File.exists?(dir)
107
99
  FileUtils.mkdir_p(dir)
108
100
  elsif !File.directory?(dir)
109
101
  raise SitemapError.new("#{dir} should be a directory!")
110
102
  end
111
103
 
112
- open(path, 'wb') do |file|
104
+ # Write out the file
105
+ open(@location.path, 'wb') do |file|
113
106
  gz = Zlib::GzipWriter.new(file)
114
107
  gz.write @xml_wrapper_start
115
108
  gz.write @xml_content
116
109
  gz.write @xml_wrapper_end
117
110
  gz.close
118
111
  end
112
+
113
+ # Increment the namer (SitemapFile only)
114
+ @location.namer.next if @location.namer
115
+
116
+ # Cleanup and freeze the object
119
117
  @xml_content = @xml_wrapper_start = @xml_wrapper_end = ''
120
118
  freeze
121
119
  end
@@ -125,8 +123,10 @@ module SitemapGenerator
125
123
  end
126
124
 
127
125
  # Return a new instance of the sitemap file with the same options, and the next name in the sequence.
128
- def next
129
- self.class.new(:location => @location.dup, :namer => @namer)
126
+ def new
127
+ location = @location.dup
128
+ location.delete(:filename) if location.namer
129
+ self.class.new(location)
130
130
  end
131
131
 
132
132
  # Return a summary string
@@ -136,26 +136,12 @@ module SitemapGenerator
136
136
  "+ #{'%-21s' % @location.path_in_public} #{'%13s' % @link_count} links / #{'%10s' % uncompressed_size} / #{'%10s' % compressed_size} gzipped"
137
137
  end
138
138
 
139
- # Create a new namer given a filename base and set the filename of this sitemap from it.
140
- # It is a bit confusing because the setter takes a filename base whereas the getter
141
- # returns a full filename including extension.
142
- def filename=(base)
143
- @namer = new_namer(base)
144
- @filename = @location[:filename] = @namer.next
145
- end
146
-
147
139
  protected
148
140
 
149
- # Return a new namer given a filename base and set the filename of this sitemap from it.
150
- # Default filename base is 'sitemap'.
151
- def new_namer(base=nil)
152
- SitemapGenerator::SitemapNamer.new(base ||= :sitemap)
153
- end
154
-
155
141
  # Return the bytesize length of the string. Ruby 1.8.6 compatible.
156
142
  def bytesize(string)
157
143
  string.respond_to?(:bytesize) ? string.bytesize : string.length
158
144
  end
159
145
  end
160
146
  end
161
- end
147
+ end
@@ -1,16 +1,13 @@
1
1
  module SitemapGenerator
2
2
  module Builder
3
3
  class SitemapIndexFile < SitemapFile
4
- attr_accessor :sitemaps
5
4
 
5
+ # === Options
6
+ #
7
+ # * <tt>location</tt> - a SitemapGenerator::SitemapIndexLocation instance or a Hash of options
8
+ # from which a SitemapLocation will be created for you.
6
9
  def initialize(opts={})
7
- @options = [:location, :filename]
8
- SitemapGenerator::Utilities.assert_valid_keys(opts, @options)
9
-
10
- @location = opts.delete(:location) || SitemapGenerator::SitemapLocation.new
11
- @filename = "#{opts.fetch(:filename, :sitemap_index)}.xml.gz"
12
- @location[:filename] = @filename
13
-
10
+ @location = opts.is_a?(Hash) ? SitemapGenerator::SitemapIndexLocation.new(opts) : opts
14
11
  @link_count = 0
15
12
  @sitemaps_link_count = 0
16
13
  @xml_content = '' # XML urlset content
@@ -37,16 +34,19 @@ module SitemapGenerator
37
34
  super(SitemapGenerator::Builder::SitemapIndexUrl.new(link, options))
38
35
  end
39
36
 
37
+ # Return a boolean indicating whether the sitemap file can fit another link
38
+ # of <tt>bytes</tt> bytes in size. You can also pass a string and the
39
+ # bytesize will be calculated for you.
40
+ def file_can_fit?(bytes)
41
+ bytes = bytes.is_a?(String) ? bytesize(bytes) : bytes
42
+ (@filesize + bytes) < SitemapGenerator::MAX_SITEMAP_FILESIZE && @link_count < SitemapGenerator::MAX_SITEMAP_FILES
43
+ end
44
+
40
45
  # Return the total number of links in all sitemaps reference by this index file
41
46
  def total_link_count
42
47
  @sitemaps_link_count
43
48
  end
44
49
 
45
- # Set a new filename on the instance. Should not include any extensions e.g. :sitemap_index
46
- def filename=(filename)
47
- @filename = @location[:filename] = "#{filename}_index.xml.gz"
48
- end
49
-
50
50
  # Return a summary string
51
51
  def summary(opts={})
52
52
  uncompressed_size = number_to_human_size(@filesize) rescue "#{@filesize / 8} KB"
@@ -60,4 +60,4 @@ module SitemapGenerator
60
60
  end
61
61
  end
62
62
  end
63
- end
63
+ end
@@ -2,8 +2,8 @@ require 'sitemap_generator'
2
2
 
3
3
  module SitemapGenerator
4
4
 
5
- # Evaluate a sitemap config file within the context of a class that includes the
6
- # Rails URL helpers.
5
+ # Provide a class for evaluating blocks, making the URL helpers from the framework
6
+ # and API methods available to it.
7
7
  class Interpreter
8
8
 
9
9
  if SitemapGenerator.app.rails3?
@@ -16,26 +16,54 @@ module SitemapGenerator
16
16
  # Call with a block to evaluate a dynamic config. The only method exposed for you is
17
17
  # `add` to add a link to the sitemap object attached to this interpreter.
18
18
  #
19
- # @param sitemap a sitemap object
20
- # @param sitemap_config_file full path to the config file (default is config/sitemap.rb)
21
- def initialize(sitemap, sitemap_config_file=nil, &block)
22
- @sitemap = sitemap
23
- if block_given?
24
- instance_eval(&block)
25
- else
26
- sitemap_config_file ||= SitemapGenerator.app.root + 'config/sitemap.rb'
27
- eval(File.read(sitemap_config_file), nil, sitemap_config_file.to_s)
28
- end
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.reverse_merge!(:link_set => SitemapGenerator::Sitemap)
25
+ @linkset = opts.delete :link_set
26
+ @linkset.send(:set_options, opts)
27
+ eval(&block) if block_given?
29
28
  end
30
29
 
31
30
  def add(*args)
32
- @sitemap.add(*args)
31
+ @linkset.add(*args)
32
+ end
33
+
34
+ # Start a new group of sitemaps. Any of the options to SitemapGenerator.new may
35
+ # be passed. Pass a block with calls to +add+ to add links to the sitemaps.
36
+ #
37
+ # All groups use the same sitemap index.
38
+ def group(*args, &block)
39
+ @linkset.group(*args, &block)
33
40
  end
34
41
 
35
- # Evaluate the sitemap config file in this namespace which includes the
36
- # URL helpers.
37
- def self.run
38
- new(SitemapGenerator::Sitemap)
42
+ # Evaluate the block in the interpreter. Pass :yield_sitemap => true to
43
+ # yield the Interpreter instance to the block...for old-style calling.
44
+ def eval(opts={}, &block)
45
+ if block_given?
46
+ if opts[:yield_sitemap]
47
+ yield self
48
+ else
49
+ instance_eval(&block)
50
+ end
51
+ end
52
+ end
53
+
54
+ # Run the interpreter on a config file using
55
+ # the default <tt>SitemapGenerator::Sitemap</tt> sitemap object.
56
+ #
57
+ # === Options
58
+ # * <tt>:config_file</tt> - full path to the config file to evaluate.
59
+ # Default is config/sitemap.rb in your application's root directory.
60
+ # All other options are passed to +new+.
61
+ def self.run(opts={}, &block)
62
+ config_file = opts.delete(:config_file)
63
+ config_file ||= SitemapGenerator.app.root + 'config/sitemap.rb'
64
+ interpreter = self.new(opts)
65
+ interpreter.instance_eval(File.read(config_file), config_file.to_s)
66
+ interpreter
39
67
  end
40
68
  end
41
- end
69
+ end
@@ -4,100 +4,90 @@ require 'builder'
4
4
  # which lists all the sitemap files written.
5
5
  module SitemapGenerator
6
6
  class LinkSet
7
+ @@requires_finalization_opts = [:filename, :sitemaps_path, :sitemaps_namer, :sitemaps_host]
8
+ @@new_location_opts = [:filename, :sitemaps_path, :sitemaps_namer]
7
9
 
8
- attr_reader :default_host, :public_path, :sitemaps_path, :filename, :sitemap, :location
9
- attr_accessor :verbose, :yahoo_app_id, :include_root, :include_index
10
+ attr_reader :default_host, :sitemaps_path, :filename
11
+ attr_accessor :verbose, :yahoo_app_id, :include_root, :include_index, :sitemaps_host
10
12
 
11
- # Evaluate the sitemap config file and write all sitemaps.
13
+ # Add links to the link set by evaluating the block. The block should
14
+ # contains calls to sitemap methods like:
15
+ # * +add+ - Add a link to the current sitemap
16
+ # * +group+ - Start a new group of sitemaps
12
17
  #
13
- # The Sitemap Interpreter includes the URL helpers and API methods
14
- # that the block argument to `add_links` is evaluted within.
18
+ # == Options
15
19
  #
16
- # TODO: Refactor so that we can have multiple instances
17
- # of LinkSet.
18
- def create(config_file = 'config/sitemap.rb', &block)
19
- require 'sitemap_generator/interpreter'
20
-
21
- # Clear out the current objects. New objects will be lazy-initialized.
22
- @sitemap_index = @sitemap = nil
23
-
24
- start_time = Time.now
25
- SitemapGenerator::Interpreter.new(self, config_file, &block)
26
- finalize_sitemap
27
- finalize_sitemap_index
28
- end_time = Time.now
20
+ # Any option supported by +new+ can be passed. The options will be
21
+ # set on the instance using the accessor methods. This is provided mostly
22
+ # as a convenience.
23
+ #
24
+ # In addition to the options to +new+, the following options are supported:
25
+ # * <tt>:finalize</tt> - The sitemaps are written as they get full and at the end
26
+ # of the block. Pass +false+ as the value to prevent the sitemap or sitemap index
27
+ # from being finalized. Default is +true+.
28
+ def create(opts={}, &block)
29
+ @sitemap_index = nil if @sitemap_index && @sitemap_index.finalized? && !@protect_index
30
+ @sitemap = nil if @sitemap && @sitemap.finalized?
31
+ set_options(opts)
32
+ start_time = Time.now if @verbose
33
+ interpreter.eval(:yield_sitemap => @yield_sitemap || SitemapGenerator.yield_sitemap?, &block)
34
+ finalize!
35
+ end_time = Time.now if @verbose
36
+ puts sitemap_index.stats_summary(:time_taken => end_time - start_time) if @verbose
37
+ self
38
+ end
29
39
 
30
- puts sitemap_index.stats_summary(:time_taken => end_time - start_time) if verbose
40
+ # Dreprecated. Use create.
41
+ def add_links(&block)
42
+ @yield_sitemap = true
43
+ create(&block)
44
+ @yield_sitemap = false
31
45
  end
32
46
 
33
47
  # Constructor
34
48
  #
35
- # Call with a hash of options. Options:
49
+ # == Options:
50
+ # * <tt>:default_host</tt> - host including protocol to use in all sitemap links
51
+ # e.g. http://en.google.ca
36
52
  #
37
- # <tt>public_path</tt> full path to the directory to write sitemaps in.
38
- # Defaults to your Rails <tt>public/</tt> directory.
53
+ # * <tt>:public_path</tt> - Full or relative path to the directory to write sitemaps into.
54
+ # Defaults to the <tt>public/</tt> directory in your application root directory or
55
+ # the current working directory.
39
56
  #
40
- # <tt>sitemaps_path</tt> path fragment within public to write sitemaps
57
+ # * <tt>:sitemaps_host</tt> - host (including protocol) to use in links to the sitemaps. Useful if your sitemaps
58
+ # are hosted o different server e.g. 'http://amazon.aws.com/'
59
+ #
60
+ # * <tt>:sitemaps_path</tt> - path fragment within public to write sitemaps
41
61
  # to e.g. 'en/'. Sitemaps are written to <tt>public_path</tt> + <tt>sitemaps_path</tt>
42
62
  #
43
- # <tt>default_host</tt> host including protocol to use in all sitemap links
44
- # e.g. http://en.google.ca
63
+ # * <tt>:filename</tt> - symbol giving the base name for files (default <tt>:sitemap</tt>).
64
+ # The sitemap names are generated like "#{filename}1.xml.gz", "#{filename}2.xml.gz"
65
+ # and the index name is like "#{filename}_index.xml.gz".
45
66
  #
46
- # <tt>filename</tt> symbol giving the base name for files (default <tt>:sitemap</tt>).
47
- # The sitemap names are generated like "#{@filename}1.xml.gzip", "#{@filename}2.xml.gzip"
48
- # and the index name is like "#{@filename}_index.xml.gzip".
67
+ # * <tt>:sitemaps_namer</tt> - A +SitemapNamer+ instance for generating the sitemap names.
49
68
  #
50
- # <tt>include_root</tt> whether to include the root url i.e. '/' in each group of sitemaps.
51
- # Default is false.
69
+ # * <tt>:include_root</tt> - whether to include the root url i.e. '/' in each group of sitemaps.
70
+ # Default is true.
52
71
  #
53
- # <tt>include_index</tt> whether to include the sitemap index URL in each group of sitemaps.
54
- # Default is false.
55
- def initialize(*args)
56
-
57
- # Extract options
58
- options = if (!args.first.nil? && !args.first.is_a?(Hash)) || args.size > 1
59
- warn "Deprecated. Please call with an options hash instead."
60
- [:public_path, :sitemaps_path, :default_host, :filename].each_with_index.inject({}) do |hash, arg|
61
- hash[arg[0]] = args[arg[1]]
62
- hash
63
- end
64
- else
65
- args.first || {}
66
- end
67
-
68
- # Option defaults
72
+ # * <tt>:include_index</tt> - whether to include the sitemap index URL in each group of sitemaps.
73
+ # Default is true.
74
+ #
75
+ # * <tt>:verbose</tt> - If +true+, output a summary line for each sitemap and sitemap
76
+ # index that is created. Default is +false+.
77
+ def initialize(options={})
69
78
  options.reverse_merge!({
70
79
  :include_root => true,
71
80
  :include_index => true,
72
81
  :filename => :sitemap,
73
- :public_path => SitemapGenerator.app.root + 'public/',
74
- :sitemaps_path => nil
82
+ :verbose => false
75
83
  })
76
84
  options.each_pair { |k, v| instance_variable_set("@#{k}".to_sym, v) }
77
85
 
78
-
79
- # Create a location object to store all the location options
80
- @location = SitemapGenerator::SitemapLocation.new(
81
- :sitemaps_path => @sitemaps_path,
82
- :public_path => @public_path,
83
- :host => @default_host
84
- )
85
- end
86
-
87
- # Entry point for users.
88
- #
89
- # Called within the user's eval'ed sitemap config file. Add links to sitemap files
90
- # passing a block. This instance is passed in as an argument. You can call
91
- # `add` on it to add links.
92
- #
93
- # Example:
94
- # add_links do |sitemap|
95
- # sitemap.add '/'
96
- # end
97
- def add_links
98
- sitemap.add('/', :lastmod => Time.now, :changefreq => 'always', :priority => 1.0, :host => @location.host) if include_root
99
- sitemap.add(sitemap_index, :lastmod => Time.now, :changefreq => 'always', :priority => 1.0) if include_index
100
- yield self
86
+ # If an index is passed in, protect it from modification.
87
+ # Sitemaps can be added to the index but nothing else can be changed.
88
+ if options[:sitemap_index]
89
+ @protect_index = true
90
+ end
101
91
  end
102
92
 
103
93
  # Add a link to a Sitemap. If a new Sitemap is required, one will be created for
@@ -107,15 +97,69 @@ module SitemapGenerator
107
97
  # options - see README.
108
98
  # host - host for the link, defaults to your <tt>default_host</tt>.
109
99
  def add(link, options={})
110
- sitemap.add(link, options.reverse_merge!(:host => @location.host))
100
+ add_default_links if !@added_default_links
101
+ sitemap.add(link, options.reverse_merge!(:host => @default_host))
111
102
  rescue SitemapGenerator::SitemapFullError
112
- finalize_sitemap
103
+ finalize_sitemap!
113
104
  retry
114
105
  rescue SitemapGenerator::SitemapFinalizedError
115
- @sitemap = sitemap.next
106
+ @sitemap = sitemap.new
116
107
  retry
117
108
  end
118
109
 
110
+ # Create a new group of sitemaps. Returns a new LinkSet instance with options set on it.
111
+ #
112
+ # All groups share this LinkSet's sitemap index, which is not modified by any of the options
113
+ # passed to +group+.
114
+ #
115
+ # === Options
116
+ # Any of the options to LinkSet.new. Except for <tt>:public_path</tt> which is shared
117
+ # by all groups.
118
+ #
119
+ # The current options are inherited by the new group of sitemaps. The only exceptions
120
+ # being <tt>:include_index</tt> and <tt>:include_root</tt> which default to +false+.
121
+ #
122
+ # Pass a block to add links to the new LinkSet. If you pass a block the sitemaps will
123
+ # be finalized when the block returns.
124
+ #
125
+ # If you are not changing any of the location settings like <tt>filename<tt>,
126
+ # <tt>sitemaps_path</tt>, <tt>sitemaps_host</tt> or <tt>sitemaps_namer</tt>
127
+ # the current sitemap will be used in the group. All of the options you have
128
+ # specified which affect the way the links are generated will still be applied
129
+ # for the duration of the group.
130
+ def group(opts={}, &block)
131
+ @created_group = true
132
+ original_opts = opts.dup
133
+
134
+ if (@@requires_finalization_opts & original_opts.keys).empty?
135
+ # If no new filename or path is specified reuse the default sitemap file.
136
+ # A new location object will be set on it for the duration of the group.
137
+ opts[:sitemap] = sitemap
138
+ elsif original_opts.key?(:sitemaps_host) && (@@new_location_opts & original_opts.keys).empty?
139
+ # If no location options are provided we are creating the next sitemap in the
140
+ # current series, so finalize and inherit the namer.
141
+ finalize_sitemap!
142
+ opts[:sitemaps_namer] = sitemaps_namer
143
+ end
144
+
145
+ opts = options_for_group(opts)
146
+ @group = SitemapGenerator::LinkSet.new(opts)
147
+ if opts.key?(:sitemap)
148
+ # If the group is sharing the current sitemap, set the
149
+ # new location options on the location object.
150
+ @original_location = @sitemap.location.dup
151
+ @sitemap.location.merge!(@group.sitemap_location)
152
+ if block_given?
153
+ @group.interpreter.eval(:yield_sitemap => @yield_sitemap || SitemapGenerator.yield_sitemap?, &block)
154
+ @sitemap.location.merge!(@original_location)
155
+ end
156
+ elsif block_given?
157
+ @group.interpreter.eval(:yield_sitemap => @yield_sitemap || SitemapGenerator.yield_sitemap?, &block)
158
+ @group.finalize_sitemap!
159
+ end
160
+ @group
161
+ end
162
+
119
163
  # Ping search engines.
120
164
  #
121
165
  # @see http://en.wikipedia.org/wiki/Sitemap_index
@@ -135,7 +179,9 @@ module SitemapGenerator
135
179
  search_engines.each do |engine, link|
136
180
  next if engine == :yahoo && !self.yahoo_app_id
137
181
  begin
138
- open(link)
182
+ Timeout::timeout(10) {
183
+ open(link)
184
+ }
139
185
  puts "Successful ping of #{engine.to_s.titleize}" if verbose
140
186
  rescue Timeout::Error, StandardError => e
141
187
  puts "Ping failed for #{engine.to_s.titleize}: #{e.inspect} (URL #{link})" if verbose
@@ -159,84 +205,218 @@ module SitemapGenerator
159
205
  sitemap_index.total_link_count
160
206
  end
161
207
 
162
- # Set the host name, including protocol, that will be used by default on each
163
- # of your sitemap links. You can pass a different host in your options to `add`
164
- # if you need to change it on a per-link basis.
165
- def default_host=(value)
166
- update_location_info(:host, value)
208
+ # Return the host to use in links to the sitemap files. This defaults to your
209
+ # +default_host+.
210
+ def sitemaps_host
211
+ @sitemaps_host || @default_host
167
212
  end
168
213
 
169
- # Set the public_path. This path gives the location of your public directory.
170
- # The default is the public/ directory in your Rails root. Or if Rails is not
171
- # found, it defaults to public/ in the current directory (of the process).
172
- #
173
- # Example: 'tmp/' if you don't want to generate in public for some reason.
174
- #
175
- # Set to nil to use the current directory.
176
- def public_path=(value)
177
- update_location_info(:public_path, value)
214
+ # Lazy-initialize a sitemap instance when it's accessed
215
+ def sitemap
216
+ @sitemap ||= SitemapGenerator::Builder::SitemapFile.new(sitemap_location)
178
217
  end
179
218
 
180
- # Set the sitemaps_path. This path gives the location to write sitemaps to
181
- # relative to your public_path.
182
- # Example: 'sitemaps/' to generate your sitemaps in 'public/sitemaps/'.
183
- def sitemaps_path=(value)
184
- update_location_info(:sitemaps_path, value)
219
+ # Lazy-initialize a sitemap index instance when it's accessed
220
+ def sitemap_index
221
+ @sitemap_index ||= SitemapGenerator::Builder::SitemapIndexFile.new(sitemap_index_location)
185
222
  end
186
223
 
187
- # Set the filename base to use when generating sitemaps and sitemap indexes.
188
- def filename=(value)
189
- @filename = value
190
- update_sitemap_info(:filename, value)
224
+ def finalize!
225
+ finalize_sitemap!
226
+ finalize_sitemap_index!
191
227
  end
192
228
 
193
- # Lazy-initialize a sitemap instance when it's accessed
194
- def sitemap
195
- @sitemap ||= SitemapGenerator::Builder::SitemapFile.new(
196
- :location => @location.dup,
197
- :filename => @filename
198
- )
229
+ protected
230
+
231
+ # Set each option on this instance using accessor methods. This will affect
232
+ # both the sitemap and the sitemap index.
233
+ def set_options(opts={})
234
+ opts.each_pair do |key, value|
235
+ send("#{key}=", value)
236
+ end
199
237
  end
200
238
 
201
- # Lazy-initialize a sitemap index instance when it's accessed
202
- def sitemap_index
203
- @sitemap_index ||= SitemapGenerator::Builder::SitemapIndexFile.new(
204
- :location => @location.dup,
205
- :filename => "#{@filename}_index"
239
+ # Given +opts+, return a hash of options prepped for creating a new group from this LinkSet.
240
+ # If <tt>:public_path</tt> is present in +opts+ it is removed because groups cannot
241
+ # change the public path.
242
+ def options_for_group(opts)
243
+ opts.delete(:public_path)
244
+ opts.reverse_merge!(
245
+ :include_index => false,
246
+ :include_root => false,
247
+ :sitemap_index => sitemap_index
206
248
  )
249
+
250
+ # Reverse merge the current settings
251
+ current_settings = [
252
+ :include_root,
253
+ :include_index,
254
+ :sitemaps_path,
255
+ :public_path,
256
+ :sitemaps_host,
257
+ :verbose,
258
+ :default_host
259
+ ].inject({}) do |hash, key|
260
+ if value = instance_variable_get(:"@#{key}")
261
+ hash[key] = value
262
+ end
263
+ hash
264
+ end
265
+ opts.reverse_merge!(current_settings)
266
+ opts
207
267
  end
208
268
 
209
- protected
269
+ # Add default links if those options are turned on. Record the fact that we have done so
270
+ # in an instance variable.
271
+ def add_default_links
272
+ sitemap.add('/', :lastmod => Time.now, :changefreq => 'always', :priority => 1.0, :host => @default_host) if include_root
273
+ sitemap.add(sitemap_index, :lastmod => Time.now, :changefreq => 'always', :priority => 1.0) if include_index
274
+ @added_default_links = true
275
+ end
210
276
 
211
277
  # Finalize a sitemap by including it in the index and outputting a summary line.
212
278
  # Do nothing if it has already been finalized.
213
- def finalize_sitemap
214
- return if sitemap.finalized?
279
+ #
280
+ # Don't finalize if the sitemap is empty and a group has been created. The reason
281
+ # being that the group will have written out its sitemap.
282
+ #
283
+ # Add the default links if they have not been added yet and no groups have been created.
284
+ # If the default links haven't been added we know that the sitemap is empty,
285
+ # because they are added on the first call to add(). This ensure that if the
286
+ # block passed to create() is empty the default links are still included in the
287
+ # sitemap.
288
+ def finalize_sitemap!
289
+ add_default_links if !@added_default_links && !@created_group
290
+ return if sitemap.finalized? || sitemap.empty? && @created_group
215
291
  sitemap_index.add(sitemap)
216
292
  puts sitemap.summary if verbose
217
293
  end
218
294
 
219
295
  # Finalize a sitemap index and output a summary line. Do nothing if it has already
220
296
  # been finalized.
221
- def finalize_sitemap_index
222
- return if sitemap_index.finalized?
297
+ def finalize_sitemap_index!
298
+ return if @protect_index || sitemap_index.finalized?
223
299
  sitemap_index.finalize!
224
300
  puts sitemap_index.summary if verbose
225
301
  end
226
302
 
227
- # Update the given attribute on the current sitemap index and sitemap files. But
228
- # don't create the index or sitemap files yet if they are not already created.
229
- def update_sitemap_info(attribute, value)
230
- sitemap_index.send("#{attribute}=", value) if @sitemap_index && !@sitemap_index.finalized?
231
- sitemap.send("#{attribute}=", value) if @sitemap && !@sitemap.finalized?
303
+ # Return the interpreter linked to this instance.
304
+ def interpreter
305
+ require 'sitemap_generator/interpreter'
306
+ @interpreter ||= SitemapGenerator::Interpreter.new(:link_set => self)
232
307
  end
233
308
 
234
- # Update the given attribute on the current sitemap index and sitemap file location objects.
235
- # But don't create the index or sitemap files yet if they are not already created.
236
- def update_location_info(attribute, value)
237
- @location.merge!(attribute => value)
238
- sitemap_index.location.merge!(attribute => value) if @sitemap_index && !@sitemap_index.finalized?
239
- sitemap.location.merge!(attribute => value) if @sitemap && !@sitemap.finalized?
309
+ module LocationHelpers
310
+ public
311
+
312
+ # Set the host name, including protocol, that will be used by default on each
313
+ # of your sitemap links. You can pass a different host in your options to `add`
314
+ # if you need to change it on a per-link basis.
315
+ def default_host=(value)
316
+ @default_host = value
317
+ update_location_info(:host, value)
318
+ end
319
+
320
+ # Set the public_path. This path gives the location of your public directory.
321
+ # The default is the public/ directory in your Rails root. Or if Rails is not
322
+ # found, it defaults to public/ in the current directory (of the process).
323
+ #
324
+ # Example: 'tmp/' if you don't want to generate in public for some reason.
325
+ #
326
+ # Set to nil to use the current directory.
327
+ def public_path=(value)
328
+ @public_path = Pathname.new(value.to_s)
329
+ @public_path = SitemapGenerator.app.root + @public_path if @public_path.relative?
330
+ update_location_info(:public_path, @public_path)
331
+ @public_path
332
+ end
333
+
334
+ # Return a Pathname with the full path to the public directory
335
+ def public_path
336
+ @public_path ||= self.send(:public_path=, 'public/')
337
+ end
338
+
339
+ # Set the sitemaps_path. This path gives the location to write sitemaps to
340
+ # relative to your public_path.
341
+ # Example: 'sitemaps/' to generate your sitemaps in 'public/sitemaps/'.
342
+ def sitemaps_path=(value)
343
+ @sitemaps_path = value
344
+ update_location_info(:sitemaps_path, value)
345
+ end
346
+
347
+ # Set the host name, including protocol, that will be used on all links to your sitemap
348
+ # files. Useful when the server that hosts the sitemaps is not on the same host as
349
+ # the links in the sitemap.
350
+ def sitemaps_host=(value)
351
+ @sitemaps_host = value
352
+ update_location_info(:host, value)
353
+ end
354
+
355
+ # Set the filename base to use when generating sitemaps and sitemap indexes.
356
+ # The index name will be +value+ with <tt>_index.xml.gz</tt> appended.
357
+ # === Example
358
+ # <tt>filename = :sitemap</tt>
359
+ def filename=(value)
360
+ @filename = value
361
+ self.sitemaps_namer = SitemapGenerator::SitemapNamer.new(@filename)
362
+ self.sitemap_index_namer = SitemapGenerator::SitemapIndexNamer.new("#{@filename}_index")
363
+ end
364
+
365
+ # Set the namer to use when generating SitemapFiles (does not apply to the
366
+ # SitemapIndexFile)
367
+ def sitemaps_namer=(value)
368
+ @sitemaps_namer = value
369
+ @sitemap.location[:namer] = value if @sitemap && !@sitemap.finalized?
370
+ end
371
+
372
+ # Return the current sitemaps namer object. If it not set, looks for it on
373
+ # the current sitemap and if there is no sitemap, creates a new one using
374
+ # the current filename.
375
+ def sitemaps_namer
376
+ @sitemaps_namer ||= @sitemap && @sitemap.location.namer || SitemapGenerator::SitemapNamer.new(@filename)
377
+ end
378
+
379
+ # Set the namer to use when generating SitemapFiles (does not apply to the
380
+ # SitemapIndexFile)
381
+ def sitemap_index_namer=(value)
382
+ @sitemap_index_namer = value
383
+ @sitemap_index.location[:namer] = value if @sitemap_index && !@sitemap_index.finalized? && !@protect_index
384
+ end
385
+
386
+ def sitemap_index_namer
387
+ @sitemap_index_namer ||= @sitemap_index && @sitemap_index.location.namer || SitemapGenerator::SitemapIndexNamer.new("#{@filename}_index")
388
+ end
389
+
390
+ # Return a new +SitemapLocation+ instance with the current options included
391
+ def sitemap_location
392
+ SitemapGenerator::SitemapLocation.new(
393
+ :host => sitemaps_host,
394
+ :namer => sitemaps_namer,
395
+ :public_path => public_path,
396
+ :sitemaps_path => @sitemaps_path
397
+ )
398
+ end
399
+
400
+ # Return a new +SitemapIndexLocation+ instance with the current options included
401
+ def sitemap_index_location
402
+ SitemapGenerator::SitemapLocation.new(
403
+ :host => sitemaps_host,
404
+ :namer => sitemap_index_namer,
405
+ :public_path => public_path,
406
+ :sitemaps_path => @sitemaps_path
407
+ )
408
+ end
409
+
410
+ protected
411
+
412
+ # Update the given attribute on the current sitemap index and sitemap file location objects.
413
+ # But don't create the index or sitemap files yet if they are not already created.
414
+ def update_location_info(attribute, value, opts={})
415
+ opts.reverse_merge!(:include_index => !@protect_index)
416
+ @sitemap_index.location[attribute] = value if opts[:include_index] && @sitemap_index && !@sitemap_index.finalized?
417
+ @sitemap.location[attribute] = value if @sitemap && !@sitemap.finalized?
418
+ end
240
419
  end
420
+ include LocationHelpers
241
421
  end
242
- end
422
+ end