net 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +4 -0
- data/README.md +69 -9
- data/lib/net/instagram.rb +10 -0
- data/lib/net/instagram/api/configuration.rb +14 -0
- data/lib/net/instagram/api/request.rb +51 -0
- data/lib/net/instagram/config.rb +16 -0
- data/lib/net/instagram/errors.rb +3 -0
- data/lib/net/instagram/errors/private_user.rb +11 -0
- data/lib/net/instagram/errors/response_error.rb +14 -0
- data/lib/net/instagram/errors/unknown_user.rb +11 -0
- data/lib/net/instagram/models.rb +1 -0
- data/lib/net/instagram/models/user.rb +64 -0
- data/lib/net/twitter/models/user.rb +4 -4
- data/lib/net/version.rb +1 -1
- data/spec/net/instagram/models/user_spec.rb +61 -0
- data/spec/net/twitter/models/user_spec.rb +59 -59
- data/spec/spec_helper.rb +0 -11
- data/spec/support/cassettes/Net_Instagram_Models_User/_find_by/given_a_private_username/.yml +144 -0
- data/spec/support/cassettes/Net_Instagram_Models_User/_find_by/given_an_existing_case-insensitive_username/returns_an_object_representing_that_user.yml +149 -0
- data/spec/support/cassettes/Net_Instagram_Models_User/_find_by/given_an_unknown_username/.yml +54 -0
- data/spec/support/cassettes/Net_Instagram_Models_User/_find_by_/given_a_private_username/.yml +144 -0
- data/spec/support/cassettes/Net_Instagram_Models_User/_find_by_/given_an_existing_case-insensitive_username/returns_an_object_representing_that_user.yml +149 -0
- data/spec/support/cassettes/Net_Instagram_Models_User/_find_by_/given_an_unknown_username/.yml +54 -0
- data/spec/support/vcr.rb +4 -1
- metadata +26 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 936c43b38462cae57221b9992994d3e8e767f5cd
|
4
|
+
data.tar.gz: ea789f7e15df8dd201fcaac9bb74f80a3f5982fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9780280470cdcf98a13c1d3c2cf384a0dd6f1ea3e913224d851ba682a67dd118549fe619987eeaec92852976def7695ecf7e94a88530594b3a0cca8a7f710986
|
7
|
+
data.tar.gz: 1c7d9f4a06aa83f4bac0a5f189feed5023a9f50d79ba7b6162a853e027af81ab1d516493e974588a030e8e506117e3f22e78e10aa7f0996c8df9eea7158c7259
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,16 +1,23 @@
|
|
1
1
|
Net - a Ruby client for social networks API
|
2
2
|
===========================================
|
3
3
|
|
4
|
-
Net helps you write apps that need to interact with Twitter.
|
4
|
+
Net helps you write apps that need to interact with Twitter and Instagram.
|
5
5
|
|
6
6
|
|
7
|
-
After [configuring your Twitter app](#configuring-your-app), you can run commands like:
|
7
|
+
After [configuring your Twitter app](#configuring-your-twitter-app), you can run commands like:
|
8
8
|
|
9
9
|
```ruby
|
10
10
|
user = Net::Twitter::User.find_by screen_name: 'fullscreen'
|
11
11
|
user.screen_name #=> "Fullscreen"
|
12
12
|
user.followers_count #=> 48_200
|
13
13
|
```
|
14
|
+
After [configuring your Instagram app](#configuring-your-instagram-app), you can run commands like:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
user = Net::Instagram::User.find_by username: 'fullscreen_inc'
|
18
|
+
user.username #=> "fullscreen_inc"
|
19
|
+
user.follower_count #=> 7025
|
20
|
+
```
|
14
21
|
|
15
22
|
How to install
|
16
23
|
==============
|
@@ -21,7 +28,7 @@ To install on your system, run
|
|
21
28
|
|
22
29
|
To use inside a bundled Ruby project, add this line to the Gemfile:
|
23
30
|
|
24
|
-
gem 'net', '~> 0.1.
|
31
|
+
gem 'net', '~> 0.1.1'
|
25
32
|
|
26
33
|
Since the gem follows [Semantic Versioning](http://semver.org),
|
27
34
|
indicating the full version in your Gemfile (~> *major*.*minor*.*patch*)
|
@@ -32,9 +39,9 @@ Available resources
|
|
32
39
|
===================
|
33
40
|
|
34
41
|
Net::Twitter::User
|
35
|
-
|
42
|
+
------------------
|
36
43
|
|
37
|
-
Use [Net::
|
44
|
+
Use [Net::Twitter::User]() to:
|
38
45
|
|
39
46
|
* retrieve a Twitter user by screen name
|
40
47
|
* retrieve a list of Twitter users by screen names
|
@@ -50,8 +57,24 @@ users.map(&:followers_count).sort #=> [12, 48_200]
|
|
50
57
|
|
51
58
|
*The methods above require a configured Twitter app (see below).*
|
52
59
|
|
53
|
-
|
54
|
-
|
60
|
+
Net::Instagram::User
|
61
|
+
--------------------
|
62
|
+
|
63
|
+
Use [Net::Instagram::User]() to:
|
64
|
+
|
65
|
+
* retrieve an Instagram user by username
|
66
|
+
* access the number of followers of an Instagram user
|
67
|
+
* access the number of following of an Instagram user
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
user = Net::Instagram::User.find_by username: 'fullscreen'
|
71
|
+
user.follower_count #=> 7025
|
72
|
+
```
|
73
|
+
|
74
|
+
*The methods above require a configured Instagram app (see below).*
|
75
|
+
|
76
|
+
Configuring your Twitter app
|
77
|
+
============================
|
55
78
|
|
56
79
|
In order to use Net you must create an app in the [Twitter Application Manager](https://apps.twitter.com/app/new).
|
57
80
|
|
@@ -87,6 +110,43 @@ end
|
|
87
110
|
so use the approach that you prefer.
|
88
111
|
If a variable is set in both places, then `Net::Twitter.configure` takes precedence.
|
89
112
|
|
113
|
+
Configuring your Instagram app
|
114
|
+
============================
|
115
|
+
|
116
|
+
In order to use Net you must create an app in the
|
117
|
+
[Instagram Client Manager](http://instagram.com/developer/clients/register).
|
118
|
+
|
119
|
+
Once the app is created, copy the Client ID and add it to your
|
120
|
+
code with the following snippet of code (replacing with your own client id)
|
121
|
+
:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
Net::Instagram.configure do |config|
|
125
|
+
config.client_id = 'abcdefg'
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
Configuring with environment variables
|
130
|
+
--------------------------------------
|
131
|
+
|
132
|
+
As an alternative to the approach above, you can configure your app with
|
133
|
+
a variable. Setting the following environment variable:
|
134
|
+
|
135
|
+
```bash
|
136
|
+
export INSTAGRAM_CLIENT_ID='abcdefg'
|
137
|
+
```
|
138
|
+
|
139
|
+
is equivalent to configuring your app with the initializer:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
Net::Instagram.configure do |config|
|
143
|
+
config.client_id = 'abcdefg'
|
144
|
+
end
|
145
|
+
```
|
146
|
+
|
147
|
+
so use the approach that you prefer.
|
148
|
+
If a variable is set in both places, then `Net::Instagram.configure` takes precedence.
|
149
|
+
|
90
150
|
How to test
|
91
151
|
===========
|
92
152
|
|
@@ -99,8 +159,8 @@ rspec
|
|
99
159
|
Net uses [VCR](https://github.com/vcr/vcr) so by default tests do not run
|
100
160
|
HTTP requests.
|
101
161
|
|
102
|
-
If you need to run tests against the live Twitter API,
|
103
|
-
|
162
|
+
If you need to run tests against the live Twitter API or Instagram API,
|
163
|
+
configure your [Twitter app](#configuring-your-twitter-app) or your [Instagram app](#configuring-your-instagram-app) using environment variables,
|
104
164
|
erase the cassettes, then run `rspec`.
|
105
165
|
|
106
166
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'net/instagram/errors/response_error'
|
2
|
+
require 'net/instagram/errors/unknown_user'
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/core_ext'
|
5
|
+
|
6
|
+
module Net
|
7
|
+
module Instagram
|
8
|
+
module Api
|
9
|
+
class Request
|
10
|
+
def initialize(attrs = {})
|
11
|
+
@host = 'api.instagram.com'
|
12
|
+
@path = attrs.fetch :path, "/v1/#{attrs[:endpoint]}"
|
13
|
+
@query = attrs[:params] if attrs[:params]
|
14
|
+
@method = attrs.fetch :method, :get
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
case response = run_http_request
|
19
|
+
when Net::HTTPOK
|
20
|
+
JSON(response.body)['data']
|
21
|
+
else
|
22
|
+
raise Errors::ResponseError, response
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def run_http_request
|
28
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
29
|
+
http.request http_request
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def http_request
|
34
|
+
http_class = "Net::HTTP::#{@method.capitalize}".constantize
|
35
|
+
@http_request ||= http_class.new(uri.request_uri)
|
36
|
+
end
|
37
|
+
|
38
|
+
def uri
|
39
|
+
@uri ||= URI::HTTPS.build host: @host, path: @path, query: query
|
40
|
+
end
|
41
|
+
|
42
|
+
def query
|
43
|
+
{}.tap do |query|
|
44
|
+
query.merge! @query if @query
|
45
|
+
query.merge! client_id: Net::Instagram.configuration.client_id
|
46
|
+
end.to_param
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'net/instagram/api/configuration'
|
2
|
+
|
3
|
+
module Net
|
4
|
+
module Instagram
|
5
|
+
module Config
|
6
|
+
def configure
|
7
|
+
yield configuration if block_given?
|
8
|
+
end
|
9
|
+
|
10
|
+
def configuration
|
11
|
+
@configuration ||= Api::Configuration.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'net/instagram/models/user'
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'net/instagram/api/request'
|
2
|
+
require 'net/instagram/errors'
|
3
|
+
|
4
|
+
module Net
|
5
|
+
module Instagram
|
6
|
+
module Models
|
7
|
+
class User
|
8
|
+
attr_reader :username, :follower_count
|
9
|
+
|
10
|
+
def initialize(attrs = {})
|
11
|
+
@username = attrs['username']
|
12
|
+
@follower_count = attrs['counts']['followed_by']
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the existing Instagram user matching the provided attributes or
|
16
|
+
# nil when the user is not found.
|
17
|
+
#
|
18
|
+
# @return [Net::Instagram::Models::User] when the user is found.
|
19
|
+
# @return [nil] when the user is not found or has a private account.
|
20
|
+
# @param [Hash] params the attributes to find a user by.
|
21
|
+
# @option params [String] :username The Instagram user’s username
|
22
|
+
# (case-insensitive).
|
23
|
+
def self.find_by(params = {})
|
24
|
+
find_by! params
|
25
|
+
rescue Errors::PrivateUser, Errors::UnknownUser
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the existing Instagram user matching the provided attributes or
|
30
|
+
# nil when the user is not found, and raises an error when the user account is private.
|
31
|
+
#
|
32
|
+
# @return [Net::Instagram::Models::User] the Instagram user.
|
33
|
+
# @param [Hash] params the attributes to find a user by.
|
34
|
+
# @option params [String] :username The Instagram user’s username
|
35
|
+
# (case-insensitive).
|
36
|
+
# @raise [Net::Errors::PrivateUser] if the user account is private.
|
37
|
+
def self.find_by!(params = {})
|
38
|
+
find_by_username! params[:username]
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def self.find_by_username!(username)
|
44
|
+
request = Api::Request.new endpoint: "users/search", params: {q: username}
|
45
|
+
users = Array.wrap request.run
|
46
|
+
if user = users.find{|u| u['username'].casecmp(username).zero?}
|
47
|
+
find_by_id! user['id']
|
48
|
+
else
|
49
|
+
raise Errors::UnknownUser
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.find_by_id!(id)
|
54
|
+
request = Api::Request.new endpoint: "users/#{id}"
|
55
|
+
new request.run
|
56
|
+
rescue Errors::ResponseError => error
|
57
|
+
case error.response
|
58
|
+
when Net::HTTPBadRequest then raise Errors::PrivateUser
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -20,8 +20,8 @@ module Net
|
|
20
20
|
# @option params [String] :screen_name The Twitter user’s screen name
|
21
21
|
# (case-insensitive).
|
22
22
|
def self.find_by(params = {})
|
23
|
-
|
24
|
-
|
23
|
+
find_by! params
|
24
|
+
rescue Errors::UnknownUser, Errors::SuspendedUser
|
25
25
|
nil
|
26
26
|
end
|
27
27
|
|
@@ -67,9 +67,9 @@ module Net
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
|
70
|
+
private
|
71
71
|
|
72
|
-
|
72
|
+
def self.to_where_params(conditions = {})
|
73
73
|
conditions.dup.tap do |params|
|
74
74
|
params.each{|k,v| params[k] = v.join(',') if v.is_a?(Array)}
|
75
75
|
end
|
data/lib/net/version.rb
CHANGED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'net/instagram'
|
3
|
+
|
4
|
+
describe Net::Instagram::User, :vcr do
|
5
|
+
before :all do
|
6
|
+
Net::Instagram.configure do |config|
|
7
|
+
if config.client_id.blank?
|
8
|
+
config.client_id = 'CLIENT_ID'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:existing_username) { 'Fullscreen' }
|
14
|
+
let(:unknown_username) { '01LjqweoojkjR' }
|
15
|
+
let(:private_username) { 'brohemian' }
|
16
|
+
|
17
|
+
describe '.find_by' do
|
18
|
+
subject(:user) { Net::Instagram::User.find_by username: username }
|
19
|
+
|
20
|
+
context 'given an existing (case-insensitive) username' do
|
21
|
+
let(:username) { existing_username }
|
22
|
+
|
23
|
+
it 'returns an object representing that user' do
|
24
|
+
expect(user.username).to eq 'fullscreen'
|
25
|
+
expect(user.follower_count).to be_an Integer
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'given an unknown username' do
|
30
|
+
let(:username) { unknown_username }
|
31
|
+
it { expect(user).to be_nil }
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'given a private username' do
|
35
|
+
let(:username) { private_username }
|
36
|
+
it { expect(user).to be_nil }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '.find_by!' do
|
41
|
+
subject(:user) { Net::Instagram::User.find_by! username: username }
|
42
|
+
context 'given an existing (case-insensitive) username' do
|
43
|
+
let(:username) { existing_username }
|
44
|
+
|
45
|
+
it 'returns an object representing that user' do
|
46
|
+
expect(user.username).to eq 'fullscreen'
|
47
|
+
expect(user.follower_count).to be_an Integer
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'given an unknown username' do
|
52
|
+
let(:username) { unknown_username }
|
53
|
+
it { expect{user}.to raise_error Net::Instagram::UnknownUser }
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'given a private username' do
|
57
|
+
let(:username) { private_username }
|
58
|
+
it { expect{user}.to raise_error Net::Instagram::PrivateUser }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|