sitemap_generator_ftbpro 5.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +13 -0
  3. data/Gemfile.lock +35 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +1139 -0
  6. data/Rakefile +43 -0
  7. data/VERSION +1 -0
  8. data/lib/capistrano/sitemap_generator.rb +1 -0
  9. data/lib/capistrano/tasks/sitemap_generator.cap +36 -0
  10. data/lib/sitemap_generator/adapters/file_adapter.rb +43 -0
  11. data/lib/sitemap_generator/adapters/fog_adapter.rb +28 -0
  12. data/lib/sitemap_generator/adapters/s3_adapter.rb +41 -0
  13. data/lib/sitemap_generator/adapters/wave_adapter.rb +21 -0
  14. data/lib/sitemap_generator/adapters.rb +0 -0
  15. data/lib/sitemap_generator/application.rb +49 -0
  16. data/lib/sitemap_generator/builder/sitemap_file.rb +171 -0
  17. data/lib/sitemap_generator/builder/sitemap_index_file.rb +149 -0
  18. data/lib/sitemap_generator/builder/sitemap_index_url.rb +28 -0
  19. data/lib/sitemap_generator/builder/sitemap_url.rb +250 -0
  20. data/lib/sitemap_generator/builder.rb +8 -0
  21. data/lib/sitemap_generator/core_ext/big_decimal.rb +45 -0
  22. data/lib/sitemap_generator/core_ext/numeric.rb +48 -0
  23. data/lib/sitemap_generator/core_ext.rb +3 -0
  24. data/lib/sitemap_generator/helpers/number_helper.rb +237 -0
  25. data/lib/sitemap_generator/interpreter.rb +80 -0
  26. data/lib/sitemap_generator/link_set.rb +665 -0
  27. data/lib/sitemap_generator/railtie.rb +7 -0
  28. data/lib/sitemap_generator/sitemap_location.rb +192 -0
  29. data/lib/sitemap_generator/sitemap_namer.rb +75 -0
  30. data/lib/sitemap_generator/tasks.rb +53 -0
  31. data/lib/sitemap_generator/templates.rb +41 -0
  32. data/lib/sitemap_generator/utilities.rb +181 -0
  33. data/lib/sitemap_generator.rb +82 -0
  34. data/lib/tasks/sitemap_generator_tasks.rake +1 -0
  35. data/rails/install.rb +2 -0
  36. data/rails/uninstall.rb +2 -0
  37. data/spec/blueprint.rb +15 -0
  38. data/spec/files/sitemap.create.rb +12 -0
  39. data/spec/files/sitemap.groups.rb +49 -0
  40. data/spec/sitemap_generator/adapters/s3_adapter_spec.rb +23 -0
  41. data/spec/sitemap_generator/alternate_sitemap_spec.rb +79 -0
  42. data/spec/sitemap_generator/application_spec.rb +69 -0
  43. data/spec/sitemap_generator/builder/sitemap_file_spec.rb +110 -0
  44. data/spec/sitemap_generator/builder/sitemap_index_file_spec.rb +124 -0
  45. data/spec/sitemap_generator/builder/sitemap_index_url_spec.rb +28 -0
  46. data/spec/sitemap_generator/builder/sitemap_url_spec.rb +186 -0
  47. data/spec/sitemap_generator/core_ext/bigdecimal_spec.rb +20 -0
  48. data/spec/sitemap_generator/core_ext/numeric_spec.rb +43 -0
  49. data/spec/sitemap_generator/file_adaptor_spec.rb +20 -0
  50. data/spec/sitemap_generator/geo_sitemap_spec.rb +30 -0
  51. data/spec/sitemap_generator/helpers/number_helper_spec.rb +196 -0
  52. data/spec/sitemap_generator/interpreter_spec.rb +90 -0
  53. data/spec/sitemap_generator/link_set_spec.rb +864 -0
  54. data/spec/sitemap_generator/mobile_sitemap_spec.rb +27 -0
  55. data/spec/sitemap_generator/news_sitemap_spec.rb +42 -0
  56. data/spec/sitemap_generator/pagemap_sitemap_spec.rb +57 -0
  57. data/spec/sitemap_generator/sitemap_generator_spec.rb +582 -0
  58. data/spec/sitemap_generator/sitemap_groups_spec.rb +144 -0
  59. data/spec/sitemap_generator/sitemap_location_spec.rb +210 -0
  60. data/spec/sitemap_generator/sitemap_namer_spec.rb +96 -0
  61. data/spec/sitemap_generator/templates_spec.rb +24 -0
  62. data/spec/sitemap_generator/utilities/existence_spec.rb +26 -0
  63. data/spec/sitemap_generator/utilities/hash_spec.rb +57 -0
  64. data/spec/sitemap_generator/utilities/rounding_spec.rb +31 -0
  65. data/spec/sitemap_generator/utilities_spec.rb +101 -0
  66. data/spec/sitemap_generator/video_sitemap_spec.rb +117 -0
  67. data/spec/spec_helper.rb +24 -0
  68. data/spec/support/file_macros.rb +39 -0
  69. data/spec/support/schemas/siteindex.xsd +73 -0
  70. data/spec/support/schemas/sitemap-geo.xsd +41 -0
  71. data/spec/support/schemas/sitemap-mobile.xsd +32 -0
  72. data/spec/support/schemas/sitemap-news.xsd +159 -0
  73. data/spec/support/schemas/sitemap-pagemap.xsd +97 -0
  74. data/spec/support/schemas/sitemap-video.xsd +643 -0
  75. data/spec/support/schemas/sitemap.xsd +115 -0
  76. data/spec/support/xml_macros.rb +67 -0
  77. data/templates/sitemap.rb +27 -0
  78. 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
@@ -0,0 +1,2 @@
1
+ # Install hook code here
2
+ SitemapGenerator::Utilities.install_sitemap_rb
@@ -0,0 +1,2 @@
1
+ # Uninstall hook code here
2
+ SitemapGenerator::Utilities.uninstall_sitemap_rb
data/spec/blueprint.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'machinist/active_record'
2
+ require 'sham'
3
+
4
+ Sham.title { Time.now.to_i }
5
+ Content.blueprint do
6
+ title
7
+ end
8
+
9
+ module Blueprint
10
+ def self.seed
11
+ 14.times do |i|
12
+ content = Content.make(:title => "Link #{i}")
13
+ end
14
+ end
15
+ end
@@ -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