singly 0.1.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 (90) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +63 -0
  5. data/Rakefile +8 -0
  6. data/lib/singly/account.rb +63 -0
  7. data/lib/singly/api/auth/merge.rb +8 -0
  8. data/lib/singly/api/auth/service/oauth1_apply.rb +13 -0
  9. data/lib/singly/api/auth/service/oauth2_apply.rb +13 -0
  10. data/lib/singly/api/auth/service.rb +23 -0
  11. data/lib/singly/api/auth.rb +163 -0
  12. data/lib/singly/api/friends/group.rb +12 -0
  13. data/lib/singly/api/friends.rb +76 -0
  14. data/lib/singly/api/id.rb +6 -0
  15. data/lib/singly/api/multi.rb +6 -0
  16. data/lib/singly/api/profile.rb +6 -0
  17. data/lib/singly/api/profiles/delete.rb +8 -0
  18. data/lib/singly/api/profiles/delete_profile.rb +8 -0
  19. data/lib/singly/api/profiles/delete_service.rb +8 -0
  20. data/lib/singly/api/profiles/self.rb +8 -0
  21. data/lib/singly/api/profiles/self_update.rb +8 -0
  22. data/lib/singly/api/profiles/service.rb +18 -0
  23. data/lib/singly/api/profiles.rb +178 -0
  24. data/lib/singly/api/proxy/delete.rb +8 -0
  25. data/lib/singly/api/proxy/get.rb +8 -0
  26. data/lib/singly/api/proxy/post.rb +8 -0
  27. data/lib/singly/api/proxy/put.rb +8 -0
  28. data/lib/singly/api/proxy.rb +169 -0
  29. data/lib/singly/api/services/37signals.rb +14 -0
  30. data/lib/singly/api/services/bodymedia.rb +30 -0
  31. data/lib/singly/api/services/dropbox.rb +22 -0
  32. data/lib/singly/api/services/dwolla.rb +14 -0
  33. data/lib/singly/api/services/endpoint.rb +12 -0
  34. data/lib/singly/api/services/facebook.rb +62 -0
  35. data/lib/singly/api/services/fitbit.rb +34 -0
  36. data/lib/singly/api/services/flickr.rb +26 -0
  37. data/lib/singly/api/services/foursquare.rb +34 -0
  38. data/lib/singly/api/services/gcal.rb +18 -0
  39. data/lib/singly/api/services/gcontacts.rb +18 -0
  40. data/lib/singly/api/services/gdocs.rb +18 -0
  41. data/lib/singly/api/services/github.rb +34 -0
  42. data/lib/singly/api/services/gmail.rb +22 -0
  43. data/lib/singly/api/services/google.rb +14 -0
  44. data/lib/singly/api/services/gplus.rb +18 -0
  45. data/lib/singly/api/services/id_endpoint.rb +12 -0
  46. data/lib/singly/api/services/imgur.rb +14 -0
  47. data/lib/singly/api/services/instagram.rb +26 -0
  48. data/lib/singly/api/services/klout.rb +26 -0
  49. data/lib/singly/api/services/linkedin.rb +26 -0
  50. data/lib/singly/api/services/meetup.rb +30 -0
  51. data/lib/singly/api/services/paypal.rb +14 -0
  52. data/lib/singly/api/services/picasa.rb +22 -0
  53. data/lib/singly/api/services/rdio.rb +26 -0
  54. data/lib/singly/api/services/reddit.rb +14 -0
  55. data/lib/singly/api/services/runkeeper.rb +38 -0
  56. data/lib/singly/api/services/service.rb +48 -0
  57. data/lib/singly/api/services/shutterfly.rb +22 -0
  58. data/lib/singly/api/services/soundcloud.rb +14 -0
  59. data/lib/singly/api/services/stocktwits.rb +22 -0
  60. data/lib/singly/api/services/tout.rb +14 -0
  61. data/lib/singly/api/services/tumblr.rb +26 -0
  62. data/lib/singly/api/services/twitter.rb +42 -0
  63. data/lib/singly/api/services/withings.rb +18 -0
  64. data/lib/singly/api/services/wordpress.rb +22 -0
  65. data/lib/singly/api/services/yammer.rb +26 -0
  66. data/lib/singly/api/services/youtube.rb +18 -0
  67. data/lib/singly/api/services/zeo.rb +26 -0
  68. data/lib/singly/api/services.rb +158 -0
  69. data/lib/singly/api/types/type.rb +12 -0
  70. data/lib/singly/api/types.rb +68 -0
  71. data/lib/singly/endpoint.rb +112 -0
  72. data/lib/singly/error.rb +24 -0
  73. data/lib/singly/http.rb +38 -0
  74. data/lib/singly/logger.rb +14 -0
  75. data/lib/singly.rb +37 -0
  76. data/lib/version.rb +3 -0
  77. data/singly.gemspec +25 -0
  78. data/spec/integration/auth_spec.rb +14 -0
  79. data/spec/singly/account_spec.rb +108 -0
  80. data/spec/singly/api/auth_spec.rb +8 -0
  81. data/spec/singly/endpoint_spec.rb +100 -0
  82. data/spec/singly/error_spec.rb +40 -0
  83. data/spec/singly/http_spec.rb +52 -0
  84. data/spec/singly/logger_spec.rb +32 -0
  85. data/spec/singly_spec.rb +53 -0
  86. data/spec/spec_helper.rb +27 -0
  87. data/spec/vcr_cassettes/http_fetch_with_api_error.yml +39 -0
  88. data/spec/vcr_cassettes/http_fetch_with_json_response.yml +102 -0
  89. data/spec/vcr_cassettes/http_fetch_with_non_json_response.yml +39 -0
  90. metadata +216 -0
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in singly.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Timehop
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # Singly
2
+
3
+ A Ruby Gem to interact with the Singly API.
4
+
5
+ Developed using straight-up bunder, as per [these instructions](https://github.com/radar/guides/blob/master/gem-development.md).
6
+
7
+ ## Installation
8
+
9
+ This gem has not been released to rubygems yet. To install it manually:
10
+
11
+ ```sh
12
+ git clone git@github.com:timehop/singly.git singly
13
+ cd singly
14
+ bundle install
15
+ rake install
16
+ ```
17
+
18
+ ## Use in your project
19
+
20
+ Add Singly to your Gemfile:
21
+
22
+ ```ruby
23
+ gem "singly"
24
+ ```
25
+
26
+ Then, initialize the gem. If you're using Rails, then this can be easily accomplished with an initializer file. Edit a file at `config/initializers/singly.rb` to include:
27
+
28
+ ```ruby
29
+ Singly.client_id = "<client_id>"
30
+ Singly.client_secret = "<client_secret>"
31
+ Singly.verbose = true # Set to false to disable logging
32
+ ```
33
+
34
+ ## Use the gem directly
35
+
36
+ You may also experiment with this gem in a headless fashion (ie: without installing the gem):
37
+
38
+ ```sh
39
+ git clone git@github.com:timehop/singly.git singly
40
+ cd singly
41
+ bundle install
42
+ rake console
43
+ ```
44
+
45
+ This will look for an optional file at `.config/console.rb` where you can write arbitrary ruby code and have it loaded into your irb session.
46
+
47
+ For example, edit `.config/console.rb` to include:
48
+
49
+ ```ruby
50
+ Singly.client_id = "<client_id>"
51
+ Singly.client_secret = "<client_secret>"
52
+ Singly.verbose = true # Set to false to disable logging
53
+ ```
54
+
55
+ This avoids having to configure your singly credentials every time you run `rake console`.
56
+
57
+ ## Contributing
58
+
59
+ 1. Fork it
60
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
61
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
62
+ 4. Push to the branch (`git push origin my-new-feature`)
63
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ desc "Open an irb session preloaded with this library and an optional file at .config/console.rb"
4
+ task :console do
5
+ singly_class = "#{File.dirname(__FILE__)}/lib/singly.rb"
6
+ console_script = "#{File.dirname(__FILE__)}/.config/console.rb"
7
+ sh "irb -r #{singly_class} -r #{console_script}"
8
+ end
@@ -0,0 +1,63 @@
1
+ module Singly
2
+ class Account
3
+ attr_reader :access_token
4
+
5
+ def initialize(access_token, account=nil)
6
+ @access_token = access_token
7
+ @account = account
8
+ end
9
+
10
+ def account_id
11
+ @account ||= profiles.fetch["id"]
12
+ end
13
+
14
+ def profile
15
+ Singly::Profile.new(access_token: access_token)
16
+ end
17
+
18
+ def profiles(params={})
19
+ Singly::Profiles.new(params.merge(access_token: access_token))
20
+ end
21
+
22
+ def types
23
+ Singly::Types.new(access_token: access_token)
24
+ end
25
+
26
+ def services
27
+ Singly::Services.new(access_token: access_token)
28
+ end
29
+
30
+ def friends
31
+ Singly::Friends.new(access_token: access_token)
32
+ end
33
+
34
+ def id(id, params={})
35
+ Singly::Id.new(params.merge(access_token: access_token, id: id))
36
+ end
37
+
38
+ def proxy
39
+ Singly::Proxy.new(access_token)
40
+ end
41
+
42
+ # Alternative to calling #profiles.<service>.delete.
43
+ # Useful if you don't know the exact service at runtime.
44
+ def delete(service, id=nil)
45
+ Singly::Profiles::Service.new(access_token: access_token, service: service.to_s).delete(id)
46
+ end
47
+
48
+ # Shortcut to Singly.auth.merge(source: <source>, dest: <dest>)
49
+ # where <dest> is always this account's access_token.
50
+ def merge(source)
51
+ Singly.auth.merge(source: source, dest: access_token)
52
+ end
53
+
54
+ # Shortcut to Singly.auth.<service>.apply(account: <account_id>, token: <token> [, token_secret: <token_secret>])
55
+ # where <account_id> is always this account's account_id.
56
+ # If the account_id is not present, it is fetched from the api.
57
+ def apply(service, params)
58
+ is_oauth1 = !params[:token_secret].nil?
59
+ service = Singly::Auth::Service.new(service, is_oauth1)
60
+ service.apply(params.merge(account: account_id))
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,8 @@
1
+ module Singly
2
+ class Auth
3
+ class Merge
4
+ include Singly::Endpoint
5
+ endpoint :get, "/auth/merge", required: [:source, :dest]
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ module Singly
2
+ class Auth
3
+ class Service
4
+ class Oauth1Apply
5
+ include Singly::Endpoint
6
+ endpoint :get, "/auth/:service/apply", {
7
+ required: [:token, :token_secret, :client_id, :client_secret],
8
+ optional: [:account]
9
+ }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Singly
2
+ class Auth
3
+ class Service
4
+ class Oauth2Apply
5
+ include Singly::Endpoint
6
+ endpoint :get, "/auth/:service/apply", {
7
+ required: [:token, :client_id, :client_secret],
8
+ optional: [:account]
9
+ }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ module Singly
2
+ class Auth
3
+ class Service
4
+ attr_reader :service
5
+ attr_reader :is_oauth1
6
+
7
+ def initialize(service, is_oauth1=false)
8
+ @service = service
9
+ @is_oauth1 = is_oauth1
10
+ end
11
+
12
+ def apply(params={})
13
+ params ||= {}
14
+ apply_type = is_oauth1 ? Singly::Auth::Service::Oauth1Apply : Singly::Auth::Service::Oauth2Apply
15
+ apply_type.new(params.merge({
16
+ service: service.to_s,
17
+ client_id: Singly.client_id,
18
+ client_secret: Singly.client_secret
19
+ }))
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,163 @@
1
+ module Singly
2
+ class Auth
3
+
4
+ def merge(params)
5
+ params ||= {}
6
+ Singly::Auth::Merge.new(params)
7
+ end
8
+
9
+ def thirtysevensignals
10
+ oauth2_service("37signals")
11
+ end
12
+
13
+ def bodymedia
14
+ oauth2_service(__method__)
15
+ end
16
+
17
+ def dropbox
18
+ oauth2_service(__method__)
19
+ end
20
+
21
+ def dwolla
22
+ oauth2_service(__method__)
23
+ end
24
+
25
+ def facebook
26
+ oauth2_service(__method__)
27
+ end
28
+
29
+ def fitbit
30
+ oauth2_service(__method__)
31
+ end
32
+
33
+ def foursquare
34
+ oauth2_service(__method__)
35
+ end
36
+
37
+ def gcal
38
+ oauth2_service(__method__)
39
+ end
40
+
41
+ def gcontacts
42
+ oauth2_service(__method__)
43
+ end
44
+
45
+ def gdocs
46
+ oauth2_service(__method__)
47
+ end
48
+
49
+ def github
50
+ oauth2_service(__method__)
51
+ end
52
+
53
+ def gmail
54
+ oauth2_service(__method__)
55
+ end
56
+
57
+ def google
58
+ oauth2_service(__method__)
59
+ end
60
+
61
+ def gplus
62
+ oauth2_service(__method__)
63
+ end
64
+
65
+ def imgur
66
+ oauth2_service(__method__)
67
+ end
68
+
69
+ def instagram
70
+ oauth2_service(__method__)
71
+ end
72
+
73
+ def klout
74
+ oauth2_service(__method__)
75
+ end
76
+
77
+ def linkedin
78
+ oauth2_service(__method__)
79
+ end
80
+
81
+ def meetup
82
+ oauth2_service(__method__)
83
+ end
84
+
85
+ def paypal
86
+ oauth2_service(__method__)
87
+ end
88
+
89
+ def picasa
90
+ oauth2_service(__method__)
91
+ end
92
+
93
+ def rdio
94
+ oauth2_service(__method__)
95
+ end
96
+
97
+ def reddit
98
+ oauth2_service(__method__)
99
+ end
100
+
101
+ def runkeeper
102
+ oauth2_service(__method__)
103
+ end
104
+
105
+ def shutterfly
106
+ oauth2_service(__method__)
107
+ end
108
+
109
+ def soundcloud
110
+ oauth2_service(__method__)
111
+ end
112
+
113
+ def stocktwits
114
+ oauth2_service(__method__)
115
+ end
116
+
117
+ def tout
118
+ oauth2_service(__method__)
119
+ end
120
+
121
+ def withings
122
+ oauth2_service(__method__)
123
+ end
124
+
125
+ def wordpress
126
+ oauth2_service(__method__)
127
+ end
128
+
129
+ def yammer
130
+ oauth2_service(__method__)
131
+ end
132
+
133
+ def youtube
134
+ oauth2_service(__method__)
135
+ end
136
+
137
+ def zeo
138
+ oauth2_service(__method__)
139
+ end
140
+
141
+ def flickr
142
+ oauth1_service(__method__)
143
+ end
144
+
145
+ def tumblr
146
+ oauth1_service(__method__)
147
+ end
148
+
149
+ def twitter
150
+ oauth1_service(__method__)
151
+ end
152
+
153
+ private
154
+
155
+ def oauth1_service(service)
156
+ Singly::Auth::Service.new(service, true)
157
+ end
158
+
159
+ def oauth2_service(service)
160
+ Singly::Auth::Service.new(service)
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,12 @@
1
+ module Singly
2
+ class Friends
3
+ class Group
4
+ include Singly::Endpoint
5
+
6
+ endpoint :get, "/friends/:group", {
7
+ required: [:access_token],
8
+ optional: [:limit, :offset, :services, :full, :sort, :toc, :q, :bio]
9
+ }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,76 @@
1
+ module Singly
2
+ class Friends
3
+ include Singly::Endpoint
4
+
5
+ endpoint :get, "/friends", required: [:access_token], optional: [:data, :verify]
6
+
7
+ def all(params={})
8
+ group_endpoint(__method__, params)
9
+ end
10
+
11
+ def peers(params={})
12
+ group_endpoint(__method__, params)
13
+ end
14
+
15
+ def ios(params={})
16
+ group_endpoint(__method__, params)
17
+ end
18
+
19
+ def android(params={})
20
+ group_endpoint(__method__, params)
21
+ end
22
+
23
+ def facebook(params={})
24
+ group_endpoint(__method__, params)
25
+ end
26
+
27
+ def twitter(params={})
28
+ group_endpoint(__method__, params)
29
+ end
30
+
31
+ def linkedin(params={})
32
+ group_endpoint(__method__, params)
33
+ end
34
+
35
+ def gcontacts(params={})
36
+ group_endpoint(__method__, params)
37
+ end
38
+
39
+ def instagram(params={})
40
+ group_endpoint(__method__, params)
41
+ end
42
+
43
+ def foursquare(params={})
44
+ group_endpoint(__method__, params)
45
+ end
46
+
47
+ def github(params={})
48
+ group_endpoint(__method__, params)
49
+ end
50
+
51
+ def tumblr(params={})
52
+ group_endpoint(__method__, params)
53
+ end
54
+
55
+ def flickr(params={})
56
+ group_endpoint(__method__, params)
57
+ end
58
+
59
+ def yammer(params={})
60
+ group_endpoint(__method__, params)
61
+ end
62
+
63
+ def klout(params={})
64
+ group_endpoint(__method__, params)
65
+ end
66
+
67
+ private
68
+
69
+ def group_endpoint(group, params)
70
+ params ||= {}
71
+ Singly::Friends::Group.new(creds.merge(params.merge({
72
+ group: group.to_s
73
+ })))
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,6 @@
1
+ module Singly
2
+ class Id
3
+ include Singly::Endpoint
4
+ endpoint :get, "/id/:id", required: [:access_token], optional: [:map]
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Singly
2
+ class Multi
3
+ include Singly::Endpoint
4
+ endpoint :get, "/multi", required: [:urls]
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Singly
2
+ class Profile
3
+ include Singly::Endpoint
4
+ endpoint :get, "/profile", required: [:access_token]
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ module Singly
2
+ class Profiles
3
+ class Delete
4
+ include Singly::Endpoint
5
+ endpoint :delete, "/profiles", required: [:access_token]
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Singly
2
+ class Profiles
3
+ class DeleteProfile
4
+ include Singly::Endpoint
5
+ endpoint :delete, "/profiles/:id@:service", required: [:access_token]
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Singly
2
+ class Profiles
3
+ class DeleteService
4
+ include Singly::Endpoint
5
+ endpoint :delete, "/profiles/:service", required: [:access_token]
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Singly
2
+ class Profiles
3
+ class Self
4
+ include Singly::Endpoint
5
+ endpoint :get, "/profiles/self", required: [:access_token]
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Singly
2
+ class Profiles
3
+ class SelfUpdate
4
+ include Singly::Endpoint
5
+ endpoint :post, "/profiles/self", required: [:access_token]
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,18 @@
1
+ module Singly
2
+ class Profiles
3
+ class Service
4
+ include Singly::Endpoint
5
+
6
+ endpoint :get, "/profiles/:service", required: [:access_token], optional: [:auth]
7
+
8
+ def delete(id=nil)
9
+ service = route_params[:service]
10
+ if id
11
+ Singly::Profiles::DeleteProfile.new(creds.merge({service: service, id: id.to_s}))
12
+ else
13
+ Singly::Profiles::DeleteService.new(creds.merge({service: service}))
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end