net 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +3 -0
  3. data/CHANGELOG.md +11 -0
  4. data/{LICENSE.txt → MIT-LICENSE} +2 -4
  5. data/README.md +108 -17
  6. data/lib/net.rb +0 -1
  7. data/lib/net/twitter.rb +11 -0
  8. data/lib/net/twitter/api/configuration.rb +16 -0
  9. data/lib/net/twitter/api/request.rb +121 -0
  10. data/lib/net/twitter/config.rb +15 -0
  11. data/lib/net/twitter/errors.rb +4 -0
  12. data/lib/net/twitter/errors/response_error.rb +14 -0
  13. data/lib/net/twitter/errors/suspended_user.rb +11 -0
  14. data/lib/net/twitter/errors/too_many_users.rb +11 -0
  15. data/lib/net/twitter/errors/unknown_user.rb +11 -0
  16. data/lib/net/twitter/models.rb +1 -0
  17. data/lib/net/twitter/models/user.rb +80 -0
  18. data/lib/net/version.rb +1 -1
  19. data/net.gemspec +14 -7
  20. data/spec/net/twitter/models/user_spec.rb +98 -0
  21. data/spec/spec_helper.rb +21 -0
  22. data/spec/support/cassettes/Net_Twitter_Models_User/_find_by/given_a_suspended_screen_name/.yml +69 -0
  23. data/spec/support/cassettes/Net_Twitter_Models_User/_find_by/given_an_existing_case-insensitive_screen_name/returns_an_object_representing_that_user.yml +136 -0
  24. data/spec/support/cassettes/Net_Twitter_Models_User/_find_by/given_an_unknown_screen_name/.yml +69 -0
  25. data/spec/support/cassettes/Net_Twitter_Models_User/_find_by_/given_a_suspended_screen_name/.yml +69 -0
  26. data/spec/support/cassettes/Net_Twitter_Models_User/_find_by_/given_an_existing_case-insensitive_screen_name/returns_an_object_representing_that_user.yml +80 -0
  27. data/spec/support/cassettes/Net_Twitter_Models_User/_find_by_/given_an_unknown_screen_name/.yml +69 -0
  28. data/spec/support/cassettes/Net_Twitter_Models_User/_where/called_more_times_than_Twitter_s_rate_limit/waits_for_the_rate_limit_to_expire_then_continues.yml +4802 -0
  29. data/spec/support/cassettes/Net_Twitter_Models_User/_where/given_more_screen_names_than_allowed_by_Twitter/.yml +69 -0
  30. data/spec/support/cassettes/Net_Twitter_Models_User/_where/given_multiple_existing_case-insensitive_screen_names/returns_an_array_of_objects_representing_those_users.yml +87 -0
  31. data/spec/support/cassettes/Net_Twitter_Models_User/_where/given_multiple_unknown_or_suspended_screen_names/returns_an_empty_array.yml +69 -0
  32. data/spec/support/vcr.rb +22 -0
  33. metadata +138 -13
@@ -1,3 +1,3 @@
1
1
  module Net
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -6,11 +6,11 @@ require 'net/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "net"
8
8
  spec.version = Net::VERSION
9
- spec.authors = ["claudiob"]
10
- spec.email = ["claudiob@gmail.com"]
11
- spec.summary = %q{Write a short summary. Required.}
12
- spec.description = %q{Write a longer description. Optional.}
13
- spec.homepage = ""
9
+ spec.authors = ["Jeremy Cohen Hoffing", "Claudio Baccigalupo"]
10
+ spec.email = ["jcohenhoffing@gmail.com", "claudio@fullscreen.net"]
11
+ spec.summary = %q{An API Client for social networks}
12
+ spec.description = %q{Retrieves information for Twitter users}
13
+ spec.homepage = "https://github.com/Fullscreen/net"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
@@ -18,6 +18,13 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency 'activesupport'
22
+
21
23
  spec.add_development_dependency "bundler", "~> 1.6"
22
- spec.add_development_dependency "rake"
23
- end
24
+ spec.add_development_dependency "rake", "~> 10.3"
25
+ spec.add_development_dependency "rspec", "~> 3.1"
26
+ spec.add_development_dependency "yard", "~> 0.8.7"
27
+ spec.add_development_dependency "coveralls", "~> 0.7.1"
28
+ spec.add_development_dependency "vcr", "~> 2.9"
29
+ spec.add_development_dependency "webmock", "~> 1.19"
30
+ end
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+ require 'net/twitter'
3
+
4
+ describe Net::Twitter::User, :vcr do
5
+ let(:unknown_screen_name) { '09hlQHE29534awe' }
6
+ let(:suspended_screen_name) { 'CodFatherLucas' }
7
+ let(:existing_screen_name) { 'fullscreen' }
8
+
9
+ describe '.find_by' do
10
+ subject(:user) { Net::Twitter::User.find_by screen_name: screen_name }
11
+
12
+ context 'given an existing (case-insensitive) screen name' do
13
+ let(:screen_name) { existing_screen_name }
14
+
15
+ it 'returns an object representing that user' do
16
+ expect(user.screen_name).to eq 'Fullscreen'
17
+ expect(user.followers_count).to be_an Integer
18
+ end
19
+ end
20
+
21
+ context 'given an unknown screen name' do
22
+ let(:screen_name) { unknown_screen_name }
23
+ it { expect(user).to be_nil }
24
+ end
25
+
26
+ context 'given a suspended screen name' do
27
+ let(:screen_name) { suspended_screen_name }
28
+ it { expect(user).to be_nil }
29
+ end
30
+ end
31
+
32
+ describe '.find_by!' do
33
+ subject(:user) { Net::Twitter::User.find_by! screen_name: screen_name }
34
+
35
+ context 'given an existing (case-insensitive) screen name' do
36
+ let(:screen_name) { existing_screen_name }
37
+
38
+ it 'returns an object representing that user' do
39
+ expect(user.screen_name).to eq 'Fullscreen'
40
+ expect(user.followers_count).to be_an Integer
41
+ end
42
+ end
43
+
44
+ context 'given an unknown screen name' do
45
+ let(:screen_name) { unknown_screen_name }
46
+ it { expect{user}.to raise_error Net::Twitter::UnknownUser }
47
+ end
48
+
49
+ context 'given a suspended screen name' do
50
+ let(:screen_name) { suspended_screen_name }
51
+ it { expect{user}.to raise_error Net::Twitter::SuspendedUser }
52
+ end
53
+ end
54
+
55
+ describe '.where' do
56
+ context 'given multiple existing (case-insensitive) screen names' do
57
+ let(:screen_names) { ['brohemian6', existing_screen_name, suspended_screen_name, unknown_screen_name] }
58
+ subject(:users) { Net::Twitter::User.where screen_name: screen_names }
59
+
60
+ it 'returns an array of objects representing those users' do
61
+ expect(users.map &:screen_name).to contain_exactly('Fullscreen', 'brohemian6')
62
+ expect(users.map &:followers_count).to all(be_an Integer)
63
+ end
64
+ end
65
+
66
+ context 'given multiple unknown or suspended screen names' do
67
+ let(:screen_names) { [suspended_screen_name, unknown_screen_name] }
68
+ subject(:users) { Net::Twitter::User.where screen_name: screen_names }
69
+
70
+ it 'returns an empty array' do
71
+ expect(users).to be_empty
72
+ end
73
+ end
74
+
75
+ # @see https://dev.twitter.com/rest/reference/get/users/lookup
76
+ context 'given more screen names than allowed by Twitter' do
77
+ let(:screen_names) { ('a'..'z').map{|x| ('a'..'e').map{|y| "#{x}#{y}"}}.flatten }
78
+ subject(:users) { Net::Twitter::User.where screen_name: screen_names }
79
+
80
+ it { expect{users}.to raise_error Net::Twitter::TooManyUsers }
81
+ end
82
+
83
+ # @see https://dev.twitter.com/rest/public/rate-limits
84
+ context 'called more times than Twitter’s rate limit' do
85
+
86
+ before { expect(Time).to receive(:now).at_least(:once).and_return 12345678 }
87
+ let(:lookup_limit) { 60 }
88
+ let(:screen_names) { [existing_screen_name] }
89
+ subject(:user_sets) { (lookup_limit + 1).times.map do
90
+ Net::Twitter::User.where screen_name: screen_names
91
+ end}
92
+
93
+ it 'waits for the rate limit to expire then continues' do
94
+ expect(user_sets.compact.size).to be > lookup_limit
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,21 @@
1
+ require 'simplecov'
2
+ require 'coveralls'
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter
7
+ ]
8
+ SimpleCov.start
9
+
10
+ Dir['./spec/support/**/*.rb'].each {|f| require f}
11
+
12
+ RSpec.configure do |config|
13
+ # config.order = 'random'
14
+ config.before(:all) do
15
+ Net::Twitter.configure do |config|
16
+ if config.apps.empty?
17
+ config.apps.push key: 'TWITTER_API_KEY', secret: 'TWITTER_API_SECRET'
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,69 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://api.twitter.com/1.1/users/show.json?screen_name=CodFatherLucas
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - "*/*"
14
+ User-Agent:
15
+ - Ruby
16
+ Authorization:
17
+ - ACCESS_TOKEN
18
+ response:
19
+ status:
20
+ code: 403
21
+ message: Forbidden
22
+ headers:
23
+ Cache-Control:
24
+ - no-cache, no-store, must-revalidate, pre-check=0, post-check=0
25
+ Content-Length:
26
+ - '86'
27
+ Content-Type:
28
+ - application/json;charset=utf-8
29
+ Date:
30
+ - Sat, 11 Oct 2014 01:08:22 UTC
31
+ Expires:
32
+ - Tue, 31 Mar 1981 05:00:00 GMT
33
+ Last-Modified:
34
+ - Sat, 11 Oct 2014 01:08:22 GMT
35
+ Pragma:
36
+ - no-cache
37
+ Server:
38
+ - tsa_a
39
+ Set-Cookie:
40
+ - guest_id=v1%3A141298970231864986; Domain=.twitter.com; Path=/; Expires=Mon,
41
+ 10-Oct-2016 01:08:22 UTC
42
+ Status:
43
+ - 403 Forbidden
44
+ Strict-Transport-Security:
45
+ - max-age=631138519
46
+ X-Access-Level:
47
+ - read
48
+ X-Connection-Hash:
49
+ - 5a90ce3d1871c791b4020318e67b4e6e
50
+ X-Content-Type-Options:
51
+ - nosniff
52
+ X-Frame-Options:
53
+ - SAMEORIGIN
54
+ X-Rate-Limit-Limit:
55
+ - '180'
56
+ X-Rate-Limit-Remaining:
57
+ - '177'
58
+ X-Rate-Limit-Reset:
59
+ - '1412990602'
60
+ X-Transaction:
61
+ - c977632fada49967
62
+ X-Xss-Protection:
63
+ - 1; mode=block
64
+ body:
65
+ encoding: UTF-8
66
+ string: '{"errors":[{"code":63,"message":"User has been suspended."}]}'
67
+ http_version:
68
+ recorded_at: Sat, 11 Oct 2014 01:08:15 GMT
69
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,136 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://TWITTER_API_KEY:TWITTER_API_SECRET@api.twitter.com/oauth2/token
6
+ body:
7
+ encoding: US-ASCII
8
+ string: grant_type=client_credentials
9
+ headers:
10
+ Content-Type:
11
+ - application/x-www-form-urlencoded
12
+ response:
13
+ status:
14
+ code: 200
15
+ message: OK
16
+ headers:
17
+ Cache-Control:
18
+ - no-cache, no-store, must-revalidate, pre-check=0, post-check=0
19
+ Content-Length:
20
+ - '157'
21
+ Content-Type:
22
+ - application/json;charset=utf-8
23
+ Date:
24
+ - Sat, 11 Oct 2014 01:08:21 UTC
25
+ Expires:
26
+ - Tue, 31 Mar 1981 05:00:00 GMT
27
+ Last-Modified:
28
+ - Sat, 11 Oct 2014 01:08:21 GMT
29
+ Ml:
30
+ - S
31
+ Pragma:
32
+ - no-cache
33
+ Server:
34
+ - tsa_a
35
+ Set-Cookie:
36
+ - guest_id=v1%3A141298970195572286; Domain=.twitter.com; Path=/; Expires=Mon,
37
+ 10-Oct-2016 01:08:21 UTC
38
+ Status:
39
+ - 200 OK
40
+ Strict-Transport-Security:
41
+ - max-age=631138519
42
+ X-Connection-Hash:
43
+ - d63d4d3bf2e355106c486bf3c279d075
44
+ X-Content-Type-Options:
45
+ - nosniff
46
+ X-Frame-Options:
47
+ - SAMEORIGIN
48
+ X-Transaction:
49
+ - 038d099f9b129c61
50
+ X-Ua-Compatible:
51
+ - IE=edge,chrome=1
52
+ X-Xss-Protection:
53
+ - 1; mode=block
54
+ body:
55
+ encoding: UTF-8
56
+ string: '{"token_type":"bearer","access_token":"ACCESS_TOKEN"}'
57
+ http_version:
58
+ recorded_at: Sat, 11 Oct 2014 01:08:15 GMT
59
+ - request:
60
+ method: get
61
+ uri: https://api.twitter.com/1.1/users/show.json?screen_name=fullscreen
62
+ body:
63
+ encoding: US-ASCII
64
+ string: ''
65
+ headers:
66
+ Accept-Encoding:
67
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
68
+ Accept:
69
+ - "*/*"
70
+ User-Agent:
71
+ - Ruby
72
+ Authorization:
73
+ - ACCESS_TOKEN
74
+ response:
75
+ status:
76
+ code: 200
77
+ message: OK
78
+ headers:
79
+ Cache-Control:
80
+ - no-cache, no-store, must-revalidate, pre-check=0, post-check=0
81
+ Content-Length:
82
+ - '1270'
83
+ Content-Type:
84
+ - application/json;charset=utf-8
85
+ Date:
86
+ - Sat, 11 Oct 2014 01:08:22 UTC
87
+ Expires:
88
+ - Tue, 31 Mar 1981 05:00:00 GMT
89
+ Last-Modified:
90
+ - Sat, 11 Oct 2014 01:08:22 GMT
91
+ Pragma:
92
+ - no-cache
93
+ Server:
94
+ - tsa_a
95
+ Set-Cookie:
96
+ - guest_id=v1%3A141298970205889731; Domain=.twitter.com; Path=/; Expires=Mon,
97
+ 10-Oct-2016 01:08:22 UTC
98
+ Status:
99
+ - 200 OK
100
+ Strict-Transport-Security:
101
+ - max-age=631138519
102
+ X-Access-Level:
103
+ - read
104
+ X-Connection-Hash:
105
+ - 212c0e3bb4a455bc0ab147f8f4b9524b
106
+ X-Content-Type-Options:
107
+ - nosniff
108
+ X-Frame-Options:
109
+ - SAMEORIGIN
110
+ X-Rate-Limit-Limit:
111
+ - '180'
112
+ X-Rate-Limit-Remaining:
113
+ - '179'
114
+ X-Rate-Limit-Reset:
115
+ - '1412990602'
116
+ X-Transaction:
117
+ - f0566e9fa1c91113
118
+ X-Xss-Protection:
119
+ - 1; mode=block
120
+ body:
121
+ encoding: UTF-8
122
+ string: '{"id":238110322,"id_str":"238110322","name":"Fullscreen","screen_name":"Fullscreen","location":"LA
123
+ \/ Worldwide","description":"The First Media Company for the Connected Generation.\r\n#PowerToTheCreators","url":"http:\/\/t.co\/IuYBnxFitD","entities":{"url":{"urls":[{"url":"http:\/\/t.co\/IuYBnxFitD","expanded_url":"http:\/\/www.fullscreen.com","display_url":"fullscreen.com","indices":[0,22]}]},"description":{"urls":[]}},"protected":false,"followers_count":48138,"friends_count":2713,"listed_count":378,"created_at":"Fri
124
+ Jan 14 11:36:27 +0000 2011","favourites_count":58329,"utc_offset":-25200,"time_zone":"Pacific
125
+ Time (US & Canada)","geo_enabled":true,"verified":true,"statuses_count":19163,"lang":"en","status":{"created_at":"Sat
126
+ Oct 11 00:52:51 +0000 2014","id":520738765266886656,"id_str":"520738765266886656","text":"#ICYMI:
127
+ 15 Secs of Fullscreen with @SourPatchKids @WalkingDead_AMC @AsapSCIENCE @WeeklyChris
128
+ @AndreaRussett + More! http:\/\/t.co\/zoLiS9CZSL","source":"\u003ca href=\"http:\/\/twitter.com\"
129
+ rel=\"nofollow\"\u003eTwitter Web Client\u003c\/a\u003e","truncated":false,"in_reply_to_status_id":null,"in_reply_to_status_id_str":null,"in_reply_to_user_id":null,"in_reply_to_user_id_str":null,"in_reply_to_screen_name":null,"geo":null,"coordinates":null,"place":null,"contributors":null,"retweet_count":4,"favorite_count":9,"entities":{"hashtags":[{"text":"ICYMI","indices":[0,6]}],"symbols":[],"urls":[{"url":"http:\/\/t.co\/zoLiS9CZSL","expanded_url":"http:\/\/instagram.com\/p\/t_iCt4rhXy\/","display_url":"instagram.com\/p\/t_iCt4rhXy\/","indices":[116,138]}],"user_mentions":[{"screen_name":"SourPatchKids","name":"Sour
130
+ Patch Kids","id":122480273,"id_str":"122480273","indices":[35,49]},{"screen_name":"WalkingDead_AMC","name":"The
131
+ Walking Dead AMC","id":65184105,"id_str":"65184105","indices":[50,66]},{"screen_name":"AsapSCIENCE","name":"AsapSCIENCE","id":592912724,"id_str":"592912724","indices":[67,79]},{"screen_name":"WeeklyChris","name":"Christian
132
+ Collins","id":125806240,"id_str":"125806240","indices":[80,92]},{"screen_name":"AndreaRussett","name":"Andrea
133
+ Russett","id":30495613,"id_str":"30495613","indices":[93,107]}]},"favorited":false,"retweeted":false,"possibly_sensitive":false,"lang":"en"},"contributors_enabled":false,"is_translator":false,"is_translation_enabled":false,"profile_background_color":"16121E","profile_background_image_url":"http:\/\/pbs.twimg.com\/profile_background_images\/449347350306111489\/zWlAXsXf.png","profile_background_image_url_https":"https:\/\/pbs.twimg.com\/profile_background_images\/449347350306111489\/zWlAXsXf.png","profile_background_tile":false,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/449344241752227841\/xJeF6VQn_normal.png","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/449344241752227841\/xJeF6VQn_normal.png","profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/238110322\/1411497387","profile_link_color":"E62E4C","profile_sidebar_border_color":"FFFFFF","profile_sidebar_fill_color":"DDEEF6","profile_text_color":"333333","profile_use_background_image":false,"default_profile":false,"default_profile_image":false,"following":null,"follow_request_sent":null,"notifications":null}'
134
+ http_version:
135
+ recorded_at: Sat, 11 Oct 2014 01:08:15 GMT
136
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,69 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://api.twitter.com/1.1/users/show.json?screen_name=09hlQHE29534awe
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - "*/*"
14
+ User-Agent:
15
+ - Ruby
16
+ Authorization:
17
+ - ACCESS_TOKEN
18
+ response:
19
+ status:
20
+ code: 404
21
+ message: Not Found
22
+ headers:
23
+ Cache-Control:
24
+ - no-cache, no-store, must-revalidate, pre-check=0, post-check=0
25
+ Content-Length:
26
+ - '92'
27
+ Content-Type:
28
+ - application/json;charset=utf-8
29
+ Date:
30
+ - Sat, 11 Oct 2014 01:08:22 UTC
31
+ Expires:
32
+ - Tue, 31 Mar 1981 05:00:00 GMT
33
+ Last-Modified:
34
+ - Sat, 11 Oct 2014 01:08:22 GMT
35
+ Pragma:
36
+ - no-cache
37
+ Server:
38
+ - tsa_a
39
+ Set-Cookie:
40
+ - guest_id=v1%3A141298970220021935; Domain=.twitter.com; Path=/; Expires=Mon,
41
+ 10-Oct-2016 01:08:22 UTC
42
+ Status:
43
+ - 404 Not Found
44
+ Strict-Transport-Security:
45
+ - max-age=631138519
46
+ X-Access-Level:
47
+ - read
48
+ X-Connection-Hash:
49
+ - 278156e7b09f629df55ab8d5cf289b58
50
+ X-Content-Type-Options:
51
+ - nosniff
52
+ X-Frame-Options:
53
+ - SAMEORIGIN
54
+ X-Rate-Limit-Limit:
55
+ - '180'
56
+ X-Rate-Limit-Remaining:
57
+ - '178'
58
+ X-Rate-Limit-Reset:
59
+ - '1412990602'
60
+ X-Transaction:
61
+ - 2b2b1106b457ce4a
62
+ X-Xss-Protection:
63
+ - 1; mode=block
64
+ body:
65
+ encoding: UTF-8
66
+ string: '{"errors":[{"message":"Sorry, that page does not exist","code":34}]}'
67
+ http_version:
68
+ recorded_at: Sat, 11 Oct 2014 01:08:15 GMT
69
+ recorded_with: VCR 2.9.3
@@ -0,0 +1,69 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://api.twitter.com/1.1/users/show.json?screen_name=CodFatherLucas
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept-Encoding:
11
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
12
+ Accept:
13
+ - "*/*"
14
+ User-Agent:
15
+ - Ruby
16
+ Authorization:
17
+ - ACCESS_TOKEN
18
+ response:
19
+ status:
20
+ code: 403
21
+ message: Forbidden
22
+ headers:
23
+ Cache-Control:
24
+ - no-cache, no-store, must-revalidate, pre-check=0, post-check=0
25
+ Content-Length:
26
+ - '86'
27
+ Content-Type:
28
+ - application/json;charset=utf-8
29
+ Date:
30
+ - Sat, 11 Oct 2014 01:08:22 UTC
31
+ Expires:
32
+ - Tue, 31 Mar 1981 05:00:00 GMT
33
+ Last-Modified:
34
+ - Sat, 11 Oct 2014 01:08:22 GMT
35
+ Pragma:
36
+ - no-cache
37
+ Server:
38
+ - tsa_a
39
+ Set-Cookie:
40
+ - guest_id=v1%3A141298970268472432; Domain=.twitter.com; Path=/; Expires=Mon,
41
+ 10-Oct-2016 01:08:22 UTC
42
+ Status:
43
+ - 403 Forbidden
44
+ Strict-Transport-Security:
45
+ - max-age=631138519
46
+ X-Access-Level:
47
+ - read
48
+ X-Connection-Hash:
49
+ - d5f954bca7a9b3a762c62153a96e442e
50
+ X-Content-Type-Options:
51
+ - nosniff
52
+ X-Frame-Options:
53
+ - SAMEORIGIN
54
+ X-Rate-Limit-Limit:
55
+ - '180'
56
+ X-Rate-Limit-Remaining:
57
+ - '174'
58
+ X-Rate-Limit-Reset:
59
+ - '1412990602'
60
+ X-Transaction:
61
+ - 5ec8678f24b910dd
62
+ X-Xss-Protection:
63
+ - 1; mode=block
64
+ body:
65
+ encoding: UTF-8
66
+ string: '{"errors":[{"code":63,"message":"User has been suspended."}]}'
67
+ http_version:
68
+ recorded_at: Sat, 11 Oct 2014 01:08:16 GMT
69
+ recorded_with: VCR 2.9.3