sitemap_generator 4.1.1 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -5,7 +5,7 @@ gem 'sitemap_generator', :path => './'
5
5
 
6
6
  group :development, :test do
7
7
  gem 'mocha'
8
- gem 'nokogiri'
8
+ gem 'nokogiri', '=1.5.10' # last release to support Ruby 1.8.7
9
9
  gem 'rake'
10
10
  gem 'rspec'
11
11
  #gem 'ruby-debug19', :require => 'ruby-debug'
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ./
3
3
  specs:
4
- sitemap_generator (4.1.1)
4
+ sitemap_generator (4.2)
5
5
  builder
6
6
 
7
7
  GEM
@@ -12,7 +12,7 @@ GEM
12
12
  metaclass (0.0.1)
13
13
  mocha (0.10.0)
14
14
  metaclass (~> 0.0.1)
15
- nokogiri (1.5.0)
15
+ nokogiri (1.5.10)
16
16
  rake (10.0.4)
17
17
  rspec (2.8.0)
18
18
  rspec-core (~> 2.8.0)
@@ -29,7 +29,7 @@ PLATFORMS
29
29
  DEPENDENCIES
30
30
  builder
31
31
  mocha
32
- nokogiri
32
+ nokogiri (= 1.5.10)
33
33
  rake
34
34
  rspec
35
35
  sitemap_generator!
data/README.md CHANGED
@@ -105,6 +105,7 @@ That's it! Welcome to the future!
105
105
 
106
106
  ## Changelog
107
107
 
108
+ * v4.2: Update Google ping URL. Quote the ping URL in the output. Support Video `video:price` element ([#117][https://github.com/kjvarga/sitemap_generator/issues/117]). Support symbols as well as strings for most arguments to `add()` ([#113][https://github.com/kjvarga/sitemap_generator/issues/113]). Ensure that `public_path` and `sitemaps_path` end with a slash (`/`) ([#113][https://github.com/kjvarga/sitemap_generator/issues/118]).
108
109
  * v4.1.1: Support setting the S3 region. Fixed bug where incorrect URL was being used in the ping to search engines - only affected sites with a single sitemap file and no index file. Output the URL being pinged in the verbose output. Test in Rails 4.
109
110
  * v4.1.0: [PageMap sitemap][using_pagemaps] support. Tested with Rails 4 pre-release.
110
111
  * v4.0.1: Add a post install message regarding the naming convention change.
@@ -912,6 +913,10 @@ end
912
913
  * `:gallery_title` - Title attribute of the gallery location element
913
914
  * `:uploader`
914
915
  * `:uploader_info` - Info attribute of uploader element
916
+ * `:price` - Only one price supported at this time
917
+ * `:price_currency` - Required. In [ISO_4217][iso_4217] format.
918
+ * `:price_type` - Optional. `rent` or `own`
919
+ * `:price_resolution` - Optional. `HD` or `SD`
915
920
 
916
921
  ### Geo Sitemaps
917
922
 
@@ -1078,3 +1083,4 @@ Copyright (c) 2009 Karl Varga released under the MIT license
1078
1083
  [ehoch]:https://github.com/ehoch
1079
1084
  [alternate_links]:http://support.google.com/webmasters/bin/answer.py?hl=en&answer=2620865
1080
1085
  [using_pagemaps]:https://developers.google.com/custom-search/docs/structured_data#pagemaps
1086
+ [iso_4217]:http://en.wikipedia.org/wiki/ISO_4217
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.1.1
1
+ 4.2.0
@@ -26,7 +26,15 @@ module SitemapGenerator
26
26
  MAX_SITEMAP_IMAGES = 1_000 # max images per url
27
27
  MAX_SITEMAP_NEWS = 1_000 # max news sitemap per index_file
28
28
  MAX_SITEMAP_FILESIZE = SitemapGenerator::Numeric.new(10).megabytes # bytes
29
-
29
+ SCHEMAS = {
30
+ 'geo' => 'http://www.google.com/geo/schemas/sitemap/1.0',
31
+ 'image' => 'http://www.google.com/schemas/sitemap-image/1.1',
32
+ 'mobile' => 'http://www.google.com/schemas/sitemap-mobile/1.0',
33
+ 'news' => 'http://www.google.com/schemas/sitemap-news/0.9',
34
+ 'pagemap' => 'http://www.google.com/schemas/sitemap-pagemap/1.0',
35
+ 'video' => 'http://www.google.com/schemas/sitemap-video/1.1'
36
+ }
37
+
30
38
  # Lazy-initialize the LinkSet instance
31
39
  Sitemap = (Class.new do
32
40
  def method_missing(*args, &block)
@@ -28,15 +28,15 @@ module SitemapGenerator
28
28
  <?xml version="1.0" encoding="UTF-8"?>
29
29
  <urlset
30
30
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
31
- xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
32
31
  xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
33
32
  http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
34
33
  xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
35
- xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"
36
- xmlns:geo="http://www.google.com/geo/schemas/sitemap/1.0"
37
- xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
38
- xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0"
39
- xmlns:pagemap="http://www.google.com/schemas/sitemap-pagemap/1.0"
34
+ xmlns:image="#{SitemapGenerator::SCHEMAS['image']}"
35
+ xmlns:video="#{SitemapGenerator::SCHEMAS['video']}"
36
+ xmlns:geo="#{SitemapGenerator::SCHEMAS['geo']}"
37
+ xmlns:news="#{SitemapGenerator::SCHEMAS['news']}"
38
+ xmlns:mobile="#{SitemapGenerator::SCHEMAS['mobile']}"
39
+ xmlns:pagemap="#{SitemapGenerator::SCHEMAS['pagemap']}"
40
40
  xmlns:xhtml="http://www.w3.org/1999/xhtml"
41
41
  >
42
42
  HTML
@@ -72,72 +72,73 @@ module SitemapGenerator
72
72
  builder.url do
73
73
  builder.loc self[:loc]
74
74
  builder.lastmod w3c_date(self[:lastmod]) if self[:lastmod]
75
- builder.changefreq self[:changefreq] if self[:changefreq]
75
+ builder.changefreq self[:changefreq].to_s if self[:changefreq]
76
76
  builder.priority format_float(self[:priority]) if self[:priority]
77
77
 
78
78
  unless SitemapGenerator::Utilities.blank?(self[:news])
79
79
  news_data = self[:news]
80
80
  builder.news:news do
81
81
  builder.news:publication do
82
- builder.news :name, news_data[:publication_name] if news_data[:publication_name]
83
- builder.news :language, news_data[:publication_language] if news_data[:publication_language]
82
+ builder.news :name, news_data[:publication_name].to_s if news_data[:publication_name]
83
+ builder.news :language, news_data[:publication_language].to_s if news_data[:publication_language]
84
84
  end
85
85
 
86
- builder.news :access, news_data[:access] if news_data[:access]
87
- builder.news :genres, news_data[:genres] if news_data[:genres]
86
+ builder.news :access, news_data[:access].to_s if news_data[:access]
87
+ builder.news :genres, news_data[:genres].to_s if news_data[:genres]
88
88
  builder.news :publication_date, w3c_date(news_data[:publication_date]) if news_data[:publication_date]
89
- builder.news :title, news_data[:title] if news_data[:title]
90
- builder.news :keywords, news_data[:keywords] if news_data[:keywords]
91
- builder.news :stock_tickers, news_data[:stock_tickers] if news_data[:stock_tickers]
89
+ builder.news :title, news_data[:title].to_s if news_data[:title]
90
+ builder.news :keywords, news_data[:keywords].to_s if news_data[:keywords]
91
+ builder.news :stock_tickers, news_data[:stock_tickers].to_s if news_data[:stock_tickers]
92
92
  end
93
93
  end
94
94
 
95
95
  self[:images].each do |image|
96
96
  builder.image:image do
97
97
  builder.image :loc, image[:loc]
98
- builder.image :caption, image[:caption] if image[:caption]
99
- builder.image :geo_location, image[:geo_location] if image[:geo_location]
100
- builder.image :title, image[:title] if image[:title]
101
- builder.image :license, image[:license] if image[:license]
98
+ builder.image :caption, image[:caption].to_s if image[:caption]
99
+ builder.image :geo_location, image[:geo_location].to_s if image[:geo_location]
100
+ builder.image :title, image[:title].to_s if image[:title]
101
+ builder.image :license, image[:license].to_s if image[:license]
102
102
  end
103
103
  end
104
104
 
105
105
  self[:videos].each do |video|
106
106
  builder.video :video do
107
- builder.video :thumbnail_loc, video[:thumbnail_loc]
108
- builder.video :title, video[:title]
109
- builder.video :description, video[:description]
110
- builder.video :content_loc, video[:content_loc] if video[:content_loc]
107
+ builder.video :thumbnail_loc, video[:thumbnail_loc].to_s
108
+ builder.video :title, video[:title].to_s
109
+ builder.video :description, video[:description].to_s
110
+ builder.video :content_loc, video[:content_loc].to_s if video[:content_loc]
111
111
  if video[:player_loc]
112
112
  loc_attributes = { :allow_embed => yes_or_no_with_default(video[:allow_embed], true) }
113
- loc_attributes[:autoplay] = video[:autoplay] if SitemapGenerator::Utilities.present?(video[:autoplay])
114
- builder.video :player_loc, video[:player_loc], loc_attributes
113
+ loc_attributes[:autoplay] = video[:autoplay].to_s if SitemapGenerator::Utilities.present?(video[:autoplay])
114
+ builder.video :player_loc, video[:player_loc].to_s, loc_attributes
115
115
  end
116
- builder.video :duration, video[:duration] if video[:duration]
116
+ builder.video :duration, video[:duration].to_s if video[:duration]
117
117
  builder.video :expiration_date, w3c_date(video[:expiration_date]) if video[:expiration_date]
118
118
  builder.video :rating, format_float(video[:rating]) if video[:rating]
119
- builder.video :view_count, video[:view_count] if video[:view_count]
119
+ builder.video :view_count, video[:view_count].to_s if video[:view_count]
120
120
  builder.video :publication_date, w3c_date(video[:publication_date]) if video[:publication_date]
121
- video[:tags].each {|tag| builder.video :tag, tag } if video[:tags]
122
- builder.video :tag, video[:tag] if video[:tag]
123
- builder.video :category, video[:category] if video[:category]
121
+ video[:tags].each {|tag| builder.video :tag, tag.to_s } if video[:tags]
122
+ builder.video :tag, video[:tag].to_s if video[:tag]
123
+ builder.video :category, video[:category].to_s if video[:category]
124
124
  builder.video :family_friendly, yes_or_no_with_default(video[:family_friendly], true) if video.has_key?(:family_friendly)
125
- builder.video :gallery_loc, video[:gallery_loc], :title => video[:gallery_title] if video[:gallery_loc]
125
+ builder.video :gallery_loc, video[:gallery_loc].to_s, :title => video[:gallery_title].to_s if video[:gallery_loc]
126
+ builder.video :price, video[:price].to_s, prepare_video_price_attribs(video) if SitemapGenerator::Utilities.present?(video[:price])
126
127
  if video[:uploader]
127
- builder.video :uploader, video[:uploader], video[:uploader_info] ? { :info => video[:uploader_info] } : {}
128
+ builder.video :uploader, video[:uploader].to_s, video[:uploader_info] ? { :info => video[:uploader_info].to_s } : {}
128
129
  end
129
130
  end
130
131
  end
131
132
 
132
133
  self[:alternates].each do |alternate|
133
134
  rel = alternate[:nofollow] ? 'alternate nofollow' : 'alternate'
134
- builder.xhtml :link, :rel => rel, :hreflang => alternate[:lang], :href => alternate[:href]
135
+ builder.xhtml :link, :rel => rel, :hreflang => alternate[:lang].to_s, :href => alternate[:href].to_s
135
136
  end
136
137
 
137
138
  unless SitemapGenerator::Utilities.blank?(self[:geo])
138
139
  geo = self[:geo]
139
140
  builder.geo :geo do
140
- builder.geo :format, geo[:format] if geo[:format]
141
+ builder.geo :format, geo[:format].to_s if geo[:format]
141
142
  end
142
143
  end
143
144
 
@@ -148,9 +149,9 @@ module SitemapGenerator
148
149
  unless SitemapGenerator::Utilities.blank?(self[:pagemap])
149
150
  builder.pagemap :PageMap do
150
151
  SitemapGenerator::Utilities.as_array(self[:pagemap][:dataobjects]).each do |dataobject|
151
- builder.pagemap :DataObject, :type => dataobject[:type], :id => dataobject[:id] do
152
+ builder.pagemap :DataObject, :type => dataobject[:type].to_s, :id => dataobject[:id].to_s do
152
153
  SitemapGenerator::Utilities.as_array(dataobject[:attributes]).each do |attribute|
153
- builder.pagemap :Attribute, attribute[:value], :name => attribute[:name]
154
+ builder.pagemap :Attribute, attribute[:value].to_s, :name => attribute[:name].to_s
154
155
  end
155
156
  end
156
157
  end
@@ -166,6 +167,14 @@ module SitemapGenerator
166
167
 
167
168
  protected
168
169
 
170
+ def prepare_video_price_attribs(video)
171
+ attribs = {}
172
+ attribs[:currency] = video[:price_currency].to_s # required
173
+ attribs[:type] = video[:price_type] if SitemapGenerator::Utilities.present?(video[:price_type])
174
+ attribs[:resolution] = video[:price_resolution] if SitemapGenerator::Utilities.present?(video[:price_resolution])
175
+ attribs
176
+ end
177
+
169
178
  def prepare_news(news)
170
179
  SitemapGenerator::Utilities.assert_valid_keys(news, :publication_name, :publication_language, :publication_date, :genres, :access, :title, :keywords, :stock_tickers) unless news.empty?
171
180
  news
@@ -34,7 +34,7 @@ module SitemapGenerator
34
34
  set_options(opts)
35
35
  if verbose
36
36
  start_time = Time.now
37
- puts "In #{sitemap_index.location.public_path}"
37
+ puts "In '#{sitemap_index.location.public_path}':"
38
38
  end
39
39
  interpreter.eval(:yield_sitemap => yield_sitemap?, &block)
40
40
  finalize!
@@ -123,7 +123,7 @@ module SitemapGenerator
123
123
  :include_index => false,
124
124
  :filename => :sitemap,
125
125
  :search_engines => {
126
- :google => "http://www.google.com/webmasters/sitemaps/ping?sitemap=%s",
126
+ :google => "http://www.google.com/webmasters/tools/ping?sitemap=%s",
127
127
  :bing => "http://www.bing.com/webmaster/ping.aspx?siteMap=%s",
128
128
  :sitemap_writer => "http://www.sitemapwriter.com/notify.php?crawler=all&url=%s"
129
129
  },
@@ -285,7 +285,7 @@ module SitemapGenerator
285
285
  index_url = CGI.escape(unescaped_url)
286
286
 
287
287
  output("\n")
288
- output("Pinging with URL #{unescaped_url}:")
288
+ output("Pinging with URL '#{unescaped_url}':")
289
289
  search_engines.merge(engines).each do |engine, link|
290
290
  link = link % index_url
291
291
  name = Utilities.titleize(engine.to_s)
@@ -506,8 +506,10 @@ module SitemapGenerator
506
506
  #
507
507
  # Set to nil to use the current directory.
508
508
  def public_path=(value)
509
- @public_path = Pathname.new(value.to_s)
510
- @public_path = SitemapGenerator.app.root + @public_path if @public_path.relative?
509
+ @public_path = Pathname.new(SitemapGenerator::Utilities.append_slash(value))
510
+ if @public_path.relative?
511
+ @public_path = SitemapGenerator.app.root + @public_path
512
+ end
511
513
  update_location_info(:public_path, @public_path)
512
514
  @public_path
513
515
  end
@@ -10,7 +10,7 @@ module SitemapGenerator
10
10
 
11
11
  [:public_path, :sitemaps_path].each do |method|
12
12
  define_method(method) do
13
- Pathname.new(self[method].nil? ? '' : self[method].to_s)
13
+ Pathname.new(SitemapGenerator::Utilities.append_slash(self[method]))
14
14
  end
15
15
  end
16
16
 
@@ -151,5 +151,16 @@ module SitemapGenerator
151
151
  def falsy?(value)
152
152
  ['0', 0, 'f', 'false', false].include?(value)
153
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
154
165
  end
155
166
  end
@@ -14,7 +14,7 @@ describe "SitemapGenerator" do
14
14
  ).to_xml
15
15
 
16
16
  # Check that the options were parsed correctly
17
- doc = Nokogiri::XML.parse("<root xmlns:geo='http://www.google.com/geo/schemas/sitemap/1.0'>#{geo_xml_fragment}</root>")
17
+ doc = Nokogiri::XML.parse("<root xmlns:geo='#{SitemapGenerator::SCHEMAS['geo']}'>#{geo_xml_fragment}</root>")
18
18
  url = doc.at_xpath("//url")
19
19
  url.should_not be_nil
20
20
  url.at_xpath("loc").text.should == loc
@@ -25,6 +25,6 @@ describe "SitemapGenerator" do
25
25
 
26
26
  # Google's documentation and published schema don't match some valid elements may
27
27
  # not validate.
28
- xml_fragment_should_validate_against_schema(geo, 'http://www.google.com/geo/schemas/sitemap/1.0', 'sitemap-geo')
28
+ xml_fragment_should_validate_against_schema(geo, 'sitemap-geo', 'xmlns:geo' => SitemapGenerator::SCHEMAS['geo'])
29
29
  end
30
30
  end
@@ -72,15 +72,26 @@ describe SitemapGenerator::LinkSet do
72
72
 
73
73
  describe "sitemaps public_path" do
74
74
  it "should default to public/" do
75
- ls.public_path.should == SitemapGenerator.app.root + 'public/'
76
- ls.sitemap.location.public_path.should == ls.public_path
77
- ls.sitemap_index.location.public_path.should == ls.public_path
75
+ path = SitemapGenerator.app.root + 'public/'
76
+ ls.public_path.should == path
77
+ ls.sitemap.location.public_path.should == path
78
+ ls.sitemap_index.location.public_path.should == path
78
79
  end
79
80
 
80
81
  it "should change when the public_path is changed" do
82
+ path = SitemapGenerator.app.root + 'tmp/'
83
+ ls.public_path = 'tmp/'
84
+ ls.public_path.should == path
85
+ ls.sitemap.location.public_path.should == path
86
+ ls.sitemap_index.location.public_path.should == path
87
+ end
88
+
89
+ it "should append a slash to the path" do
90
+ path = SitemapGenerator.app.root + 'tmp/'
81
91
  ls.public_path = 'tmp'
82
- ls.sitemap.location.public_path.should == ls.public_path
83
- ls.sitemap_index.location.public_path.should == ls.public_path
92
+ ls.public_path.should == path
93
+ ls.sitemap.location.public_path.should == path
94
+ ls.sitemap_index.location.public_path.should == path
84
95
  end
85
96
  end
86
97
 
@@ -98,6 +109,13 @@ describe SitemapGenerator::LinkSet do
98
109
  ls.sitemap.location.url.should == 'http://one.com/sitemaps/sitemap.xml.gz'
99
110
  ls.sitemap_index.location.url.should == 'http://one.com/sitemaps/sitemap.xml.gz'
100
111
  end
112
+
113
+ it "should append a slash to the path" do
114
+ ls.default_host = 'http://one.com'
115
+ ls.sitemaps_path = 'sitemaps'
116
+ ls.sitemap.location.url.should == 'http://one.com/sitemaps/sitemap.xml.gz'
117
+ ls.sitemap_index.location.url.should == 'http://one.com/sitemaps/sitemap.xml.gz'
118
+ end
101
119
  end
102
120
 
103
121
  describe "sitemap_index_url" do
@@ -317,7 +335,7 @@ describe SitemapGenerator::LinkSet do
317
335
  path = 'new/path'
318
336
  group = ls.group(:sitemaps_path => path)
319
337
  group.sitemaps_path.should == path
320
- group.sitemap.location.sitemaps_path.to_s.should == path
338
+ group.sitemap.location.sitemaps_path.to_s.should == 'new/path/'
321
339
  end
322
340
  end
323
341
 
@@ -489,7 +507,7 @@ describe SitemapGenerator::LinkSet do
489
507
  path = 'new/path'
490
508
  ls.create(:sitemaps_path => path)
491
509
  ls.sitemaps_path.should == path
492
- ls.sitemap.location.sitemaps_path.to_s.should == path
510
+ ls.sitemap.location.sitemaps_path.to_s.should == 'new/path/'
493
511
  end
494
512
 
495
513
  it "should set the default_host" do
@@ -12,7 +12,7 @@ describe "SitemapGenerator" do
12
12
  ).to_xml
13
13
 
14
14
  # Check that the options were parsed correctly
15
- doc = Nokogiri::XML.parse("<root xmlns:mobile='http://www.google.com/schemas/sitemap-mobile/1.0'>#{mobile_xml_fragment}</root>")
15
+ doc = Nokogiri::XML.parse("<root xmlns:mobile='#{SitemapGenerator::SCHEMAS['mobile']}'>#{mobile_xml_fragment}</root>")
16
16
  url = doc.at_xpath("//url")
17
17
  url.should_not be_nil
18
18
  url.at_xpath("loc").text.should == loc
@@ -22,6 +22,6 @@ describe "SitemapGenerator" do
22
22
 
23
23
  # Google's documentation and published schema don't match some valid elements may
24
24
  # not validate.
25
- xml_fragment_should_validate_against_schema(mobile, 'http://www.google.com/schemas/sitemap-mobile/1.0', 'sitemap-mobile')
25
+ xml_fragment_should_validate_against_schema(mobile, 'sitemap-mobile', 'xmlns:mobile' => SitemapGenerator::SCHEMAS['mobile'])
26
26
  end
27
27
  end
@@ -20,7 +20,7 @@ describe "SitemapGenerator" do
20
20
  }
21
21
  }).to_xml
22
22
 
23
- doc = Nokogiri::XML.parse("<root xmlns:news='http://www.google.com/schemas/sitemap-news/0.9'>#{news_xml_fragment}</root>")
23
+ doc = Nokogiri::XML.parse("<root xmlns:news='#{SitemapGenerator::SCHEMAS['news']}'>#{news_xml_fragment}</root>")
24
24
 
25
25
  url = doc.at_xpath("//url")
26
26
  loc = url.at_xpath("loc")
@@ -37,6 +37,6 @@ describe "SitemapGenerator" do
37
37
  news.at_xpath("//news:name").text.should == "Example"
38
38
  news.at_xpath("//news:language").text.should == "en"
39
39
 
40
- xml_fragment_should_validate_against_schema(news, 'http://www.google.com/schemas/sitemap-news/0.9', 'sitemap-news')
40
+ xml_fragment_should_validate_against_schema(news, 'sitemap-news', 'xmlns:news' => SitemapGenerator::SCHEMAS['news'])
41
41
  end
42
42
  end
@@ -1,7 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "SitemapGenerator" do
4
-
4
+ let(:schema) { SitemapGenerator::SCHEMAS['pagemap'] }
5
+
5
6
  it "should add the pagemap sitemap element" do
6
7
  pagemap_xml_fragment = SitemapGenerator::Builder::SitemapUrl.new('my_page.html', {
7
8
  :host => 'http://www.example.com',
@@ -9,42 +10,48 @@ describe "SitemapGenerator" do
9
10
  :pagemap => {
10
11
  :dataobjects => [
11
12
  {
12
- type: 'document',
13
- id: 'hibachi',
14
- attributes: [
15
- {name: 'name', value: 'Dragon'},
16
- {name: 'review', value: 3.5},
13
+ :type => 'document',
14
+ :id => 'hibachi',
15
+ :attributes => [
16
+ {:name => 'name', :value => 'Dragon'},
17
+ {:name => 'review', :value => 3.5},
17
18
  ]
18
19
  },
19
20
  {
20
- type: 'stats',
21
- attributes: [
22
- {name: 'installs', value: 2000},
23
- {name: 'comments', value: 200},
21
+ :type => 'stats',
22
+ :attributes => [
23
+ {:name => 'installs', :value => 2000},
24
+ {:name => 'comments', :value => 200},
24
25
  ]
25
26
  }
26
27
  ]
27
28
  }
28
29
  }).to_xml
29
30
 
31
+ # Nokogiri is a fickle beast. We have to add the namespace and define
32
+ # the prefix in order for XPath queries to work. And then we have to
33
+ # reingest because otherwise Nokogiri doesn't use it.
30
34
  doc = Nokogiri::XML.parse(pagemap_xml_fragment)
31
-
35
+ doc.root.add_namespace_definition('pagemap', schema)
36
+ doc = Nokogiri::XML.parse(doc.to_xml)
37
+
32
38
  url = doc.at_xpath("//url")
33
39
  loc = url.at_xpath("loc")
34
40
  loc.text.should == 'http://www.example.com/my_page.html'
35
-
36
- pagemap = doc.at_xpath("//PageMap")
37
- pagemap.children.count.should == 2
38
- pagemap.at_xpath('//DataObject').attributes['type'].value.should == 'document'
39
- pagemap.at_xpath('//DataObject').attributes['id'].value.should == 'hibachi'
40
- pagemap.at_xpath('//DataObject').children.count.should == 2
41
- first_attribute = pagemap.at_xpath('//DataObject').children.first
42
- second_attribute = pagemap.at_xpath('//DataObject').children.last
41
+
42
+ pagemap = doc.at_xpath('//pagemap:PageMap', 'pagemap' => schema)
43
+ pagemap.element_children.count.should == 2
44
+ dataobject = pagemap.at_xpath('//pagemap:DataObject')
45
+ dataobject.attributes['type'].value.should == 'document'
46
+ dataobject.attributes['id'].value.should == 'hibachi'
47
+ dataobject.element_children.count.should == 2
48
+ first_attribute = dataobject.element_children.first
49
+ second_attribute = dataobject.element_children.last
43
50
  first_attribute.text.should == 'Dragon'
44
51
  first_attribute.attributes['name'].value.should == 'name'
45
52
  second_attribute.text.should == '3.5'
46
53
  second_attribute.attributes['name'].value.should == 'review'
47
54
 
48
- xml_fragment_should_validate_against_schema(pagemap, 'http://www.google.com/schemas/sitemap-pagemap/1.0', 'sitemap-pagemap')
55
+ xml_fragment_should_validate_against_schema(pagemap, 'sitemap-pagemap', 'xmlns:pagemap' => schema)
49
56
  end
50
57
  end
@@ -112,6 +112,37 @@ describe SitemapGenerator::SitemapLocation do
112
112
  location.filesize
113
113
  end
114
114
  end
115
+
116
+ describe "public_path" do
117
+ it "should append a trailing slash" do
118
+ location = SitemapGenerator::SitemapLocation.new(:public_path => 'public/google')
119
+ location.public_path.to_s.should == 'public/google/'
120
+ location[:public_path] = 'new/path'
121
+ location.public_path.to_s.should == 'new/path/'
122
+ location[:public_path] = 'already/slashed/'
123
+ location.public_path.to_s.should == 'already/slashed/'
124
+ end
125
+ end
126
+
127
+ describe "sitemaps_path" do
128
+ it "should append a trailing slash" do
129
+ location = SitemapGenerator::SitemapLocation.new(:sitemaps_path => 'public/google')
130
+ location.sitemaps_path.to_s.should == 'public/google/'
131
+ location[:sitemaps_path] = 'new/path'
132
+ location.sitemaps_path.to_s.should == 'new/path/'
133
+ location[:sitemaps_path] = 'already/slashed/'
134
+ location.sitemaps_path.to_s.should == 'already/slashed/'
135
+ end
136
+ end
137
+
138
+ describe "url" do
139
+ it "should handle paths not ending in slash" do
140
+ location = SitemapGenerator::SitemapLocation.new(
141
+ :public_path => 'public/google', :filename => 'xxx',
142
+ :host => default_host, :sitemaps_path => 'sub/dir')
143
+ location.url.should == default_host + '/sub/dir/xxx'
144
+ end
145
+ end
115
146
  end
116
147
 
117
148
  describe SitemapGenerator::SitemapIndexLocation do
@@ -66,4 +66,14 @@ describe SitemapGenerator::Utilities do
66
66
  SitemapGenerator::Utilities.as_array({}).should == [{}]
67
67
  end
68
68
  end
69
+
70
+ describe "append_slash" do
71
+ SitemapGenerator::Utilities.append_slash('').should == ''
72
+ SitemapGenerator::Utilities.append_slash(nil).should == ''
73
+ SitemapGenerator::Utilities.append_slash(Pathname.new('')).should == ''
74
+ SitemapGenerator::Utilities.append_slash('tmp').should == 'tmp/'
75
+ SitemapGenerator::Utilities.append_slash(Pathname.new('tmp')).should == 'tmp/'
76
+ SitemapGenerator::Utilities.append_slash('tmp/').should == 'tmp/'
77
+ SitemapGenerator::Utilities.append_slash(Pathname.new('tmp/')).should == 'tmp/'
78
+ end
69
79
  end
@@ -28,7 +28,11 @@ describe "SitemapGenerator" do
28
28
  :family_friendly => true,
29
29
  :view_count => 123,
30
30
  :duration => 456,
31
- :rating => 0.499999999
31
+ :rating => 0.499999999,
32
+ :price => 123.45,
33
+ :price_currency => 'CAD',
34
+ :price_resolution => 'HD',
35
+ :price_type => 'rent'
32
36
  }
33
37
  end
34
38
 
@@ -42,7 +46,7 @@ describe "SitemapGenerator" do
42
46
 
43
47
  # Return a Nokogiri document from the XML. The root of the document is the <URL> element.
44
48
  def video_doc(xml)
45
- Nokogiri::XML.parse("<root xmlns:video='http://www.google.com/schemas/sitemap-video/1.1'>#{xml}</root>")
49
+ Nokogiri::XML.parse("<root xmlns:video='#{SitemapGenerator::SCHEMAS['video']}'>#{xml}</root>")
46
50
  end
47
51
 
48
52
  # Validate the contents of the video element
@@ -65,7 +69,11 @@ describe "SitemapGenerator" do
65
69
  video_doc.at_xpath("video:player_loc").attribute('autoplay').text.should == video_options[:autoplay]
66
70
  video_doc.at_xpath("video:uploader").text.should == video_options[:uploader]
67
71
  video_doc.at_xpath("video:uploader").attribute("info").text.should == video_options[:uploader_info]
68
- xml_fragment_should_validate_against_schema(video_doc, 'http://www.google.com/schemas/sitemap-video/1.1', 'sitemap-video')
72
+ video_doc.at_xpath("video:price").text.should == video_options[:price].to_s
73
+ video_doc.at_xpath("video:price").attribute("resolution").text.should == video_options[:price_resolution].to_s
74
+ video_doc.at_xpath("video:price").attribute("type").text.should == video_options[:price_type].to_s
75
+ video_doc.at_xpath("video:price").attribute("currency").text.should == video_options[:price_currency].to_s
76
+ xml_fragment_should_validate_against_schema(video_doc, 'sitemap-video', 'xmlns:video' => SitemapGenerator::SCHEMAS['video'])
69
77
  end
70
78
 
71
79
  it "should add a valid video sitemap element" do
@@ -50,9 +50,19 @@
50
50
  </xsd:restriction>
51
51
  </xsd:simpleType>
52
52
 
53
- <xsd:simpleType name="tNonNegativeDecimal">
54
- <xsd:restriction base="xsd:decimal">
55
- <xsd:minInclusive value="0"/>
53
+ <xsd:simpleType name="tPlatformList">
54
+ <xsd:annotation>
55
+ <xsd:documentation>
56
+ Space-separated platform names.
57
+
58
+ Platform names:
59
+ web - desktop and laptop browsers.
60
+ mobile - mobile devices such as phones and tablets.
61
+ tv - tv platforms such as GoogleTV.
62
+ </xsd:documentation>
63
+ </xsd:annotation>
64
+ <xsd:restriction base="xsd:string">
65
+ <xsd:pattern value="((web|mobile|tv)( (web|mobile|tv))*)?"/>
56
66
  </xsd:restriction>
57
67
  </xsd:simpleType>
58
68
 
@@ -63,11 +73,12 @@
63
73
  <xsd:annotation>
64
74
  <xsd:documentation>
65
75
  A URL pointing to the URL for the video thumbnail image file. We can
66
- accept most image sizes/types but recommend your thumbs are at least
67
- 120x90 pixels in .jpg, .png, or. gif formats.
76
+ accept most image sizes/types but recommend your thumbnails are at
77
+ least 120x90 pixels in .jpg, .png, or. gif formats.
68
78
  </xsd:documentation>
69
79
  </xsd:annotation>
70
80
  </xsd:element>
81
+
71
82
  <xsd:element name="title">
72
83
  <xsd:annotation>
73
84
  <xsd:documentation>
@@ -80,6 +91,7 @@
80
91
  </xsd:restriction>
81
92
  </xsd:simpleType>
82
93
  </xsd:element>
94
+
83
95
  <xsd:element name="description">
84
96
  <xsd:annotation>
85
97
  <xsd:documentation>
@@ -92,6 +104,7 @@
92
104
  </xsd:restriction>
93
105
  </xsd:simpleType>
94
106
  </xsd:element>
107
+
95
108
  <xsd:element name="content_loc" minOccurs="0" type="xsd:anyURI">
96
109
  <xsd:annotation>
97
110
  <xsd:documentation>
@@ -107,6 +120,7 @@
107
120
  </xsd:documentation>
108
121
  </xsd:annotation>
109
122
  </xsd:element>
123
+
110
124
  <xsd:element name="player_loc" minOccurs="0">
111
125
  <xsd:annotation>
112
126
  <xsd:documentation>
@@ -148,6 +162,7 @@
148
162
  </xsd:simpleContent>
149
163
  </xsd:complexType>
150
164
  </xsd:element>
165
+
151
166
  <xsd:element name="duration" minOccurs="0">
152
167
  <xsd:annotation>
153
168
  <xsd:documentation>
@@ -160,6 +175,7 @@
160
175
  </xsd:restriction>
161
176
  </xsd:simpleType>
162
177
  </xsd:element>
178
+
163
179
  <xsd:element name="expiration_date" minOccurs="0">
164
180
  <xsd:annotation>
165
181
  <xsd:documentation>
@@ -181,6 +197,7 @@
181
197
  </xsd:union>
182
198
  </xsd:simpleType>
183
199
  </xsd:element>
200
+
184
201
  <xsd:element name="rating" minOccurs="0">
185
202
  <xsd:annotation>
186
203
  <xsd:documentation>
@@ -194,6 +211,7 @@
194
211
  </xsd:restriction>
195
212
  </xsd:simpleType>
196
213
  </xsd:element>
214
+
197
215
  <xsd:element name="content_segment_loc"
198
216
  minOccurs="0"
199
217
  maxOccurs="unbounded">
@@ -231,6 +249,7 @@
231
249
  </xsd:simpleContent>
232
250
  </xsd:complexType>
233
251
  </xsd:element>
252
+
234
253
  <xsd:element name="view_count"
235
254
  minOccurs="0"
236
255
  type="xsd:nonNegativeInteger">
@@ -240,6 +259,7 @@
240
259
  </xsd:documentation>
241
260
  </xsd:annotation>
242
261
  </xsd:element>
262
+
243
263
  <xsd:element name="publication_date" minOccurs="0">
244
264
  <xsd:annotation>
245
265
  <xsd:documentation>
@@ -260,6 +280,7 @@
260
280
  </xsd:union>
261
281
  </xsd:simpleType>
262
282
  </xsd:element>
283
+
263
284
  <xsd:element name="tag" type="xsd:string" minOccurs="0" maxOccurs="32">
264
285
  <xsd:annotation>
265
286
  <xsd:documentation>
@@ -273,10 +294,11 @@
273
294
  </xsd:documentation>
274
295
  </xsd:annotation>
275
296
  </xsd:element>
297
+
276
298
  <xsd:element name="category" minOccurs="0">
277
299
  <xsd:annotation>
278
300
  <xsd:documentation>
279
- The video's category. For example, cooking. In general, categories
301
+ The video's category - for example, cooking. In general, categories
280
302
  are broad groupings of content by subject. For example, a site about
281
303
  cooking could have categories for Broiling, Baking, and Grilling.
282
304
  </xsd:documentation>
@@ -287,6 +309,7 @@
287
309
  </xsd:restriction>
288
310
  </xsd:simpleType>
289
311
  </xsd:element>
312
+
290
313
  <xsd:element name="family_friendly" minOccurs="0" type="tYesNo">
291
314
  <xsd:annotation>
292
315
  <xsd:documentation>
@@ -295,6 +318,7 @@
295
318
  </xsd:documentation>
296
319
  </xsd:annotation>
297
320
  </xsd:element>
321
+
298
322
  <xsd:element name="restriction" minOccurs="0">
299
323
  <xsd:annotation>
300
324
  <xsd:documentation>
@@ -324,6 +348,7 @@
324
348
  </xsd:simpleContent>
325
349
  </xsd:complexType>
326
350
  </xsd:element>
351
+
327
352
  <xsd:element name="gallery_loc" minOccurs="0">
328
353
  <xsd:annotation>
329
354
  <xsd:documentation>
@@ -345,21 +370,27 @@
345
370
  </xsd:simpleContent>
346
371
  </xsd:complexType>
347
372
  </xsd:element>
373
+
348
374
  <xsd:element name="price" minOccurs="0" maxOccurs="unbounded">
349
375
  <xsd:annotation>
350
376
  <xsd:documentation>
351
377
  The price to download or view the video. More than one
352
378
  &lt;video:price&gt; element can be listed (for example, in order to
353
- specify various currencies).
379
+ specify various currencies). The price value must either be a
380
+ non-negative decimal or be empty. If a price value is specified, the
381
+ currency attribute is required. If no price value is specified, the
382
+ type attribute must be valid and present. The resolution attribute
383
+ is optional.
354
384
  </xsd:documentation>
355
385
  </xsd:annotation>
356
386
  <xsd:complexType>
357
387
  <xsd:simpleContent>
358
- <xsd:extension base="tNonNegativeDecimal">
359
- <xsd:attribute name="currency" use="required">
388
+ <xsd:extension base="xsd:string">
389
+ <xsd:attribute name="currency">
360
390
  <xsd:annotation>
361
391
  <xsd:documentation>
362
- The currency in ISO 4217 format.
392
+ The currency in ISO 4217 format. This attribute is required
393
+ if a value is given for price.
363
394
  </xsd:documentation>
364
395
  </xsd:annotation>
365
396
  <xsd:simpleType>
@@ -368,10 +399,42 @@
368
399
  </xsd:restriction>
369
400
  </xsd:simpleType>
370
401
  </xsd:attribute>
402
+ <xsd:attribute name="type">
403
+ <xsd:annotation>
404
+ <xsd:documentation>
405
+ The type (purchase or rent) of price. This value is required
406
+ if there is no value given for price.
407
+ </xsd:documentation>
408
+ </xsd:annotation>
409
+ <xsd:simpleType>
410
+ <xsd:restriction base="xsd:string">
411
+ <xsd:enumeration value="purchase"/>
412
+ <xsd:enumeration value="PURCHASE"/>
413
+ <xsd:enumeration value="rent"/>
414
+ <xsd:enumeration value="RENT"/>
415
+ </xsd:restriction>
416
+ </xsd:simpleType>
417
+ </xsd:attribute>
418
+ <xsd:attribute name="resolution">
419
+ <xsd:annotation>
420
+ <xsd:documentation>
421
+ The resolution of the video at this price (SD or HD).
422
+ </xsd:documentation>
423
+ </xsd:annotation>
424
+ <xsd:simpleType>
425
+ <xsd:restriction base="xsd:string">
426
+ <xsd:enumeration value="sd"/>
427
+ <xsd:enumeration value="SD"/>
428
+ <xsd:enumeration value="hd"/>
429
+ <xsd:enumeration value="HD"/>
430
+ </xsd:restriction>
431
+ </xsd:simpleType>
432
+ </xsd:attribute>
371
433
  </xsd:extension>
372
434
  </xsd:simpleContent>
373
435
  </xsd:complexType>
374
436
  </xsd:element>
437
+
375
438
  <xsd:element name="requires_subscription" minOccurs="0" type="tYesNo">
376
439
  <xsd:annotation>
377
440
  <xsd:documentation>
@@ -380,6 +443,7 @@
380
443
  </xsd:documentation>
381
444
  </xsd:annotation>
382
445
  </xsd:element>
446
+
383
447
  <xsd:element name="uploader" minOccurs="0">
384
448
  <xsd:annotation>
385
449
  <xsd:documentation>
@@ -402,8 +466,178 @@
402
466
  </xsd:simpleContent>
403
467
  </xsd:complexType>
404
468
  </xsd:element>
469
+
470
+ <xsd:element name="tvshow" minOccurs="0">
471
+ <xsd:annotation>
472
+ <xsd:documentation>
473
+ Encloses all information about a single TV video.
474
+ </xsd:documentation>
475
+ </xsd:annotation>
476
+ <xsd:complexType>
477
+ <xsd:sequence>
478
+ <xsd:element name="show_title" type="xsd:string">
479
+ <xsd:annotation>
480
+ <xsd:documentation>
481
+ The title of the TV show. This should be the same for all
482
+ episodes from the same series.
483
+ </xsd:documentation>
484
+ </xsd:annotation>
485
+ </xsd:element>
486
+ <xsd:element name="video_type">
487
+ <xsd:annotation>
488
+ <xsd:documentation>
489
+ Describes the relationship of the video to the specified
490
+ TV show/episode.
491
+ </xsd:documentation>
492
+ </xsd:annotation>
493
+ <xsd:simpleType>
494
+ <xsd:restriction base="xsd:string">
495
+ <!-- Complete episode -->
496
+ <xsd:enumeration value="full"/>
497
+ <!-- Episode promo -->
498
+ <xsd:enumeration value="preview"/>
499
+ <!-- Episode clip -->
500
+ <xsd:enumeration value="clip"/>
501
+ <!-- Interview -->
502
+ <xsd:enumeration value="interview"/>
503
+ <!-- News related to the content -->
504
+ <xsd:enumeration value="news"/>
505
+ <!-- If none of the above options accurately describe
506
+ the relationship -->
507
+ <xsd:enumeration value="other"/>
508
+ </xsd:restriction>
509
+ </xsd:simpleType>
510
+ </xsd:element>
511
+ <xsd:element name="episode_title" type="xsd:string" minOccurs="0">
512
+ <xsd:annotation>
513
+ <xsd:documentation>
514
+ The title of the episode—for example, "Flesh and Bone" is the
515
+ title of the Season 1, Episode 8 episode of Battlestar
516
+ Galactica. This tag is not necessary if the video is not
517
+ related to a specific episode (for example, if it's a trailer
518
+ for an entire series or season).
519
+ </xsd:documentation>
520
+ </xsd:annotation>
521
+ </xsd:element>
522
+ <xsd:element name="season_number" minOccurs="0">
523
+ <xsd:annotation>
524
+ <xsd:documentation>
525
+ Only for shows with a per-season schedule.
526
+ </xsd:documentation>
527
+ </xsd:annotation>
528
+ <xsd:simpleType>
529
+ <xsd:restriction base="xsd:integer">
530
+ <xsd:minInclusive value="1"/>
531
+ </xsd:restriction>
532
+ </xsd:simpleType>
533
+ </xsd:element>
534
+ <xsd:element name="episode_number" minOccurs="0">
535
+ <xsd:annotation>
536
+ <xsd:documentation>
537
+ The episode number in number format. For TV shoes with a
538
+ per-season schedule, the first episode of each series should
539
+ be numbered 1.
540
+ </xsd:documentation>
541
+ </xsd:annotation>
542
+ <xsd:simpleType>
543
+ <xsd:restriction base="xsd:integer">
544
+ <xsd:minInclusive value="1"/>
545
+ </xsd:restriction>
546
+ </xsd:simpleType>
547
+ </xsd:element>
548
+ <xsd:element name="premier_date" minOccurs="0">
549
+ <xsd:annotation>
550
+ <xsd:documentation>
551
+ The date the content of the video was first broadcast, in
552
+ W3C format (for example, 2010-11-05.)
553
+ </xsd:documentation>
554
+ </xsd:annotation>
555
+ <xsd:simpleType>
556
+ <xsd:union>
557
+ <xsd:simpleType>
558
+ <xsd:restriction base="xsd:date"/>
559
+ </xsd:simpleType>
560
+ <xsd:simpleType>
561
+ <xsd:restriction base="xsd:dateTime"/>
562
+ </xsd:simpleType>
563
+ </xsd:union>
564
+ </xsd:simpleType>
565
+ </xsd:element>
566
+ </xsd:sequence>
567
+ </xsd:complexType>
568
+ </xsd:element>
569
+
570
+ <xsd:element name="platform" minOccurs="0">
571
+ <xsd:annotation>
572
+ <xsd:documentation>
573
+ A list of platforms where the video may or may not be played.
574
+ If there is no &lt;video:platform&gt; tag, it is assumed that
575
+ the video can be played on all platforms.
576
+ </xsd:documentation>
577
+ </xsd:annotation>
578
+ <xsd:complexType>
579
+ <xsd:simpleContent>
580
+ <xsd:extension base="tPlatformList">
581
+ <xsd:attribute name="relationship" use="required">
582
+ <xsd:annotation>
583
+ <xsd:documentation>
584
+ Attribute "relationship" specifies whether the video is
585
+ restricted or permitted for the specified platforms.
586
+ </xsd:documentation>
587
+ </xsd:annotation>
588
+ <xsd:simpleType>
589
+ <xsd:restriction base="xsd:string">
590
+ <xsd:enumeration value="allow"/>
591
+ <xsd:enumeration value="deny"/>
592
+ </xsd:restriction>
593
+ </xsd:simpleType>
594
+ </xsd:attribute>
595
+ </xsd:extension>
596
+ </xsd:simpleContent>
597
+ </xsd:complexType>
598
+ </xsd:element>
599
+
600
+ <xsd:element name="live" minOccurs="0" type="tYesNo">
601
+ <xsd:annotation>
602
+ <xsd:documentation>
603
+ Whether the video is a live internet broadcast.
604
+ </xsd:documentation>
605
+ </xsd:annotation>
606
+ </xsd:element>
607
+
608
+ <xsd:element name="id" minOccurs="0" maxOccurs="unbounded">
609
+ <xsd:annotation>
610
+ <xsd:documentation>
611
+ An unambiguous identifier for the video within a given
612
+ identification context.
613
+ </xsd:documentation>
614
+ </xsd:annotation>
615
+ <xsd:complexType>
616
+ <xsd:simpleContent>
617
+ <xsd:extension base="xsd:string">
618
+ <xsd:attribute name="type" use="required">
619
+ <xsd:annotation>
620
+ <xsd:documentation>
621
+ The identification context.
622
+ </xsd:documentation>
623
+ </xsd:annotation>
624
+ <xsd:simpleType>
625
+ <xsd:restriction base="xsd:string">
626
+ <xsd:enumeration value="tms:series"/>
627
+ <xsd:enumeration value="tms:program"/>
628
+ <xsd:enumeration value="rovi:series"/>
629
+ <xsd:enumeration value="rovi:program"/>
630
+ <xsd:enumeration value="freebase"/>
631
+ <xsd:enumeration value="url"/>
632
+ </xsd:restriction>
633
+ </xsd:simpleType>
634
+ </xsd:attribute>
635
+ </xsd:extension>
636
+ </xsd:simpleContent>
637
+ </xsd:complexType>
638
+ </xsd:element>
405
639
  </xsd:sequence>
406
640
  </xsd:complexType>
407
641
  </xsd:element>
408
642
 
409
- </xsd:schema>
643
+ </xsd:schema>
@@ -8,6 +8,10 @@ module XmlMacros
8
8
  end
9
9
  end
10
10
 
11
+ # Validate XML against a local schema file.
12
+ #
13
+ # `schema_name` gives the name of the schema file to validate against. The schema
14
+ # file is looked for in `spec/support/schemas/<schema_name>.xsd`.
11
15
  def xml_data_should_validate_against_schema(xml, schema_name)
12
16
  xml = xml.is_a?(String) ? xml : xml.to_s
13
17
  doc = Nokogiri::XML(xml)
@@ -26,15 +30,23 @@ module XmlMacros
26
30
  #
27
31
  # Element 'video': No matching global declaration available for the validation root.
28
32
  #
29
- # <tt>xmlns</tt> the XML namespace of the root element.
30
- # <tt>xml_fragment</tt> XML string
33
+ # <tt>xml</tt> The XML fragment
34
+ # <tt>schema_name</tt> the name of the schema file to validate against. The schema
35
+ # file is looked for in `spec/support/schemas/<schema_name>.xsd`.
36
+ # <tt>xmlns</tt> A hash with only one key which gives the XML namespace and associated
37
+ # URI. Sometimes one needs to specify a prefix to the namespace, in which case this would
38
+ # look like: 'xmlns:video' => 'http://www.google.com/schemas/sitemap-video/1.1'
31
39
  #
32
40
  # Example:
33
- # xml_fragment_should_validate('<video/>', { 'video' => 'http://www.google.com/schemas/sitemap-video/1.1' })
34
- def xml_fragment_should_validate_against_schema(xml, xmlns, schema_name)
41
+ # xml_fragment_should_validate_against_schema('<video/>', 'sitemap-video', 'xmlns:video' => 'http://www.google.com/schemas/sitemap-video/1.1')
42
+ #
43
+ # This validates the given XML using the spec/support/schemas/sitemap-video.xsd`
44
+ # schema. The XML namespace `xmlns:video='http://www.google.com/schemas/sitemap-video/1.1'` is automatically
45
+ # added to the root element for you.
46
+ def xml_fragment_should_validate_against_schema(xml, schema_name, xmlns={})
35
47
  xml = xml.is_a?(String) ? xml : xml.to_s
36
48
  doc = Nokogiri::XML(xml)
37
- doc.root['xmlns'] = xmlns
49
+ doc.root.send(:[]=, *xmlns.first)
38
50
  xml_data_should_validate_against_schema(doc, schema_name)
39
51
  end
40
52
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sitemap_generator
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.1
4
+ version: 4.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-13 00:00:00.000000000 Z
12
+ date: 2013-08-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mocha
@@ -183,7 +183,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
183
183
  version: '0'
184
184
  segments:
185
185
  - 0
186
- hash: -880166997178231543
186
+ hash: 629438297049129393
187
187
  required_rubygems_version: !ruby/object:Gem::Requirement
188
188
  none: false
189
189
  requirements:
@@ -192,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
192
192
  version: '0'
193
193
  segments:
194
194
  - 0
195
- hash: -880166997178231543
195
+ hash: 629438297049129393
196
196
  requirements: []
197
197
  rubyforge_project:
198
198
  rubygems_version: 1.8.25