riaction 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG.md +7 -0
  3. data/Gemfile.lock +47 -26
  4. data/README.md +101 -52
  5. data/db/riaction.db +0 -0
  6. data/lib/riaction.rb +1 -1
  7. data/lib/riaction/constants.rb +10 -0
  8. data/lib/riaction/crud_event_callback.rb +3 -3
  9. data/lib/riaction/event_performer.rb +11 -16
  10. data/lib/riaction/profile_creation_callback.rb +1 -1
  11. data/lib/riaction/profile_creator.rb +13 -6
  12. data/lib/riaction/railtie.rb +4 -0
  13. data/lib/riaction/riaction.rb +302 -282
  14. data/lib/riaction/version.rb +1 -1
  15. data/lib/tasks/riaction.rake +16 -14
  16. data/riaction.gemspec +3 -2
  17. data/spec/event_performer_spec.rb +233 -0
  18. data/spec/profile_creation_spec.rb +135 -0
  19. data/spec/riaction_spec.rb +820 -253
  20. data/spec/spec_helper.rb +8 -1
  21. metadata +38 -71
  22. data/lib/riaction/iactionable/api.rb +0 -170
  23. data/lib/riaction/iactionable/connection.rb +0 -114
  24. data/lib/riaction/iactionable/error.rb +0 -17
  25. data/lib/riaction/iactionable/objects.rb +0 -27
  26. data/lib/riaction/iactionable/objects/achievement.rb +0 -29
  27. data/lib/riaction/iactionable/objects/awardable.rb +0 -50
  28. data/lib/riaction/iactionable/objects/challenge.rb +0 -27
  29. data/lib/riaction/iactionable/objects/goal.rb +0 -30
  30. data/lib/riaction/iactionable/objects/i_actionable_object.rb +0 -36
  31. data/lib/riaction/iactionable/objects/identifier.rb +0 -17
  32. data/lib/riaction/iactionable/objects/leaderboard.rb +0 -15
  33. data/lib/riaction/iactionable/objects/leaderboard_report.rb +0 -30
  34. data/lib/riaction/iactionable/objects/level.rb +0 -24
  35. data/lib/riaction/iactionable/objects/level_type.rb +0 -15
  36. data/lib/riaction/iactionable/objects/point_type.rb +0 -15
  37. data/lib/riaction/iactionable/objects/profile_achievements.rb +0 -20
  38. data/lib/riaction/iactionable/objects/profile_challenges.rb +0 -20
  39. data/lib/riaction/iactionable/objects/profile_goals.rb +0 -20
  40. data/lib/riaction/iactionable/objects/profile_level.rb +0 -20
  41. data/lib/riaction/iactionable/objects/profile_notifications.rb +0 -29
  42. data/lib/riaction/iactionable/objects/profile_points.rb +0 -29
  43. data/lib/riaction/iactionable/objects/profile_summary.rb +0 -37
  44. data/lib/riaction/iactionable/objects/progress.rb +0 -46
  45. data/lib/riaction/iactionable/settings.rb +0 -30
  46. data/spec/api_spec.rb +0 -314
  47. data/spec/connection_spec.rb +0 -111
  48. data/spec/get_achievements_api_response_spec.rb +0 -46
  49. data/spec/get_challenges_api_response_spec.rb +0 -42
  50. data/spec/get_goals_api_response_spec.rb +0 -46
  51. data/spec/get_leaderboard_api_response_spec.rb +0 -76
  52. data/spec/get_profile_achievements_api_response_spec.rb +0 -99
  53. data/spec/get_profile_api_response_spec.rb +0 -103
  54. data/spec/get_profile_challenges_api_response_spec.rb +0 -85
  55. data/spec/get_profile_goals_api_response_spec.rb +0 -89
  56. data/spec/get_profile_notifications_api_response_spec.rb +0 -75
  57. data/spec/get_profile_points_api_response_spec.rb +0 -67
  58. data/spec/settings_spec.rb +0 -52
@@ -1,3 +1,3 @@
1
1
  module Riaction
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
@@ -7,7 +7,7 @@ namespace 'riaction' do
7
7
  require rbfile
8
8
  end
9
9
 
10
- Riaction::Riaction::EVENT_LOGGING_CLASSES.each do |class_name|
10
+ Riaction::Riaction::EVENT_CLASSES.each do |class_name|
11
11
  klass = class_name.constantize
12
12
  puts "#{klass} defines the following events:"
13
13
  klass.riaction_events.each_pair do |name, deets|
@@ -17,6 +17,7 @@ namespace 'riaction' do
17
17
  else
18
18
  puts " Trigger: By calling :trigger_#{deets[:trigger]}!"
19
19
  end
20
+
20
21
  case deets[:profile]
21
22
  when Symbol
22
23
  if deets[:profile] == :self
@@ -27,6 +28,14 @@ namespace 'riaction' do
27
28
  when Proc
28
29
  puts " Profile: Returned via Proc"
29
30
  end
31
+
32
+ case deets[:profile_type]
33
+ when Symbol
34
+ puts " Profile Type: #{deets[:profile_type]}"
35
+ when NilClass
36
+ puts " Profile Type: uses default"
37
+ end
38
+
30
39
  case deets[:params]
31
40
  when NilClass
32
41
  puts " Event Params: None"
@@ -37,6 +46,7 @@ namespace 'riaction' do
37
46
  when Hash
38
47
  puts " Event Params: #{deets[:params]}"
39
48
  end
49
+
40
50
  case deets[:guard]
41
51
  when NilClass
42
52
  puts " Guard: None"
@@ -78,20 +88,12 @@ namespace 'riaction' do
78
88
 
79
89
  Riaction::Riaction::PROFILE_CLASSES.each do |class_name|
80
90
  klass = class_name.constantize
81
- begin
82
- klass.all.each do |obj|
83
- declaration = klass.riaction_profiles.first
84
- puts "Addressing #{klass} record #{obj.id}; creating profile under type '#{declaration[0]}'"
85
- obj.riaction_create_profile
86
- default_keys = obj.riaction_profile_keys(declaration[0])
87
- declaration[1].each_pair do |id_type, id|
88
- value = obj.send(id)
89
- puts "...updating profile with id type #{id_type} and value #{value}"
90
- obj.riaction_update_profile(id_type)
91
- end
91
+ if (klass.riactionary? && klass.riaction_profile? && klass.riaction_profile_types_defined > 0)
92
+ puts "Addressing #{class_name}: defines the profile(s) #{klass.riaction_profile_keys.keys.map(&:to_s).join(', ')}"
93
+ klass.select(:id).all.each do |obj|
94
+ puts " Addressing record ##{obj.id};"
95
+ ::Riaction::ProfileCreator.perform(class_name, obj.id)
92
96
  end
93
- rescue Riaction::NoProfileDefined => e
94
- puts "ERROR: #{klass} does not properly define a profile; skipping"
95
97
  end
96
98
  end
97
99
  end
data/riaction.gemspec CHANGED
@@ -20,11 +20,12 @@ Gem::Specification.new do |s|
20
20
 
21
21
 
22
22
  s.add_development_dependency "rspec", ">= 2.6"
23
+ s.add_development_dependency "sqlite3"
24
+ s.add_development_dependency "ruby-debug19"
23
25
 
24
26
  s.add_runtime_dependency "rake"
25
- s.add_runtime_dependency "faraday"
26
- s.add_runtime_dependency "faraday-stack"
27
27
  s.add_runtime_dependency "activerecord", ">= 3.0.0"
28
28
  s.add_runtime_dependency "activesupport", ">= 3.0.0"
29
29
  s.add_runtime_dependency "resque"
30
+ s.add_runtime_dependency "ruby-iactionable", ">= 0.0.2"
30
31
  end
@@ -0,0 +1,233 @@
1
+ require 'spec_helper.rb'
2
+
3
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'users'")
4
+ ActiveRecord::Base.connection.create_table(:users) do |t|
5
+ t.string :name
6
+ t.string :email
7
+ t.timestamps
8
+ end
9
+
10
+ class User < ActiveRecord::Base
11
+ extend Riaction::Riaction::ClassMethods
12
+
13
+ has_many :comments, :dependent => :destroy
14
+ end
15
+
16
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'comments'")
17
+ ActiveRecord::Base.connection.create_table(:comments) do |t|
18
+ t.belongs_to :user
19
+ t.string :content
20
+ end
21
+
22
+ class Comment < ActiveRecord::Base
23
+ extend Riaction::Riaction::ClassMethods
24
+
25
+ belongs_to :user
26
+ end
27
+
28
+ describe "sending an event to IActionable from the name of a riaction class and an ID to locate the instance" do
29
+ before do
30
+ ActiveRecord::Base.connection.increment_open_transactions
31
+ ActiveRecord::Base.connection.begin_db_transaction
32
+
33
+ @api = mock("mocked IActionable API")
34
+ IActionable::Api.stub!(:new).and_return(@api)
35
+ Resque.stub(:enqueue).and_return true
36
+
37
+ User.reset_riaction if User.riactionary?
38
+ Comment.reset_riaction if Comment.riactionary?
39
+
40
+ # multiple test runs are building up the callbacks
41
+ Comment.class_eval do
42
+ reset_callbacks :create
43
+ reset_callbacks :update
44
+ reset_callbacks :destroy
45
+ end
46
+ end
47
+
48
+ describe ::Riaction::EventPerformer do
49
+ before do
50
+ User.class_eval do
51
+ riaction :profile, :type => :player, :custom => :id
52
+ riaction :profile, :type => :npc, :username => :name, :custom => :id
53
+ end
54
+ @user = User.riactionless{ User.create(:name => 'zortnac') }
55
+ end
56
+
57
+ describe "and where an event is defined with parameters" do
58
+ before do
59
+ Comment.class_eval do
60
+ riaction :event, :name => :make_a_comment, :trigger => :create, :profile => :user, :profile_type => :npc, :params => {:foo => 'bar'}
61
+ end
62
+
63
+ @comment = Comment.riactionless{ Comment.create(:user_id => @user.id, :content => 'this is a comment') }
64
+ end
65
+
66
+ it "should create the event through the API wrapper with the correct parameters" do
67
+ @api.should_receive(:log_event).once.with(@comment.riaction_event_params[:make_a_comment][:profile][:type],
68
+ @comment.riaction_event_params[:make_a_comment][:profile][:id_type],
69
+ @comment.riaction_event_params[:make_a_comment][:profile][:id],
70
+ :make_a_comment,
71
+ @comment.riaction_event_params[:make_a_comment][:params])
72
+ ::Riaction::EventPerformer.perform(:make_a_comment, 'Comment', @comment.id)
73
+ end
74
+ end
75
+
76
+ describe "and where an event is defined without parameters" do
77
+ before do
78
+ Comment.class_eval do
79
+ riaction :event, :name => :make_a_comment, :trigger => :create, :profile => :user, :profile_type => :player
80
+ end
81
+
82
+ @comment = Comment.riactionless{ Comment.create(:user_id => @user.id, :content => 'this is a comment') }
83
+ end
84
+
85
+ it "should create the event through the API wrapper with no parameters" do
86
+ @api.should_receive(:log_event).once.with(@comment.riaction_event_params[:make_a_comment][:profile][:type],
87
+ @comment.riaction_event_params[:make_a_comment][:profile][:id_type],
88
+ @comment.riaction_event_params[:make_a_comment][:profile][:id],
89
+ :make_a_comment,
90
+ {})
91
+ ::Riaction::EventPerformer.perform(:make_a_comment, 'Comment', @comment.id)
92
+ end
93
+ end
94
+
95
+ describe "when fetching the event params raises a" do
96
+ before do
97
+ Comment.class_eval do
98
+ riaction :event, :name => :make_a_comment, :trigger => :create, :profile => :user, :profile_type => :npc, :params => {:foo => 'bar'}
99
+ end
100
+
101
+ @comment = Comment.riactionless{ Comment.create(:user_id => @user.id, :content => 'this is a comment') }
102
+ end
103
+
104
+ describe "RuntimeError" do
105
+ before do
106
+ @comment.stub!(:riaction_event_params).and_raise(::Riaction::RuntimeError)
107
+ Comment.stub!(:find_by_id!).and_return(@comment)
108
+ end
109
+
110
+ it "should not try to create the event" do
111
+ @api.should_not_receive(:log_event)
112
+ begin
113
+ ::Riaction::EventPerformer.perform(:make_a_comment, 'Comment', @comment.id)
114
+ rescue Exception => e
115
+ end
116
+ end
117
+
118
+ it "should raise a RuntimeError" do
119
+ lambda { ::Riaction::EventPerformer.perform(:make_a_comment, 'Comment', @comment.id) }.should raise_error(::Riaction::RuntimeError)
120
+ end
121
+ end
122
+
123
+ describe "ConfigurationError" do
124
+ before do
125
+ @comment.stub!(:riaction_event_params).and_raise(::Riaction::ConfigurationError)
126
+ Comment.stub!(:find_by_id!).and_return(@comment)
127
+ end
128
+
129
+ it "should not try to create the event" do
130
+ @api.should_not_receive(:log_event)
131
+ begin
132
+ ::Riaction::EventPerformer.perform(:make_a_comment, 'Comment', @comment.id)
133
+ rescue Exception => e
134
+ end
135
+ end
136
+
137
+ it "should raise a ConfigurationError" do
138
+ lambda { ::Riaction::EventPerformer.perform(:make_a_comment, 'Comment', @comment.id) }.should raise_error(::Riaction::ConfigurationError)
139
+ end
140
+ end
141
+ end
142
+
143
+ describe "when the class does not actually define any riaction events" do
144
+ before do
145
+ Comment.reset_riaction if Comment.riactionary?
146
+ # multiple test runs are building up the callbacks
147
+ Comment.class_eval do
148
+ reset_callbacks :create
149
+ reset_callbacks :update
150
+ reset_callbacks :destroy
151
+ end
152
+ @comment = Comment.create(:user_id => @user.id, :content => 'this is a comment')
153
+ end
154
+
155
+ it "should not try to create the event" do
156
+ @api.should_not_receive(:log_event)
157
+ begin
158
+ ::Riaction::EventPerformer.perform(:make_a_comment, 'Comment', @comment.id)
159
+ rescue Exception => e
160
+ end
161
+ end
162
+
163
+ it "should raise a ConfigurationError" do
164
+ lambda { ::Riaction::EventPerformer.perform(:make_a_comment, 'Comment', @comment.id) }.should raise_error(::Riaction::ConfigurationError)
165
+ end
166
+ end
167
+
168
+ describe "when the class does not actually define the event specified" do
169
+ before do
170
+ Comment.class_eval do
171
+ riaction :event, :name => :make_a_comment, :trigger => :create, :profile => :user, :profile_type => :npc, :params => {:foo => 'bar'}
172
+ end
173
+
174
+ @comment = Comment.riactionless{ Comment.create(:user_id => @user.id, :content => 'this is a comment') }
175
+ end
176
+
177
+ it "should not try to create the event" do
178
+ @api.should_not_receive(:log_event)
179
+ begin
180
+ ::Riaction::EventPerformer.perform(:bogus, 'Comment', @comment.id)
181
+ rescue Exception => e
182
+ end
183
+ end
184
+
185
+ it "should raise a ConfigurationError" do
186
+ lambda { ::Riaction::EventPerformer.perform(:bogus, 'Comment', @comment.id) }.should raise_error(::Riaction::ConfigurationError)
187
+ end
188
+ end
189
+
190
+ describe "when the object specified is missing" do
191
+ before do
192
+ Comment.class_eval do
193
+ riaction :event, :name => :make_a_comment, :trigger => :create, :profile => :user, :profile_type => :npc, :params => {:foo => 'bar'}
194
+ end
195
+
196
+ @comment = Comment.riactionless{ Comment.create(:user_id => @user.id, :content => 'this is a comment') }
197
+ @comment.destroy
198
+ end
199
+
200
+ it "should not try to create the event" do
201
+ @api.should_not_receive(:log_event)
202
+ begin
203
+ ::Riaction::EventPerformer.perform(:make_a_comment, 'Comment', @comment.id)
204
+ rescue Exception => e
205
+ end
206
+ end
207
+
208
+ it "should not raise an error" do
209
+ lambda { ::Riaction::EventPerformer.perform(:make_a_comment, 'Comment', @comment.id) }.should_not raise_error
210
+ end
211
+ end
212
+
213
+ describe "when the call to IActionable, through API wrapper, fails" do
214
+ before do
215
+ @api.stub!(:log_event).and_raise(IActionable::Error::Internal.new(""))
216
+ Comment.class_eval do
217
+ riaction :event, :name => :make_a_comment, :trigger => :create, :profile => :user, :profile_type => :npc, :params => {:foo => 'bar'}
218
+ end
219
+ @comment = Comment.riactionless{ Comment.create(:user_id => @user.id, :content => 'this is a comment') }
220
+ end
221
+
222
+ it "should re-enqueue the job with an attempt count" do
223
+ Resque.should_receive(:enqueue).once.with(Riaction::EventPerformer, :make_a_comment, 'Comment', @comment.id, 1)
224
+ ::Riaction::EventPerformer.perform(:make_a_comment, 'Comment', @comment.id)
225
+ end
226
+ end
227
+ end
228
+
229
+ after do
230
+ ActiveRecord::Base.connection.rollback_db_transaction
231
+ ActiveRecord::Base.connection.decrement_open_transactions
232
+ end
233
+ end
@@ -0,0 +1,135 @@
1
+ require "spec_helper.rb"
2
+
3
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'users'")
4
+ ActiveRecord::Base.connection.create_table(:users) do |t|
5
+ t.string :name
6
+ t.string :email
7
+ t.timestamps
8
+ end
9
+
10
+ class User < ActiveRecord::Base
11
+ extend Riaction::Riaction::ClassMethods
12
+
13
+ has_many :comments, :dependent => :destroy
14
+ end
15
+
16
+ describe "automatic profile creation from riaction definitions:" do
17
+ before do
18
+ ActiveRecord::Base.connection.increment_open_transactions
19
+ ActiveRecord::Base.connection.begin_db_transaction
20
+
21
+ @api = mock("mocked IActionable API")
22
+ IActionable::Api.stub!(:new).and_return(@api)
23
+ Resque.stub(:enqueue).and_return true
24
+
25
+ User.reset_riaction if User.riactionary?
26
+ end
27
+
28
+ describe ::Riaction::ProfileCreator do
29
+ describe "when a class declares a single profile type with a single identifer" do
30
+ before do
31
+ User.class_eval do
32
+ riaction :profile, :type => :player, :custom => :id
33
+ end
34
+ @user = User.riactionless{ User.create(:name => 'zortnac') }
35
+ end
36
+
37
+ it "should use the API wraper to create the profile with that identifer" do
38
+ @api.should_receive(:create_profile).once.with('player', 'custom', @user.id.to_s, nil)
39
+ ::Riaction::ProfileCreator.perform('User', @user.id)
40
+ end
41
+ end
42
+
43
+ describe "when a class declares a single profile type with multiple identifers" do
44
+ before do
45
+ User.class_eval do
46
+ riaction :profile, :type => :player, :custom => :id, :username => :name
47
+ end
48
+ @user = User.riactionless{ User.create(:name => 'zortnac') }
49
+ end
50
+
51
+ it "should use the API wrapper to create the profile with the first identifer given, then make additional calls to the API to add the extra identifiers" do
52
+ @api.should_receive(:create_profile).once.ordered.with('player', 'custom', @user.id.to_s, nil)
53
+ @api.should_receive(:add_profile_identifier).once.ordered.with('player', 'custom', @user.id.to_s, 'username', @user.name)
54
+ ::Riaction::ProfileCreator.perform('User', @user.id)
55
+ end
56
+ end
57
+
58
+ describe "when a class declares multiple profile types, each with a different number of identifers" do
59
+ before do
60
+ User.class_eval do
61
+ riaction :profile, :type => :player, :custom => :id
62
+ riaction :profile, :type => :npc, :custom => :id, :username => :name
63
+ end
64
+ @user = User.riactionless{ User.create(:name => 'zortnac') }
65
+ end
66
+
67
+ it "should use the API wrapper to create a profile for each type defined, each followed by the correct API calls for the extra identifiers" do
68
+ @api.should_receive(:create_profile).once.ordered.with('player', 'custom', @user.id.to_s, nil)
69
+ @api.should_receive(:create_profile).once.ordered.with('npc', 'custom', @user.id.to_s, nil)
70
+ @api.should_receive(:add_profile_identifier).once.ordered.with('npc', 'custom', @user.id.to_s, 'username', @user.name)
71
+ ::Riaction::ProfileCreator.perform('User', @user.id)
72
+ end
73
+ end
74
+
75
+ describe "when a class declares an optional display name" do
76
+ describe "as a method" do
77
+ before do
78
+ User.class_eval do
79
+ riaction :profile, :type => :player, :custom => :id, :display_name => :name
80
+ end
81
+ @user = User.riactionless{ User.create(:name => 'zortnac') }
82
+ end
83
+
84
+ it "should use the API wraper to create the profile with that display name" do
85
+ @api.should_receive(:create_profile).once.with('player', 'custom', @user.id.to_s, @user.name)
86
+ ::Riaction::ProfileCreator.perform('User', @user.id)
87
+ end
88
+ end
89
+
90
+ describe "as a proc" do
91
+ before do
92
+ User.class_eval do
93
+ riaction :profile, :type => :player, :custom => :id, :display_name => Proc.new{|record| record.name}
94
+ end
95
+ @user = User.riactionless{ User.create(:name => 'zortnac') }
96
+ end
97
+
98
+ it "should use the API wraper to create the profile with that display name" do
99
+ @api.should_receive(:create_profile).once.with('player', 'custom', @user.id.to_s, @user.name)
100
+ ::Riaction::ProfileCreator.perform('User', @user.id)
101
+ end
102
+ end
103
+ end
104
+
105
+ describe "when the class does not actually define itself as a riaction profile" do
106
+ before do
107
+ @user = User.create(:name => 'zortnac')
108
+ end
109
+
110
+ it "should raise a Riaction runtime error" do
111
+ lambda {::Riaction::ProfileCreator.perform('User', @user.id)}.should raise_error(::Riaction::RuntimeError)
112
+ end
113
+ end
114
+
115
+ describe "when the call to IActionable, through API wrapper, fails" do
116
+ before do
117
+ @api.stub!(:create_profile).and_raise(IActionable::Error::Internal.new(""))
118
+ User.class_eval do
119
+ riaction :profile, :type => :player, :custom => :id, :username => :name
120
+ end
121
+ @user = User.riactionless{ User.create(:name => 'zortnac') }
122
+ end
123
+
124
+ it "should re-enqueue the job with an attempt count" do
125
+ Resque.should_receive(:enqueue).once.with(Riaction::ProfileCreator, "User", @user.id, 1)
126
+ ::Riaction::ProfileCreator.perform('User', @user.id, 0)
127
+ end
128
+ end
129
+ end
130
+
131
+ after do
132
+ ActiveRecord::Base.connection.rollback_db_transaction
133
+ ActiveRecord::Base.connection.decrement_open_transactions
134
+ end
135
+ end