gravatar-ultimate 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +24 -0
- data/LICENSE +20 -0
- data/README.rdoc +100 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/gravatar-ultimate.gemspec +77 -0
- data/lib/gravatar-ultimate.rb +1 -0
- data/lib/gravatar.rb +282 -0
- data/lib/gravatar/cache.rb +133 -0
- data/lib/gravatar/dependencies.rb +16 -0
- data/lib/gravatar_ultimate.rb +1 -0
- data/spec/credentials.yml.example +11 -0
- data/spec/fixtures/image.jpg +0 -0
- data/spec/lib/gravatar/cache_and_logger_spec.rb +94 -0
- data/spec/lib/gravatar/cache_setup_spec.rb +42 -0
- data/spec/lib/gravatar/dependencies_spec.rb +29 -0
- data/spec/lib/gravatar_spec.rb +141 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +30 -0
- metadata +132 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Colin MacKenzie IV
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
= gravatar-ultimate
|
2
|
+
|
3
|
+
The Ultimate Gravatar Gem!
|
4
|
+
|
5
|
+
This gem is used to interface with the entire Gravatar API: it's not just for generating image URLs, but for connecting
|
6
|
+
to and communicating with the XML-RPC API too! Additionally, it can be used to download the Gravatar image data itself,
|
7
|
+
rather than just a URL to that data. This saves you the extra step of having to do so.
|
8
|
+
|
9
|
+
== Installation
|
10
|
+
|
11
|
+
gem install gravitar-ultimate
|
12
|
+
|
13
|
+
== Activate the gem...
|
14
|
+
|
15
|
+
As with any gem, you have to type a few lines to tell Ruby to actually *use* it. Here's how to do that...
|
16
|
+
|
17
|
+
==== ...in Ruby on Rails (v3.x)
|
18
|
+
|
19
|
+
* This isn't ready yet, but it's in the works.
|
20
|
+
|
21
|
+
==== ...in Ruby on Rails (v2.x)
|
22
|
+
|
23
|
+
* Edit your config/environment.rb file
|
24
|
+
* Add this line beneath "Rails::Initializer.run do |config|":
|
25
|
+
config.gem 'gravitar-ultimate'
|
26
|
+
|
27
|
+
==== ...in vanilla Ruby
|
28
|
+
|
29
|
+
require 'rubygems'
|
30
|
+
gem 'gravitar-ultimate'
|
31
|
+
require 'gravitar-ultimate'
|
32
|
+
|
33
|
+
== Usage
|
34
|
+
Using the gem is actually pretty simple. Let's say you want the Gravatar image URL for "generic@example.com":
|
35
|
+
url = Gravatar.new("generic@example.com").image_url
|
36
|
+
|
37
|
+
Cool, huh? Let's take it a step further and grab the actual image *data* so that we can render it on the screen:
|
38
|
+
data = Gravatar.new("generic@example.com").image_data
|
39
|
+
|
40
|
+
Fine, but how about the rest of the API as advertised at http://en.gravatar.com/site/implement/xmlrpc? Well, for
|
41
|
+
that you need either the user's Gravatar password, or their API key:
|
42
|
+
|
43
|
+
api = Gravatar.new("generic@example.com", :password => "helloworld")
|
44
|
+
api = Gravatar.new("generic@example.com", :api_key => "AbCdEfG1234")
|
45
|
+
|
46
|
+
After you have that, things get a lot easier:
|
47
|
+
|
48
|
+
api.exists? #=> true or false, depending on whether this user has an account.
|
49
|
+
api.addresses #=> a list of email addresses and their corresponding images
|
50
|
+
api.save_data!(rating, image_data) #=> saves an image to this user's account and returns a handle to it
|
51
|
+
api.use_user_image!(handle, an_email_address) #=> uses the specified image handle for the specified email address(es)
|
52
|
+
api.exists?("another@example.com") #=> true or false, depending on whether the specified email exists.
|
53
|
+
|
54
|
+
|
55
|
+
== Caching
|
56
|
+
|
57
|
+
As you can see this is quite powerful. But it gets better. Gravatar Ultimate even manages caching of API responses for
|
58
|
+
you! That way, if an error occurs, (such as the Gravatar site being offline), your code won't break. It'll instead
|
59
|
+
gracefully fall back to the cached copy! By default, if you are using Rails, it'll use the Rails cache. Otherwise, it'll
|
60
|
+
use whatever cache you're using with Gravatar (by default an instance of ActiveSupport::Cache::FileStore).
|
61
|
+
|
62
|
+
This has obvious benefits when used for the API calls that do not result in changing the user's profile, but what you
|
63
|
+
might not have thought of yet is that it also caches #image_data, so you can hook your application up to that method
|
64
|
+
without fear of what might happen to all those Gravatar images if the Gravatar server should be unavailable!
|
65
|
+
|
66
|
+
To customize exactly which cache is used, see the next section...
|
67
|
+
|
68
|
+
=== Configuration
|
69
|
+
|
70
|
+
To see settings and options you can give for a particular Gravatar instance, check out the Gravatar class documentation.
|
71
|
+
There are a few things you can set for Gravatar on a system-wide basis, and that's what we'll go over next.
|
72
|
+
|
73
|
+
For a non-Rails project, simply set these options before you start using Gravatar. For a Rails project, you should set
|
74
|
+
them within an Initializer in config/initializers/any_filename.rb in order to ensure that the settings are applied
|
75
|
+
(A) after Gravatar has been included into the project, and (B) before it is actually used by Rails.
|
76
|
+
|
77
|
+
# You can set the default cache for Gravatar to use:
|
78
|
+
Gravatar.cache = ActiveSupport::Cache::SynchronizedMemoryStore.new
|
79
|
+
|
80
|
+
# You can also set the length of time an item in the Gravatar cache is valid. Default is 24.hours
|
81
|
+
Gravatar.duration = 20.minutes
|
82
|
+
|
83
|
+
# You can also change the logger used by default. It's worth mentioning that, once again, Gravatar will use
|
84
|
+
# the Rails logger if it's available. Otherwise, the default is $stdout.
|
85
|
+
grav_log = ""
|
86
|
+
Gravatar.logger = StringIO.new(grav_log) # logs Gravatar output to a String
|
87
|
+
|
88
|
+
== Note on Patches/Pull Requests
|
89
|
+
|
90
|
+
* Fork the project.
|
91
|
+
* Make your feature addition or bug fix.
|
92
|
+
* Add tests for it. This is important so I don't break it in a
|
93
|
+
future version unintentionally.
|
94
|
+
* Commit, do not mess with rakefile, version, or history.
|
95
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
96
|
+
* Send me a pull request. Bonus points for topic branches.
|
97
|
+
|
98
|
+
== Copyright
|
99
|
+
|
100
|
+
Copyright (c) 2010 Colin MacKenzie IV. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "gravatar-ultimate"
|
8
|
+
gem.summary = %Q{A gem for interfacing with the entire Gravatar API: not just images, but the XML-RPC API too!}
|
9
|
+
gem.description = %Q{The Ultimate Gravatar Gem!
|
10
|
+
|
11
|
+
This gem is used to interface with the entire Gravatar API: it's not just for generating image URLs, but for connecting
|
12
|
+
to and communicating with the XML-RPC API too! Additionally, it can be used to download the Gravatar image data itself,
|
13
|
+
rather than just a URL to that data. This saves you the extra step of having to do so.}
|
14
|
+
gem.email = "sinisterchipmunk@gmail.com"
|
15
|
+
gem.homepage = "http://github.com/sinisterchipmunk/gravatar"
|
16
|
+
gem.authors = ["Colin MacKenzie IV"]
|
17
|
+
gem.add_dependency "sc-core-ext", ">= 1.2.0"
|
18
|
+
gem.add_development_dependency "rspec", ">= 1.3.0"
|
19
|
+
gem.add_development_dependency "fakeweb", ">= 1.2.8"
|
20
|
+
end
|
21
|
+
Jeweler::GemcutterTasks.new
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'spec/rake/spectask'
|
27
|
+
Spec::Rake::SpecTask.new(:test) do |test|
|
28
|
+
test.libs << 'lib' << 'spec'
|
29
|
+
test.pattern = 'spec/**/*_spec.rb'
|
30
|
+
test.verbose = true
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Run all specs"
|
34
|
+
task :spec => :test
|
35
|
+
|
36
|
+
begin
|
37
|
+
gem 'rcov'
|
38
|
+
require 'rcov/rcovtask'
|
39
|
+
Spec::Rake::SpecTask.new(:coverage) do |test|
|
40
|
+
test.libs << 'lib' << 'spec'
|
41
|
+
test.pattern = "spec/**/*_spec.rb"
|
42
|
+
test.verbose = true
|
43
|
+
test.rcov = true
|
44
|
+
test.rcov_opts = ['--html', '--exclude spec']
|
45
|
+
end
|
46
|
+
rescue LoadError
|
47
|
+
task :coverage do
|
48
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
task :test => :check_dependencies
|
53
|
+
|
54
|
+
task :default => :test
|
55
|
+
|
56
|
+
require 'rake/rdoctask'
|
57
|
+
Rake::RDocTask.new do |rdoc|
|
58
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
59
|
+
|
60
|
+
rdoc.rdoc_dir = 'rdoc'
|
61
|
+
rdoc.title = "gravatar #{version}"
|
62
|
+
rdoc.rdoc_files.include('README*')
|
63
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
64
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{gravatar-ultimate}
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Colin MacKenzie IV"]
|
12
|
+
s.date = %q{2010-06-16}
|
13
|
+
s.description = %q{The Ultimate Gravatar Gem!
|
14
|
+
|
15
|
+
This gem is used to interface with the entire Gravatar API: it's not just for generating image URLs, but for connecting
|
16
|
+
to and communicating with the XML-RPC API too! Additionally, it can be used to download the Gravatar image data itself,
|
17
|
+
rather than just a URL to that data. This saves you the extra step of having to do so.}
|
18
|
+
s.email = %q{sinisterchipmunk@gmail.com}
|
19
|
+
s.extra_rdoc_files = [
|
20
|
+
"LICENSE",
|
21
|
+
"README.rdoc"
|
22
|
+
]
|
23
|
+
s.files = [
|
24
|
+
".document",
|
25
|
+
".gitignore",
|
26
|
+
"LICENSE",
|
27
|
+
"README.rdoc",
|
28
|
+
"Rakefile",
|
29
|
+
"VERSION",
|
30
|
+
"gravatar-ultimate.gemspec",
|
31
|
+
"lib/gravatar-ultimate.rb",
|
32
|
+
"lib/gravatar.rb",
|
33
|
+
"lib/gravatar/cache.rb",
|
34
|
+
"lib/gravatar/dependencies.rb",
|
35
|
+
"lib/gravatar_ultimate.rb",
|
36
|
+
"spec/credentials.yml.example",
|
37
|
+
"spec/fixtures/image.jpg",
|
38
|
+
"spec/lib/gravatar/cache_and_logger_spec.rb",
|
39
|
+
"spec/lib/gravatar/cache_setup_spec.rb",
|
40
|
+
"spec/lib/gravatar/dependencies_spec.rb",
|
41
|
+
"spec/lib/gravatar_spec.rb",
|
42
|
+
"spec/spec.opts",
|
43
|
+
"spec/spec_helper.rb"
|
44
|
+
]
|
45
|
+
s.homepage = %q{http://github.com/sinisterchipmunk/gravatar}
|
46
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
47
|
+
s.require_paths = ["lib"]
|
48
|
+
s.rubygems_version = %q{1.3.6}
|
49
|
+
s.summary = %q{A gem for interfacing with the entire Gravatar API: not just images, but the XML-RPC API too!}
|
50
|
+
s.test_files = [
|
51
|
+
"spec/spec_helper.rb",
|
52
|
+
"spec/lib/gravatar_spec.rb",
|
53
|
+
"spec/lib/gravatar/dependencies_spec.rb",
|
54
|
+
"spec/lib/gravatar/cache_and_logger_spec.rb",
|
55
|
+
"spec/lib/gravatar/cache_setup_spec.rb"
|
56
|
+
]
|
57
|
+
|
58
|
+
if s.respond_to? :specification_version then
|
59
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
60
|
+
s.specification_version = 3
|
61
|
+
|
62
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
63
|
+
s.add_runtime_dependency(%q<sc-core-ext>, [">= 1.2.0"])
|
64
|
+
s.add_development_dependency(%q<rspec>, [">= 1.3.0"])
|
65
|
+
s.add_development_dependency(%q<fakeweb>, [">= 1.2.8"])
|
66
|
+
else
|
67
|
+
s.add_dependency(%q<sc-core-ext>, [">= 1.2.0"])
|
68
|
+
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
69
|
+
s.add_dependency(%q<fakeweb>, [">= 1.2.8"])
|
70
|
+
end
|
71
|
+
else
|
72
|
+
s.add_dependency(%q<sc-core-ext>, [">= 1.2.0"])
|
73
|
+
s.add_dependency(%q<rspec>, [">= 1.3.0"])
|
74
|
+
s.add_dependency(%q<fakeweb>, [">= 1.2.8"])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path("../gravatar", __FILE__)
|
data/lib/gravatar.rb
ADDED
@@ -0,0 +1,282 @@
|
|
1
|
+
require File.expand_path('../gravatar/dependencies', __FILE__)
|
2
|
+
require File.expand_path("../gravatar/cache", __FILE__)
|
3
|
+
|
4
|
+
# ==== Errors ====
|
5
|
+
#
|
6
|
+
# Errors usually come with a number and human readable text. Generally the text should be followed whenever possible,
|
7
|
+
# but a brief description of the numeric error codes are as follows:
|
8
|
+
#
|
9
|
+
# -7 Use secure.gravatar.com
|
10
|
+
# -8 Internal error
|
11
|
+
# -9 Authentication error
|
12
|
+
# -10 Method parameter missing
|
13
|
+
# -11 Method parameter incorrect
|
14
|
+
# -100 Misc error (see text)
|
15
|
+
#
|
16
|
+
class Gravatar
|
17
|
+
attr_reader :email
|
18
|
+
|
19
|
+
# Creates a new instance of Gravatar. Valid options include:
|
20
|
+
# :password => the password for this account, to be used instead of :api_key (don't supply both)
|
21
|
+
# :api_key or :apikey or :key => the API key for this account, to be used instead of :password (don't supply both)
|
22
|
+
# :duration => the cache duration to use for this instance
|
23
|
+
# :logger => the logger to use for this instance
|
24
|
+
#
|
25
|
+
# Note that :password and :api_key are both optional. If omitted, no web services will be available but this
|
26
|
+
# user's Gravatar image can still be constructed using #image_uri or #image_data.
|
27
|
+
#
|
28
|
+
def initialize(email, options = {})
|
29
|
+
raise ArgumentError, "Expected :email" unless email
|
30
|
+
@options = options || {}
|
31
|
+
@email = email
|
32
|
+
|
33
|
+
pw_or_key = auth.keys.first || :none
|
34
|
+
@cache = Gravatar::Cache.new(self.class.cache, options[:duration] || self.class.duration,
|
35
|
+
"gravatar-#{email_hash}-#{pw_or_key}", options[:logger] || self.class.logger)
|
36
|
+
|
37
|
+
if !auth.empty?
|
38
|
+
@api = XMLRPC::Client.new("secure.gravatar.com", "/xmlrpc?user=#{email_hash}", 443, nil, nil, nil, nil, true)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# The duration of the cache for this instance of Gravatar, independent of any other instance
|
43
|
+
def cache_duration
|
44
|
+
@cache.duration
|
45
|
+
end
|
46
|
+
|
47
|
+
# Sets the duration of the cache for this instance of Gravatar, independent of any other instance
|
48
|
+
def cache_duration=(time)
|
49
|
+
@cache.duration = time
|
50
|
+
end
|
51
|
+
|
52
|
+
# Check whether one or more email addresses have corresponding avatars. If no email addresses are
|
53
|
+
# specified, the one associated with this object is used.
|
54
|
+
#
|
55
|
+
# Returns: Boolean for a single email address; a hash of emails => booleans for multiple addresses.
|
56
|
+
#
|
57
|
+
# This method is cached for up to the value of @duration or Gravatar.duration.
|
58
|
+
def exists?(*emails)
|
59
|
+
hashed_emails = normalize_email_addresses(emails)
|
60
|
+
cache('exists', hashed_emails) do
|
61
|
+
hash = call('grav.exists', :hashes => hashed_emails)
|
62
|
+
if hash.length == 1
|
63
|
+
boolean(hash.values.first)
|
64
|
+
else
|
65
|
+
dehashify_emails(hash, emails) { |value| boolean(value) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Gets a list of addresses for this account, returning a hash following this format:
|
71
|
+
# {
|
72
|
+
# address => {
|
73
|
+
# :rating => rating,
|
74
|
+
# :userimage => userimage,
|
75
|
+
# :userimage_url => userimage_url
|
76
|
+
# }
|
77
|
+
# }
|
78
|
+
#
|
79
|
+
# This method is cached for up to the value of @duration or Gravatar.duration.
|
80
|
+
def addresses
|
81
|
+
cache('addresses') do
|
82
|
+
call('grav.addresses').inject({}) do |hash, (address, info)|
|
83
|
+
hash[address] = info.merge(:rating => rating(info[:rating]))
|
84
|
+
hash
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns a hash of user images for this account in the following format:
|
90
|
+
# { user_img_hash => [rating, url] }
|
91
|
+
#
|
92
|
+
# This method is cached for up to the value of @duration or Gravatar.duration.
|
93
|
+
def user_images
|
94
|
+
cache('user_images') do
|
95
|
+
call('grav.userimages').inject({}) do |hash, (key, array)|
|
96
|
+
hash[key] = [rating(array.first), array.last]
|
97
|
+
hash
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Saves binary image data as a userimage for this account and returns the ID of the image.
|
103
|
+
#
|
104
|
+
# This method is not cached.
|
105
|
+
def save_data!(rating, data)
|
106
|
+
call('grav.saveData', :data => Base64.encode64(data), :rating => _rating(rating))
|
107
|
+
end
|
108
|
+
alias save_image! save_data!
|
109
|
+
|
110
|
+
# Read an image via its URL and save that as a userimage for this account, returning true or false
|
111
|
+
#
|
112
|
+
# This method is not cached.
|
113
|
+
def save_url!(rating, url)
|
114
|
+
call('grav.saveUrl', :url => url, :rating => _rating(rating))
|
115
|
+
end
|
116
|
+
|
117
|
+
# Use a userimage as a gravatar for one or more addresses on this account. Returns a hash:
|
118
|
+
# { email_address => true/false }
|
119
|
+
#
|
120
|
+
# This method is not cached.
|
121
|
+
#
|
122
|
+
# This method will clear out the cache, since it may have an effect on what the API methods respond with.
|
123
|
+
def use_user_image!(image_hash, *email_addresses)
|
124
|
+
hashed_email_addresses = normalize_email_addresses(email_addresses)
|
125
|
+
hash = call('grav.useUserimage', :userimage => image_hash, :addresses => hashed_email_addresses)
|
126
|
+
returning dehashify_emails(hash, email_addresses) { |value| boolean(value) } do
|
127
|
+
expire_cache!
|
128
|
+
end
|
129
|
+
end
|
130
|
+
alias use_image! use_user_image!
|
131
|
+
|
132
|
+
# Remove the userimage associated with one or more email addresses. Returns a hash of booleans.
|
133
|
+
# NOTE: This appears to always return false, even when it is really removing an image. If you
|
134
|
+
# know what the deal with that is, drop me a line so I can update this documentation!
|
135
|
+
#
|
136
|
+
# This method is not cached.
|
137
|
+
#
|
138
|
+
# This method will clear out the cache, since it may have an effect on what the API methods respond with.
|
139
|
+
def remove_image!(*emails)
|
140
|
+
hashed_email_addresses = normalize_email_addresses(emails)
|
141
|
+
hash = call('grav.removeImage', :addresses => hashed_email_addresses)
|
142
|
+
returning dehashify_emails(hash, emails) { |value| boolean(value) } do
|
143
|
+
expire_cache!
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Remove a userimage from the account and any email addresses with which it is associated. Returns
|
148
|
+
# true or false.
|
149
|
+
#
|
150
|
+
# This method is not cached.
|
151
|
+
#
|
152
|
+
# This method will clear out the cache, since it may have an effect on what the API methods respond with.
|
153
|
+
def delete_user_image!(userimage)
|
154
|
+
returning boolean(call('grav.deleteUserimage', :userimage => userimage)) do
|
155
|
+
expire_cache!
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Runs a simple Gravatar test. Useful for debugging. Gravatar will echo back any arguments you pass.
|
160
|
+
# This method is not cached.
|
161
|
+
def test(hash)
|
162
|
+
call('grav.test', hash)
|
163
|
+
end
|
164
|
+
|
165
|
+
# Returns the MD5 hash for the specified email address, or the one associated with this object.
|
166
|
+
def email_hash(email = self.email)
|
167
|
+
Digest::MD5.hexdigest(email.downcase.strip)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns the URL for this user's gravatar image. Options include:
|
171
|
+
#
|
172
|
+
# :ssl or :secure if true, HTTPS will be used instead of HTTP. Default is false.
|
173
|
+
# :rating or :r a rating threshold for this image. Can be one of [ :g, :pg, :r, :x ]. Default is :g.
|
174
|
+
# :size or :s a size for this image. Can be anywhere between 1 and 512. Default is 80.
|
175
|
+
# :default or :d a default URL for this image to display if the specified user has no image;
|
176
|
+
# or this can be one of [ :identicon, :monsterid, :wavatar, 404 ]. By default a generic
|
177
|
+
# Gravatar image URL will be returned.
|
178
|
+
# :filetype an extension such as :jpg or :png. Default is omitted.
|
179
|
+
#
|
180
|
+
# See http://en.gravatar.com/site/implement/url for much more detailed information.
|
181
|
+
def image_url(options = {})
|
182
|
+
secure = options[:ssl] || options[:secure]
|
183
|
+
proto = "http#{secure ? 's' : ''}"
|
184
|
+
sub = secure ? "secure" : "www"
|
185
|
+
|
186
|
+
"#{proto}://#{sub}.gravatar.com/avatar/#{email_hash}#{extension_for_image(options)}#{query_for_image(options)}"
|
187
|
+
end
|
188
|
+
|
189
|
+
# Returns the image data for this user's gravatar image. This is the same as reading the data at #image_url. See
|
190
|
+
# that method for more information.
|
191
|
+
#
|
192
|
+
# This method is cached for up to the value of @duration or Gravatar.duration.
|
193
|
+
def image_data(options = {})
|
194
|
+
url = image_url(options)
|
195
|
+
cache(url) { OpenURI.open_uri(URI.parse(url)).read }
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.version
|
199
|
+
@version ||= File.read(File.join(File.dirname(__FILE__), "../VERSION")).chomp
|
200
|
+
end
|
201
|
+
|
202
|
+
private
|
203
|
+
def cache(*key, &block)
|
204
|
+
@cache.call(*key, &block)
|
205
|
+
end
|
206
|
+
|
207
|
+
def expire_cache!
|
208
|
+
@cache.clear!
|
209
|
+
end
|
210
|
+
|
211
|
+
def dehashify_emails(response, emails)
|
212
|
+
hashed_emails = emails.collect { |email| email_hash(email) }
|
213
|
+
response.inject({}) do |hash, (hashed_email, value)|
|
214
|
+
value = yield(value) if value
|
215
|
+
email = emails[hashed_emails.index(hashed_email)]
|
216
|
+
hash[email] = value
|
217
|
+
hash
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def normalize_email_addresses(addresses)
|
222
|
+
addresses.flatten!
|
223
|
+
addresses << @email if addresses.empty?
|
224
|
+
addresses.map { |email| email_hash(email) }
|
225
|
+
end
|
226
|
+
|
227
|
+
def rating(i)
|
228
|
+
case i
|
229
|
+
when 0, '0' then :g
|
230
|
+
when 1, '1' then :pg
|
231
|
+
when 2, '2' then :r
|
232
|
+
when 3, '3' then :x
|
233
|
+
when :g then 0
|
234
|
+
when :pg then 1
|
235
|
+
when :r then 2
|
236
|
+
when :x then 3
|
237
|
+
else raise ArgumentError, "Unexpected rating index: #{i} (expected between 0..3)"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
alias _rating rating
|
241
|
+
|
242
|
+
def boolean(i)
|
243
|
+
i.kind_of?(Numeric) ? i != 0 : i
|
244
|
+
end
|
245
|
+
|
246
|
+
def call(name, args_hash = {})
|
247
|
+
r = @api.call(name, auth.merge(args_hash))
|
248
|
+
r = r.with_indifferent_access if r.kind_of?(Hash)
|
249
|
+
r
|
250
|
+
end
|
251
|
+
|
252
|
+
def auth
|
253
|
+
api_key ? {:apikey => api_key} : (password ? {:password => password} : {})
|
254
|
+
end
|
255
|
+
|
256
|
+
def api_key
|
257
|
+
options[:apikey] || options[:api_key] || options[:key]
|
258
|
+
end
|
259
|
+
|
260
|
+
def password
|
261
|
+
options[:password]
|
262
|
+
end
|
263
|
+
|
264
|
+
def options
|
265
|
+
@options
|
266
|
+
end
|
267
|
+
|
268
|
+
def query_for_image(options)
|
269
|
+
query = ''
|
270
|
+
[:rating, :size, :default, :r, :s, :d].each do |key|
|
271
|
+
if options.key?(key)
|
272
|
+
query.blank? ? query.concat("?") : query.concat("&")
|
273
|
+
query.concat("#{key}=#{CGI::escape options[key].to_s}")
|
274
|
+
end
|
275
|
+
end
|
276
|
+
query
|
277
|
+
end
|
278
|
+
|
279
|
+
def extension_for_image(options)
|
280
|
+
options.key?(:filetype) ? "." + (options[:filetype] || "jpg").to_s : ""
|
281
|
+
end
|
282
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
class Gravatar
|
2
|
+
# A wrapper around any given Cache object which provides Gravatar-specific helpers. Used internally.
|
3
|
+
class Cache
|
4
|
+
attr_reader :real_cache, :namespace
|
5
|
+
attr_accessor :duration, :logger
|
6
|
+
|
7
|
+
def initialize(real_cache, duration, namespace = nil, logger = Gravatar.logger)
|
8
|
+
@duration = duration
|
9
|
+
@real_cache = real_cache
|
10
|
+
@namespace = namespace
|
11
|
+
@logger = logger
|
12
|
+
end
|
13
|
+
|
14
|
+
# Provide a series of arguments to be used as a cache key, and a block to be executed when the cache
|
15
|
+
# is expired or needs to be populated.
|
16
|
+
#
|
17
|
+
# Example:
|
18
|
+
# cache = Gravatar::Cache.new(Rails.cache, 30.minutes)
|
19
|
+
# cache.call(:first_name => "Colin", :last_name => "MacKenzie") { call_webservice(with_some_args) }
|
20
|
+
#
|
21
|
+
def call(*key, &block)
|
22
|
+
cached_copy = read_cache(*key)
|
23
|
+
if expired?(*key) && block_given?
|
24
|
+
begin
|
25
|
+
returning(yield) do |object|
|
26
|
+
write_cache(object, *key)
|
27
|
+
end
|
28
|
+
rescue
|
29
|
+
log_error($!)
|
30
|
+
cached_copy.nil? ? nil : cached_copy[:object]
|
31
|
+
end
|
32
|
+
else
|
33
|
+
cached_copy.nil? ? nil : cached_copy[:object]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Clears out the entire cache for this object's namespace. This actually removes the objects,
|
38
|
+
# instead of simply marking them as expired, so it will be as if the object never existed.
|
39
|
+
def clear!
|
40
|
+
@real_cache.delete_matched(/^#{Regexp::escape @namespace}/)
|
41
|
+
end
|
42
|
+
|
43
|
+
# forces the specified key to become expired
|
44
|
+
def expire!(*key)
|
45
|
+
unless expired?(*key)
|
46
|
+
@real_cache.write(cache_key(*key), { :expires_at => 1.minute.ago, :object => read_cache(*key)[:object] })
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns true if the cached copy is nil or expired based on @duration.
|
51
|
+
def expired?(*key)
|
52
|
+
cached_copy = read_cache(*key)
|
53
|
+
cached_copy.nil? || cached_copy[:expires_at] < Time.now
|
54
|
+
end
|
55
|
+
|
56
|
+
# Reads an object from the cache based on the cache key constructed from *key.
|
57
|
+
def read_cache(*key)
|
58
|
+
@real_cache.read(cache_key(*key))
|
59
|
+
end
|
60
|
+
|
61
|
+
# Writes an object to the cache based on th cache key constructed from *key.
|
62
|
+
def write_cache(object, *key)
|
63
|
+
@real_cache.write(cache_key(*key), { :expires_at => Time.now + duration, :object => object })
|
64
|
+
end
|
65
|
+
|
66
|
+
# Constructs a cache key from the specified *args and @namespace.
|
67
|
+
def cache_key(*args)
|
68
|
+
ActiveSupport::Cache.expand_cache_key(args, @namespace)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Logs an error message, as long as self.logger responds to :error or :write.
|
72
|
+
# Otherwise, re-raises the error.
|
73
|
+
def log_error(error)
|
74
|
+
if logger.respond_to?(:error)
|
75
|
+
logger.error error.message
|
76
|
+
error.backtrace.each { |line| logger.error " #{line}" }
|
77
|
+
elsif logger.respond_to?(:write)
|
78
|
+
logger.write(([error.message]+error.backtrace).join("\n "))
|
79
|
+
logger.write("\n")
|
80
|
+
else raise error
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class << self
|
86
|
+
def default_cache_instance
|
87
|
+
if defined?(Rails)
|
88
|
+
Rails.cache
|
89
|
+
else
|
90
|
+
ActiveSupport::Cache::FileStore.new("tmp/cache")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def default_logger_instance
|
95
|
+
if defined?(Rails)
|
96
|
+
Rails.logger
|
97
|
+
else
|
98
|
+
$stdout
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def cache
|
103
|
+
@cache ||= default_cache_instance
|
104
|
+
end
|
105
|
+
|
106
|
+
def cache=(instance)
|
107
|
+
@cache = instance
|
108
|
+
end
|
109
|
+
|
110
|
+
def logger
|
111
|
+
@logger ||= default_logger_instance
|
112
|
+
end
|
113
|
+
|
114
|
+
def logger=(logger)
|
115
|
+
@logger = logger
|
116
|
+
end
|
117
|
+
|
118
|
+
# How long is a cached object good for? Default is 30 minutes.
|
119
|
+
def duration
|
120
|
+
@duration ||= 24.hours
|
121
|
+
end
|
122
|
+
|
123
|
+
def duration=(duration)
|
124
|
+
@duration = duration
|
125
|
+
end
|
126
|
+
|
127
|
+
# Resets any changes to the cache and initializes a new cache. If using Rails, the
|
128
|
+
# new cache will be the Rails cache.
|
129
|
+
def reset_cache!
|
130
|
+
@cache = nil
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
if defined?(Rails)
|
2
|
+
Rails.configuration.gem "sc-core-ext", ">= 1.2.0"
|
3
|
+
elsif !defined?(Gem)
|
4
|
+
require 'rubygems'
|
5
|
+
gem 'sc-core-ext', '>= 1.2.0'
|
6
|
+
end
|
7
|
+
|
8
|
+
unless defined?(ScCoreExt) || defined?(Rails) # because Rails will load it later and we don't really need it quite yet.
|
9
|
+
require 'sc-core-ext'
|
10
|
+
end
|
11
|
+
|
12
|
+
# The rest of this is core Ruby stuff so it's safe to load immediately, even if Rails is running the show.
|
13
|
+
require 'open-uri'
|
14
|
+
require "digest/md5"
|
15
|
+
require 'xmlrpc/client'
|
16
|
+
require 'base64'
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path("../gravatar", __FILE__)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# To run this test suite, we need to set up some credentials because we're running real HTTP requests.
|
2
|
+
# Make sure you have a working Gravatar account, and enter the following options:
|
3
|
+
primary_email: email@example.com
|
4
|
+
email: email@example.com
|
5
|
+
api_key: YOUR_API_KEY
|
6
|
+
|
7
|
+
# The primary email is the one that's marked 'primary' on your Gravatar account page. Both emails can
|
8
|
+
# be the same. The API Key is your Gravatar API key, which you can optionally replace with:
|
9
|
+
# password: YOUR_GRAVATAR_PASSWORD
|
10
|
+
#
|
11
|
+
# Take care not to commit your credentials!
|
Binary file
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Gravatar::Cache do
|
4
|
+
subject { Gravatar::Cache.new(new_cache, 30.minutes, "gravatar-specs") }
|
5
|
+
|
6
|
+
context "with a nonexistent cache item" do
|
7
|
+
it "should be expired" do
|
8
|
+
subject.expired?(:nothing).should be_true
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should fire the block" do
|
12
|
+
subject.call(:nothing) { @fired = 1 }
|
13
|
+
@fired.should == 1
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should return nil if no block given" do
|
17
|
+
subject.call(:nothing).should be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return the block value" do
|
21
|
+
subject.call(:nothing) { 1 }.should == 1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "with a pre-existing cache item" do
|
26
|
+
before(:each) { subject.call(:nothing) { 1 } }
|
27
|
+
|
28
|
+
it "should not be expired" do
|
29
|
+
subject.expired?(:nothing).should be_false
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should not fire the block" do
|
33
|
+
subject.call(:nothing) { @fired = 1 }
|
34
|
+
@fired.should_not == 1
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return the cached value" do
|
38
|
+
subject.call(:nothing) { raise "Block expected not to fire" }.should == 1
|
39
|
+
end
|
40
|
+
|
41
|
+
context "that is expired" do
|
42
|
+
before(:each) { subject.expire!(:nothing) }
|
43
|
+
|
44
|
+
it "should be expired" do
|
45
|
+
subject.expired?(:nothing).should be_true
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should fire the block" do
|
49
|
+
subject.call(:nothing) { @fired = 1 }
|
50
|
+
@fired.should == 1
|
51
|
+
end
|
52
|
+
|
53
|
+
context "in the event of an error while refreshing" do
|
54
|
+
before(:each) { subject.logger = StringIO.new("") }
|
55
|
+
|
56
|
+
it "should recover" do
|
57
|
+
proc { subject.call(:nothing) { raise "something bad happened" } }.should_not raise_error(RuntimeError)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should return the cached copy" do
|
61
|
+
subject.call(:nothing) { raise "something bad happened" }.should == 1
|
62
|
+
end
|
63
|
+
|
64
|
+
context "its logger" do
|
65
|
+
before(:each) { subject.logger = Object.new }
|
66
|
+
|
67
|
+
it "should log it if #error is available" do
|
68
|
+
subject.logger.stub!(:error => nil)
|
69
|
+
subject.logger.should_receive(:error).and_return(nil)
|
70
|
+
subject.call(:nothing) { raise "something bad happened" }
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should log it if #write is available" do
|
74
|
+
subject.logger.stub!(:write => nil)
|
75
|
+
subject.logger.should_receive(:write).and_return(nil)
|
76
|
+
subject.call(:nothing) { raise "something bad happened" }
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should re-raise the error if no other methods are available" do
|
80
|
+
proc { subject.call(:nothing) { raise "something bad happened" } }.should raise_error(RuntimeError)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should return the block value" do
|
86
|
+
subject.call(:nothing) { 2 }.should == 2
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should return the cached value if there is no block value" do
|
90
|
+
subject.call(:nothing).should == 1
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
describe "gravatar cache setup" do
|
2
|
+
context "within Rails" do
|
3
|
+
before(:each) do
|
4
|
+
# We reset it here because we've already set it to MemoryStore for the sake of the majority.
|
5
|
+
Gravatar.reset_cache!
|
6
|
+
module Rails
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should get the default cache instance from Rails" do
|
11
|
+
Rails.should_receive(:cache).and_return("a cache object")
|
12
|
+
Gravatar.cache
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should get the current cache from cache assignment, if any" do
|
16
|
+
Gravatar.cache = "a cache object"
|
17
|
+
Gravatar.cache.should == "a cache object"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "out of Rails" do
|
22
|
+
it "should get the default cache from ActiveSupport" do
|
23
|
+
Gravatar.cache.should be_kind_of(ActiveSupport::Cache::FileStore)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should get the current cache from cache assignment, if any" do
|
27
|
+
Gravatar.cache = "a cache object"
|
28
|
+
Gravatar.cache.should == "a cache object"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
after(:each) do
|
33
|
+
# We reset it here because we've already fubarred it with the Rails tests.
|
34
|
+
Gravatar.reset_cache!
|
35
|
+
|
36
|
+
silence_warnings do
|
37
|
+
if defined?(Rails)
|
38
|
+
Object.send :remove_const, :Rails
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Dependencies" do
|
4
|
+
context "within Rails" do
|
5
|
+
before(:each) do
|
6
|
+
module ::Rails
|
7
|
+
def self.configuration
|
8
|
+
return @config if @config
|
9
|
+
@config = Object.new
|
10
|
+
klass = class << @config; self; end
|
11
|
+
klass.instance_eval do
|
12
|
+
def gem(*a, &b); end
|
13
|
+
public :gem
|
14
|
+
end
|
15
|
+
@config
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should set a Rails gem dependency" do
|
21
|
+
Rails.configuration.should_receive(:gem, :with => ["sc-core-ext", ">= 1.2.0"])
|
22
|
+
load File.expand_path("../../../../lib/gravatar/dependencies.rb", __FILE__)
|
23
|
+
end
|
24
|
+
|
25
|
+
after(:each) { silence_warnings { Object.send(:remove_const, :Rails) } }
|
26
|
+
end
|
27
|
+
|
28
|
+
# Don't know how to test the inclusion of sc-core-ext via rubygems, but I suppose there's no reason that should fail.
|
29
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Gravatar do
|
4
|
+
it "should have a valid version number" do
|
5
|
+
Gravatar.version.should =~ /^\d+\.\d+\.\d+$/
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should allow setting cache duration by instance" do
|
9
|
+
grav = Gravatar.new($credentials[:primary_email])
|
10
|
+
grav.cache_duration = 10.minutes
|
11
|
+
grav.cache_duration.should == 10.minutes
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should allow setting cache duration globally" do
|
15
|
+
Gravatar.duration = 10.minutes
|
16
|
+
Gravatar.new($credentials[:primary_email]).cache_duration.should == 10.minutes
|
17
|
+
Gravatar.duration = 30.minutes
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should require :email" do
|
21
|
+
proc { subject }.should raise_error(ArgumentError)
|
22
|
+
end
|
23
|
+
|
24
|
+
context "given :email and :key" do
|
25
|
+
subject { Gravatar.new($credentials[:primary_email], $credentials)}
|
26
|
+
|
27
|
+
context "varying image ratings" do
|
28
|
+
[:g, :pg, :r, :x].each do |rating|
|
29
|
+
it "should save #{rating}-rated URLs and delete them" do
|
30
|
+
subject.save_url!(rating, "http://jigsaw.w3.org/css-validator/images/vcss").should ==
|
31
|
+
"2df7db511c46303983f0092556a1e47c"
|
32
|
+
subject.delete_user_image!("2df7db511c46303983f0092556a1e47c").should == true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should raise an ArgumentError given an invalid rating" do
|
37
|
+
proc { subject.save_url!(:invalid_rating, "http://jigsaw.w3.org/css-validator/images/vcss") }.should \
|
38
|
+
raise_error(ArgumentError)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should return addresses" do
|
43
|
+
subject.addresses.should_not be_empty
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should test successfully" do
|
47
|
+
subject.test(:greeting => 'hello').should have_key(:response)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should save URLs and delete them" do
|
51
|
+
subject.save_url!(:g, "http://jigsaw.w3.org/css-validator/images/vcss").should == "2df7db511c46303983f0092556a1e47c"
|
52
|
+
subject.delete_user_image!("2df7db511c46303983f0092556a1e47c").should == true
|
53
|
+
end
|
54
|
+
|
55
|
+
# Not really the ideal approach but it's a valid test, at least
|
56
|
+
it "should save and delete images and associate/unassociate them with accounts" do
|
57
|
+
begin
|
58
|
+
subject.save_data!(:g, image_data).should == "23f086a793459fa25aab280054fec1b2"
|
59
|
+
subject.use_user_image!("23f086a793459fa25aab280054fec1b2", $credentials[:email]).should ==
|
60
|
+
{ $credentials[:email] => false }
|
61
|
+
# See rdoc for #remove_image! for why we're not checking this.
|
62
|
+
subject.remove_image!($credentials[:email])#.should == { $credentials[:email] => true }
|
63
|
+
subject.delete_user_image!("23f086a793459fa25aab280054fec1b2").should == true
|
64
|
+
ensure
|
65
|
+
subject.remove_image!($credentials[:email])
|
66
|
+
begin
|
67
|
+
subject.delete_user_image!("23f086a793459fa25aab280054fec1b2")
|
68
|
+
rescue XMLRPC::FaultException
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should return user images" do
|
74
|
+
subject.user_images.should == {"fe9dee44a1df19967db30a04083722d5"=>
|
75
|
+
[:g, "http://en.gravatar.com/userimage/14612723/fe9dee44a1df19967db30a04083722d5.jpg"]}
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should determine that the user exists" do
|
79
|
+
subject.exists?.should be_true
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should determine that a fake user does not exist" do
|
83
|
+
subject.exists?("not-even-a-valid-email").should be_false
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should determine that multiple fake users do not exist" do
|
87
|
+
subject.exists?("invalid-1", "invalid-2").should == { "invalid-1" => false, "invalid-2" => false }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "given :email" do
|
92
|
+
subject { Gravatar.new("sinisterchipmunk@gmail.com") }
|
93
|
+
|
94
|
+
it "should not raise an error" do
|
95
|
+
proc { subject }.should_not raise_error(ArgumentError)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should return email_hash" do
|
99
|
+
subject.email_hash.should == "5d8c7a8d951a28e10bd7407f33df6d63"
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should return gravatar image_url" do
|
103
|
+
subject.image_url.should == "http://www.gravatar.com/avatar/5d8c7a8d951a28e10bd7407f33df6d63"
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should return gravitar image data" do
|
107
|
+
subject.image_data.should == image_data
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should return gravatar image_url with SSL" do
|
111
|
+
subject.image_url(:ssl => true).should == "https://secure.gravatar.com/avatar/5d8c7a8d951a28e10bd7407f33df6d63"
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should return gravatar image_url with size" do
|
115
|
+
subject.image_url(:size => 512).should == "http://www.gravatar.com/avatar/5d8c7a8d951a28e10bd7407f33df6d63?size=512"
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should return gravatar image_url with rating" do
|
119
|
+
subject.image_url(:rating => 'pg').should == "http://www.gravatar.com/avatar/5d8c7a8d951a28e10bd7407f33df6d63?rating=pg"
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should return gravatar image_url with file type" do
|
123
|
+
subject.image_url(:filetype => 'png').should == "http://www.gravatar.com/avatar/5d8c7a8d951a28e10bd7407f33df6d63.png"
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should return gravatar image_url with default image" do
|
127
|
+
subject.image_url(:default => "http://example.com/images/example.jpg").should ==
|
128
|
+
"http://www.gravatar.com/avatar/5d8c7a8d951a28e10bd7407f33df6d63?default=http%3A%2F%2Fexample.com%2Fimages%2Fexample.jpg"
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should return gravatar image_url with SSL and default and size and rating" do
|
132
|
+
combinations = %w(
|
133
|
+
https://secure.gravatar.com/avatar/5d8c7a8d951a28e10bd7407f33df6d63?default=identicon&size=80&rating=g
|
134
|
+
https://secure.gravatar.com/avatar/5d8c7a8d951a28e10bd7407f33df6d63?size=80&rating=g&default=identicon
|
135
|
+
https://secure.gravatar.com/avatar/5d8c7a8d951a28e10bd7407f33df6d63?size=80&default=identicon&rating=g
|
136
|
+
https://secure.gravatar.com/avatar/5d8c7a8d951a28e10bd7407f33df6d63?rating=g&size=80&default=identicon
|
137
|
+
)
|
138
|
+
combinations.should include(subject.image_url(:ssl => true, :default => "identicon", :size => 80, :rating => :g))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.expand_path("../../lib/gravatar", __FILE__)
|
2
|
+
unless defined?(Spec)
|
3
|
+
gem 'rspec'
|
4
|
+
require 'spec'
|
5
|
+
end
|
6
|
+
|
7
|
+
def image_data
|
8
|
+
File.read(File.expand_path("../fixtures/image.jpg", __FILE__))
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'fakeweb'
|
12
|
+
FakeWeb.register_uri(:get, "http://www.gravatar.com/avatar/5d8c7a8d951a28e10bd7407f33df6d63", :response =>
|
13
|
+
"HTTP/1.1 200 OK\nContent-Type: image/jpg\n\n" +image_data)
|
14
|
+
|
15
|
+
def new_cache
|
16
|
+
ActiveSupport::Cache::MemoryStore.new
|
17
|
+
end
|
18
|
+
|
19
|
+
Gravatar.cache = new_cache
|
20
|
+
|
21
|
+
class Net::HTTP
|
22
|
+
alias_method :original_initialize, :initialize
|
23
|
+
def initialize(*args, &block)
|
24
|
+
original_initialize(*args, &block)
|
25
|
+
@ssl_context = OpenSSL::SSL::SSLContext.new
|
26
|
+
@ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
$credentials = YAML::load(File.read(File.expand_path("../credentials.yml", __FILE__))).with_indifferent_access
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gravatar-ultimate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Colin MacKenzie IV
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-06-16 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: sc-core-ext
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 2
|
30
|
+
- 0
|
31
|
+
version: 1.2.0
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rspec
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 1
|
43
|
+
- 3
|
44
|
+
- 0
|
45
|
+
version: 1.3.0
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: fakeweb
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
segments:
|
56
|
+
- 1
|
57
|
+
- 2
|
58
|
+
- 8
|
59
|
+
version: 1.2.8
|
60
|
+
type: :development
|
61
|
+
version_requirements: *id003
|
62
|
+
description: |-
|
63
|
+
The Ultimate Gravatar Gem!
|
64
|
+
|
65
|
+
This gem is used to interface with the entire Gravatar API: it's not just for generating image URLs, but for connecting
|
66
|
+
to and communicating with the XML-RPC API too! Additionally, it can be used to download the Gravatar image data itself,
|
67
|
+
rather than just a URL to that data. This saves you the extra step of having to do so.
|
68
|
+
email: sinisterchipmunk@gmail.com
|
69
|
+
executables: []
|
70
|
+
|
71
|
+
extensions: []
|
72
|
+
|
73
|
+
extra_rdoc_files:
|
74
|
+
- LICENSE
|
75
|
+
- README.rdoc
|
76
|
+
files:
|
77
|
+
- .document
|
78
|
+
- .gitignore
|
79
|
+
- LICENSE
|
80
|
+
- README.rdoc
|
81
|
+
- Rakefile
|
82
|
+
- VERSION
|
83
|
+
- gravatar-ultimate.gemspec
|
84
|
+
- lib/gravatar-ultimate.rb
|
85
|
+
- lib/gravatar.rb
|
86
|
+
- lib/gravatar/cache.rb
|
87
|
+
- lib/gravatar/dependencies.rb
|
88
|
+
- lib/gravatar_ultimate.rb
|
89
|
+
- spec/credentials.yml.example
|
90
|
+
- spec/fixtures/image.jpg
|
91
|
+
- spec/lib/gravatar/cache_and_logger_spec.rb
|
92
|
+
- spec/lib/gravatar/cache_setup_spec.rb
|
93
|
+
- spec/lib/gravatar/dependencies_spec.rb
|
94
|
+
- spec/lib/gravatar_spec.rb
|
95
|
+
- spec/spec.opts
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
has_rdoc: true
|
98
|
+
homepage: http://github.com/sinisterchipmunk/gravatar
|
99
|
+
licenses: []
|
100
|
+
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options:
|
103
|
+
- --charset=UTF-8
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
segments:
|
111
|
+
- 0
|
112
|
+
version: "0"
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
segments:
|
118
|
+
- 0
|
119
|
+
version: "0"
|
120
|
+
requirements: []
|
121
|
+
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 1.3.6
|
124
|
+
signing_key:
|
125
|
+
specification_version: 3
|
126
|
+
summary: "A gem for interfacing with the entire Gravatar API: not just images, but the XML-RPC API too!"
|
127
|
+
test_files:
|
128
|
+
- spec/spec_helper.rb
|
129
|
+
- spec/lib/gravatar_spec.rb
|
130
|
+
- spec/lib/gravatar/dependencies_spec.rb
|
131
|
+
- spec/lib/gravatar/cache_and_logger_spec.rb
|
132
|
+
- spec/lib/gravatar/cache_setup_spec.rb
|