riaction 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +13 -13
- data/lib/riaction/riaction.rb +22 -2
- data/lib/riaction/version.rb +1 -1
- data/spec/riaction_spec.rb +36 -0
- metadata +16 -16
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Overview #
|
2
2
|
|
3
|
-
riaction provides both a ruby wrapper for IActionable's restful API and an "acts-as" style interface for
|
3
|
+
riaction provides both a ruby wrapper for IActionable's restful API and an "acts-as" style interface for the models in your Rails application. This document assumes knowledge of IActionable's API.
|
4
4
|
|
5
5
|
# How To Use #
|
6
6
|
|
@@ -17,7 +17,7 @@ The wrapper for IActionable's API is used internally by the rest of the gem, but
|
|
17
17
|
:version => 3 )
|
18
18
|
@api = IActionable::Api.new
|
19
19
|
|
20
|
-
IActionable's API speaks in JSON, and here those responses are wrapped in simple objects where nesting and variable names are determined by [IActionable's documentation](http://www.
|
20
|
+
IActionable's API speaks in JSON, and here those responses are wrapped in simple objects where nesting and variable names are determined by [IActionable's documentation](http://www.iactionable.com/api/). For example, here the wrapper is making a call to load a profile summary:
|
21
21
|
|
22
22
|
profile_summary = @api.get_profile_summary("user", "username", "zortnac", 10)
|
23
23
|
profile_summary.display_name # => "Chris Eberz"
|
@@ -51,11 +51,11 @@ Models in your application may declare themselves as profiles that exist on IAct
|
|
51
51
|
# id :integer(4)
|
52
52
|
# nickname :string(255)
|
53
53
|
|
54
|
-
Here, the class User declares itself as a profile of type "player", identifiable by two of IActionable's supported
|
54
|
+
Here, the class User declares itself as a profile of type "player", identifiable by two of IActionable's supported identifier types, username and custom. The values of these identifiers are the fields nickname and id, respectively, and can be any method that an instance of the class responds to. When a class declares itself as a riaction profile, an after_create callback will be added to create the profile on IActionable with the identifiers declared in the class.
|
55
55
|
|
56
56
|
#### Profile Instance Methods ####
|
57
57
|
|
58
|
-
Classes that declare themselves as IActionable profiles are given instance methods that tie in to the IActionable API, as many uses of the API
|
58
|
+
Classes that declare themselves as IActionable profiles are given instance methods that tie in to the IActionable API, as many uses of the API treat the profile as a top-level resource.
|
59
59
|
|
60
60
|
@api.get_profile_summary("player", "username", "zortnac", 10)
|
61
61
|
# is equivalent to the following...
|
@@ -71,14 +71,14 @@ Classes that declare themselves as IActionable profiles are given instance metho
|
|
71
71
|
|
72
72
|
### Declaring Events ###
|
73
73
|
|
74
|
-
Models in your application may declare any number of events that they log through IActionable. For each event that is declared the important elements are:
|
74
|
+
Models in your application may declare any number of events that they wish to log through IActionable. For each event that is declared the important elements are:
|
75
75
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
76
|
+
* The event's name (or key).
|
77
|
+
* The type of trigger that causes the event to be logged.
|
78
|
+
* The profile under which the event is logged.
|
79
|
+
* Any optional parameters (key-value pairs) that you want to pass.
|
80
80
|
|
81
|
-
|
81
|
+
<!-- end list -->
|
82
82
|
|
83
83
|
class Comment
|
84
84
|
belongs_to :user
|
@@ -99,17 +99,17 @@ Here, the name of the event is `make_a_comment`. The trigger for the event, in
|
|
99
99
|
|
100
100
|
_Note: If the trigger is one of :create, :update, or :destroy, then the appropriate ActiveRecord callback will log the event. If the trigger is anything else, then an instance method is provided to log the event by hand. For example, an argument of `:trigger => :foo` will provide an instance method `trigger_foo!`_
|
101
101
|
|
102
|
-
The profile that this event will be logged under can be any object whose class declares itself as a profile. Here, the profile is the object returned by the ActiveRecord association `:user
|
102
|
+
The profile that this event will be logged under can be any object whose class declares itself as a profile. Here, the profile is the object returned by the ActiveRecord association `:user` (for this example we assume this is an instance of the User class from above). Lastly, the optional params passed along with the event is the key-value pair `{:post => :post_id}`, where `:post_id` is an ActiveRecord table column.
|
103
103
|
|
104
104
|
Putting this all together, whenever an instance of the Comment class is created, an event is logged for which the equivalent call to the API might look like this:
|
105
105
|
|
106
106
|
@api.log_event("player", "username", "zortnac", "make_a_comment", {:post => 33})
|
107
107
|
|
108
|
-
_Note: If a class
|
108
|
+
_Note: If a class declares itself as a profile and also declares one or more events, but wants to refer to itself as the profile for any of those events, use `:profile => :self` in the event's declaration_
|
109
109
|
|
110
110
|
### Rails Rake Tasks ###
|
111
111
|
|
112
|
-
There are 3
|
112
|
+
There are 3 rake tasks included for summarizing all of your models' declarations as well as a way to initialize profiles on IActionable. To see a report of all the events declared across your application, run the following:
|
113
113
|
|
114
114
|
rake riaction:rails:list:events
|
115
115
|
|
data/lib/riaction/riaction.rb
CHANGED
@@ -19,10 +19,14 @@ module Riaction
|
|
19
19
|
Set.new [:create, :update, :destroy]
|
20
20
|
end
|
21
21
|
|
22
|
+
def self.retry_attempts_for_internal_error
|
23
|
+
3
|
24
|
+
end
|
25
|
+
|
22
26
|
class ProfileCreator
|
23
27
|
@queue = :riaction_profile_creator
|
24
28
|
|
25
|
-
def self.perform(klass_name, id)
|
29
|
+
def self.perform(klass_name, id, attempt=0)
|
26
30
|
if klass_name.constantize.riaction_profile?
|
27
31
|
iactionable_api = IActionable::Api.new
|
28
32
|
profile_object = klass_name.constantize.find_by_id!(id)
|
@@ -36,13 +40,21 @@ module Riaction
|
|
36
40
|
rescue IActionable::Error::BadRequest => e
|
37
41
|
# This should only be thrown if the profile type names specified in the model don't match what's on IActionable's dashboard
|
38
42
|
raise e
|
43
|
+
rescue IActionable::Error::Internal => e
|
44
|
+
# upon an intenal error from IActionable, retry some set number of times by requeueing the task through Resque
|
45
|
+
# after the max number of attempts, re-raise
|
46
|
+
if attempt < Riaction.retry_attempts_for_internal_error
|
47
|
+
Resque.enqueue(Riaction::ProfileCreator, klass_name, id, attempt+1)
|
48
|
+
else
|
49
|
+
raise e
|
50
|
+
end
|
39
51
|
end
|
40
52
|
end
|
41
53
|
|
42
54
|
class EventPerformer
|
43
55
|
@queue = :riaction_event_logger
|
44
56
|
|
45
|
-
def self.perform(event_name, klass_name, id)
|
57
|
+
def self.perform(event_name, klass_name, id, attempt=0)
|
46
58
|
iactionable_api = IActionable::Api.new
|
47
59
|
|
48
60
|
event_object = klass_name.constantize.find_by_id!(id)
|
@@ -66,6 +78,14 @@ module Riaction
|
|
66
78
|
# Log event should never throw this as of IActionable API v3
|
67
79
|
rescue NoMethodError => e
|
68
80
|
raise NoEventDefined.new
|
81
|
+
rescue IActionable::Error::Internal => e
|
82
|
+
# upon an intenal error from IActionable, retry some set number of times by requeueing the task through Resque
|
83
|
+
# after the max number of attempts, re-raise
|
84
|
+
if attempt < Riaction.retry_attempts_for_internal_error
|
85
|
+
Resque.enqueue(Riaction::EventPerformer, event_name, klass_name, id, attempt+1)
|
86
|
+
else
|
87
|
+
raise e
|
88
|
+
end
|
69
89
|
end
|
70
90
|
end
|
71
91
|
|
data/lib/riaction/version.rb
CHANGED
data/spec/riaction_spec.rb
CHANGED
@@ -86,6 +86,24 @@ describe Riaction do
|
|
86
86
|
lambda { Riaction::EventPerformer.perform(:create_profile, "BadClass", @bad_instance.id) }.should raise_error(Riaction::NoEventDefined)
|
87
87
|
end
|
88
88
|
end
|
89
|
+
|
90
|
+
describe "when the API raises an IActionable internal error" do
|
91
|
+
before do
|
92
|
+
@api.stub!(:get_profile_summary)
|
93
|
+
@api.stub!(:create_profile)
|
94
|
+
@api.stub!(:log_event).and_raise(IActionable::Error::Internal.new(nil))
|
95
|
+
Resque.stub!(:enqueue)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should re-schedule the task some defined number of times before re-raising again on the last attempt" do
|
99
|
+
Resque.should_receive(:enqueue).exactly(Riaction.retry_attempts_for_internal_error).times.with(Riaction::EventPerformer, :create_profile, "MyClass", @instance.id, instance_of(Fixnum))
|
100
|
+
|
101
|
+
(Riaction.retry_attempts_for_internal_error).times do |i|
|
102
|
+
lambda { Riaction::EventPerformer.perform(:create_profile, "MyClass", @bad_instance.id, i) }.should_not raise_error
|
103
|
+
end
|
104
|
+
lambda { Riaction::EventPerformer.perform(:create_profile, "MyClass", @bad_instance.id, Riaction.retry_attempts_for_internal_error) }.should raise_error(IActionable::Error::Internal)
|
105
|
+
end
|
106
|
+
end
|
89
107
|
end
|
90
108
|
|
91
109
|
describe "profile generation" do
|
@@ -119,6 +137,24 @@ describe Riaction do
|
|
119
137
|
lambda { Riaction::ProfileCreator.perform("BadClass", @instance.id) }.should raise_error(Riaction::NoProfileDefined)
|
120
138
|
end
|
121
139
|
end
|
140
|
+
|
141
|
+
describe "when the API raises an IActionable internal error" do
|
142
|
+
before do
|
143
|
+
@instance = MyClass.new
|
144
|
+
MyClass.stub!(:find_by_id!).and_return(@instance)
|
145
|
+
@api.stub!(:create_profile).and_raise(IActionable::Error::Internal.new(nil))
|
146
|
+
Resque.stub!(:enqueue)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should re-schedule the task some defined number of times before re-raising again on the last attempt" do
|
150
|
+
Resque.should_receive(:enqueue).exactly(Riaction.retry_attempts_for_internal_error).times.with(Riaction::ProfileCreator, "MyClass", @instance.id, instance_of(Fixnum))
|
151
|
+
|
152
|
+
(Riaction.retry_attempts_for_internal_error).times do |i|
|
153
|
+
lambda { Riaction::ProfileCreator.perform("MyClass", @instance.id, i) }.should_not raise_error
|
154
|
+
end
|
155
|
+
lambda { Riaction::ProfileCreator.perform("MyClass", @instance.id, Riaction.retry_attempts_for_internal_error) }.should raise_error(IActionable::Error::Internal)
|
156
|
+
end
|
157
|
+
end
|
122
158
|
end
|
123
159
|
|
124
160
|
describe "event triggering" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: riaction
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-11-
|
12
|
+
date: 2011-11-11 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &2156451960 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '2.6'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2156451960
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
requirement: &
|
27
|
+
requirement: &2156451540 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2156451540
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: faraday
|
38
|
-
requirement: &
|
38
|
+
requirement: &2156447860 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2156447860
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: faraday-stack
|
49
|
-
requirement: &
|
49
|
+
requirement: &2156447440 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2156447440
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: activemodel
|
60
|
-
requirement: &
|
60
|
+
requirement: &2156447000 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *2156447000
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: activerecord
|
71
|
-
requirement: &
|
71
|
+
requirement: &2156446380 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *2156446380
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: resque
|
82
|
-
requirement: &
|
82
|
+
requirement: &2156445720 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,7 +87,7 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :runtime
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *2156445720
|
91
91
|
description: Wrapper for IActionable's restful API and an "acts-as" style interface
|
92
92
|
for models to behave as profiles and drive game events.
|
93
93
|
email:
|