net 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|