instagram 0.3.2 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/.gitignore +12 -0
  2. data/.rspec +3 -0
  3. data/.yardopts +9 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE.md +20 -0
  6. data/README.md +144 -55
  7. data/Rakefile +21 -9
  8. data/instagram.gemspec +41 -0
  9. data/lib/faraday/oauth2.rb +36 -0
  10. data/lib/faraday/raise_http_4xx.rb +37 -0
  11. data/lib/faraday/raise_http_5xx.rb +29 -0
  12. data/lib/instagram.rb +21 -55
  13. data/lib/instagram/api.rb +23 -0
  14. data/lib/instagram/client.rb +19 -0
  15. data/lib/instagram/client/comments.rb +62 -0
  16. data/lib/instagram/client/likes.rb +58 -0
  17. data/lib/instagram/client/locations.rb +59 -0
  18. data/lib/instagram/client/media.rb +63 -0
  19. data/lib/instagram/client/real_time.rb +8 -0
  20. data/lib/instagram/client/subscriptions.rb +141 -0
  21. data/lib/instagram/client/tags.rb +59 -0
  22. data/lib/instagram/client/users.rb +165 -0
  23. data/lib/instagram/client/utils.rb +15 -0
  24. data/lib/instagram/configuration.rb +90 -0
  25. data/lib/instagram/connection.rb +31 -0
  26. data/lib/instagram/error.rb +16 -0
  27. data/lib/instagram/oauth.rb +27 -0
  28. data/lib/instagram/request.rb +45 -0
  29. data/lib/instagram/version.rb +3 -0
  30. data/spec/faraday/response_spec.rb +28 -0
  31. data/spec/fixtures/access_token.json +9 -0
  32. data/spec/fixtures/followed_by.json +1 -0
  33. data/spec/fixtures/follows.json +1 -0
  34. data/spec/fixtures/location.json +1 -0
  35. data/spec/fixtures/location_recent_media.json +1 -0
  36. data/spec/fixtures/location_search.json +1 -0
  37. data/spec/fixtures/media.json +1 -0
  38. data/spec/fixtures/media_comment.json +1 -0
  39. data/spec/fixtures/media_comment_deleted.json +1 -0
  40. data/spec/fixtures/media_comments.json +1 -0
  41. data/spec/fixtures/media_liked.json +1 -0
  42. data/spec/fixtures/media_likes.json +1 -0
  43. data/spec/fixtures/media_popular.json +1 -0
  44. data/spec/fixtures/media_search.json +1 -0
  45. data/spec/fixtures/media_unliked.json +1 -0
  46. data/spec/fixtures/mikeyk.json +1 -0
  47. data/spec/fixtures/recent_media.json +1 -0
  48. data/spec/fixtures/requested_by.json +12 -0
  49. data/spec/fixtures/shayne.json +1 -0
  50. data/spec/fixtures/subscription.json +12 -0
  51. data/spec/fixtures/subscription_deleted.json +1 -0
  52. data/spec/fixtures/subscription_payload.json +14 -0
  53. data/spec/fixtures/subscriptions.json +22 -0
  54. data/spec/fixtures/tag.json +1 -0
  55. data/spec/fixtures/tag_recent_media.json +1 -0
  56. data/spec/fixtures/tag_search.json +1 -0
  57. data/spec/fixtures/user_media_feed.json +1 -0
  58. data/spec/fixtures/user_search.json +1 -0
  59. data/spec/instagram/api_spec.rb +110 -0
  60. data/spec/instagram/client/comments_spec.rb +71 -0
  61. data/spec/instagram/client/likes_spec.rb +66 -0
  62. data/spec/instagram/client/locations_spec.rb +78 -0
  63. data/spec/instagram/client/media_spec.rb +78 -0
  64. data/spec/instagram/client/real_time_spec.rb +13 -0
  65. data/spec/instagram/client/subscriptions_spec.rb +118 -0
  66. data/spec/instagram/client/tags_spec.rb +78 -0
  67. data/spec/instagram/client/users_spec.rb +237 -0
  68. data/spec/instagram/client_spec.rb +23 -0
  69. data/spec/instagram_spec.rb +97 -0
  70. data/spec/spec_helper.rb +54 -0
  71. metadata +265 -33
  72. data/MIT-LICENSE +0 -18
  73. data/lib/instagram/cached.rb +0 -25
  74. data/lib/instagram/failsafe_store.rb +0 -52
  75. data/lib/instagram/models.rb +0 -163
@@ -1,18 +0,0 @@
1
- Copyright (c) 2010 Mislav Marohnić
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy of
4
- this software and associated documentation files (the "Software"), to deal in
5
- the Software without restriction, including without limitation the rights to
6
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
- the Software, and to permit persons to whom the Software is furnished to do so,
8
- subject to the following conditions:
9
-
10
- The above copyright notice and this permission notice shall be included in all
11
- copies or substantial portions of the Software.
12
-
13
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,25 +0,0 @@
1
- require 'instagram'
2
- require 'instagram/failsafe_store'
3
-
4
- module Instagram
5
- module Cached
6
- extend Instagram
7
-
8
- class << self
9
- attr_accessor :cache
10
-
11
- def setup(cache_dir, options = {})
12
- self.cache = FailsafeStore.new(cache_dir, {
13
- namespace: 'instagram',
14
- exceptions: [Net::HTTPServerException, JSON::ParserError]
15
- }.update(options))
16
- end
17
-
18
- private
19
- def get_url(url)
20
- cache.fetch(url.to_s) { super }
21
- end
22
- end
23
-
24
- end
25
- end
@@ -1,52 +0,0 @@
1
- require 'active_support/cache'
2
-
3
- module Instagram
4
- class FailsafeStore < ActiveSupport::Cache::FileStore
5
- # Reuses the stale cache if a known exception occurs while yielding to the block.
6
- # The list of exception classes is read from the ":exceptions" array.
7
- def fetch(name, options = nil)
8
- options = merged_options(options)
9
- key = namespaced_key(name, options)
10
- entry = unless options[:force]
11
- instrument(:read, name, options) do |payload|
12
- payload[:super_operation] = :fetch if payload
13
- read_entry(key, options)
14
- end
15
- end
16
-
17
- if entry and not entry.expired?
18
- instrument(:fetch_hit, name, options) { |payload| }
19
- entry.value
20
- else
21
- reusing_stale = false
22
-
23
- result = begin
24
- instrument(:generate, name, options) do |payload|
25
- yield
26
- end
27
- rescue
28
- if entry and ignore_exception?($!)
29
- reusing_stale = true
30
- instrument(:reuse_stale, name, options) do |payload|
31
- payload[:exception] = $! if payload
32
- entry.value
33
- end
34
- else
35
- # TODO: figure out if deleting entries is ever necessary
36
- # delete_entry(key, options) if entry
37
- raise
38
- end
39
- end
40
-
41
- write(name, result, options) unless reusing_stale
42
- result
43
- end
44
- end
45
-
46
- private
47
-
48
- def ignore_exception?(ex)
49
- options[:exceptions] && options[:exceptions].any? { |klass| ex.is_a? klass }
50
- end
51
- end
52
- end
@@ -1,163 +0,0 @@
1
- require 'yajl/json_gem'
2
- require 'nibbler/json'
3
-
4
- module Instagram
5
-
6
- class Base < NibblerJSON
7
- # `pk` is such a dumb property name
8
- element 'pk' => :id
9
- end
10
-
11
- class User < Base
12
- element :username
13
- element :full_name
14
- element 'profile_pic_url' => :avatar_url
15
- alias avatar avatar_url # `avatar` is deprecated
16
-
17
- # extended info
18
- element :media_count
19
- element :following_count
20
- alias following following_count # `following` will return an array of users in future!
21
- element :follower_count
22
- alias followers follower_count # `followers` will return an array of users in future!
23
-
24
- def ==(other)
25
- User === other and other.id == self.id
26
- end
27
- end
28
-
29
- class UserWrap < NibblerJSON
30
- element :user, :with => User
31
- # return user instead of self when done
32
- def parse() super.user end
33
- end
34
-
35
- class Media < Base
36
- # short string used for permalink
37
- element :code
38
- # type is always 1 (other values possibly reserved for video in the future?)
39
- element :media_type
40
- # filter code; use `filter_name` to get human name of the filter used
41
- element :filter_type
42
- # I don't know what "device timestamp" is and how it relates to `taken_at`?
43
- element :device_timestamp
44
- # timestamp of when the picture was taken
45
- element :taken_at, :with => lambda { |sec| Time.at(sec) }
46
- # user who uploaded the media
47
- element :user, :with => User
48
-
49
- # array of people who liked this media
50
- elements :likers, :with => User
51
- # user IDs of people who liked this (only if "likers" are not present)
52
- element :liker_ids
53
-
54
- elements :comments, :with => NibblerJSON do
55
- element :created_at, :with => lambda { |sec| Time.at(sec) }
56
- # content type is always "comment"
57
- element :content_type
58
- # `type` is always 1 (other values possibly reserved for comments in form of media?)
59
- element :type
60
- # the `pk` of parent media
61
- element :media_id
62
- # comment body
63
- element :text
64
- # comment author
65
- element :user, :with => User
66
- end
67
-
68
- elements 'image_versions' => :images, :with => NibblerJSON do
69
- element :url
70
- # `type` is 5 for 150px, 6 for 306px and 7 for 612px
71
- element :type
72
- element :width
73
- element :height
74
-
75
- alias to_s url
76
- end
77
-
78
- # image location
79
- element :lat
80
- element :lng
81
-
82
- def geolocated?
83
- self.lat and self.lng
84
- end
85
-
86
- element :location, :with => Base do
87
- # ID on a 3rd-party service
88
- element :external_id
89
- # name of 3rd-party service, like "foursquare"
90
- element :external_source
91
- # name of location
92
- element :name
93
- # address in the external service's database
94
- element :address
95
- element :lat
96
- element :lng
97
- end
98
-
99
- # author's caption for the image; can be nil
100
- def caption
101
- # caption is implemented as a first comment made by the owner
102
- if comments.first and self.user == comments.first.user
103
- comments.first.text
104
- end
105
- end
106
-
107
- # typical sizes: 150px / 306px / 612px square
108
- def image_url(size = 150)
109
- self.images.find { |img| img.width == size }.to_s
110
- end
111
-
112
- FILTERS = {
113
- 1 => 'X-Pro II',
114
- 2 => 'Lomo-fi',
115
- 3 => 'Earlybird',
116
- 4 => 'Apollo',
117
- 5 => 'Poprocket',
118
- 10 => 'Inkwell',
119
- 13 => 'Gotham',
120
- 14 => '1977',
121
- 15 => 'Nashville',
122
- 16 => 'Lord Kelvin',
123
- 17 => 'Lily',
124
- 18 => 'Sutro',
125
- 19 => 'Toaster',
126
- 20 => 'Walden',
127
- 21 => 'Hefe'
128
- }
129
-
130
- def filter_name
131
- FILTERS[filter_type.to_i]
132
- end
133
- end
134
-
135
- class Tag < String
136
- attr_reader :media_count
137
-
138
- def initialize(str, count)
139
- super(str)
140
- @media_count = count
141
- end
142
-
143
- def self.parse(hash)
144
- new hash['name'], hash['media_count']
145
- end
146
-
147
- def inspect
148
- "#{super} (#{media_count})"
149
- end
150
- end
151
-
152
- class SearchTagsResults < NibblerJSON
153
- elements :results, :with => Tag
154
- def parse() super.results end
155
- end
156
-
157
- class Timeline < NibblerJSON
158
- elements :items, :with => Media
159
- # return items instead of self when done
160
- def parse() super.items end
161
- end
162
-
163
- end