imgurapi 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +123 -0
- data/Rakefile +7 -0
- data/lib/imgur/api/account.rb +23 -0
- data/lib/imgur/api/base.rb +11 -0
- data/lib/imgur/api/image.rb +37 -0
- data/lib/imgur/communication.rb +59 -0
- data/lib/imgur/extensions/array.rb +9 -0
- data/lib/imgur/extensions/hash.rb +61 -0
- data/lib/imgur/extensions/string.rb +9 -0
- data/lib/imgur/models/account.rb +3 -0
- data/lib/imgur/models/base.rb +12 -0
- data/lib/imgur/models/image.rb +19 -0
- data/lib/imgur/session.rb +45 -0
- data/lib/imgur/tasks/railtie.rb +10 -0
- data/lib/imgur/tasks/rake.rb +36 -0
- data/lib/imgur/tasks/tasks.rake +14 -0
- data/lib/imgur/version.rb +5 -0
- data/lib/imgur.rb +20 -0
- data/spec/imgur/session_spec.rb +20 -0
- data/spec/imgur_spec.rb +146 -0
- data/spec/spec_helper.rb +29 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1bf0890e8455b773f65d61bf4610a1c184ae1efe
|
4
|
+
data.tar.gz: 2def72d0ba0969f465fa2068e804f893656c56d6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 28772edd6e0ddc0fdf123b422e740b7d0d245c0ff238e60112f2d94b4f59482b2e33a06f27addd3f5779d2af1779bf5fdc087bf65e4b8c05f80ec16537780b7f
|
7
|
+
data.tar.gz: 719bd53a67db00ead9a5db9d7dd239edafdb1238f5ef6e8bccdc5fcea09092f543126ec3ad2f693ae6c3e00669abf26f813219eb7ec69acd07b615c9ba68454d
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Daniel Cruz Horts
|
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,123 @@
|
|
1
|
+
# Imgur
|
2
|
+
|
3
|
+
This gem allows you to interact with Imgur's authenticated API, version 3.
|
4
|
+
It doesn't implement all the available endpoints. So far:
|
5
|
+
- image upload, find and delete
|
6
|
+
- account image count, account details, account image list
|
7
|
+
|
8
|
+
## Imgur set-up
|
9
|
+
|
10
|
+
In order to upload images to Imgur you are going to need an Imgur application. Using an application is the preferred way, because you get twice the credits (100 per hour) than uploading as an anonymous user.
|
11
|
+
Of course, if you already have an Imgur application, you can skip this section.
|
12
|
+
|
13
|
+
To create an application visit https://imgur.com/register/api_oauth and fill the form. Pay attention to select these options:
|
14
|
+
- Application Type: Browser
|
15
|
+
- Access Type: Read & Write
|
16
|
+
|
17
|
+
Check your inbox, you will receive an email with your application Client Id and Client Secret. We are going to need them later on.
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
```ruby
|
23
|
+
gem 'imgurruby'
|
24
|
+
```
|
25
|
+
|
26
|
+
And then run:
|
27
|
+
```bash
|
28
|
+
$ bundle install
|
29
|
+
```
|
30
|
+
|
31
|
+
## Authorize your Ruby application
|
32
|
+
|
33
|
+
We now need to grant access to our Imgur user to Imgur the application, so we can upload images in his behalf. Type this and follow the instructions:
|
34
|
+
```bash
|
35
|
+
$ rake imgur:authorize CLIENT_ID='CLIENT_ID' CLIENT_SECRET='CLIENT_SECRET'
|
36
|
+
Visit this URL: http://api.imgur.com/oauth/authorize?oauth_token=xxx
|
37
|
+
And after you approved the authorization please enter your verification code: yyy
|
38
|
+
|
39
|
+
Authorization was successful. Use these credentials to initialize the library:
|
40
|
+
|
41
|
+
access_token: ACCESS_TOKEN
|
42
|
+
refresh_token: REFRESH_TOKEN
|
43
|
+
```
|
44
|
+
|
45
|
+
## Usage and overview
|
46
|
+
|
47
|
+
Create a session object to communicate to Imgur.
|
48
|
+
```ruby
|
49
|
+
imgur_session = Imgur::Session.new(client_id: 'CLIENT_ID', client_secret: 'CLIENT_SECRET', refresh_token: 'REFRESH_TOKEN')
|
50
|
+
```
|
51
|
+
|
52
|
+
Your account:
|
53
|
+
```ruby
|
54
|
+
account = imgur_session.account
|
55
|
+
{"id"=>123, "url"=>"my_account", "bio"=>nil, "reputation"=>7, "created"=>1352279501, "pro_expiration"=>false}
|
56
|
+
```
|
57
|
+
|
58
|
+
How many images you have:
|
59
|
+
```ruby
|
60
|
+
puts imgur_session.account.image_count
|
61
|
+
```
|
62
|
+
|
63
|
+
Upload your first image. Argument can be either a String or a File:
|
64
|
+
```ruby
|
65
|
+
image = imgur_session.image.image.upload('portrait.jpg')
|
66
|
+
```
|
67
|
+
|
68
|
+
image is now an instance of Imgur::Image, a convenient way to manage all the attributes of your image (at least more convenient than a multilevel dictionary):
|
69
|
+
```ruby
|
70
|
+
name = nil
|
71
|
+
title = nil
|
72
|
+
caption = nil
|
73
|
+
hash = "xyzzy"
|
74
|
+
deletehash = "abcdef"
|
75
|
+
datetime = "2012-11-18 16:22:00"
|
76
|
+
type = "image/jpeg"
|
77
|
+
animated = "false"
|
78
|
+
width = 654
|
79
|
+
height = 273
|
80
|
+
size = 47584
|
81
|
+
views = 0
|
82
|
+
bandwidth = 0
|
83
|
+
link = "http://imgur.com/xyzzy"
|
84
|
+
```
|
85
|
+
|
86
|
+
Do you need to retrieve a previously uploaded image?
|
87
|
+
```ruby
|
88
|
+
my_image = imgur_session.image.image('hash_code')
|
89
|
+
```
|
90
|
+
Granted, another Image object. It will return nil if it could not find an image matching your hash.
|
91
|
+
|
92
|
+
Feel free to use it in your Rails views:
|
93
|
+
```ruby
|
94
|
+
<%= image_tag my_image.link %>
|
95
|
+
```
|
96
|
+
|
97
|
+
How many images do you have at the moment?
|
98
|
+
```ruby
|
99
|
+
puts imgur_session.account.image_count
|
100
|
+
```
|
101
|
+
|
102
|
+
We want to delete some images. Argument can be either a String or an Image:
|
103
|
+
```ruby
|
104
|
+
imgur_session.image.image_delete(image)
|
105
|
+
imgur_session.image.image_delete('xyzzy')
|
106
|
+
```
|
107
|
+
It will return true if succeeded, false otherwise.
|
108
|
+
|
109
|
+
## Available endpoints
|
110
|
+
Not all the endpoints available at https://api.imgur.com/ have been implemented.
|
111
|
+
Feel free to suggest or pull request your needs.
|
112
|
+
|
113
|
+
The API methods have been named following Imgur's endpoints, for easy mental mapping.
|
114
|
+
Although I consider this is clearer, in the future it may change to follow the naming conventions of the official Python API.
|
115
|
+
|
116
|
+
| Type | API method | Imgur doc URL |
|
117
|
+
|---|---|---|
|
118
|
+
| Account | account.account | https://api.imgur.com/endpoints/account#account |
|
119
|
+
| Account | account.images | https://api.imgur.com/endpoints/account#images |
|
120
|
+
| Account | account.image_count | https://api.imgur.com/endpoints/account#image-count |
|
121
|
+
| Image | image.image | https://api.imgur.com/endpoints/image#image |
|
122
|
+
| Image | image.image_upload | https://api.imgur.com/endpoints/image#image-upload |
|
123
|
+
| Image | image.image_delete | https://api.imgur.com/endpoints/image#image-delete |
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Imgur
|
2
|
+
module Api
|
3
|
+
class Account < Base
|
4
|
+
|
5
|
+
# https://api.imgur.com/endpoints/account#account
|
6
|
+
def account
|
7
|
+
Imgur::Account.new communication.call(:get, 'account/me')
|
8
|
+
end
|
9
|
+
|
10
|
+
# https://api.imgur.com/endpoints/account#images
|
11
|
+
def images(page = 0)
|
12
|
+
communication.call(:get, "account/me/images/#{page}").map do |image|
|
13
|
+
Imgur::Image.new image
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# https://api.imgur.com/endpoints/account#image-count
|
18
|
+
def image_count
|
19
|
+
communication.call(:get, 'account/me/images/count')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Imgur
|
2
|
+
module Api
|
3
|
+
class Image < Base
|
4
|
+
|
5
|
+
# https://api.imgur.com/endpoints/image#image
|
6
|
+
def image(id)
|
7
|
+
raise 'Please provide a valid image identificator' if id.nil? or !id.kind_of? String or id == '' or !!(id =~ /[^\w]/)
|
8
|
+
|
9
|
+
Imgur::Image.new communication.call(:get, "image/#{id}")
|
10
|
+
end
|
11
|
+
|
12
|
+
# https://api.imgur.com/endpoints/image#image-upload
|
13
|
+
def image_upload(local_file)
|
14
|
+
if local_file.kind_of? String
|
15
|
+
file = File.open(local_file, 'rb')
|
16
|
+
elsif local_file.respond_to? :read
|
17
|
+
file = local_file
|
18
|
+
else
|
19
|
+
raise 'Must provide a File or file path'
|
20
|
+
end
|
21
|
+
|
22
|
+
Imgur::Image.new communication.call(:post, 'image', image: Base64.encode64(file.read))
|
23
|
+
end
|
24
|
+
|
25
|
+
# https://api.imgur.com/endpoints/image#image-delete
|
26
|
+
def image_delete(id)
|
27
|
+
if id.kind_of? Imgur::Image
|
28
|
+
id = id.id
|
29
|
+
end
|
30
|
+
|
31
|
+
raise 'Please provide a valid image identificator' if id.nil? or !id.kind_of? String or id == '' or !!(id =~ /[^\w]/)
|
32
|
+
|
33
|
+
communication.call(:delete, "image/#{id}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Imgur
|
2
|
+
Communication = Struct.new(:session) do
|
3
|
+
|
4
|
+
API_VERSION = 3
|
5
|
+
|
6
|
+
# RESTful network call
|
7
|
+
def call(method, endpoint, params = nil)
|
8
|
+
request do
|
9
|
+
session.connection.send method, "/#{API_VERSION}/#{endpoint}.json", params
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# Processes RESTful response according the status code
|
16
|
+
def request(&block)
|
17
|
+
3.times do
|
18
|
+
response = yield
|
19
|
+
|
20
|
+
case response.status
|
21
|
+
when 200, 404
|
22
|
+
return parse_message(response.body)['data']
|
23
|
+
when 401, 500
|
24
|
+
error_message = parse_message response.body
|
25
|
+
raise "Unauthorized: #{error_message['error']['message']}"
|
26
|
+
when 403
|
27
|
+
get_new_and_reset_token
|
28
|
+
|
29
|
+
request &block # and retry the request
|
30
|
+
else
|
31
|
+
puts response.body
|
32
|
+
raise "Response code #{response.status} not recognized"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
raise "Retried 3 times but could not get an access_token"
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_new_and_reset_token
|
40
|
+
access_token = parse_message(
|
41
|
+
session.connection.post(
|
42
|
+
'/oauth2/token',
|
43
|
+
session.params.merge(grant_type: 'refresh_token')
|
44
|
+
).body
|
45
|
+
)['access_token']
|
46
|
+
|
47
|
+
session.access_token = access_token
|
48
|
+
end
|
49
|
+
|
50
|
+
# Parses the response as JSON and returns the resulting hash
|
51
|
+
def parse_message(message)
|
52
|
+
begin
|
53
|
+
JSON.parse(message)
|
54
|
+
rescue => e
|
55
|
+
raise "Failed trying to parse response: #{e}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class Hash # :nodoc:
|
2
|
+
def slice(*keys) #:nodoc:
|
3
|
+
keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
|
4
|
+
hash = self.class.new
|
5
|
+
keys.each { |k| hash[k] = self[k] if has_key?(k) }
|
6
|
+
hash
|
7
|
+
end unless method_defined?(:slice)
|
8
|
+
|
9
|
+
def symbolize_keys # :nodoc:
|
10
|
+
inject({}) do |options, (key, value)|
|
11
|
+
options[(key.to_sym rescue key) || key] = value
|
12
|
+
options
|
13
|
+
end
|
14
|
+
end unless method_defined?(:symbolize_keys)
|
15
|
+
|
16
|
+
def symbolize_keys! # :nodoc:
|
17
|
+
self.replace(self.symbolize_keys)
|
18
|
+
end unless method_defined?(:symbolize_keys!)
|
19
|
+
|
20
|
+
def symbolize_keys_recursively # :nodoc:
|
21
|
+
hsh = symbolize_keys
|
22
|
+
hsh.each { |k, v| hsh[k] = v.symbolize_keys_recursively if v.kind_of?(Hash) }
|
23
|
+
hsh.each { |k, v| hsh[k] = v.map { |i| i.kind_of?(Hash) ? i.symbolize_keys_recursively : i } if v.kind_of?(Array) }
|
24
|
+
return hsh
|
25
|
+
end unless method_defined?(:symbolize_keys_recursively)
|
26
|
+
|
27
|
+
def stringify_keys # :nodoc:
|
28
|
+
inject({}) do |options, (key, value)|
|
29
|
+
options[(key.to_s rescue key) || key] = value
|
30
|
+
options
|
31
|
+
end
|
32
|
+
end unless method_defined?(:stringify_keys)
|
33
|
+
|
34
|
+
def stringify_keys! # :nodoc:
|
35
|
+
self.replace(self.stringify_keys)
|
36
|
+
end unless method_defined?(:stringify_keys!)
|
37
|
+
|
38
|
+
def stringify_keys_recursively # :nodoc:
|
39
|
+
hsh = stringify_keys
|
40
|
+
hsh.each { |k, v| hsh[k] = v.stringify_keys_recursively if v.kind_of?(Hash) }
|
41
|
+
hsh.each { |k, v| hsh[k] = v.map { |i| i.kind_of?(Hash) ? i.stringify_keys_recursively : i } if v.kind_of?(Array) }
|
42
|
+
return hsh
|
43
|
+
end unless method_defined?(:stringify_keys_recursively)
|
44
|
+
|
45
|
+
def to_struct # :nodoc:
|
46
|
+
struct = Struct.new(*keys).new(*values)
|
47
|
+
# attach methods for any predicate keys, since Struct.new doesn't seem to do that
|
48
|
+
pred_keys = slice(*(keys.select { |key| key.to_s.ends_with?('?') }))
|
49
|
+
pred_keys.each do |key, val|
|
50
|
+
struct.eigenclass.send(:define_method, key.to_sym) { return val }
|
51
|
+
end
|
52
|
+
return struct
|
53
|
+
end unless method_defined?(:to_struct)
|
54
|
+
|
55
|
+
def to_struct_recursively # :nodoc:
|
56
|
+
hsh = dup
|
57
|
+
hsh.each { |k, v| hsh[k] = v.to_struct_recursively if v.kind_of?(Hash) }
|
58
|
+
hsh.each { |k, v| hsh[k] = v.map { |i| i.kind_of?(Hash) ? i.to_struct_recursively : i } if v.kind_of?(Array) }
|
59
|
+
return hsh.to_struct
|
60
|
+
end unless method_defined?(:to_struct_recursively)
|
61
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class String # :nodoc:
|
2
|
+
def starts_with?(prefix) # :nodoc:
|
3
|
+
self[0, prefix.length] == prefix
|
4
|
+
end unless method_defined?(:starts_with?)
|
5
|
+
|
6
|
+
def ends_with?(suffix) # :nodoc:
|
7
|
+
self[-suffix.length, suffix.length] == suffix
|
8
|
+
end unless method_defined?(:ends_with?)
|
9
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Imgur
|
2
|
+
class Image < Base
|
3
|
+
|
4
|
+
# Provides the download URL in case you know a valid imgur hash and don't want to make a network trip with .find
|
5
|
+
# Just in case you don't need the full Imgur::Image object
|
6
|
+
def url(size = nil)
|
7
|
+
size = case size
|
8
|
+
when :small_square
|
9
|
+
's'
|
10
|
+
when :large_thumbnail
|
11
|
+
'l'
|
12
|
+
end
|
13
|
+
|
14
|
+
splitted_link = link.split('.')
|
15
|
+
|
16
|
+
splitted_link.insert(splitted_link.size - 1, size).join
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Imgur
|
2
|
+
class Session
|
3
|
+
HOST = 'https://api.imgur.com'
|
4
|
+
|
5
|
+
# Creates the session instance that handles all the API calls to Imgur
|
6
|
+
# access_token is optional
|
7
|
+
def initialize(options)
|
8
|
+
required_arguments = %i(client_id client_secret refresh_token)
|
9
|
+
raise ArgumentError if required_arguments & options.keys != required_arguments
|
10
|
+
|
11
|
+
@client_id = options[:client_id]
|
12
|
+
@client_secret = options[:client_secret]
|
13
|
+
@access_token = options[:access_token]
|
14
|
+
@refresh_token = options[:refresh_token]
|
15
|
+
end
|
16
|
+
|
17
|
+
%w(Account Image).each do |clazz|
|
18
|
+
define_method clazz.downcase do
|
19
|
+
Imgur::Api.const_get(clazz).new(self)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def access_token=(access_token)
|
24
|
+
@access_token = access_token
|
25
|
+
|
26
|
+
# Forces to create a new connection with new header
|
27
|
+
@connection = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def params
|
31
|
+
{
|
32
|
+
refresh_token: @refresh_token,
|
33
|
+
client_id: @client_id,
|
34
|
+
client_secret: @client_secret
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def connection
|
39
|
+
@connection ||= Faraday.new(
|
40
|
+
HOST,
|
41
|
+
headers: {'Authorization' => 'Bearer ' << @access_token}
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Imgur
|
2
|
+
|
3
|
+
module Rake
|
4
|
+
extend self
|
5
|
+
|
6
|
+
AUTHORIZE_ENDPOINT = '/oauth2/authorize'
|
7
|
+
TOKEN_ENDPOINT = '/oauth2/token'
|
8
|
+
|
9
|
+
def authorize(client_id, client_secret)
|
10
|
+
connection = Faraday.new(HOST)
|
11
|
+
|
12
|
+
puts "\nVisit this URL: #{HOST}#{AUTHORIZE_ENDPOINT}?client_id=#{client_id}&response_type=pin"
|
13
|
+
print 'And after you approved the authorization please enter your verification code: '
|
14
|
+
|
15
|
+
pin = STDIN.gets.strip
|
16
|
+
|
17
|
+
begin
|
18
|
+
response = JSON.parse connection.post(TOKEN_ENDPOINT, pin: pin, client_id: client_id, client_secret: client_secret, grant_type: 'pin').body
|
19
|
+
rescue
|
20
|
+
puts "Authorization failed.\nPlease try again."
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
|
24
|
+
puts <<-MESSAGE
|
25
|
+
|
26
|
+
Authorization was successful. Use these credentials to initialize the library:
|
27
|
+
|
28
|
+
access_token: #{response['access_token']}
|
29
|
+
refresh_secret: #{response['refresh_token']}
|
30
|
+
|
31
|
+
MESSAGE
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'imgur' # We need HOST to be available
|
2
|
+
require 'imgur/tasks/rake'
|
3
|
+
|
4
|
+
namespace :imgur do
|
5
|
+
desc 'Obtain your Imgur tokens'
|
6
|
+
task :authorize do
|
7
|
+
if ENV['CLIENT_ID'].nil? or ENV['CLIENT_SECRET'].nil?
|
8
|
+
puts "USAGE: `rake imgur:authorize CLIENT_ID=your_client_id CLIENT_SECRET=your_client_secret`"
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
|
12
|
+
Imgur::Rake.authorize(ENV['CLIENT_ID'], ENV['CLIENT_SECRET'])
|
13
|
+
end
|
14
|
+
end
|
data/lib/imgur.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# Gem dependencies
|
2
|
+
require 'faraday'
|
3
|
+
require 'json'
|
4
|
+
require 'base64'
|
5
|
+
|
6
|
+
# Some nice extensions to base classes
|
7
|
+
require 'imgur/extensions/array'
|
8
|
+
require 'imgur/extensions/hash'
|
9
|
+
require 'imgur/extensions/string'
|
10
|
+
|
11
|
+
# This gem real code
|
12
|
+
require 'imgur/version'
|
13
|
+
require 'imgur/api/base'
|
14
|
+
require 'imgur/api/account'
|
15
|
+
require 'imgur/api/image'
|
16
|
+
require 'imgur/communication'
|
17
|
+
require 'imgur/session'
|
18
|
+
require 'imgur/models/base'
|
19
|
+
require 'imgur/models/account'
|
20
|
+
require 'imgur/models/image'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require 'imgur'
|
3
|
+
|
4
|
+
describe Imgur::Session do
|
5
|
+
|
6
|
+
context 'incorrect credentials' do
|
7
|
+
it { expect { Imgur::Session.new }.to raise_error }
|
8
|
+
it { expect { Imgur::Session.new(random_key: nil) }.to raise_error }
|
9
|
+
it { expect { Imgur::Session.new(client_id: nil, random_key: nil) }.to raise_error }
|
10
|
+
it { expect { Imgur::Session.new({}) }.to raise_error }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'correct credentials' do
|
14
|
+
it do
|
15
|
+
expect(
|
16
|
+
Imgur::Session.new(client_id: 'ID', client_secret: 'SECRET', refresh_token: 'TOKEN')
|
17
|
+
).to be_an_instance_of Imgur::Session
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/spec/imgur_spec.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
require 'imgur'
|
3
|
+
|
4
|
+
describe Imgur do
|
5
|
+
|
6
|
+
describe 'placeholder classes' do
|
7
|
+
|
8
|
+
it 'should create an Image with the fields provided' do
|
9
|
+
image = Imgur::Image.new
|
10
|
+
image.should be_an_instance_of Imgur::Image
|
11
|
+
|
12
|
+
fields = {:a => 1, :b => 2}
|
13
|
+
image = Imgur::Image.new(fields)
|
14
|
+
image.should be_an_instance_of Imgur::Image
|
15
|
+
image.a.should eq(1)
|
16
|
+
image.b.should eq(2)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should create a Link with the fields provided' do
|
20
|
+
links = Imgur::Links.new
|
21
|
+
links.should be_an_instance_of Imgur::Links
|
22
|
+
|
23
|
+
fields = {:a => 1, :b => 2}
|
24
|
+
links = Imgur::Links.new(fields)
|
25
|
+
links.should be_an_instance_of Imgur::Links
|
26
|
+
links.a.should eq(1)
|
27
|
+
links.b.should eq(2)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'api' do
|
33
|
+
|
34
|
+
it 'should return a download URL' do
|
35
|
+
imgur_hash = 'random_valid_hash'
|
36
|
+
|
37
|
+
@session.url(:foo).should eq('')
|
38
|
+
@session.url().should eq('')
|
39
|
+
@session.url(imgur_hash).should eq("http://i.imgur.com/#{imgur_hash}.jpg")
|
40
|
+
@session.url(imgur_hash, :random_size).should eq("http://i.imgur.com/#{imgur_hash}.jpg")
|
41
|
+
@session.url(imgur_hash, :small_square).should eq("http://i.imgur.com/#{imgur_hash}s.jpg")
|
42
|
+
@session.url(imgur_hash, :large_thumbnail).should eq("http://i.imgur.com/#{imgur_hash}l.jpg")
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'communication' do
|
48
|
+
|
49
|
+
before(:all) do
|
50
|
+
credentials = read_credentials_file
|
51
|
+
@session = Imgur::Session.new(credentials)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should parse_message' do
|
55
|
+
@session.send(:parse_message, '[]').should eq([])
|
56
|
+
expect { session.send(:parse_message) }.to raise_error
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should process_message' do
|
60
|
+
Response = Struct.new(:code, :body)
|
61
|
+
|
62
|
+
response = Response.new(200, '[]')
|
63
|
+
@session.send(:process_response, response).should eq([])
|
64
|
+
|
65
|
+
response = Response.new(404, '[]')
|
66
|
+
@session.send(:process_response, response).should eq([])
|
67
|
+
|
68
|
+
response = Response.new(401, '{"error": {"message": "1"}}')
|
69
|
+
expect { @session.send(:process_response, response) }.to raise_error "Unauthorized: 1"
|
70
|
+
|
71
|
+
response = Response.new(500, '{"error": {"message": "1"}}')
|
72
|
+
expect { @session.send(:process_response, response) }.to raise_error "Unauthorized: 1"
|
73
|
+
|
74
|
+
code = rand(999)
|
75
|
+
response = Response.new(code, '')
|
76
|
+
expect { @session.send(:process_response, response) }.to raise_error "Response code #{code} not recognized"
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should compose_image' do
|
80
|
+
@session.send(:compose_image, {}).should eq(nil)
|
81
|
+
@session.send(:compose_image, {:imags => {:image => {}, :links => {}}}).should eq(nil)
|
82
|
+
@session.send(:compose_image, {:images => {:imae => {}, :links => {}}}).should eq(nil)
|
83
|
+
@session.send(:compose_image, {:images => {:image => {}, :lins => {}}}).should eq(nil)
|
84
|
+
@session.send(:compose_image, {:images => {}}).should eq(nil)
|
85
|
+
|
86
|
+
from_hash = {:images => {:image => {}, :links => {}}}
|
87
|
+
@session.send(:compose_image, from_hash).should be_an_instance_of Imgur::Image
|
88
|
+
@session.send(:compose_image, from_hash).links.should be_an_instance_of Imgur::Links
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'image management calls' do
|
94
|
+
|
95
|
+
before(:all) do
|
96
|
+
credentials = read_credentials_file
|
97
|
+
@session = Imgur::Session.new(credentials)
|
98
|
+
@upload_path, @upload_file = my_sample_image
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should return my account information' do
|
102
|
+
@session.account.should be_an_instance_of Hash
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should return the number of images stored' do
|
106
|
+
@session.images_count.should > 0
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should upload the image' do
|
110
|
+
expect { @session.upload('') }.to raise_error
|
111
|
+
expect { @session.upload(:not_the_expected_object) }.to raise_error
|
112
|
+
|
113
|
+
@@image_by_path = @session.upload(@upload_path) #FIXME I know this is horrible, but I need to share the same image between tests http://brentlavelle.wordpress.com/2011/04/04/rspec-and-instance-variables/
|
114
|
+
@@image_by_path.should be_an_instance_of Imgur::Image
|
115
|
+
|
116
|
+
@@image_by_file = @session.upload(@upload_file)
|
117
|
+
@@image_by_file.should be_an_instance_of Imgur::Image
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should retrieve the image' do
|
121
|
+
expect { @session.find(:not_an_image_hash) }.to raise_error
|
122
|
+
expect { @session.find('r4ndom ha5h') }.to raise_error
|
123
|
+
|
124
|
+
image = @session.find('valid_hash_not_related_to_any_image')
|
125
|
+
image.should be_nil
|
126
|
+
|
127
|
+
image = @session.find(@@image_by_path.hash)
|
128
|
+
image.should be_an_instance_of Imgur::Image
|
129
|
+
|
130
|
+
image.hash.should eq(@@image_by_path.hash)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'should delete the image' do
|
134
|
+
expect { @session.destroy(:not_an_image_hash) }.to raise_error
|
135
|
+
expect { @session.destroy('r4ndom ha5h') }.to raise_error
|
136
|
+
|
137
|
+
@session.destroy('valid_hash_not_related_to_any_image').should be_false
|
138
|
+
|
139
|
+
@session.destroy(@@image_by_path).should be_true #deletes first image
|
140
|
+
|
141
|
+
@session.destroy(@@image_by_file.hash).should be_true #deletes second image
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module EverythingAsExpected
|
2
|
+
|
3
|
+
def read_credentials_file
|
4
|
+
unless File.exist? 'credentials.json'
|
5
|
+
raise "Please add a credentials.json file to the project directory containing your Imgur app_key, app_secret, access_token and access_token_secret. See credentials.json.example to get started."
|
6
|
+
end
|
7
|
+
|
8
|
+
credentials_file_contents = File.open('credentials.json', 'r').read
|
9
|
+
credentials = JSON.parse(credentials_file_contents)
|
10
|
+
if credentials.keys.count != 4 and credentials.keys & [:app_key, :app_secret, :access_token, :access_token_secret] != [:app_key, :app_secret, :access_token, :access_token_secret]
|
11
|
+
raise "Your credentials.json file does contain all the required information. See credentials.json.example for more help."
|
12
|
+
end
|
13
|
+
|
14
|
+
credentials.symbolize_keys
|
15
|
+
end
|
16
|
+
|
17
|
+
def my_sample_image
|
18
|
+
unless File.exist? 'sample.jpg'
|
19
|
+
raise "Please add a sample.jpg file to the project directory to test upload and download. Recommended size: under 30kB"
|
20
|
+
end
|
21
|
+
|
22
|
+
['sample.jpg', File.open('sample.jpg', 'r')]
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
RSpec.configure do |config|
|
28
|
+
config.include(EverythingAsExpected)
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: imgurapi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Cruz Horts
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry-byebug
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: An interface to the Imgur authenticated API
|
56
|
+
email:
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- LICENSE.txt
|
62
|
+
- README.md
|
63
|
+
- Rakefile
|
64
|
+
- lib/imgur.rb
|
65
|
+
- lib/imgur/api/account.rb
|
66
|
+
- lib/imgur/api/base.rb
|
67
|
+
- lib/imgur/api/image.rb
|
68
|
+
- lib/imgur/communication.rb
|
69
|
+
- lib/imgur/extensions/array.rb
|
70
|
+
- lib/imgur/extensions/hash.rb
|
71
|
+
- lib/imgur/extensions/string.rb
|
72
|
+
- lib/imgur/models/account.rb
|
73
|
+
- lib/imgur/models/base.rb
|
74
|
+
- lib/imgur/models/image.rb
|
75
|
+
- lib/imgur/session.rb
|
76
|
+
- lib/imgur/tasks/railtie.rb
|
77
|
+
- lib/imgur/tasks/rake.rb
|
78
|
+
- lib/imgur/tasks/tasks.rake
|
79
|
+
- lib/imgur/version.rb
|
80
|
+
- spec/imgur/session_spec.rb
|
81
|
+
- spec/imgur_spec.rb
|
82
|
+
- spec/spec_helper.rb
|
83
|
+
homepage: https://github.com/dncrht/imgur
|
84
|
+
licenses:
|
85
|
+
- MIT
|
86
|
+
metadata: {}
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubyforge_project:
|
103
|
+
rubygems_version: 2.2.2
|
104
|
+
signing_key:
|
105
|
+
specification_version: 4
|
106
|
+
summary: Imgur authenticated API
|
107
|
+
test_files:
|
108
|
+
- spec/imgur/session_spec.rb
|
109
|
+
- spec/imgur_spec.rb
|
110
|
+
- spec/spec_helper.rb
|
111
|
+
has_rdoc:
|