xml-sitemap 1.0.5 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +24 -0
- data/.rspec +3 -0
- data/Gemfile +3 -0
- data/README.md +91 -0
- data/Rakefile +9 -0
- data/lib/xml-sitemap.rb +4 -96
- data/lib/xml-sitemap/index.rb +50 -0
- data/lib/xml-sitemap/map.rb +112 -0
- data/lib/xml-sitemap/options.rb +22 -0
- data/lib/xml-sitemap/version.rb +3 -0
- data/spec/fixtures/empty_index.xml +3 -0
- data/spec/fixtures/encoded_map.xml +15 -0
- data/spec/fixtures/sample_index.xml +11 -0
- data/spec/fixtures/saved_map.xml +27 -0
- data/spec/fixtures/simple_map.xml +9 -0
- data/spec/index_spec.rb +50 -0
- data/spec/map_spec.rb +72 -0
- data/spec/spec_helper.rb +16 -0
- data/xml-sitemap.gemspec +25 -0
- metadata +81 -24
- data/README +0 -37
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
*.swp
|
4
|
+
*.tmproj
|
5
|
+
*~
|
6
|
+
.DS_Store
|
7
|
+
.\#*
|
8
|
+
.bundle
|
9
|
+
.config
|
10
|
+
.yardoc
|
11
|
+
Gemfile.lock
|
12
|
+
InstalledFiles
|
13
|
+
\#*
|
14
|
+
_yardoc
|
15
|
+
coverage
|
16
|
+
doc/
|
17
|
+
lib/bundler/man
|
18
|
+
pkg
|
19
|
+
rdoc
|
20
|
+
spec/reports
|
21
|
+
test/tmp
|
22
|
+
test/version_tmp
|
23
|
+
tmp
|
24
|
+
tmtags
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
XmlSitemap
|
2
|
+
==========
|
3
|
+
|
4
|
+
XmlSitemap is a Ruby library that provides an easy way to generate XML sitemaps and indexes.
|
5
|
+
|
6
|
+
It does not have any web-framework dependencies thus might be used almost anywhere.
|
7
|
+
|
8
|
+
## Installing XmlSitemap
|
9
|
+
|
10
|
+
$ gem install xml-sitemap
|
11
|
+
|
12
|
+
## Sample usage
|
13
|
+
|
14
|
+
In your Gemfile:
|
15
|
+
|
16
|
+
gem 'xml-sitemap'
|
17
|
+
|
18
|
+
Simple map usage:
|
19
|
+
|
20
|
+
map = XmlSitemap::Map.new('domain.com') do |m|
|
21
|
+
# Adds a simple page
|
22
|
+
m.add '/page1'
|
23
|
+
|
24
|
+
# You can drop leading slash, it will be automatically added
|
25
|
+
m.add 'page2'
|
26
|
+
|
27
|
+
# Set the page priority
|
28
|
+
m.add 'page3', :priority => 0.2
|
29
|
+
|
30
|
+
# Specify last modification date and update frequiency
|
31
|
+
m.add 'page4', :updated => Date.today, :period => :never
|
32
|
+
end
|
33
|
+
|
34
|
+
map.render # => render to XML
|
35
|
+
map.render_to('/path/to/file.xml') # => render into a file
|
36
|
+
|
37
|
+
By default XmlSitemap creates a map with link to homepage of your domain. It's a priority 1.0. Default priority is 0.5.
|
38
|
+
|
39
|
+
List of periods:
|
40
|
+
|
41
|
+
- :none,
|
42
|
+
- :always
|
43
|
+
- :hourly
|
44
|
+
- :daily
|
45
|
+
- :weekly
|
46
|
+
- :monthly
|
47
|
+
- :yearly
|
48
|
+
- :never
|
49
|
+
|
50
|
+
## XmlSitemap::Map
|
51
|
+
|
52
|
+
When creating a new map object, you can specify a set of options.
|
53
|
+
|
54
|
+
map = XmlSitemap::Map.new('mydomain.com', options)
|
55
|
+
|
56
|
+
Available options:
|
57
|
+
|
58
|
+
- :secure - Will add all sitemap items with https prefix. (default: false)
|
59
|
+
- :home - Disable homepage autocreation, but you still can do that manually. (default: true)
|
60
|
+
- :root - Force all links to fall under the main domain. You can add full urls (not paths) if set to false. (default: true)
|
61
|
+
- :time - Provide a creation time for the sitemap. (default: current time)
|
62
|
+
|
63
|
+
## XmlSitemap::Index
|
64
|
+
|
65
|
+
Regular sitemap does not support more than 50k records, so if you generation a huge sitemap you need to use XmlSitemap::Index.
|
66
|
+
Index is just a collection of links to all the website's sitemaps.
|
67
|
+
|
68
|
+
Usage:
|
69
|
+
|
70
|
+
map = XmlSitemap::Map.new('domain.com')
|
71
|
+
map.add 'page'
|
72
|
+
|
73
|
+
index = XmlSitemap::Index.new
|
74
|
+
index.add map
|
75
|
+
|
76
|
+
index.render # => render index to XML
|
77
|
+
index.render_to('/path/to/file.xml') # => render into a file
|
78
|
+
|
79
|
+
## TODO
|
80
|
+
|
81
|
+
- Gzip sitemaps and index file
|
82
|
+
|
83
|
+
## License
|
84
|
+
|
85
|
+
Copyright © 2010 Dan Sosedoff.
|
86
|
+
|
87
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
88
|
+
|
89
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
90
|
+
|
91
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/lib/xml-sitemap.rb
CHANGED
@@ -1,98 +1,6 @@
|
|
1
1
|
require 'time'
|
2
|
+
require 'builder'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
class Item
|
7
|
-
attr_reader :path
|
8
|
-
attr_reader :updated
|
9
|
-
attr_reader :priority
|
10
|
-
attr_reader :changefreq
|
11
|
-
|
12
|
-
def initialize(opts={})
|
13
|
-
@path = opts[:url] if opts.key?(:url)
|
14
|
-
@updated = opts[:updated] || Time.now
|
15
|
-
@priority = opts[:priority] || 1.0
|
16
|
-
@changefreq = opts[:period] || :weekly
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
class Map
|
21
|
-
attr_reader :domain, :items
|
22
|
-
attr_reader :buffer
|
23
|
-
attr_reader :created_at
|
24
|
-
attr_accessor :index_path
|
25
|
-
|
26
|
-
# Creates new Map class for specified domain
|
27
|
-
def initialize(domain)
|
28
|
-
@domain = domain
|
29
|
-
@created_at = Time.now
|
30
|
-
@items = []
|
31
|
-
yield self if block_given?
|
32
|
-
end
|
33
|
-
|
34
|
-
# Yields Map class for easier access
|
35
|
-
def generate
|
36
|
-
raise ArgumentError, 'Block required' unless block_given?
|
37
|
-
yield self
|
38
|
-
end
|
39
|
-
|
40
|
-
# Add new item to sitemap list
|
41
|
-
def add(opts)
|
42
|
-
@items << XmlSitemap::Item.new(opts)
|
43
|
-
end
|
44
|
-
|
45
|
-
# Get map items count
|
46
|
-
def size
|
47
|
-
@items.size
|
48
|
-
end
|
49
|
-
|
50
|
-
# Render XML
|
51
|
-
def render
|
52
|
-
return '' if @items.size == 0
|
53
|
-
output = []
|
54
|
-
output << '<?xml version="1.0" encoding="UTF-8"?>'
|
55
|
-
output << '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">'
|
56
|
-
@items.each do |item|
|
57
|
-
output << '<url>'
|
58
|
-
output << "<loc>http://#{@domain}#{item.path.to_s}</loc>"
|
59
|
-
output << "<lastmod>#{item.updated.utc.iso8601}</lastmod>"
|
60
|
-
output << "<changefreq>#{item.changefreq.to_s}</changefreq>"
|
61
|
-
output << "<priority>#{item.priority.to_s}</priority>"
|
62
|
-
output << '</url>'
|
63
|
-
end
|
64
|
-
output << '</urlset>'
|
65
|
-
return output.join("\n")
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
class Index
|
70
|
-
attr_reader :domain, :maps
|
71
|
-
|
72
|
-
def initialize(domain)
|
73
|
-
@domain = domain
|
74
|
-
@maps = []
|
75
|
-
end
|
76
|
-
|
77
|
-
# Add XmlSitemap::Map item to sitemap index
|
78
|
-
def add(map)
|
79
|
-
raise 'XmlSitemap::Map object requred!' unless map.kind_of?(Map)
|
80
|
-
@maps << {:loc => "http://#{@domain}/#{map.index_path}", :lastmod => map.created_at.utc.iso8601}
|
81
|
-
end
|
82
|
-
|
83
|
-
# Generate sitemap XML index
|
84
|
-
def render
|
85
|
-
output = [] ; map_id = 1
|
86
|
-
output << '<?xml version="1.0" encoding="UTF-8"?>'
|
87
|
-
output << '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'
|
88
|
-
@maps.each do |m|
|
89
|
-
output << '<sitemap>'
|
90
|
-
output << "<loc>#{m[:loc]}</loc>"
|
91
|
-
output << "<lastmod>#{m[:lastmod]}</lastmod>"
|
92
|
-
output << '</sitemap>'
|
93
|
-
end
|
94
|
-
output << '</sitemapindex>'
|
95
|
-
return output.join("\n")
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
4
|
+
require 'xml-sitemap/options'
|
5
|
+
require 'xml-sitemap/map'
|
6
|
+
require 'xml-sitemap/index'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module XmlSitemap
|
2
|
+
class Index
|
3
|
+
attr_reader :maps
|
4
|
+
|
5
|
+
def initialize(opts={})
|
6
|
+
@maps = []
|
7
|
+
@offset = 0
|
8
|
+
|
9
|
+
yield self if block_given?
|
10
|
+
end
|
11
|
+
|
12
|
+
# Add map object to index
|
13
|
+
def add(map)
|
14
|
+
raise ArgumentError, 'XmlSitemap::Map object requred!' unless map.kind_of?(XmlSitemap::Map)
|
15
|
+
raise ArgumentError, 'Map is empty!' if map.empty?
|
16
|
+
|
17
|
+
@maps << {
|
18
|
+
:loc => map.index_url(@offset),
|
19
|
+
:lastmod => map.created_at.utc.iso8601
|
20
|
+
}
|
21
|
+
@offset += 1
|
22
|
+
end
|
23
|
+
|
24
|
+
# Generate sitemap XML index
|
25
|
+
def render
|
26
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
27
|
+
xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
|
28
|
+
xml.urlset(XmlSitemap::INDEX_SCHEMA_OPTIONS) { |s|
|
29
|
+
@maps.each do |item|
|
30
|
+
s.sitemap do |m|
|
31
|
+
m.loc item[:loc]
|
32
|
+
m.lastmod item[:lastmod]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
}.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
# Render XML sitemap index into the file
|
39
|
+
def render_to(path, opts={})
|
40
|
+
overwrite = opts[:overwrite] || true
|
41
|
+
path = File.expand_path(path)
|
42
|
+
|
43
|
+
if File.exists?(path) && !overwrite
|
44
|
+
raise RuntimeError, "File already exists and not overwritable!"
|
45
|
+
end
|
46
|
+
|
47
|
+
File.open(path, 'w') { |f| f.write(self.render) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module XmlSitemap
|
2
|
+
class Item
|
3
|
+
attr_reader :target, :updated, :priority, :changefreq
|
4
|
+
|
5
|
+
def initialize(target, opts={})
|
6
|
+
@target = target.to_s.strip
|
7
|
+
@updated = opts[:updated] || Time.now.utc
|
8
|
+
@priority = opts[:priority] || 0.5
|
9
|
+
@changefreq = opts[:period] || :weekly
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Map
|
14
|
+
attr_reader :domain, :items
|
15
|
+
attr_reader :buffer
|
16
|
+
attr_reader :created_at
|
17
|
+
attr_reader :root
|
18
|
+
|
19
|
+
# Creates new Map class for specified domain
|
20
|
+
def initialize(domain, opts={})
|
21
|
+
@domain = domain.to_s.strip
|
22
|
+
raise ArgumentError, 'Domain required!' if @domain.empty?
|
23
|
+
|
24
|
+
@created_at = opts[:time] || Time.now.utc
|
25
|
+
@secure = opts[:secure] || false
|
26
|
+
@home = opts.key?(:home) ? opts[:home] : true
|
27
|
+
@root = opts.key?(:root) ? opts[:root] : true
|
28
|
+
@items = []
|
29
|
+
|
30
|
+
self.add('/', :priority => 1.0) if @home === true
|
31
|
+
|
32
|
+
yield self if block_given?
|
33
|
+
end
|
34
|
+
|
35
|
+
# Yields Map class for easier access
|
36
|
+
def generate
|
37
|
+
raise ArgumentError, 'Block required' unless block_given?
|
38
|
+
yield self
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add new item to sitemap list
|
42
|
+
def add(target, opts={})
|
43
|
+
raise RuntimeError, 'Only less than 50k records allowed!' if @items.size >= 50000
|
44
|
+
raise ArgumentError, 'Target required!' if target.nil?
|
45
|
+
raise ArgumentError, 'Target is empty!' if target.to_s.strip.empty?
|
46
|
+
|
47
|
+
opts[:updated] = @created_at unless opts.key?(:updated)
|
48
|
+
item = XmlSitemap::Item.new(process_target(target), opts)
|
49
|
+
@items << item
|
50
|
+
item
|
51
|
+
end
|
52
|
+
|
53
|
+
# Get map items count
|
54
|
+
def size
|
55
|
+
@items.size
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns true if sitemap does not have any items
|
59
|
+
def empty?
|
60
|
+
@items.empty?
|
61
|
+
end
|
62
|
+
|
63
|
+
# Generate full url for path
|
64
|
+
def url(path='')
|
65
|
+
"#{@secure ? 'https' : 'http'}://#{@domain}#{path}"
|
66
|
+
end
|
67
|
+
|
68
|
+
# Get full url for index
|
69
|
+
def index_url(offset)
|
70
|
+
"http://#{@domain}/sitemap-#{offset}.xml"
|
71
|
+
end
|
72
|
+
|
73
|
+
# Render XML
|
74
|
+
def render
|
75
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
76
|
+
xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
|
77
|
+
xml.urlset(XmlSitemap::MAP_SCHEMA_OPTIONS) { |s|
|
78
|
+
@items.each do |item|
|
79
|
+
s.url do |u|
|
80
|
+
u.loc item.target
|
81
|
+
u.lastmod item.updated.utc.iso8601
|
82
|
+
u.changefreq item.changefreq.to_s
|
83
|
+
u.priority item.priority.to_s
|
84
|
+
end
|
85
|
+
end
|
86
|
+
}.to_s
|
87
|
+
end
|
88
|
+
|
89
|
+
# Render XML sitemap into the file
|
90
|
+
def render_to(path, opts={})
|
91
|
+
overwrite = opts[:overwrite] || true
|
92
|
+
path = File.expand_path(path)
|
93
|
+
|
94
|
+
if File.exists?(path) && !overwrite
|
95
|
+
raise RuntimeError, "File already exists and not overwritable!"
|
96
|
+
end
|
97
|
+
|
98
|
+
File.open(path, 'w') { |f| f.write(self.render) }
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
# Process target path or url
|
104
|
+
def process_target(str)
|
105
|
+
if @root == true
|
106
|
+
url(str =~ /^\// ? str : "/#{str}")
|
107
|
+
else
|
108
|
+
str =~ /^(http|https)/i ? str : url(str =~ /^\// ? str : "/#{str}")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module XmlSitemap
|
2
|
+
PERIODS = [
|
3
|
+
:none,
|
4
|
+
:always,
|
5
|
+
:hourly,
|
6
|
+
:daily,
|
7
|
+
:weekly,
|
8
|
+
:monthly,
|
9
|
+
:yearly,
|
10
|
+
:never
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
MAP_SCHEMA_OPTIONS = {
|
14
|
+
'xsi:schemaLocation' => "http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd",
|
15
|
+
'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance",
|
16
|
+
'xmlns' => "http://www.sitemaps.org/schemas/sitemap/0.9"
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
INDEX_SCHEMA_OPTIONS = {
|
20
|
+
'xmlns' => "http://www.sitemaps.org/schemas/sitemap/0.9"
|
21
|
+
}.freeze
|
22
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<urlset xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
3
|
+
<url>
|
4
|
+
<loc>http://foobar.com/</loc>
|
5
|
+
<lastmod>2011-06-01T05:00:01Z</lastmod>
|
6
|
+
<changefreq>weekly</changefreq>
|
7
|
+
<priority>1.0</priority>
|
8
|
+
</url>
|
9
|
+
<url>
|
10
|
+
<loc>http://foobar.com/path?a=b&c=d&e=sample string</loc>
|
11
|
+
<lastmod>2011-06-01T05:00:01Z</lastmod>
|
12
|
+
<changefreq>weekly</changefreq>
|
13
|
+
<priority>0.5</priority>
|
14
|
+
</url>
|
15
|
+
</urlset>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
3
|
+
<sitemap>
|
4
|
+
<loc>http://foobar.com/sitemap-0.xml</loc>
|
5
|
+
<lastmod>2011-06-01T05:00:01Z</lastmod>
|
6
|
+
</sitemap>
|
7
|
+
<sitemap>
|
8
|
+
<loc>http://foobar.com/sitemap-1.xml</loc>
|
9
|
+
<lastmod>2011-06-01T05:00:01Z</lastmod>
|
10
|
+
</sitemap>
|
11
|
+
</urlset>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<urlset xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
3
|
+
<url>
|
4
|
+
<loc>http://foobar.com/</loc>
|
5
|
+
<lastmod>2011-06-01T05:00:01Z</lastmod>
|
6
|
+
<changefreq>weekly</changefreq>
|
7
|
+
<priority>1.0</priority>
|
8
|
+
</url>
|
9
|
+
<url>
|
10
|
+
<loc>http://foobar.com/about</loc>
|
11
|
+
<lastmod>2011-06-01T05:00:01Z</lastmod>
|
12
|
+
<changefreq>weekly</changefreq>
|
13
|
+
<priority>0.5</priority>
|
14
|
+
</url>
|
15
|
+
<url>
|
16
|
+
<loc>http://foobar.com/terms</loc>
|
17
|
+
<lastmod>2011-06-01T05:00:01Z</lastmod>
|
18
|
+
<changefreq>weekly</changefreq>
|
19
|
+
<priority>0.5</priority>
|
20
|
+
</url>
|
21
|
+
<url>
|
22
|
+
<loc>http://foobar.com/privacy</loc>
|
23
|
+
<lastmod>2011-06-01T05:00:01Z</lastmod>
|
24
|
+
<changefreq>weekly</changefreq>
|
25
|
+
<priority>0.5</priority>
|
26
|
+
</url>
|
27
|
+
</urlset>
|
data/spec/index_spec.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe XmlSitemap::Index do
|
4
|
+
before :all do
|
5
|
+
@base_time = Time.mktime(2011, 6, 1, 0, 0, 1)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should be valid if no sitemaps were supplied' do
|
9
|
+
index = XmlSitemap::Index.new
|
10
|
+
index.render.should == fixture('empty_index.xml')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should raise error if passing a wrong object' do
|
14
|
+
index = XmlSitemap::Index.new
|
15
|
+
proc { index.add(nil) }.should raise_error ArgumentError, 'XmlSitemap::Map object requred!'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should raise error if passing an empty sitemap' do
|
19
|
+
map = XmlSitemap::Map.new('foobar.com', :home => false)
|
20
|
+
index = XmlSitemap::Index.new
|
21
|
+
proc { index.add(map) }.should raise_error ArgumentError, 'Map is empty!'
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should render a proper index' do
|
25
|
+
m1 = XmlSitemap::Map.new('foobar.com', :time => @base_time) { |m| m.add('about') }
|
26
|
+
m2 = XmlSitemap::Map.new('foobar.com', :time => @base_time) { |m| m.add('about') }
|
27
|
+
|
28
|
+
index = XmlSitemap::Index.new do |i|
|
29
|
+
i.add(m1)
|
30
|
+
i.add(m2)
|
31
|
+
end
|
32
|
+
|
33
|
+
index.render.should == fixture('sample_index.xml')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should save index contents to the filesystem' do
|
37
|
+
m1 = XmlSitemap::Map.new('foobar.com', :time => @base_time) { |m| m.add('about') }
|
38
|
+
m2 = XmlSitemap::Map.new('foobar.com', :time => @base_time) { |m| m.add('about') }
|
39
|
+
|
40
|
+
index = XmlSitemap::Index.new do |i|
|
41
|
+
i.add(m1)
|
42
|
+
i.add(m2)
|
43
|
+
end
|
44
|
+
|
45
|
+
path = "/tmp/index_#{Time.now.to_i}.xml"
|
46
|
+
index.render_to(path)
|
47
|
+
File.read(path).should == fixture('sample_index.xml')
|
48
|
+
File.delete(path) if File.exists?(path)
|
49
|
+
end
|
50
|
+
end
|
data/spec/map_spec.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe XmlSitemap::Map do
|
4
|
+
before :all do
|
5
|
+
@base_time = Time.mktime(2011, 6, 1, 0, 0, 1)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should not allow empty domains' do
|
9
|
+
proc { XmlSitemap::Map.new(nil) }.should raise_error ArgumentError
|
10
|
+
proc { XmlSitemap::Map.new('') }.should raise_error ArgumentError
|
11
|
+
proc { XmlSitemap::Map.new(' ') }.should raise_error ArgumentError
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should not allow empty urls' do
|
15
|
+
map = XmlSitemap::Map.new('foobar.com')
|
16
|
+
proc { map.add(nil) }.should raise_error ArgumentError
|
17
|
+
proc { map.add('') }.should raise_error ArgumentError
|
18
|
+
proc { map.add(' ') }.should raise_error ArgumentError
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should have a home path by default' do
|
22
|
+
map = XmlSitemap::Map.new('foobar.com')
|
23
|
+
map.empty?.should == false
|
24
|
+
map.items.first.target.should == 'http://foobar.com/'
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should not have a home path with option' do
|
28
|
+
map = XmlSitemap::Map.new('foobar.com', :home => false)
|
29
|
+
map.empty?.should == true
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should autocomplete path with no starting slash' do
|
33
|
+
map = XmlSitemap::Map.new('foobar.com')
|
34
|
+
map.add('about').target.should == 'http://foobar.com/about'
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should allow full urls in items' do
|
38
|
+
map = XmlSitemap::Map.new('foobar.com', :root => false)
|
39
|
+
map.add('https://foobar.com/path').target.should == 'https://foobar.com/path'
|
40
|
+
map.add('path2').target.should == 'http://foobar.com/path2'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should render urls in https mode' do
|
44
|
+
map = XmlSitemap::Map.new('foobar.com', :secure => true)
|
45
|
+
map.add('path').target.should == 'https://foobar.com/path'
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should have properly encoded entities' do
|
49
|
+
map = XmlSitemap::Map.new('foobar.com', :time => @base_time)
|
50
|
+
map.add('/path?a=b&c=d&e=sample string')
|
51
|
+
map.render.should == fixture('encoded_map.xml')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should not allow more than 50k records' do
|
55
|
+
map = XmlSitemap::Map.new('foobar.com')
|
56
|
+
proc {
|
57
|
+
1.upto(50000) { |i| map.add("url#{i}") }
|
58
|
+
}.should raise_error RuntimeError, 'Only less than 50k records allowed!'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should save contents to the filesystem' do
|
62
|
+
map = XmlSitemap::Map.new('foobar.com', :time => @base_time) do |m|
|
63
|
+
m.add('about')
|
64
|
+
m.add('terms')
|
65
|
+
m.add('privacy')
|
66
|
+
end
|
67
|
+
path = "/tmp/sitemap_#{Time.now.to_i}.xml"
|
68
|
+
map.render_to(path)
|
69
|
+
File.read(path).should == fixture('saved_map.xml')
|
70
|
+
File.delete(path) if File.exists?(path)
|
71
|
+
end
|
72
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
$:.unshift File.expand_path("../..", __FILE__)
|
2
|
+
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.start do
|
5
|
+
add_group 'XmlSitemap', 'lib/xml-sitemap'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'xml-sitemap'
|
9
|
+
|
10
|
+
def fixture_path
|
11
|
+
File.expand_path("../fixtures", __FILE__)
|
12
|
+
end
|
13
|
+
|
14
|
+
def fixture(file)
|
15
|
+
File.read(File.join(fixture_path, file))
|
16
|
+
end
|
data/xml-sitemap.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.expand_path('../lib/xml-sitemap/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "xml-sitemap"
|
5
|
+
s.version = XmlSitemap::VERSION.dup
|
6
|
+
s.summary = "Simple XML sitemap generator for Ruby/Rails applications."
|
7
|
+
s.description = "Provides a wrapper to generate XML sitemaps and sitemap indexes."
|
8
|
+
s.homepage = "http://github.com/sosedoff/xml-sitemap"
|
9
|
+
s.authors = ["Dan Sosedoff"]
|
10
|
+
s.email = ["dan.sosedoff@gmail.com"]
|
11
|
+
|
12
|
+
s.add_development_dependency 'rake', '~> 0.8'
|
13
|
+
s.add_development_dependency 'rspec', '~> 2.6'
|
14
|
+
s.add_development_dependency 'simplecov', '~> 0.4'
|
15
|
+
|
16
|
+
s.add_runtime_dependency 'builder', '~> 3.0'
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.platform = Gem::Platform::RUBY
|
24
|
+
s.required_rubygems_version = Gem::Requirement.new('>= 1.3.6') if s.respond_to? :required_rubygems_version=
|
25
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xml-sitemap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
- 5
|
10
|
-
version: 1.0.5
|
4
|
+
prerelease:
|
5
|
+
version: 1.1.0
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Dan Sosedoff
|
@@ -15,12 +10,56 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date:
|
13
|
+
date: 2011-06-23 00:00:00 -05:00
|
19
14
|
default_executable:
|
20
|
-
dependencies:
|
21
|
-
|
22
|
-
|
23
|
-
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rake
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0.8"
|
25
|
+
type: :development
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ~>
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "2.6"
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: simplecov
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0.4"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: builder
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ~>
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "3.0"
|
58
|
+
type: :runtime
|
59
|
+
version_requirements: *id004
|
60
|
+
description: Provides a wrapper to generate XML sitemaps and sitemap indexes.
|
61
|
+
email:
|
62
|
+
- dan.sosedoff@gmail.com
|
24
63
|
executables: []
|
25
64
|
|
26
65
|
extensions: []
|
@@ -28,8 +67,25 @@ extensions: []
|
|
28
67
|
extra_rdoc_files: []
|
29
68
|
|
30
69
|
files:
|
31
|
-
-
|
70
|
+
- .gitignore
|
71
|
+
- .rspec
|
72
|
+
- Gemfile
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
32
75
|
- lib/xml-sitemap.rb
|
76
|
+
- lib/xml-sitemap/index.rb
|
77
|
+
- lib/xml-sitemap/map.rb
|
78
|
+
- lib/xml-sitemap/options.rb
|
79
|
+
- lib/xml-sitemap/version.rb
|
80
|
+
- spec/fixtures/empty_index.xml
|
81
|
+
- spec/fixtures/encoded_map.xml
|
82
|
+
- spec/fixtures/sample_index.xml
|
83
|
+
- spec/fixtures/saved_map.xml
|
84
|
+
- spec/fixtures/simple_map.xml
|
85
|
+
- spec/index_spec.rb
|
86
|
+
- spec/map_spec.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
- xml-sitemap.gemspec
|
33
89
|
has_rdoc: true
|
34
90
|
homepage: http://github.com/sosedoff/xml-sitemap
|
35
91
|
licenses: []
|
@@ -44,25 +100,26 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
44
100
|
requirements:
|
45
101
|
- - ">="
|
46
102
|
- !ruby/object:Gem::Version
|
47
|
-
hash: 3
|
48
|
-
segments:
|
49
|
-
- 0
|
50
103
|
version: "0"
|
51
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
105
|
none: false
|
53
106
|
requirements:
|
54
107
|
- - ">="
|
55
108
|
- !ruby/object:Gem::Version
|
56
|
-
|
57
|
-
segments:
|
58
|
-
- 0
|
59
|
-
version: "0"
|
109
|
+
version: 1.3.6
|
60
110
|
requirements: []
|
61
111
|
|
62
112
|
rubyforge_project:
|
63
|
-
rubygems_version: 1.
|
113
|
+
rubygems_version: 1.6.2
|
64
114
|
signing_key:
|
65
115
|
specification_version: 3
|
66
|
-
summary:
|
67
|
-
test_files:
|
68
|
-
|
116
|
+
summary: Simple XML sitemap generator for Ruby/Rails applications.
|
117
|
+
test_files:
|
118
|
+
- spec/fixtures/empty_index.xml
|
119
|
+
- spec/fixtures/encoded_map.xml
|
120
|
+
- spec/fixtures/sample_index.xml
|
121
|
+
- spec/fixtures/saved_map.xml
|
122
|
+
- spec/fixtures/simple_map.xml
|
123
|
+
- spec/index_spec.rb
|
124
|
+
- spec/map_spec.rb
|
125
|
+
- spec/spec_helper.rb
|
data/README
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
== About XmlSitemap
|
2
|
-
|
3
|
-
XmlSitemap is a gem to build website XML sitemaps.
|
4
|
-
|
5
|
-
== How To Use
|
6
|
-
|
7
|
-
require 'rubygems'
|
8
|
-
require 'xml-sitemap'
|
9
|
-
|
10
|
-
== Example
|
11
|
-
|
12
|
-
# Somewhere in controller
|
13
|
-
|
14
|
-
pages = Page.all(:order => [:updated_at.desc] # DM model
|
15
|
-
|
16
|
-
@map = XmlSitemap::Map.new('somedomain.com') do |m|
|
17
|
-
m.add(:url => '/', :period => :daily, :priority => 1.0)
|
18
|
-
m.add(:url => '/contractors', :period => :daily, :priority => 1.0)
|
19
|
-
pages.each do |p|
|
20
|
-
m.add(
|
21
|
-
:url => url_for_page(p),
|
22
|
-
:updated => p.updated_at,
|
23
|
-
:priority => 0.5,
|
24
|
-
:period => :never
|
25
|
-
)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# ... then render it in your view
|
30
|
-
<%= @map.render %>
|
31
|
-
|
32
|
-
== Options
|
33
|
-
|
34
|
-
:url - page path, relative to domain (ex.: /test), String.
|
35
|
-
:period - freqchange attribute, Symbol, :none, :never, :always, :hourly, :daily, :weekly, :monthly, :yearly
|
36
|
-
:priority - priority attribute, Float class,(0.0..1.0)
|
37
|
-
:updated - (optional) last_update attribute, Time class
|