instagram-continued 1.2.0

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.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/.yardopts +9 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE.md +30 -0
  8. data/PATENTS.md +23 -0
  9. data/README.md +11 -0
  10. data/Rakefile +27 -0
  11. data/instagram.gemspec +30 -0
  12. data/lib/faraday/loud_logger.rb +75 -0
  13. data/lib/faraday/oauth2.rb +42 -0
  14. data/lib/faraday/raise_http_exception.rb +61 -0
  15. data/lib/instagram.rb +27 -0
  16. data/lib/instagram/api.rb +31 -0
  17. data/lib/instagram/client.rb +21 -0
  18. data/lib/instagram/client/comments.rb +62 -0
  19. data/lib/instagram/client/embedding.rb +28 -0
  20. data/lib/instagram/client/geographies.rb +29 -0
  21. data/lib/instagram/client/likes.rb +58 -0
  22. data/lib/instagram/client/locations.rb +75 -0
  23. data/lib/instagram/client/media.rb +82 -0
  24. data/lib/instagram/client/subscriptions.rb +211 -0
  25. data/lib/instagram/client/tags.rb +59 -0
  26. data/lib/instagram/client/users.rb +310 -0
  27. data/lib/instagram/client/utils.rb +28 -0
  28. data/lib/instagram/configuration.rb +122 -0
  29. data/lib/instagram/connection.rb +31 -0
  30. data/lib/instagram/error.rb +34 -0
  31. data/lib/instagram/oauth.rb +36 -0
  32. data/lib/instagram/request.rb +82 -0
  33. data/lib/instagram/response.rb +22 -0
  34. data/lib/instagram/version.rb +3 -0
  35. data/spec/faraday/response_spec.rb +87 -0
  36. data/spec/fixtures/access_token.json +9 -0
  37. data/spec/fixtures/approve_user.json +8 -0
  38. data/spec/fixtures/block_user.json +8 -0
  39. data/spec/fixtures/deny_user.json +8 -0
  40. data/spec/fixtures/follow_user.json +8 -0
  41. data/spec/fixtures/followed_by.json +1 -0
  42. data/spec/fixtures/follows.json +1 -0
  43. data/spec/fixtures/geography_recent_media.json +1 -0
  44. data/spec/fixtures/liked_media.json +1 -0
  45. data/spec/fixtures/location.json +1 -0
  46. data/spec/fixtures/location_recent_media.json +1 -0
  47. data/spec/fixtures/location_search.json +1 -0
  48. data/spec/fixtures/location_search_facebook.json +1 -0
  49. data/spec/fixtures/media.json +1 -0
  50. data/spec/fixtures/media_comment.json +1 -0
  51. data/spec/fixtures/media_comment_deleted.json +1 -0
  52. data/spec/fixtures/media_comments.json +1 -0
  53. data/spec/fixtures/media_liked.json +1 -0
  54. data/spec/fixtures/media_likes.json +1 -0
  55. data/spec/fixtures/media_popular.json +1 -0
  56. data/spec/fixtures/media_search.json +1 -0
  57. data/spec/fixtures/media_shortcode.json +1 -0
  58. data/spec/fixtures/media_unliked.json +1 -0
  59. data/spec/fixtures/mikeyk.json +1 -0
  60. data/spec/fixtures/oembed.json +14 -0
  61. data/spec/fixtures/recent_media.json +1 -0
  62. data/spec/fixtures/relationship.json +9 -0
  63. data/spec/fixtures/requested_by.json +12 -0
  64. data/spec/fixtures/shayne.json +1 -0
  65. data/spec/fixtures/subscription.json +12 -0
  66. data/spec/fixtures/subscription_deleted.json +1 -0
  67. data/spec/fixtures/subscription_payload.json +14 -0
  68. data/spec/fixtures/subscriptions.json +22 -0
  69. data/spec/fixtures/tag.json +1 -0
  70. data/spec/fixtures/tag_recent_media.json +1 -0
  71. data/spec/fixtures/tag_search.json +1 -0
  72. data/spec/fixtures/unblock_user.json +8 -0
  73. data/spec/fixtures/unfollow_user.json +8 -0
  74. data/spec/fixtures/user_media_feed.json +1 -0
  75. data/spec/fixtures/user_search.json +1 -0
  76. data/spec/instagram/api_spec.rb +285 -0
  77. data/spec/instagram/client/comments_spec.rb +71 -0
  78. data/spec/instagram/client/embedding_spec.rb +36 -0
  79. data/spec/instagram/client/geography_spec.rb +37 -0
  80. data/spec/instagram/client/likes_spec.rb +66 -0
  81. data/spec/instagram/client/locations_spec.rb +127 -0
  82. data/spec/instagram/client/media_spec.rb +99 -0
  83. data/spec/instagram/client/subscriptions_spec.rb +174 -0
  84. data/spec/instagram/client/tags_spec.rb +79 -0
  85. data/spec/instagram/client/users_spec.rb +432 -0
  86. data/spec/instagram/client/utils_spec.rb +32 -0
  87. data/spec/instagram/client_spec.rb +23 -0
  88. data/spec/instagram/request_spec.rb +56 -0
  89. data/spec/instagram_spec.rb +109 -0
  90. data/spec/spec_helper.rb +71 -0
  91. metadata +302 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b702f63b15f96a50e0e164d4cad1346914b5d347
4
+ data.tar.gz: d692182c21e7c66e932793e54213c081be724708
5
+ SHA512:
6
+ metadata.gz: f677242ff2af9ff5a9d2f94ffa2b35e3a9744026244184c80a6350ff7f264fb04398abc1420c7d1db5420ef42a487741e67523a92544ce598dc119c26429e81b
7
+ data.tar.gz: cc5154ea5db3bb0e5f29f82988bdceea3ee69d48f5d89ba8403723ae6ebb95a84a67f201cbb9bfe7f6141c926ea89fe5bb6d83c09b7b026003c5c3b92c10c11d
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ *.gem
2
+ *.rbc
3
+ .DS_Store
4
+ .bundle
5
+ .rvmrc
6
+ .ruby-version
7
+ .yardoc
8
+ .rake_tasks~
9
+ Gemfile.lock
10
+ coverage/*
11
+ doc/*
12
+ log/*
13
+ pkg/*
14
+ .idea/*
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format=documentation
3
+ --backtrace
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.1
4
+ - 2.3.0
5
+ - 2.2
6
+ - 2.1
7
+ - 2.0
data/.yardopts ADDED
@@ -0,0 +1,9 @@
1
+ --no-private
2
+ --protected
3
+ --tag format:"Supported formats"
4
+ --tag authenticated:"Requires Authentication"
5
+ --tag rate_limited:"Rate Limited"
6
+ --markup markdown
7
+ -
8
+ HISTORY.mkd
9
+ LICENSE.mkd
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,30 @@
1
+ BSD License
2
+
3
+ For Ruby Instagram Gem software
4
+
5
+ Copyright (c) 2014, Facebook, Inc. All rights reserved.
6
+
7
+ Redistribution and use in source and binary forms, with or without modification,
8
+ are permitted provided that the following conditions are met:
9
+
10
+ * Redistributions of source code must retain the above copyright notice, this
11
+ list of conditions and the following disclaimer.
12
+
13
+ * Redistributions in binary form must reproduce the above copyright notice,
14
+ this list of conditions and the following disclaimer in the documentation
15
+ and/or other materials provided with the distribution.
16
+
17
+ * Neither the name Facebook nor the names of its contributors may be used to
18
+ endorse or promote products derived from this software without specific
19
+ prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
25
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
28
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/PATENTS.md ADDED
@@ -0,0 +1,23 @@
1
+ Additional Grant of Patent Rights
2
+
3
+ "Software" means the Instagram Ruby Gem software distributed by Facebook, Inc.
4
+
5
+ Facebook hereby grants you a perpetual, worldwide, royalty-free, non-exclusive,
6
+ irrevocable (subject to the termination provision below) license under any
7
+ rights in any patent claims owned by Facebook, to make, have made, use, sell,
8
+ offer to sell, import, and otherwise transfer the Software. For avoidance of
9
+ doubt, no license is granted under Facebook’s rights in any patent claims that
10
+ are infringed by (i) modifications to the Software made by you or a third party,
11
+ or (ii) the Software in combination with any software or other technology
12
+ provided by you or a third party.
13
+
14
+ The license granted hereunder will terminate, automatically and without notice,
15
+ for anyone that makes any claim (including by filing any lawsuit, assertion or
16
+ other action) alleging (a) direct, indirect, or contributory infringement or
17
+ inducement to infringe any patent: (i) by Facebook or any of its subsidiaries or
18
+ affiliates, whether or not such claim is related to the Software, (ii) by any
19
+ party if such claim arises in whole or in part from any software, product or
20
+ service of Facebook or any of its subsidiaries or affiliates, whether or not
21
+ such claim is related to the Software, or (iii) by any party relating to the
22
+ Software; or (b) that any right in any patent claim of Facebook is invalid or
23
+ unenforceable.
data/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # Instagram-Continued
2
+
3
+ This is an attempt to get the instagram gem working again, despite it's abandonment by Facebook.
4
+
5
+ ## Installation
6
+
7
+ - `gem install instagram-continued` or `gem "instagram-continued", require: "instagram"`
8
+
9
+ This gem only supports Ruby >= 2.0
10
+
11
+ The original Gem, and its docs are at https://github.com/facebookarchive/instagram-ruby-gem.
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+
9
+ namespace :doc do
10
+ begin
11
+ require 'yard'
12
+ rescue LoadError
13
+ # ignore
14
+ else
15
+ YARD::Rake::YardocTask.new do |task|
16
+ task.files = ['HISTORY.mkd', 'LICENSE.mkd', 'lib/**/*.rb']
17
+ task.options = [
18
+ '--protected',
19
+ '--output-dir', 'doc/yard',
20
+ '--tag', 'format:Supported formats',
21
+ '--tag', 'authenticated:Requires Authentication',
22
+ '--tag', 'rate_limited:Rate Limited',
23
+ '--markup', 'markdown',
24
+ ]
25
+ end
26
+ end
27
+ end
data/instagram.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/instagram/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.add_development_dependency("rake", "~> 10.5.0")
6
+ s.add_development_dependency("rspec", "~> 3.4.0")
7
+ s.add_development_dependency("webmock", "~> 1.22.6")
8
+ s.add_development_dependency("bluecloth", "~> 2.2.0")
9
+
10
+ s.add_runtime_dependency("faraday", "~> 0.9.2")
11
+ s.add_runtime_dependency("faraday_middleware", "~> 0.10.0")
12
+ s.add_runtime_dependency("multi_json", "~> 1.11.2")
13
+ s.add_runtime_dependency("hashie", "~> 3.4.3")
14
+
15
+ s.authors = ["Shayne Sweeney", "Nat Welch"]
16
+ s.description = %q{A Ruby wrapper for the Instagram REST and Search APIs}
17
+ s.email = ["shayne@instagr.am", "nat@natwelch.com"]
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.files = `git ls-files`.split("\n")
20
+ s.homepage = "https://github.com/icco/instagram-continued"
21
+ s.name = "instagram-continued"
22
+ s.platform = Gem::Platform::RUBY
23
+ s.require_paths = ["lib"]
24
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.3.6")
25
+ s.required_ruby_version = Gem::Requirement.new(">= 2.0.0")
26
+ s.rubyforge_project = s.name
27
+ s.summary = %q{Ruby wrapper for the Instagram API}
28
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
29
+ s.version = Instagram::VERSION.dup
30
+ end
@@ -0,0 +1,75 @@
1
+ require 'faraday'
2
+
3
+ # @private
4
+ module FaradayMiddleware
5
+ # @private
6
+ class LoudLogger < Faraday::Middleware
7
+ extend Forwardable
8
+ def_delegators :@logger, :debug, :info, :warn, :error, :fatal
9
+
10
+ def initialize(app, options = {})
11
+ @app = app
12
+ @logger = options.fetch(:logger) {
13
+ require 'logger'
14
+ ::Logger.new($stdout)
15
+ }
16
+ end
17
+
18
+ def call(env)
19
+ start_time = Time.now
20
+ info { request_info(env) }
21
+ debug { request_debug(env) }
22
+ @app.call(env).on_complete do
23
+ end_time = Time.now
24
+ response_time = end_time - start_time
25
+ info { response_info(env, response_time) }
26
+ debug { response_debug(env) }
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def filter(output)
33
+ if ENV['INSTAGRAM_GEM_REDACT']
34
+ output = output.to_s.gsub(/client_id=[a-zA-Z0-9]*/,'client_id=[CLIENT-ID]')
35
+ output = output.to_s.gsub(/access_token=[a-zA-Z0-9]*/,'access_token=[ACCESS-TOKEN]')
36
+ else
37
+ output
38
+ end
39
+ end
40
+
41
+ def request_info(env)
42
+ "Started %s request to: %s" % [ env[:method].to_s.upcase, filter(env[:url]) ]
43
+ end
44
+
45
+ def response_info(env, response_time)
46
+ "Response from %s; Status: %d; Time: %.1fms" % [ filter(env[:url]), env[:status], (response_time * 1_000.0) ]
47
+ end
48
+
49
+ def request_debug(env)
50
+ debug_message("Request", env[:request_headers], env[:body])
51
+ end
52
+
53
+ def response_debug(env)
54
+ debug_message("Response", env[:response_headers], env[:body])
55
+ end
56
+
57
+ def debug_message(name, headers, body)
58
+ <<-MESSAGE.gsub(/^ +([^ ])/m, '\\1')
59
+ #{name} Headers:
60
+ ----------------
61
+ #{format_headers(headers)}
62
+
63
+ #{name} Body:
64
+ -------------
65
+ #{filter(body)}
66
+ MESSAGE
67
+ end
68
+
69
+ def format_headers(headers)
70
+ length = headers.map {|k,v| k.to_s.size }.max
71
+ headers.map { |name, value| "#{name.to_s.ljust(length)} : #{filter(value)}" }.join("\n")
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,42 @@
1
+ require 'faraday'
2
+
3
+ # @private
4
+ module FaradayMiddleware
5
+ # @private
6
+ class InstagramOAuth2 < Faraday::Middleware
7
+ def call(env)
8
+
9
+ if env[:method] == :get or env[:method] == :delete
10
+ if env[:url].query.nil?
11
+ query = {}
12
+ else
13
+ query = Faraday::Utils.parse_query(env[:url].query)
14
+ end
15
+
16
+ if @access_token and not query["client_secret"]
17
+ env[:url].query = Faraday::Utils.build_query(query.merge(:access_token => @access_token))
18
+ env[:request_headers] = env[:request_headers].merge('Authorization' => "Token token=\"#{@access_token}\"")
19
+ elsif @client_id
20
+ env[:url].query = Faraday::Utils.build_query(query.merge(:client_id => @client_id))
21
+ end
22
+ else
23
+ if @access_token and not env[:body] && env[:body][:client_secret]
24
+ env[:body] = {} if env[:body].nil?
25
+ env[:body] = env[:body].merge(:access_token => @access_token)
26
+ env[:request_headers] = env[:request_headers].merge('Authorization' => "Token token=\"#{@access_token}\"")
27
+ elsif @client_id
28
+ env[:body] = env[:body].merge(:client_id => @client_id)
29
+ end
30
+ end
31
+
32
+
33
+ @app.call env
34
+ end
35
+
36
+ def initialize(app, client_id, access_token=nil)
37
+ @app = app
38
+ @client_id = client_id
39
+ @access_token = access_token
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,61 @@
1
+ require 'faraday'
2
+
3
+ # @private
4
+ module FaradayMiddleware
5
+ # @private
6
+ class RaiseHttpException < Faraday::Middleware
7
+ def call(env)
8
+ @app.call(env).on_complete do |response|
9
+ case response[:status].to_i
10
+ when 400
11
+ raise Instagram::BadRequest, error_message_400(response)
12
+ when 403
13
+ raise Instagram::Forbidden, error_message_400(response)
14
+ when 404
15
+ raise Instagram::NotFound, error_message_400(response)
16
+ when 429
17
+ raise Instagram::TooManyRequests, error_message_400(response)
18
+ when 500
19
+ raise Instagram::InternalServerError, error_message_500(response, "Something is technically wrong.")
20
+ when 502
21
+ raise Instagram::BadGateway, error_message_500(response, "The server returned an invalid or incomplete response.")
22
+ when 503
23
+ raise Instagram::ServiceUnavailable, error_message_500(response, "Instagram is rate limiting your requests.")
24
+ when 504
25
+ raise Instagram::GatewayTimeout, error_message_500(response, "504 Gateway Time-out")
26
+ end
27
+ end
28
+ end
29
+
30
+ def initialize(app)
31
+ super app
32
+ @parser = nil
33
+ end
34
+
35
+ private
36
+
37
+ def error_message_400(response)
38
+ "#{response[:method].to_s.upcase} #{response[:url].to_s}: #{response[:status]}#{error_body(response[:body])}"
39
+ end
40
+
41
+ def error_body(body)
42
+ # body gets passed as a string, not sure if it is passed as something else from other spots?
43
+ if not body.nil? and not body.empty? and body.kind_of?(String)
44
+ # removed multi_json thanks to wesnolte's commit
45
+ body = ::JSON.parse(body)
46
+ end
47
+
48
+ if body.nil?
49
+ nil
50
+ elsif body['meta'] and body['meta']['error_message'] and not body['meta']['error_message'].empty?
51
+ ": #{body['meta']['error_message']}"
52
+ elsif body['error_message'] and not body['error_message'].empty?
53
+ ": #{body['error_type']}: #{body['error_message']}"
54
+ end
55
+ end
56
+
57
+ def error_message_500(response, body=nil)
58
+ "#{response[:method].to_s.upcase} #{response[:url].to_s}: #{[response[:status].to_s + ':', body].compact.join(' ')}"
59
+ end
60
+ end
61
+ end
data/lib/instagram.rb ADDED
@@ -0,0 +1,27 @@
1
+ require File.expand_path('../instagram/error', __FILE__)
2
+ require File.expand_path('../instagram/configuration', __FILE__)
3
+ require File.expand_path('../instagram/api', __FILE__)
4
+ require File.expand_path('../instagram/client', __FILE__)
5
+ require File.expand_path('../instagram/response', __FILE__)
6
+
7
+ module Instagram
8
+ extend Configuration
9
+
10
+ # Alias for Instagram::Client.new
11
+ #
12
+ # @return [Instagram::Client]
13
+ def self.client(options={})
14
+ Instagram::Client.new(options)
15
+ end
16
+
17
+ # Delegate to Instagram::Client
18
+ def self.method_missing(method, *args, &block)
19
+ return super unless client.respond_to?(method)
20
+ client.send(method, *args, &block)
21
+ end
22
+
23
+ # Delegate to Instagram::Client
24
+ def self.respond_to?(method, include_all=false)
25
+ return client.respond_to?(method, include_all) || super
26
+ end
27
+ end
@@ -0,0 +1,31 @@
1
+ require File.expand_path('../connection', __FILE__)
2
+ require File.expand_path('../request', __FILE__)
3
+ require File.expand_path('../oauth', __FILE__)
4
+
5
+ module Instagram
6
+ # @private
7
+ class API
8
+ # @private
9
+ attr_accessor *Configuration::VALID_OPTIONS_KEYS
10
+
11
+ # Creates a new API
12
+ def initialize(options={})
13
+ options = Instagram.options.merge(options)
14
+ Configuration::VALID_OPTIONS_KEYS.each do |key|
15
+ send("#{key}=", options[key])
16
+ end
17
+ end
18
+
19
+ def config
20
+ conf = {}
21
+ Configuration::VALID_OPTIONS_KEYS.each do |key|
22
+ conf[key] = send key
23
+ end
24
+ conf
25
+ end
26
+
27
+ include Connection
28
+ include Request
29
+ include OAuth
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ module Instagram
2
+ # Wrapper for the Instagram REST API
3
+ #
4
+ # @note All methods have been separated into modules and follow the same grouping used in http://instagram.com/developer/
5
+ # @see http://instagram.com/developer/
6
+ class Client < API
7
+ Dir[File.expand_path('../client/*.rb', __FILE__)].each{|f| require f}
8
+
9
+ include Instagram::Client::Utils
10
+
11
+ include Instagram::Client::Users
12
+ include Instagram::Client::Media
13
+ include Instagram::Client::Locations
14
+ include Instagram::Client::Geographies
15
+ include Instagram::Client::Tags
16
+ include Instagram::Client::Comments
17
+ include Instagram::Client::Likes
18
+ include Instagram::Client::Subscriptions
19
+ include Instagram::Client::Embedding
20
+ end
21
+ end