require 'avatar/source/abstract_source'
require 'avatar/source/static_url_source'
require 'avatar/source/nil_source'
require 'digest/md5'
module Avatar # :nodoc:
module Source # :nodoc:
# NOTE: since Gravatar always returns a URL (never a 404), instances of this
# class should only be placed at the end of a SourceChain.
# (see link:classes/Avatar/Source/SourceChain.html)
# Alternatively, use default_source = ...
to generate a site-wide
# default to be passed to Gravatar. (In fact, since default_source
# is an instance of Avatar::Source::AbstractSource, it can generate a different
# default for each person.)
class GravatarSource
include AbstractSource
attr_accessor :default_field
attr_reader :default_source
# 'http://www.gravatar.com/avatar/'
def self.base_url
'http://www.gravatar.com/avatar/'
end
# ['G', 'PG', 'R', 'X']
def self.allowed_ratings
['G', 'PG', 'R', 'X']
end
# Arguments:
# * +default_source+: a Source to generate defaults to be passed to Gravatar; optional; default: nil (a NilSource).
# * +default_field+: the field within each +person+ passed to avatar_url_for
in which to look for an email address
def initialize(default_source = nil, default_field = :email)
self.default_source = default_source #not @default_source = ... b/c want to use the setter function below
@default_field = default_field
raise "There's a bug in the code" if @default_source.nil?
end
# Generates a Gravatar URL. Returns nil if person is nil.
# Options:
# * :gravatar_field (Symbol)
- the field to call from person. By default, :email
.
# * :default (String)
- override the default generated by default_source
.
# * :gravatar_size or size or :s
- the size in pixels of the avatar to render.
# * :gravatar_rating or rating or :r
- the maximum rating; one of ['G', 'PG', 'R', 'X']
def avatar_url_for(person, options = {})
return nil if person.nil?
options = parse_options(person, options)
field = options.delete(:gravatar_field)
raise ArgumentError.new('No field specified; either specify a default field or pass in a value for :gravatar_field (probably :email)') unless field
returning(self.class.base_url) do |url|
url << Digest::MD5::hexdigest(person.send(field)).strip
options.each do |k, v|
next if v.nil?
url << (url.include?('?') ? '&' : '?')
url << "#{k}=#{v}"
end
end
end
# Returns a Hash containing
# * :field - passed through; defaults to self.default_field
# * :default - passed through; defaults to self.default_avatar_url_for(+person+, +options+)
# * :size - :gravatar_size or :size or :s passed through only if a number
# * :rating - :gravatar_rating or :rating or :r passed through only if one of self.class.allowed_ratings
def parse_options(person, options)
returning({}) do |result|
result[:gravatar_field] = options[:gravatar_field] || default_field
result[:default] = options[:default] || default_avatar_url_for(person, options)
size = options[:gravatar_size] || options[:size] || options[:s]
result[:size] = size if size.to_s =~ /^\d*/
rating = options[:gravatar_rating] || options[:rating] || options[:r]
result[:rating] = rating.upcase if rating and self.class.allowed_ratings.include?(rating.to_s)
end
end
# Set the default source for all people.
# If +default+ is a String, it will be converted to an instance of Avatar::Source::StaticUrlSource.
# If +default+ is nil, sets the default to a NilSource.
def default_source=(default)
case default
when String
@default_source = StaticUrlSource.new(default)
when AbstractSource
@default_source = default
when NilClass
@default_source = NilSource.new
else
raise ArgumentError.new("#{default} must be either a String or an instance of #{AbstractSource}")
end
end
private
def default_avatar_url_for(person, options)
@default_source.avatar_url_for(person, options)
end
end
end
end