class SitemapGenerator::Builder::SitemapUrl

A Hash-like class for holding information about a sitemap URL and generating an XML <url> element suitable for sitemaps.

Public Class Methods

new(path, options={}) click to toggle source

Return a new instance with options configured on it.

Arguments

  • sitemap - a Sitemap instance, or

  • path, options - a path string and options hash

Options

Requires a host to be set. If passing a sitemap, the sitemap must have a default_host configured. If calling with a path and options, you must include the :host option.

  • host

  • priority

  • changefreq

  • lastmod

  • images

  • video/videos

  • news

  • mobile

  • alternate/alternates

  • pagemap

# File lib/sitemap_generator/builder/sitemap_url.rb, line 32
def initialize(path, options={})
  options = SitemapGenerator::Utilities.symbolize_keys(options)
  if sitemap = path.is_a?(SitemapGenerator::Builder::SitemapFile) && path
    SitemapGenerator::Utilities.reverse_merge!(options, :host => sitemap.location.host, :lastmod => sitemap.lastmod)
    path = sitemap.location.path_in_public
  end

  SitemapGenerator::Utilities.assert_valid_keys(options, :priority, :changefreq, :lastmod, :expires, :host, :images, :video, :news, :videos, :mobile, :alternate, :alternates, :pagemap)
  SitemapGenerator::Utilities.reverse_merge!(options, :priority => 0.5, :changefreq => 'weekly', :lastmod => Time.now, :images => [], :news => {}, :videos => [], :mobile => false, :alternates => [])
  raise "Cannot generate a url without a host" unless SitemapGenerator::Utilities.present?(options[:host])

  if video = options.delete(:video)
    options[:videos] = video.is_a?(Array) ? options[:videos].concat(video) : options[:videos] << video
  end
  if alternate = options.delete(:alternate)
    options[:alternates] = alternate.is_a?(Array) ? options[:alternates].concat(alternate) : options[:alternates] << alternate
  end

  path = path.to_s.sub(/^\//, '')
  loc  = path.empty? ? options[:host] : (options[:host].to_s.sub(/\/$/, '') + '/' + path)
  self.merge!(
    :priority   => options[:priority],
    :changefreq => options[:changefreq],
    :lastmod    => options[:lastmod],
    :expires    => options[:expires],
    :host       => options[:host],
    :loc        => loc,
    :images     => prepare_images(options[:images], options[:host]),
    :news       => prepare_news(options[:news]),
    :videos     => options[:videos],
    :mobile     => options[:mobile],
    :alternates => options[:alternates],
    :pagemap    => options[:pagemap]
  )
end

Public Instance Methods

news?() click to toggle source
# File lib/sitemap_generator/builder/sitemap_url.rb, line 162
def news?
  SitemapGenerator::Utilities.present?(self[:news])
end
to_xml(builder=nil) click to toggle source

Return the URL as XML

# File lib/sitemap_generator/builder/sitemap_url.rb, line 69
def to_xml(builder=nil)
  builder = ::Builder::XmlMarkup.new if builder.nil?
  builder.url do
    builder.loc        self[:loc]
    builder.lastmod    w3c_date(self[:lastmod])      if self[:lastmod]
    builder.expires    w3c_date(self[:expires])      if self[:expires]
    builder.changefreq self[:changefreq].to_s        if self[:changefreq]
    builder.priority   format_float(self[:priority]) if self[:priority]

    unless SitemapGenerator::Utilities.blank?(self[:news])
      news_data = self[:news]
      builder.news:news do
        builder.news:publication do
          builder.news :name, news_data[:publication_name].to_s if news_data[:publication_name]
          builder.news :language, news_data[:publication_language].to_s if news_data[:publication_language]
        end

        builder.news :access, news_data[:access].to_s if news_data[:access]
        builder.news :genres, news_data[:genres].to_s if news_data[:genres]
        builder.news :publication_date, w3c_date(news_data[:publication_date]) if news_data[:publication_date]
        builder.news :title, news_data[:title].to_s if news_data[:title]
        builder.news :keywords, news_data[:keywords].to_s if news_data[:keywords]
        builder.news :stock_tickers, news_data[:stock_tickers].to_s if news_data[:stock_tickers]
      end
    end

    self[:images].each do |image|
      builder.image:image do
        builder.image :loc, image[:loc]
        builder.image :caption, image[:caption].to_s             if image[:caption]
        builder.image :geo_location, image[:geo_location].to_s   if image[:geo_location]
        builder.image :title, image[:title].to_s                 if image[:title]
        builder.image :license, image[:license].to_s             if image[:license]
      end
    end

    self[:videos].each do |video|
      builder.video :video do
        builder.video :thumbnail_loc, video[:thumbnail_loc].to_s
        builder.video :title, video[:title].to_s
        builder.video :description, video[:description].to_s
        builder.video :content_loc, video[:content_loc].to_s           if video[:content_loc]
        if video[:player_loc]
          loc_attributes = { :allow_embed => yes_or_no_with_default(video[:allow_embed], true) }
          loc_attributes[:autoplay] = video[:autoplay].to_s if SitemapGenerator::Utilities.present?(video[:autoplay])
          builder.video :player_loc, video[:player_loc].to_s, loc_attributes
        end
        builder.video :duration, video[:duration].to_s                 if video[:duration]
        builder.video :expiration_date,  w3c_date(video[:expiration_date])  if video[:expiration_date]
        builder.video :rating, format_float(video[:rating])       if video[:rating]
        builder.video :view_count, video[:view_count].to_s             if video[:view_count]
        builder.video :publication_date, w3c_date(video[:publication_date]) if video[:publication_date]
        video[:tags].each {|tag| builder.video :tag, tag.to_s }        if video[:tags]
        builder.video :tag, video[:tag].to_s                           if video[:tag]
        builder.video :category, video[:category].to_s                 if video[:category]
        builder.video :family_friendly,  yes_or_no_with_default(video[:family_friendly], true) if video.has_key?(:family_friendly)
        builder.video :gallery_loc, video[:gallery_loc].to_s, :title => video[:gallery_title].to_s if video[:gallery_loc]
        builder.video :price, video[:price].to_s, prepare_video_price_attribs(video) if SitemapGenerator::Utilities.present?(video[:price])
        if video[:uploader]
          builder.video :uploader, video[:uploader].to_s, video[:uploader_info] ? { :info => video[:uploader_info].to_s } : {}
        end
        builder.video :live, yes_or_no_with_default(video[:live], true) if video.has_key?(:live)
        builder.video :requires_subscription, yes_or_no_with_default(video[:requires_subscription], true) if video.has_key?(:requires_subscription)
      end
    end

    self[:alternates].each do |alternate|
      rel = alternate[:nofollow] ? 'alternate nofollow' : 'alternate'
      attributes = { :rel => rel, :href => alternate[:href].to_s }
      attributes[:hreflang] = alternate[:lang].to_s if SitemapGenerator::Utilities.present?(alternate[:lang])
      attributes[:media] = alternate[:media].to_s if SitemapGenerator::Utilities.present?(alternate[:media])
      builder.xhtml :link, attributes
    end

    unless SitemapGenerator::Utilities.blank?(self[:mobile])
      builder.mobile :mobile
    end

    unless SitemapGenerator::Utilities.blank?(self[:pagemap])
      builder.pagemap :PageMap do
        SitemapGenerator::Utilities.as_array(self[:pagemap][:dataobjects]).each do |dataobject|
          builder.pagemap :DataObject, :type => dataobject[:type].to_s, :id => dataobject[:id].to_s do
            SitemapGenerator::Utilities.as_array(dataobject[:attributes]).each do |attribute|
              builder.pagemap :Attribute, attribute[:value].to_s, :name => attribute[:name].to_s
            end
          end
        end
      end
    end
  end
  builder << '' # Force to string
end

Protected Instance Methods

format_float(value) click to toggle source

Format a float to to one decimal precision. TODO: Use rounding with precision once merged with framework_agnostic.

# File lib/sitemap_generator/builder/sitemap_url.rb, line 237
def format_float(value)
  value.is_a?(String) ? value : ('%0.1f' % value)
end
prepare_images(images, host) click to toggle source

Return an Array of image option Hashes suitable to be parsed by SitemapGenerator::Builder::SitemapFile

# File lib/sitemap_generator/builder/sitemap_url.rb, line 182
def prepare_images(images, host)
  images.delete_if { |key,value| key[:loc] == nil }
  images.each do |r|
    SitemapGenerator::Utilities.assert_valid_keys(r, :loc, :caption, :geo_location, :title, :license)
    r[:loc] = URI.join(host, r[:loc]).to_s
  end
  images[0..(SitemapGenerator::MAX_SITEMAP_IMAGES-1)]
end
prepare_news(news) click to toggle source
# File lib/sitemap_generator/builder/sitemap_url.rb, line 176
def prepare_news(news)
  SitemapGenerator::Utilities.assert_valid_keys(news, :publication_name, :publication_language, :publication_date, :genres, :access, :title, :keywords, :stock_tickers) unless news.empty?
  news
end
prepare_video_price_attribs(video) click to toggle source
# File lib/sitemap_generator/builder/sitemap_url.rb, line 168
def prepare_video_price_attribs(video)
  attribs = {}
  attribs[:currency] = video[:price_currency].to_s # required
  attribs[:type] = video[:price_type] if SitemapGenerator::Utilities.present?(video[:price_type])
  attribs[:resolution] = video[:price_resolution] if SitemapGenerator::Utilities.present?(video[:price_resolution])
  attribs
end
w3c_date(date) click to toggle source
# File lib/sitemap_generator/builder/sitemap_url.rb, line 191
def w3c_date(date)
  if date.is_a?(String)
    date
  elsif date.respond_to?(:iso8601)
    date.iso8601.sub(/Z$/i, '+00:00')
  elsif date.is_a?(Date) && !date.is_a?(DateTime)
    date.strftime("%Y-%m-%d")
  else
    zulutime = if date.is_a?(DateTime)
      date.new_offset(0)
    elsif date.respond_to?(:utc)
      date.utc
    elsif date.is_a?(Integer)
      Time.at(date).utc
    else
      nil
    end

    if zulutime
      zulutime.strftime("%Y-%m-%dT%H:%M:%S+00:00")
    else
      zone = date.strftime('%z').insert(-3, ':')
      date.strftime("%Y-%m-%dT%H:%M:%S") + zone
    end
  end
end
yes_or_no(value) click to toggle source

Accept a string or boolean and return 'yes' or 'no'. If a string, the value must be 'yes' or 'no'. Pass the default value as a boolean using `default`.

# File lib/sitemap_generator/builder/sitemap_url.rb, line 220
def yes_or_no(value)
  if value.is_a?(String)
    raise ArgumentError.new("Unrecognized value for yes/no field: #{value.inspect}") unless value =~ /^(yes|no)$/i
    value.downcase
  else
    value ? 'yes' : 'no'
  end
end
yes_or_no_with_default(value, default) click to toggle source

If the value is nil, return `default` converted to either 'yes' or 'no'. If the value is set, return its value converted to 'yes' or 'no'.

# File lib/sitemap_generator/builder/sitemap_url.rb, line 231
def yes_or_no_with_default(value, default)
  yes_or_no(value.nil? ? default : value)
end