social-avatar-proxy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ **.DS_Store
data/.rvmrc ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+
3
+ if ! rvm list | grep -q ruby-1.9.3-p194 ; then
4
+ rvm install 1.9.3-p194
5
+ fi
6
+
7
+ rvm 1.9.3-p194@platformq_social_avatar_proxy --create
8
+
9
+ if ! gem list | grep -q bundler ; then
10
+ gem install --no-ri --no-rdoc bundler
11
+ bundle install --without production
12
+ fi
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in social-avatar-proxy.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Platform Q LLC
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # SocialAvatarProxy
2
+
3
+ This gem acts as a proxy for avatars on Twitter & Facebook.
4
+
5
+ [![Build Status][2]][1]
6
+
7
+ [1]: http://travis-ci.org/platformq/social-avatar-proxy
8
+ [2]: https://secure.travis-ci.org/platformq/social-avatar-proxy.png?branch=master
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem "social-avatar-proxy"
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install social-avatar-proxy
25
+
26
+ ## Usage
27
+
28
+ This usage is based on Rails, however it should be easily adaptable for other languages:
29
+
30
+ In your `config/routes.rb` file:
31
+
32
+ ```ruby
33
+ mount SocialAvatarProxy::App, at: "/avatars"
34
+ ```
35
+
36
+ In your views:
37
+
38
+ ```ruby
39
+ # for a Twitter user, by username:
40
+ image_tag(twitter_avatar_path("username"))
41
+ # by ID:
42
+ image_tag(twitter_avatar_path(12345))
43
+
44
+ # for a Facebook user, by username:
45
+ image_tag(facebook_avatar_path("username"))
46
+ # by ID:
47
+ image_tag(facebook_avatar_path(12345))
48
+ ```
49
+
50
+ The above helper methods are provided by the `SocialAvatarProxy::Paths` module.
51
+
52
+ ## Contributing
53
+
54
+ 1. Fork it
55
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
56
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
57
+ 4. Push to the branch (`git push origin my-new-feature`)
58
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require "rspec/core/rake_task"
5
+
6
+ desc "Runs all the specs"
7
+ task default: %w(spec)
8
+
9
+ desc "Run specs"
10
+ RSpec::Core::RakeTask.new do |t|
11
+ t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
12
+ # Put spec opts in a file named .rspec in root
13
+ end
@@ -0,0 +1 @@
1
+ require "social_avatar_proxy"
@@ -0,0 +1,76 @@
1
+ require "social_avatar_proxy/facebook_avatar"
2
+ require "social_avatar_proxy/twitter_avatar"
3
+ require "rack"
4
+
5
+ module SocialAvatarProxy
6
+ class App
7
+ def self.call(env, options = {})
8
+ new(env, options).response.finish
9
+ end
10
+
11
+ attr_reader :options
12
+
13
+ def initialize(env, options = {})
14
+ @request = Rack::Request.new(env)
15
+ @options = {
16
+ expires: 86400, # 1 day from now
17
+ cache_control: {
18
+ max_age: 86400, # store for 1 day, after that re-request
19
+ max_stale: 86400, # allow cache to be a day stale
20
+ public: true # allow proxy caching
21
+ }
22
+ }.merge(options)
23
+ end
24
+
25
+ def not_found
26
+ Rack::Response.new("Not Found", 404)
27
+ end
28
+
29
+ def response
30
+ # ensure this is a valid avatar request
31
+ unless @request.path =~ /^\/(facebook|twitter)\/([\w\-\.]+)(\.(jpe?g|png|gif|bmp))?$/i
32
+ return not_found
33
+ end
34
+ # load the avatar
35
+ avatar = load_avatar($1, $2)
36
+ # if it exists
37
+ if avatar.exist?
38
+ # render the avatar to the response
39
+ Rack::Response.new do |response|
40
+ # set the last modified header
41
+ response["Last-Modified"] = avatar.last_modified
42
+ # set the content type header
43
+ response["Content-Type"] = avatar.content_type
44
+ # if we want to expire in a set time, calculate the header
45
+ if options[:expires]
46
+ response["Expires"] = (Time.now + options[:expires]).httpdate
47
+ end
48
+ # if we want to set cache control settings
49
+ if cc = options[:cache_control]
50
+ directives = []
51
+ directives << "no-cache" if cc[:no_cache]
52
+ directives << "max-stale=#{cc[:max_stale]}" if cc[:max_stale]
53
+ directives << "max-age=#{cc[:max_age]}" if cc[:max_age]
54
+ directives << cc[:public] ? "public" : "private"
55
+ response["Cache-Control"] = directives.join("; ")
56
+ end
57
+ # set the data
58
+ response.write(avatar.body)
59
+ end
60
+ # if the avatar doesn't exist
61
+ else
62
+ not_found
63
+ end
64
+ end
65
+
66
+ private
67
+ def load_avatar(service, id)
68
+ # titleize the service name
69
+ service = service.gsub(/[\_\-]/, " ").gsub(/\b([a-z])/) do |match|
70
+ match.upcase
71
+ end
72
+ # pass it onto the
73
+ SocialAvatarProxy.const_get("#{service}Avatar").new(id)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,58 @@
1
+ require "social_avatar_proxy/remote_file_resolver"
2
+
3
+ module SocialAvatarProxy
4
+ class Avatar
5
+ attr_reader :identifier
6
+
7
+ def initialize(identifier)
8
+ @identifier = identifier
9
+ end
10
+
11
+ # downloads the avatar from the remote server
12
+ def body
13
+ response.body
14
+ end
15
+
16
+ # returns whether the avatar returns a successful response
17
+ def exist?
18
+ @exists ||= begin
19
+ # ensure the response is success/redirect
20
+ response.code.to_i.between?(200, 399)
21
+ end
22
+ end
23
+ alias_method :exists?, :exist?
24
+
25
+ # returns the last modified timestamp
26
+ def last_modified
27
+ @last_modified ||= begin
28
+ response["last-modified"] &&
29
+ Time.parse(response["last-modified"]) or
30
+ Time.now
31
+ end
32
+ end
33
+
34
+ # returns the content type of the file
35
+ def content_type
36
+ @content_type ||= begin
37
+ response["content-type"] ||
38
+ "image/jpeg"
39
+ end
40
+ end
41
+
42
+ # returns whether the avatar has changed
43
+ def modified_since?(timestamp)
44
+ last_modified > timestamp
45
+ end
46
+
47
+ # in the base Avatar class, we'll use the identifier as the URL
48
+ def remote_url
49
+ identifier
50
+ end
51
+
52
+ private
53
+ # request the remote file
54
+ def response
55
+ @response ||= RemoteFileResolver.new(remote_url).resolve
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,13 @@
1
+ require "social_avatar_proxy/avatar"
2
+
3
+ module SocialAvatarProxy
4
+ class FacebookAvatar < Avatar
5
+ def remote_url
6
+ if identifier =~ /^[\w\-\.]+$/i
7
+ "https://graph.facebook.com/#{identifier}/picture"
8
+ else
9
+ raise RuntimeError, "Identifier contains invalid characters"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,49 @@
1
+ require "net/https"
2
+ require "net/http"
3
+ require "uri"
4
+ require "timeout"
5
+
6
+ module SocialAvatarProxy
7
+ class TooManyRedirects < StandardError; end
8
+ class TimeoutError < Timeout::Error; end
9
+
10
+ class RemoteFileResolver
11
+ def initialize(url, limit = 5)
12
+ # timeout if we have no redirects left
13
+ raise TooManyRedirects if limit <= 0
14
+ # store the limit and URL
15
+ @url, @redirect_limit = url, limit
16
+ end
17
+
18
+ def resolve
19
+ response = Timeout::timeout(30) do
20
+ perform_request
21
+ end
22
+
23
+ # if this is a redirect
24
+ if response.kind_of?(Net::HTTPRedirection)
25
+ # follow the redirect
26
+ resolver = self.class.new(response["location"], @redirect_limit - 1)
27
+ resolver.resolve
28
+ # if this is not a redirect
29
+ else
30
+ # return the response
31
+ response
32
+ end
33
+ rescue Timeout::Error => e
34
+ raise TimeoutError, e.message, e.backtrace
35
+ end
36
+
37
+ private
38
+ def uri
39
+ URI.parse(@url)
40
+ end
41
+
42
+ def perform_request
43
+ http = Net::HTTP.new(uri.host, uri.port)
44
+ http.use_ssl = uri.scheme == "https"
45
+ request = Net::HTTP::Get.new(uri.request_uri)
46
+ http.request(request)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,15 @@
1
+ require "social_avatar_proxy/avatar"
2
+
3
+ module SocialAvatarProxy
4
+ class TwitterAvatar < Avatar
5
+ def remote_url
6
+ if identifier =~ /^\d+$/
7
+ "http://api.twitter.com/1/users/profile_image?user_id=#{identifier}&size=original"
8
+ elsif identifier =~ /^[\w\-\.]+$/i
9
+ "http://api.twitter.com/1/users/profile_image?screen_name=#{identifier}&size=original"
10
+ else
11
+ raise RuntimeError, "Identifier contains invalid characters"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module SocialAvatarProxy
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,5 @@
1
+ require "social_avatar_proxy/version"
2
+ require "social_avatar_proxy/app"
3
+ require "social_avatar_proxy/avatar"
4
+ require "social_avatar_proxy/facebook_avatar"
5
+ require "social_avatar_proxy/twitter_avatar"
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require "social_avatar_proxy/version"
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "social-avatar-proxy"
9
+ s.version = SocialAvatarProxy::VERSION
10
+ s.authors = ["Ryan Townsend"]
11
+ s.email = ["ryan@ryantownsend.co.uk"]
12
+ s.description = %q{This gem acts as a proxy for avatars on Twitter & Facebook.}
13
+ s.summary = s.description
14
+ s.homepage = "https://github.com/platformq/social-avatar-proxy"
15
+ s.license = "MIT"
16
+
17
+ s.files = `git ls-files`.split($/)
18
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
19
+ s.test_files = s.files.grep(%r{^(spec|features)/})
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "rack"
23
+
24
+ s.add_development_dependency "rake"
25
+ s.add_development_dependency "rspec"
26
+ s.add_development_dependency "simplecov"
27
+ s.add_development_dependency "foreman"
28
+ end
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+ require "rack"
3
+
4
+ describe SocialAvatarProxy::App do
5
+ subject do
6
+ app = SocialAvatarProxy::App
7
+ Rack::MockRequest.new(app)
8
+ end
9
+
10
+ let(:successful_response) do
11
+ response = Net::HTTPSuccess.new("1.1", 200, "Success")
12
+ response.stub(:stream_check).and_return(true)
13
+ response.stub(:read_body).and_return("data")
14
+ response
15
+ end
16
+
17
+ let(:not_found_response) do
18
+ Net::HTTPNotFound.new("1.1", 404, "Not Found")
19
+ end
20
+
21
+ let(:response) { nil }
22
+
23
+ before(:each) do
24
+ klass = SocialAvatarProxy::Avatar
25
+ klass.any_instance.stub(:response).and_return(response)
26
+ end
27
+
28
+ context "given an invalid path" do
29
+ it "should return a 404 response" do
30
+ path = "/unknown"
31
+ expect(subject.get(path).status).to eq(404)
32
+ end
33
+ end
34
+
35
+ context "given a valid path" do
36
+ context "that finds an existing avatar" do
37
+ let(:response) { successful_response }
38
+
39
+ it "should return a 200 response" do
40
+ path = "/facebook/61413673"
41
+ expect(subject.get(path).status).to eq(200)
42
+ end
43
+ end
44
+
45
+ context "that fails to find an avatar" do
46
+ let(:response) { not_found_response }
47
+
48
+ it "should return a 404 response" do
49
+ path = "/facebook/someRandomUserThatDoesntExist"
50
+ expect(subject.get(path).status).to eq(404)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,99 @@
1
+ require "spec_helper"
2
+
3
+ describe SocialAvatarProxy::Avatar do
4
+ subject do
5
+ SocialAvatarProxy::Avatar.new(id)
6
+ end
7
+
8
+ let(:id) { "http://www.example.com/" }
9
+
10
+ let(:response) { nil }
11
+
12
+ let(:successful_response) do
13
+ response = Net::HTTPSuccess.new("1.1", 200, "Success")
14
+ response.stub(:stream_check).and_return(true)
15
+ response.stub(:read_body).and_return("data")
16
+ response
17
+ end
18
+
19
+ before(:each) do
20
+ klass = SocialAvatarProxy::RemoteFileResolver
21
+ klass.any_instance.stub(:resolve).and_return(response)
22
+ end
23
+
24
+ describe "#remote_url" do
25
+ it "should return the identifier" do
26
+ expect(subject.remote_url).to eq(id)
27
+ end
28
+ end
29
+
30
+ context "with a valid response" do
31
+ let(:response) { successful_response }
32
+
33
+ describe "#exist?" do
34
+ it "should be true" do
35
+ expect(subject.exist?).to be_true
36
+ end
37
+ end
38
+
39
+ describe "#body" do
40
+ it "should be able to download the body" do
41
+ expect(subject.body).to eq "data"
42
+ end
43
+ end
44
+
45
+ describe "#content_type" do
46
+ context "with a content-type header" do
47
+ before(:each) do
48
+ response.stub(:[]).with("content-type").and_return("image/png")
49
+ end
50
+
51
+ it "should return the header value" do
52
+ expect(subject.content_type).to eq("image/png")
53
+ end
54
+ end
55
+
56
+ context "with a content-type header" do
57
+ it "should return image/jpeg as the default" do
58
+ expect(subject.content_type).to eq("image/jpeg")
59
+ end
60
+ end
61
+ end
62
+
63
+ context "with a last-modified header" do
64
+ before(:each) do
65
+ response.stub(:[]).with("last-modified").and_return(timestamp.httpdate)
66
+ end
67
+
68
+ let(:timestamp) { Time.now - 86400 }
69
+
70
+ describe "#last_modified" do
71
+ it "should parse the header and return a DateTime object" do
72
+ expect(subject.last_modified.to_i).to eq(timestamp.to_i)
73
+ end
74
+ end
75
+
76
+ describe "#modified_since?" do
77
+ context "given a date older than the timestamp" do
78
+ it "should return true" do
79
+ expect(subject.modified_since?(timestamp - 86400)).to be_true
80
+ end
81
+ end
82
+
83
+ context "given a date newer than the timestamp" do
84
+ it "should return true" do
85
+ expect(subject.modified_since?(Time.now)).to be_false
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ context "with no last-modified header" do
92
+ describe "#last_modified" do
93
+ it "should return the current time" do
94
+ expect(subject.last_modified.to_i).to eq(Time.now.to_i)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,39 @@
1
+ require "spec_helper"
2
+
3
+ describe SocialAvatarProxy::FacebookAvatar do
4
+ subject do
5
+ SocialAvatarProxy::FacebookAvatar.new(id)
6
+ end
7
+
8
+ context "with a valid user ID" do
9
+ let(:id) { "61413673" }
10
+
11
+ describe "#remote_url" do
12
+ it "should return a valid URL" do
13
+ expected = "https://graph.facebook.com/#{id}/picture"
14
+ expect(subject.remote_url).to eq(expected)
15
+ end
16
+ end
17
+ end
18
+
19
+ context "with a valid user name" do
20
+ let(:id) { "ryandtownsend" }
21
+
22
+ describe "#remote_url" do
23
+ it "should return a valid URL" do
24
+ expected = "https://graph.facebook.com/#{id}/picture"
25
+ expect(subject.remote_url).to eq(expected)
26
+ end
27
+ end
28
+ end
29
+
30
+ context "with an invalid identifier" do
31
+ let(:id) { "$omeInvalidN@me" }
32
+
33
+ describe "#remote_url" do
34
+ it "should raise an error" do
35
+ expect { subject.remote_url }.to raise_error(RuntimeError)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,66 @@
1
+ require "spec_helper"
2
+
3
+ describe SocialAvatarProxy::RemoteFileResolver do
4
+ subject do
5
+ SocialAvatarProxy::RemoteFileResolver.new(url, limit)
6
+ end
7
+
8
+ let(:url) { "http://www.example.com/" }
9
+
10
+ let(:limit) { 5 }
11
+
12
+ let(:redirect_response) do
13
+ response = Net::HTTPRedirection.new("1.1", 301, "Moved")
14
+ response["location"] = url
15
+ response
16
+ end
17
+
18
+ let(:successful_response) do
19
+ response = Net::HTTPSuccess.new("1.1", 200, "Success")
20
+ response.body = "data"
21
+ response
22
+ end
23
+
24
+ context "when the response redirects permanently" do
25
+ before(:each) do
26
+ subject.class.any_instance.stub(:perform_request).and_return(redirect_response)
27
+ end
28
+
29
+ it "should throw an exception" do
30
+ expect {
31
+ subject.resolve
32
+ }.to raise_error(SocialAvatarProxy::TooManyRedirects)
33
+ end
34
+ end
35
+
36
+ context "when the response redirects less times than the limit" do
37
+ let(:redirect_count) { limit - 1 }
38
+ let(:responses) do
39
+ set = (1..redirect_count).to_a.map { redirect_response }
40
+ set << successful_response
41
+ set
42
+ end
43
+
44
+ before(:each) do
45
+ subject.class.any_instance.stub(:perform_request).and_return do
46
+ responses.delete_at(0)
47
+ end
48
+ end
49
+
50
+ it "should return the successful response" do
51
+ expect(subject.resolve).to eq(successful_response)
52
+ end
53
+ end
54
+
55
+ context "when the response times out" do
56
+ before(:each) do
57
+ subject.should_receive(:perform_request).once.and_raise(Timeout::Error)
58
+ end
59
+
60
+ it "should throw an exception" do
61
+ expect {
62
+ subject.resolve
63
+ }.to raise_error(SocialAvatarProxy::TimeoutError)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,39 @@
1
+ require "spec_helper"
2
+
3
+ describe SocialAvatarProxy::TwitterAvatar do
4
+ subject do
5
+ SocialAvatarProxy::TwitterAvatar.new(id)
6
+ end
7
+
8
+ context "with a valid user ID" do
9
+ let(:id) { "2202971" }
10
+
11
+ describe "#remote_url" do
12
+ it "should return a valid URL" do
13
+ expected = "http://api.twitter.com/1/users/profile_image?user_id=#{id}&size=original"
14
+ expect(subject.remote_url).to eq(expected)
15
+ end
16
+ end
17
+ end
18
+
19
+ context "with a valid user name" do
20
+ let(:id) { "RyanTownsend" }
21
+
22
+ describe "#remote_url" do
23
+ it "should return a valid URL" do
24
+ expected = "http://api.twitter.com/1/users/profile_image?screen_name=#{id}&size=original"
25
+ expect(subject.remote_url).to eq(expected)
26
+ end
27
+ end
28
+ end
29
+
30
+ context "with an invalid identifier" do
31
+ let(:id) { "$omeInvalidN@me" }
32
+
33
+ describe "#remote_url" do
34
+ it "should raise an error" do
35
+ expect { subject.remote_url }.to raise_error(RuntimeError)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ require "simplecov"
2
+ SimpleCov.start do
3
+ add_filter "/spec/"
4
+ end
5
+
6
+ require "bundler"
7
+ Bundler.require
8
+
9
+ Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].each { |f| require f }
@@ -0,0 +1,8 @@
1
+ RSpec.configure do |config|
2
+ config.expect_with :rspec do |c|
3
+ c.syntax = :expect
4
+ end
5
+
6
+ config.color_enabled = true
7
+ config.order = :random
8
+ end
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: social-avatar-proxy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ryan Townsend
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: simplecov
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: foreman
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description: This gem acts as a proxy for avatars on Twitter & Facebook.
95
+ email:
96
+ - ryan@ryantownsend.co.uk
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - .gitignore
102
+ - .rvmrc
103
+ - .travis.yml
104
+ - Gemfile
105
+ - LICENSE.txt
106
+ - README.md
107
+ - Rakefile
108
+ - lib/social-avatar-proxy.rb
109
+ - lib/social_avatar_proxy.rb
110
+ - lib/social_avatar_proxy/app.rb
111
+ - lib/social_avatar_proxy/avatar.rb
112
+ - lib/social_avatar_proxy/facebook_avatar.rb
113
+ - lib/social_avatar_proxy/remote_file_resolver.rb
114
+ - lib/social_avatar_proxy/twitter_avatar.rb
115
+ - lib/social_avatar_proxy/version.rb
116
+ - social-avatar-proxy.gemspec
117
+ - spec/social_avatar_proxy/app_spec.rb
118
+ - spec/social_avatar_proxy/avatar_spec.rb
119
+ - spec/social_avatar_proxy/facebook_avatar_spec.rb
120
+ - spec/social_avatar_proxy/remote_file_resolver_spec.rb
121
+ - spec/social_avatar_proxy/twitter_avatar_spec.rb
122
+ - spec/spec_helper.rb
123
+ - spec/support/env.rb
124
+ homepage: https://github.com/platformq/social-avatar-proxy
125
+ licenses:
126
+ - MIT
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ segments:
138
+ - 0
139
+ hash: -3304292752345164634
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ none: false
142
+ requirements:
143
+ - - ! '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ segments:
147
+ - 0
148
+ hash: -3304292752345164634
149
+ requirements: []
150
+ rubyforge_project:
151
+ rubygems_version: 1.8.24
152
+ signing_key:
153
+ specification_version: 3
154
+ summary: This gem acts as a proxy for avatars on Twitter & Facebook.
155
+ test_files:
156
+ - spec/social_avatar_proxy/app_spec.rb
157
+ - spec/social_avatar_proxy/avatar_spec.rb
158
+ - spec/social_avatar_proxy/facebook_avatar_spec.rb
159
+ - spec/social_avatar_proxy/remote_file_resolver_spec.rb
160
+ - spec/social_avatar_proxy/twitter_avatar_spec.rb
161
+ - spec/spec_helper.rb
162
+ - spec/support/env.rb