naudo-ruby-iactionable 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.
- data/.gitignore +4 -0
- data/CHANGELOG.md +29 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +39 -0
- data/README.md +49 -0
- data/Rakefile +1 -0
- data/lib/iactionable/api.rb +224 -0
- data/lib/iactionable/connection.rb +118 -0
- data/lib/iactionable/error.rb +17 -0
- data/lib/iactionable/objects.rb +27 -0
- data/lib/iactionable/objects/achievement.rb +29 -0
- data/lib/iactionable/objects/awardable.rb +50 -0
- data/lib/iactionable/objects/challenge.rb +27 -0
- data/lib/iactionable/objects/goal.rb +30 -0
- data/lib/iactionable/objects/i_actionable_object.rb +40 -0
- data/lib/iactionable/objects/identifier.rb +17 -0
- data/lib/iactionable/objects/leaderboard.rb +15 -0
- data/lib/iactionable/objects/leaderboard_report.rb +30 -0
- data/lib/iactionable/objects/level.rb +24 -0
- data/lib/iactionable/objects/level_type.rb +15 -0
- data/lib/iactionable/objects/point_type.rb +15 -0
- data/lib/iactionable/objects/profile_achievements.rb +20 -0
- data/lib/iactionable/objects/profile_challenges.rb +20 -0
- data/lib/iactionable/objects/profile_goals.rb +20 -0
- data/lib/iactionable/objects/profile_level.rb +20 -0
- data/lib/iactionable/objects/profile_notifications.rb +29 -0
- data/lib/iactionable/objects/profile_points.rb +29 -0
- data/lib/iactionable/objects/profile_summary.rb +32 -0
- data/lib/iactionable/objects/progress.rb +46 -0
- data/lib/iactionable/settings.rb +30 -0
- data/lib/iactionable/version.rb +3 -0
- data/lib/ruby-iactionable.rb +9 -0
- data/ruby_iactionable.gemspec +28 -0
- data/spec/api/get_achievements_api_response_spec.rb +46 -0
- data/spec/api/get_challenges_api_response_spec.rb +42 -0
- data/spec/api/get_goals_api_response_spec.rb +46 -0
- data/spec/api/get_leaderboard_api_response_spec.rb +76 -0
- data/spec/api/get_profile_achievements_api_response_spec.rb +113 -0
- data/spec/api/get_profile_api_response_spec.rb +103 -0
- data/spec/api/get_profile_challenges_api_response_spec.rb +99 -0
- data/spec/api/get_profile_goals_api_response_spec.rb +103 -0
- data/spec/api/get_profile_notifications_api_response_spec.rb +75 -0
- data/spec/api/get_profile_points_api_response_spec.rb +67 -0
- data/spec/api_spec.rb +399 -0
- data/spec/connection_spec.rb +111 -0
- data/spec/settings_spec.rb +52 -0
- data/spec/spec_helper.rb +1 -0
- metadata +165 -0
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# CHANGELOG #
|
2
|
+
|
3
|
+
## 0.1.1 ##
|
4
|
+
|
5
|
+
* changing use of Date to DateTime;
|
6
|
+
|
7
|
+
## 0.1.0 ##
|
8
|
+
|
9
|
+
* New feature: api instance can be set to not wrap raw response within objects with: `@api.set\_object\_wrapping(false)`
|
10
|
+
|
11
|
+
## 0.0.5 ##
|
12
|
+
|
13
|
+
* Fixed: IActionable::Objects::Awardable#awarded_on was stripping out time information when converting IActionable timestamp to Ruby time object
|
14
|
+
|
15
|
+
## 0.0.4 ##
|
16
|
+
|
17
|
+
* explicitly rescuing from timeout errors.
|
18
|
+
|
19
|
+
## 0.0.3 ##
|
20
|
+
|
21
|
+
* Gem name matches require string.
|
22
|
+
|
23
|
+
## 0.0.2 ##
|
24
|
+
|
25
|
+
* Gem name matches require string.
|
26
|
+
|
27
|
+
## 0.0.1 ##
|
28
|
+
|
29
|
+
* Pulling API wrapper out as separate gem (this).
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ruby-iactionable (0.1.1)
|
5
|
+
activesupport (>= 3.0.0)
|
6
|
+
faraday
|
7
|
+
faraday_middleware (~> 0.8.7)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activesupport (3.2.3)
|
13
|
+
i18n (~> 0.6)
|
14
|
+
multi_json (~> 1.0)
|
15
|
+
diff-lcs (1.1.3)
|
16
|
+
faraday (0.8.0)
|
17
|
+
multipart-post (~> 1.1)
|
18
|
+
faraday_middleware (0.8.7)
|
19
|
+
faraday (>= 0.7.4, < 0.9)
|
20
|
+
i18n (0.6.0)
|
21
|
+
multi_json (1.3.5)
|
22
|
+
multipart-post (1.1.5)
|
23
|
+
rspec (2.10.0)
|
24
|
+
rspec-core (~> 2.10.0)
|
25
|
+
rspec-expectations (~> 2.10.0)
|
26
|
+
rspec-mocks (~> 2.10.0)
|
27
|
+
rspec-core (2.10.0)
|
28
|
+
rspec-expectations (2.10.0)
|
29
|
+
diff-lcs (~> 1.1.3)
|
30
|
+
rspec-mocks (2.10.1)
|
31
|
+
yard (0.8.1)
|
32
|
+
|
33
|
+
PLATFORMS
|
34
|
+
ruby
|
35
|
+
|
36
|
+
DEPENDENCIES
|
37
|
+
rspec (>= 2.6)
|
38
|
+
ruby-iactionable!
|
39
|
+
yard
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Overview #
|
2
|
+
|
3
|
+
Ruby IActionable is a straightforward wrapper for IActionable's restful API. The JSON-encoded responses from IActionable are wrapped in objects that provide a few extra functions here and there, but are mostly just a representation of the API response.
|
4
|
+
|
5
|
+
# How To Use #
|
6
|
+
|
7
|
+
## Installation ##
|
8
|
+
|
9
|
+
gem install ruby-iactionable
|
10
|
+
|
11
|
+
## IRB ##
|
12
|
+
|
13
|
+
require 'ruby-iactionable'
|
14
|
+
|
15
|
+
## Bundler ##
|
16
|
+
|
17
|
+
gem 'ruby-iactionable'
|
18
|
+
|
19
|
+
## API Credentials And Initialization ##
|
20
|
+
|
21
|
+
Before the API wrapper can be instantiated or used it must be pre-initialized with your IActionable credentials and version number (IActionable supports older versions but recommends staying up to date):
|
22
|
+
|
23
|
+
IActionable::Api.init_settings( :app_key => "12345",
|
24
|
+
:api_key => "abcde",
|
25
|
+
:version => 3 )
|
26
|
+
@api = IActionable::Api.new
|
27
|
+
|
28
|
+
The responses for each of the endpoints of IActionable's API are described through example by [their documentation](http://www.iactionable.com/api/). Here is an example of the response from a [profile summary](http://iactionable.com/api/) returned as an object by the wrapper.
|
29
|
+
|
30
|
+
profile_summary = @api.get_profile_summary("user", "username", "zortnac", 10)
|
31
|
+
profile_summary.display_name # => "Chris Eberz"
|
32
|
+
profile_summary.identifiers.first # => instance of IActionable::Objects::Identifier
|
33
|
+
profile_summary.identifiers.first.id_type # => "username"
|
34
|
+
profile_summary.identifiers.first.id # => "zortnac"
|
35
|
+
|
36
|
+
Each object can be dumped back in to its original form of arrays and key/value pairs:
|
37
|
+
|
38
|
+
profile_summary.to_hash # => { "DisplayName" => "Chris Eberz", "Identifiers" => [ {"ID" => "zortnac", "IDType" => "username", ...} ] ... }
|
39
|
+
# (not shown in entirety)
|
40
|
+
|
41
|
+
----------------
|
42
|
+
|
43
|
+
## IActionable ##
|
44
|
+
|
45
|
+
[Visit their website!](http://www.iactionable.com)
|
46
|
+
|
47
|
+
## Author ##
|
48
|
+
|
49
|
+
Christopher Eberz; chris@chriseberz.com; @zortnac
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,224 @@
|
|
1
|
+
require 'iactionable/connection.rb'
|
2
|
+
require 'iactionable/settings.rb'
|
3
|
+
require 'iactionable/objects.rb'
|
4
|
+
|
5
|
+
module IActionable
|
6
|
+
|
7
|
+
class Api
|
8
|
+
attr :connection
|
9
|
+
attr :wrap_in_object
|
10
|
+
|
11
|
+
@@settings = nil
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
if @@settings
|
15
|
+
@connection = IActionable::Connection.new(@@settings)
|
16
|
+
else
|
17
|
+
raise IActionable::ConfigError.new("IActionable::Api cannot be initialized without credentials being set in IActionable::Api.init_settings()")
|
18
|
+
end
|
19
|
+
@wrap_in_object = true
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.init_settings(values)
|
23
|
+
@@settings = IActionable::Settings.new(values)
|
24
|
+
rescue IActionable::ConfigError => e
|
25
|
+
raise e
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.settings
|
29
|
+
@@settings
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_object_wrapping(bool)
|
33
|
+
@wrap_in_object = !!bool
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
# =================
|
38
|
+
# = Event Logging =
|
39
|
+
# =================
|
40
|
+
|
41
|
+
def log_event(profile_type, id_type, id, event_key, event_attrs = {})
|
42
|
+
response = @connection.request.with_app_key.with_api_key.to("/#{profile_type}/#{id_type}/#{id}/events/#{event_key}").with_params(event_attrs).post
|
43
|
+
end
|
44
|
+
|
45
|
+
# =====================
|
46
|
+
# = Profile API calls =
|
47
|
+
# =====================
|
48
|
+
|
49
|
+
def get_profile_summary(profile_type, id_type, id, achievement_count = nil)
|
50
|
+
request = @connection.request.with_app_key.to("/#{profile_type}/#{id_type}/#{id}")
|
51
|
+
request.with_params(:achievementCount => achievement_count) unless achievement_count.blank?
|
52
|
+
if @wrap_in_object
|
53
|
+
IActionable::Objects::ProfileSummary.new(request.get)
|
54
|
+
else
|
55
|
+
request.get
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_profile(profile_type, id_type, id, display_name = nil)
|
60
|
+
request = @connection.request.with_app_key.with_api_key.to("/#{profile_type}/#{id_type}/#{id}")
|
61
|
+
request.with_params(:displayName => display_name) unless display_name.blank?
|
62
|
+
request.post
|
63
|
+
end
|
64
|
+
alias_method :update_profile, :create_profile
|
65
|
+
|
66
|
+
def add_profile_identifier(profile_type, id_type, id, alt_id_type, alt_id)
|
67
|
+
@connection.request.with_app_key.with_api_key.to("/#{profile_type}/#{id_type}/#{id}/identifiers/#{alt_id_type}/#{alt_id}").post
|
68
|
+
end
|
69
|
+
|
70
|
+
# ====================
|
71
|
+
# = Points API calls =
|
72
|
+
# ====================
|
73
|
+
|
74
|
+
def get_profile_points(profile_type, id_type, id, point_type)
|
75
|
+
response = @connection.request.with_app_key.to("/#{profile_type}/#{id_type}/#{id}/points/#{point_type}").get
|
76
|
+
if @wrap_in_object
|
77
|
+
IActionable::Objects::ProfilePoints.new(response)
|
78
|
+
else
|
79
|
+
response
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def update_profile_points(profile_type, id_type, id, point_type, amount, reason = nil)
|
84
|
+
request = @connection.request.with_app_key.with_api_key.to("/#{profile_type}/#{id_type}/#{id}/points/#{point_type}").with_params(:value => amount)
|
85
|
+
request.with_params(:description => reason) unless reason.blank?
|
86
|
+
if @wrap_in_object
|
87
|
+
IActionable::Objects::ProfilePoints.new(request.post)
|
88
|
+
else
|
89
|
+
request.post
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# =========================
|
94
|
+
# = Achievement API calls =
|
95
|
+
# =========================
|
96
|
+
|
97
|
+
def get_profile_achievements(profile_type, id_type, id, filter_type = nil)
|
98
|
+
request = @connection.request.with_app_key
|
99
|
+
case filter_type
|
100
|
+
when :completed
|
101
|
+
request.to("/#{profile_type}/#{id_type}/#{id}/achievements/Completed")
|
102
|
+
when :available
|
103
|
+
request.to("/#{profile_type}/#{id_type}/#{id}/achievements/Available")
|
104
|
+
else
|
105
|
+
request.to("/#{profile_type}/#{id_type}/#{id}/achievements")
|
106
|
+
end
|
107
|
+
|
108
|
+
if @wrap_in_object
|
109
|
+
IActionable::Objects::ProfileAchievements.new(request.get)
|
110
|
+
else
|
111
|
+
request.get
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def get_achievements()
|
116
|
+
response = @connection.request.with_app_key.to("/achievements").get
|
117
|
+
if @wrap_in_object
|
118
|
+
response.map{|achievement_json| IActionable::Objects::Achievement.new(achievement_json)}
|
119
|
+
else
|
120
|
+
response
|
121
|
+
end
|
122
|
+
rescue NoMethodError => e
|
123
|
+
[]
|
124
|
+
end
|
125
|
+
|
126
|
+
# ========================
|
127
|
+
# = Challenges API calls =
|
128
|
+
# ========================
|
129
|
+
|
130
|
+
def get_profile_challenges(profile_type, id_type, id, filter_type = nil)
|
131
|
+
request = @connection.request.with_app_key
|
132
|
+
case filter_type
|
133
|
+
when :completed
|
134
|
+
request.to("/#{profile_type}/#{id_type}/#{id}/challenges/Completed")
|
135
|
+
when :available
|
136
|
+
request.to("/#{profile_type}/#{id_type}/#{id}/challenges/Available")
|
137
|
+
else
|
138
|
+
request.to("/#{profile_type}/#{id_type}/#{id}/challenges")
|
139
|
+
end
|
140
|
+
|
141
|
+
if @wrap_in_object
|
142
|
+
IActionable::Objects::ProfileChallenges.new(request.get)
|
143
|
+
else
|
144
|
+
request.get
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def get_challenges()
|
149
|
+
response = @connection.request.with_app_key.to("/challenges").get
|
150
|
+
if @wrap_in_object
|
151
|
+
response.map{|challenge_json| IActionable::Objects::Challenge.new(challenge_json)}
|
152
|
+
else
|
153
|
+
response
|
154
|
+
end
|
155
|
+
rescue NoMethodError => e
|
156
|
+
[]
|
157
|
+
end
|
158
|
+
|
159
|
+
# ===================
|
160
|
+
# = Goals API calls =
|
161
|
+
# ===================
|
162
|
+
|
163
|
+
def get_profile_goals(profile_type, id_type, id, filter_type = nil)
|
164
|
+
request = @connection.request.with_app_key
|
165
|
+
case filter_type
|
166
|
+
when :completed
|
167
|
+
request.to("/#{profile_type}/#{id_type}/#{id}/goals/Completed")
|
168
|
+
when :available
|
169
|
+
request.to("/#{profile_type}/#{id_type}/#{id}/goals/Available")
|
170
|
+
else
|
171
|
+
request.to("/#{profile_type}/#{id_type}/#{id}/goals")
|
172
|
+
end
|
173
|
+
|
174
|
+
if @wrap_in_object
|
175
|
+
IActionable::Objects::ProfileGoals.new(request.get)
|
176
|
+
else
|
177
|
+
request.get
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def get_goals()
|
182
|
+
response = @connection.request.with_app_key.to("/goals").get
|
183
|
+
if @wrap_in_object
|
184
|
+
response.map{|goal_json| IActionable::Objects::Goal.new(goal_json)}
|
185
|
+
else
|
186
|
+
response
|
187
|
+
end
|
188
|
+
rescue NoMethodError => e
|
189
|
+
[]
|
190
|
+
end
|
191
|
+
|
192
|
+
# =========================
|
193
|
+
# = Leaderboard API calls =
|
194
|
+
# =========================
|
195
|
+
|
196
|
+
def get_leaderboard(profile_type, point_type, leaderboard, page_number=nil, page_count=nil, id=nil, id_type=nil)
|
197
|
+
request = @connection.request.with_app_key.to("/#{profile_type}/leaderboards/points/#{point_type}/#{leaderboard}")
|
198
|
+
request.with_params(:pageNumber => page_number) unless page_number.blank?
|
199
|
+
request.with_params(:pageCount => page_count) unless page_count.blank?
|
200
|
+
request.with_params(:id => id) unless id.blank? || id_type.blank?
|
201
|
+
request.with_params(:idType => id_type) unless id.blank? || id_type.blank?
|
202
|
+
|
203
|
+
if @wrap_in_object
|
204
|
+
IActionable::Objects::LeaderboardReport.new(request.get)
|
205
|
+
else
|
206
|
+
request.get
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# ===================================
|
211
|
+
# = Profile Notifications API calls =
|
212
|
+
# ===================================
|
213
|
+
|
214
|
+
def get_profile_notifications(profile_type, id_type, id)
|
215
|
+
response = @connection.request.with_app_key.to("/#{profile_type}/#{id_type}/#{id}/notifications").get
|
216
|
+
|
217
|
+
if @wrap_in_object
|
218
|
+
IActionable::Objects::ProfileNotifications.new(response)
|
219
|
+
else
|
220
|
+
response
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'iactionable/error'
|
4
|
+
|
5
|
+
module IActionable
|
6
|
+
class Request < Struct.new(:path, :params, :headers, :body)
|
7
|
+
attr :settings
|
8
|
+
|
9
|
+
def initialize(settings)
|
10
|
+
@settings = settings
|
11
|
+
self.path = nil
|
12
|
+
self.params = {}
|
13
|
+
self.headers = {}
|
14
|
+
self.body = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def to(path)
|
18
|
+
self.path = path unless path.nil? || path.empty?
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def with_api_key
|
23
|
+
(self.headers[:Authorization] = @settings.api_key) and self
|
24
|
+
end
|
25
|
+
|
26
|
+
def with_app_key
|
27
|
+
(self.params[:appKey] = @settings.app_key) and self
|
28
|
+
end
|
29
|
+
|
30
|
+
def with_params(params={})
|
31
|
+
self.params.merge!(params) and self
|
32
|
+
end
|
33
|
+
|
34
|
+
def with_body(body={})
|
35
|
+
self.body.merge!(body) and self
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Connection
|
40
|
+
attr :connection
|
41
|
+
attr :settings
|
42
|
+
attr :request
|
43
|
+
attr_accessor :response
|
44
|
+
|
45
|
+
def initialize(settings)
|
46
|
+
@settings = settings
|
47
|
+
|
48
|
+
@connection = Faraday.new api_url(@settings.version) do |builder|
|
49
|
+
builder.use FaradayMiddleware::ParseJson, content_type: 'application/json'
|
50
|
+
builder.use Faraday::Response::RaiseError
|
51
|
+
builder.use Faraday::Adapter::NetHttp
|
52
|
+
end
|
53
|
+
|
54
|
+
@request = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def request
|
58
|
+
(@request = Request.new(@settings)) and self
|
59
|
+
end
|
60
|
+
|
61
|
+
def get(path=nil, query_params={})
|
62
|
+
@request ||= Request.new(@settings)
|
63
|
+
@request.to(path).with_params(query_params)
|
64
|
+
@response = @connection.get do |req|
|
65
|
+
req.headers.merge! @request.headers
|
66
|
+
req.url @request.path, @request.params
|
67
|
+
end
|
68
|
+
@response.body
|
69
|
+
rescue Faraday::Error::ClientError => e
|
70
|
+
handle_client_error e
|
71
|
+
rescue Faraday::Error::TimeoutError, Timeout::Error => e
|
72
|
+
raise e
|
73
|
+
ensure
|
74
|
+
@request = nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def post(path=nil, query_params={}, body_params={})
|
78
|
+
@request ||= Request.new(@settings)
|
79
|
+
@request.to(path).with_params(query_params)
|
80
|
+
@response = @connection.post do |req|
|
81
|
+
req.headers.merge! @request.headers
|
82
|
+
req.url @request.path, @request.params
|
83
|
+
req.body = @request.body unless @request.body.empty?
|
84
|
+
end
|
85
|
+
@response.body
|
86
|
+
rescue Faraday::Error::ClientError => e
|
87
|
+
handle_client_error e
|
88
|
+
rescue Faraday::Error::TimeoutError, Timeout::Error => e
|
89
|
+
raise e
|
90
|
+
ensure
|
91
|
+
@request = nil
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
def method_missing(symbol, *args)
|
97
|
+
@request.send(symbol, *args) and self
|
98
|
+
rescue NoMethodError => e
|
99
|
+
raise e
|
100
|
+
end
|
101
|
+
|
102
|
+
def api_url(version)
|
103
|
+
"http://api.iactionable.com/v#{version}/"
|
104
|
+
end
|
105
|
+
|
106
|
+
def handle_client_error(e)
|
107
|
+
# http://iactionable.com/api/response-codes/
|
108
|
+
case e.response[:status]
|
109
|
+
when 400
|
110
|
+
raise IActionable::Error::BadRequest.new(e.response)
|
111
|
+
when 401
|
112
|
+
raise IActionable::Error::Unauthorized.new(e.response)
|
113
|
+
when 500
|
114
|
+
raise IActionable::Error::Internal.new(e.response)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|