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.
Files changed (48) hide show
  1. data/.gitignore +4 -0
  2. data/CHANGELOG.md +29 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +39 -0
  5. data/README.md +49 -0
  6. data/Rakefile +1 -0
  7. data/lib/iactionable/api.rb +224 -0
  8. data/lib/iactionable/connection.rb +118 -0
  9. data/lib/iactionable/error.rb +17 -0
  10. data/lib/iactionable/objects.rb +27 -0
  11. data/lib/iactionable/objects/achievement.rb +29 -0
  12. data/lib/iactionable/objects/awardable.rb +50 -0
  13. data/lib/iactionable/objects/challenge.rb +27 -0
  14. data/lib/iactionable/objects/goal.rb +30 -0
  15. data/lib/iactionable/objects/i_actionable_object.rb +40 -0
  16. data/lib/iactionable/objects/identifier.rb +17 -0
  17. data/lib/iactionable/objects/leaderboard.rb +15 -0
  18. data/lib/iactionable/objects/leaderboard_report.rb +30 -0
  19. data/lib/iactionable/objects/level.rb +24 -0
  20. data/lib/iactionable/objects/level_type.rb +15 -0
  21. data/lib/iactionable/objects/point_type.rb +15 -0
  22. data/lib/iactionable/objects/profile_achievements.rb +20 -0
  23. data/lib/iactionable/objects/profile_challenges.rb +20 -0
  24. data/lib/iactionable/objects/profile_goals.rb +20 -0
  25. data/lib/iactionable/objects/profile_level.rb +20 -0
  26. data/lib/iactionable/objects/profile_notifications.rb +29 -0
  27. data/lib/iactionable/objects/profile_points.rb +29 -0
  28. data/lib/iactionable/objects/profile_summary.rb +32 -0
  29. data/lib/iactionable/objects/progress.rb +46 -0
  30. data/lib/iactionable/settings.rb +30 -0
  31. data/lib/iactionable/version.rb +3 -0
  32. data/lib/ruby-iactionable.rb +9 -0
  33. data/ruby_iactionable.gemspec +28 -0
  34. data/spec/api/get_achievements_api_response_spec.rb +46 -0
  35. data/spec/api/get_challenges_api_response_spec.rb +42 -0
  36. data/spec/api/get_goals_api_response_spec.rb +46 -0
  37. data/spec/api/get_leaderboard_api_response_spec.rb +76 -0
  38. data/spec/api/get_profile_achievements_api_response_spec.rb +113 -0
  39. data/spec/api/get_profile_api_response_spec.rb +103 -0
  40. data/spec/api/get_profile_challenges_api_response_spec.rb +99 -0
  41. data/spec/api/get_profile_goals_api_response_spec.rb +103 -0
  42. data/spec/api/get_profile_notifications_api_response_spec.rb +75 -0
  43. data/spec/api/get_profile_points_api_response_spec.rb +67 -0
  44. data/spec/api_spec.rb +399 -0
  45. data/spec/connection_spec.rb +111 -0
  46. data/spec/settings_spec.rb +52 -0
  47. data/spec/spec_helper.rb +1 -0
  48. metadata +165 -0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ pkg/*
2
+ .bundle
3
+ .DS_Store
4
+ .rvmrc
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
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in ruby_iactionable.gemspec
4
+ gemspec
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