sitemap_generator 4.1.1 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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