reactor 0.13.0 → 0.14.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +102 -17
  3. data/lib/reactor/controllers/concerns/actions/action_event.rb +11 -7
  4. data/lib/reactor/controllers/concerns/actions/create_event.rb +16 -12
  5. data/lib/reactor/controllers/concerns/actions/destroy_event.rb +8 -4
  6. data/lib/reactor/controllers/concerns/actions/edit_event.rb +8 -4
  7. data/lib/reactor/controllers/concerns/actions/index_event.rb +8 -4
  8. data/lib/reactor/controllers/concerns/actions/new_event.rb +8 -4
  9. data/lib/reactor/controllers/concerns/actions/show_event.rb +7 -3
  10. data/lib/reactor/controllers/concerns/actions/update_event.rb +16 -12
  11. data/lib/reactor/controllers/concerns/resource_actionable.rb +33 -31
  12. data/lib/reactor/controllers.rb +2 -0
  13. data/lib/reactor/errors.rb +7 -0
  14. data/lib/reactor/event.rb +2 -2
  15. data/lib/reactor/models/concerns/subscribable.rb +32 -79
  16. data/lib/reactor/models/subscriber.rb +21 -19
  17. data/lib/reactor/models.rb +5 -0
  18. data/lib/reactor/static_subscribers.rb +7 -0
  19. data/lib/reactor/subscription.rb +100 -0
  20. data/lib/reactor/testing.rb +50 -0
  21. data/lib/reactor/version.rb +1 -1
  22. data/lib/reactor/workers/database_subscriber_worker.rb +22 -0
  23. data/lib/reactor/workers/event_worker.rb +65 -0
  24. data/lib/reactor/workers/mailer_worker.rb +80 -0
  25. data/lib/reactor/workers.rb +8 -0
  26. data/lib/reactor.rb +24 -34
  27. data/reactor.gemspec +5 -1
  28. data/spec/event_spec.rb +10 -2
  29. data/spec/models/concerns/publishable_spec.rb +47 -38
  30. data/spec/models/concerns/subscribable_spec.rb +61 -5
  31. data/spec/models/subscriber_spec.rb +9 -2
  32. data/spec/reactor_spec.rb +2 -0
  33. data/spec/spec_helper.rb +19 -3
  34. data/spec/subscription_spec.rb +55 -0
  35. data/spec/support/active_record.rb +10 -0
  36. data/spec/workers/database_subscriber_worker_spec.rb +67 -0
  37. data/spec/workers/event_worker_spec.rb +126 -0
  38. data/spec/workers/mailer_worker_spec.rb +49 -0
  39. metadata +37 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c6dee2f6b8acebcf4c7d68e0fc81397a04902535
4
- data.tar.gz: e5ec764bc828e954889aca4cb8c53ff378a04a46
3
+ metadata.gz: e406cf4fa1d19fae39e7bfc19d2088d8e3975bda
4
+ data.tar.gz: 0ea82c5d9076c52f985ea09df8f4acade6b23f57
5
5
  SHA512:
6
- metadata.gz: ec7723313e82c0ce3c745e778b36c985ee0d9d4f81e8e39ee5464cc7accf865bbedbfc5d35374850b8bc599d53075f5ccab99ff168c50c0bb198e0086ced227b
7
- data.tar.gz: fdf059680229b3521218b72ae4f88d26fb04aee49659da3780c050db455ca0ea28197334279a47cf2d921ffa1ab400fc4d0eab6b7ca6612c5000dea938890d25
6
+ metadata.gz: a9cbffeb2aef6cf566d8721bbf556cf6d404e791a8e0572f610d60613b8e4881f5bd51e7ff7aef13343c14a0756399f2bbae31d7cad11356abaf99c3c1a3fde8
7
+ data.tar.gz: b9d02b1842161c50f6c084a1777cd2117469fef70a4bd926fdb7e8fcaee76d3a1e99fee11e0040d93184256293bf402709fe239f8f456494f0919137502cb1ed
data/Gemfile.lock CHANGED
@@ -1,33 +1,76 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- reactor (0.13.0)
5
- activerecord (~> 5.0.1)
4
+ reactor (0.14.0)
5
+ rails (~> 5.0.2)
6
6
  sidekiq
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activemodel (5.0.1)
12
- activesupport (= 5.0.1)
13
- activerecord (5.0.1)
14
- activemodel (= 5.0.1)
15
- activesupport (= 5.0.1)
11
+ actioncable (5.0.2)
12
+ actionpack (= 5.0.2)
13
+ nio4r (>= 1.2, < 3.0)
14
+ websocket-driver (~> 0.6.1)
15
+ actionmailer (5.0.2)
16
+ actionpack (= 5.0.2)
17
+ actionview (= 5.0.2)
18
+ activejob (= 5.0.2)
19
+ mail (~> 2.5, >= 2.5.4)
20
+ rails-dom-testing (~> 2.0)
21
+ actionpack (5.0.2)
22
+ actionview (= 5.0.2)
23
+ activesupport (= 5.0.2)
24
+ rack (~> 2.0)
25
+ rack-test (~> 0.6.3)
26
+ rails-dom-testing (~> 2.0)
27
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
28
+ actionview (5.0.2)
29
+ activesupport (= 5.0.2)
30
+ builder (~> 3.1)
31
+ erubis (~> 2.7.0)
32
+ rails-dom-testing (~> 2.0)
33
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
34
+ activejob (5.0.2)
35
+ activesupport (= 5.0.2)
36
+ globalid (>= 0.3.6)
37
+ activemodel (5.0.2)
38
+ activesupport (= 5.0.2)
39
+ activerecord (5.0.2)
40
+ activemodel (= 5.0.2)
41
+ activesupport (= 5.0.2)
16
42
  arel (~> 7.0)
17
- activesupport (5.0.1)
43
+ activesupport (5.0.2)
18
44
  concurrent-ruby (~> 1.0, >= 1.0.2)
19
45
  i18n (~> 0.7)
20
46
  minitest (~> 5.1)
21
47
  tzinfo (~> 1.1)
22
48
  arel (7.1.4)
49
+ builder (3.2.3)
23
50
  byebug (9.0.6)
24
51
  coderay (1.1.1)
25
- concurrent-ruby (1.0.4)
52
+ concurrent-ruby (1.0.5)
26
53
  connection_pool (2.2.1)
27
54
  diff-lcs (1.3)
28
- i18n (0.7.0)
55
+ docile (1.1.5)
56
+ erubis (2.7.0)
57
+ globalid (0.4.0)
58
+ activesupport (>= 4.2.0)
59
+ i18n (0.8.1)
60
+ json (2.0.3)
61
+ loofah (2.0.3)
62
+ nokogiri (>= 1.5.9)
63
+ mail (2.6.5)
64
+ mime-types (>= 1.16, < 4)
29
65
  method_source (0.8.2)
66
+ mime-types (3.1)
67
+ mime-types-data (~> 3.2015)
68
+ mime-types-data (3.2016.0521)
69
+ mini_portile2 (2.1.0)
30
70
  minitest (5.10.1)
71
+ nio4r (2.0.0)
72
+ nokogiri (1.7.2)
73
+ mini_portile2 (~> 2.1.0)
31
74
  pry (0.10.4)
32
75
  coderay (~> 1.1.0)
33
76
  method_source (~> 0.8.1)
@@ -35,11 +78,36 @@ GEM
35
78
  pry-byebug (3.4.2)
36
79
  byebug (~> 9.0)
37
80
  pry (~> 0.10)
38
- rack (2.0.1)
39
- rack-protection (1.5.3)
81
+ rack (2.0.3)
82
+ rack-protection (2.0.0)
40
83
  rack
84
+ rack-test (0.6.3)
85
+ rack (>= 1.0)
86
+ rails (5.0.2)
87
+ actioncable (= 5.0.2)
88
+ actionmailer (= 5.0.2)
89
+ actionpack (= 5.0.2)
90
+ actionview (= 5.0.2)
91
+ activejob (= 5.0.2)
92
+ activemodel (= 5.0.2)
93
+ activerecord (= 5.0.2)
94
+ activesupport (= 5.0.2)
95
+ bundler (>= 1.3.0, < 2.0)
96
+ railties (= 5.0.2)
97
+ sprockets-rails (>= 2.0.0)
98
+ rails-dom-testing (2.0.3)
99
+ activesupport (>= 4.2.0)
100
+ nokogiri (>= 1.6)
101
+ rails-html-sanitizer (1.0.3)
102
+ loofah (~> 2.0)
103
+ railties (5.0.2)
104
+ actionpack (= 5.0.2)
105
+ activesupport (= 5.0.2)
106
+ method_source
107
+ rake (>= 0.8.7)
108
+ thor (>= 0.18.1, < 2.0)
41
109
  rake (12.0.0)
42
- redis (3.3.2)
110
+ redis (3.3.3)
43
111
  rspec (3.5.0)
44
112
  rspec-core (~> 3.5.0)
45
113
  rspec-expectations (~> 3.5.0)
@@ -56,18 +124,34 @@ GEM
56
124
  diff-lcs (>= 1.2.0, < 2.0)
57
125
  rspec-support (~> 3.5.0)
58
126
  rspec-support (3.5.0)
59
- sidekiq (4.2.9)
127
+ sidekiq (4.2.10)
60
128
  concurrent-ruby (~> 1.0)
61
129
  connection_pool (~> 2.2, >= 2.2.0)
62
130
  rack-protection (>= 1.5.0)
63
131
  redis (~> 3.2, >= 3.2.1)
132
+ simplecov (0.12.0)
133
+ docile (~> 1.1.0)
134
+ json (>= 1.8, < 3)
135
+ simplecov-html (~> 0.10.0)
136
+ simplecov-html (0.10.0)
64
137
  slop (3.6.0)
138
+ sprockets (3.7.1)
139
+ concurrent-ruby (~> 1.0)
140
+ rack (> 1, < 3)
141
+ sprockets-rails (3.2.0)
142
+ actionpack (>= 4.0)
143
+ activesupport (>= 4.0)
144
+ sprockets (>= 3.0.0)
65
145
  sqlite3 (1.3.13)
66
146
  test_after_commit (1.1.0)
67
147
  activerecord (>= 3.2)
68
- thread_safe (0.3.5)
69
- tzinfo (1.2.2)
148
+ thor (0.19.4)
149
+ thread_safe (0.3.6)
150
+ tzinfo (1.2.3)
70
151
  thread_safe (~> 0.1)
152
+ websocket-driver (0.6.5)
153
+ websocket-extensions (>= 0.1.0)
154
+ websocket-extensions (0.1.2)
71
155
 
72
156
  PLATFORMS
73
157
  ruby
@@ -80,8 +164,9 @@ DEPENDENCIES
80
164
  reactor!
81
165
  rspec
82
166
  rspec-its
167
+ simplecov
83
168
  sqlite3
84
169
  test_after_commit
85
170
 
86
171
  BUNDLED WITH
87
- 1.13.6
172
+ 1.14.6
@@ -1,9 +1,13 @@
1
- class Reactor::ResourceActionable::ActionEvent
2
- def self.perform(&block)
3
- @perform_block = block
4
- end
1
+ module Reactor
2
+ module ResourceActionable
3
+ class ActionEvent
4
+ def self.perform(&block)
5
+ @perform_block = block
6
+ end
5
7
 
6
- def self.perform_on(ctx)
7
- ctx.instance_exec(&@perform_block)
8
+ def self.perform_on(ctx)
9
+ ctx.instance_exec(&@perform_block)
10
+ end
11
+ end
8
12
  end
9
- end
13
+ end
@@ -1,14 +1,18 @@
1
- class Reactor::ResourceActionable::CreateEvent < Reactor::ResourceActionable::ActionEvent
2
- perform do
3
- if actionable_resource.valid?
4
- action_event "#{resource_name}_created",
5
- target: actionable_resource,
6
- attributes: params[resource_name]
7
- else
8
- action_event "#{resource_name}_create_failed",
9
- errors: actionable_resource.errors.as_json,
10
- attributes: params[resource_name],
11
- target: nested_resource
1
+ module Reactor
2
+ module ResourceActionable
3
+ class CreateEvent < ActionEvent
4
+ perform do
5
+ if actionable_resource.valid?
6
+ action_event "#{resource_name}_created",
7
+ target: actionable_resource,
8
+ attributes: params[resource_name]
9
+ else
10
+ action_event "#{resource_name}_create_failed",
11
+ errors: actionable_resource.errors.as_json,
12
+ attributes: params[resource_name],
13
+ target: nested_resource
14
+ end
15
+ end
12
16
  end
13
17
  end
14
- end
18
+ end
@@ -1,5 +1,9 @@
1
- class Reactor::ResourceActionable::DestroyEvent < Reactor::ResourceActionable::ActionEvent
2
- perform do
3
- action_event "#{resource_name}_destroyed", last_snapshot: actionable_resource.as_json
1
+ module Reactor
2
+ module ResourceActionable
3
+ class DestroyEvent < ActionEvent
4
+ perform do
5
+ action_event "#{resource_name}_destroyed", last_snapshot: actionable_resource.as_json
6
+ end
7
+ end
4
8
  end
5
- end
9
+ end
@@ -1,5 +1,9 @@
1
- class Reactor::ResourceActionable::EditEvent < Reactor::ResourceActionable::ActionEvent
2
- perform do
3
- action_event "edit_#{resource_name}_form_viewed", target: actionable_resource
1
+ module Reactor
2
+ module ResourceActionable
3
+ class EditEvent < ActionEvent
4
+ perform do
5
+ action_event "edit_#{resource_name}_form_viewed", target: actionable_resource
6
+ end
7
+ end
4
8
  end
5
- end
9
+ end
@@ -1,5 +1,9 @@
1
- class Reactor::ResourceActionable::IndexEvent < Reactor::ResourceActionable::ActionEvent
2
- perform do
3
- action_event "#{resource_name.pluralize}_indexed", target: nested_resource
1
+ module Reactor
2
+ module ResourceActionable
3
+ class IndexEvent < ActionEvent
4
+ perform do
5
+ action_event "#{resource_name.pluralize}_indexed", target: nested_resource
6
+ end
7
+ end
4
8
  end
5
- end
9
+ end
@@ -1,5 +1,9 @@
1
- class Reactor::ResourceActionable::NewEvent < Reactor::ResourceActionable::ActionEvent
2
- perform do
3
- action_event "new_#{resource_name}_form_viewed", target: nested_resource
1
+ module Reactor
2
+ module ResourceActionable
3
+ class NewEvent < ActionEvent
4
+ perform do
5
+ action_event "new_#{resource_name}_form_viewed", target: nested_resource
6
+ end
7
+ end
4
8
  end
5
- end
9
+ end
@@ -1,5 +1,9 @@
1
- class Reactor::ResourceActionable::ShowEvent < Reactor::ResourceActionable::ActionEvent
2
- perform do
3
- action_event "#{resource_name}_viewed", target: actionable_resource
1
+ module Reactor
2
+ module ResourceActionable
3
+ class ShowEvent < ActionEvent
4
+ perform do
5
+ action_event "#{resource_name}_viewed", target: actionable_resource
6
+ end
7
+ end
4
8
  end
5
9
  end
@@ -1,14 +1,18 @@
1
- class Reactor::ResourceActionable::UpdateEvent < Reactor::ResourceActionable::ActionEvent
2
- perform do
3
- if actionable_resource.valid?
4
- action_event "#{resource_name}_updated",
5
- target: actionable_resource,
6
- changes: actionable_resource.previous_changes.as_json
7
- else
8
- action_event "#{resource_name}_update_failed",
9
- target: actionable_resource,
10
- errors: actionable_resource.errors.as_json,
11
- attributes: params[resource_name]
1
+ module Reactor
2
+ module ResourceActionable
3
+ class UpdateEvent < ActionEvent
4
+ perform do
5
+ if actionable_resource.valid?
6
+ action_event "#{resource_name}_updated",
7
+ target: actionable_resource,
8
+ changes: actionable_resource.previous_changes.as_json
9
+ else
10
+ action_event "#{resource_name}_update_failed",
11
+ target: actionable_resource,
12
+ errors: actionable_resource.errors.as_json,
13
+ attributes: params[resource_name]
14
+ end
15
+ end
12
16
  end
13
17
  end
14
- end
18
+ end
@@ -1,45 +1,47 @@
1
- module Reactor::ResourceActionable
2
- extend ActiveSupport::Concern
1
+ module Reactor
2
+ module ResourceActionable
3
+ extend ActiveSupport::Concern
3
4
 
4
- included do
5
- around_filter :infer_basic_action_event
6
- end
5
+ included do
6
+ around_filter :infer_basic_action_event
7
+ end
7
8
 
8
- def infer_basic_action_event
9
- yield if block_given?
9
+ def infer_basic_action_event
10
+ yield if block_given?
10
11
 
11
- if (event_descriptor = "Reactor::ResourceActionable::#{action_name.camelize}Event".safe_constantize).present?
12
- event_descriptor.perform_on self
13
- else
14
- action_event "#{resource_name}_#{action_name}"
12
+ if (event_descriptor = "Reactor::ResourceActionable::#{action_name.camelize}Event".safe_constantize).present?
13
+ event_descriptor.perform_on self
14
+ else
15
+ action_event "#{resource_name}_#{action_name}"
16
+ end
15
17
  end
16
- end
17
18
 
18
- module ClassMethods
19
- def actionable_resource(ivar_name = nil)
20
- @resource_ivar_name ||= ivar_name
21
- end
19
+ module ClassMethods
20
+ def actionable_resource(ivar_name = nil)
21
+ @resource_ivar_name ||= ivar_name
22
+ end
22
23
 
23
- def nested_resource(ivar_name = nil)
24
- @nested_resource_ivar_name ||= ivar_name
25
- end
24
+ def nested_resource(ivar_name = nil)
25
+ @nested_resource_ivar_name ||= ivar_name
26
+ end
26
27
 
27
- # this is so our API controller subclasses can re-use the resource declarations
28
- def inherited(subclass)
29
- [:resource_ivar_name, :nested_resource_ivar_name].each do |inheritable_attribute|
30
- instance_var = "@#{inheritable_attribute}"
31
- subclass.instance_variable_set(instance_var, instance_variable_get(instance_var))
28
+ # this is so our API controller subclasses can re-use the resource declarations
29
+ def inherited(subclass)
30
+ [:resource_ivar_name, :nested_resource_ivar_name].each do |inheritable_attribute|
31
+ instance_var = "@#{inheritable_attribute}"
32
+ subclass.instance_variable_set(instance_var, instance_variable_get(instance_var))
33
+ end
32
34
  end
33
35
  end
34
- end
35
36
 
36
- def actionable_resource; instance_variable_get(self.class.actionable_resource); end
37
- def nested_resource; self.class.nested_resource && instance_variable_get(self.class.nested_resource); end
37
+ def actionable_resource; instance_variable_get(self.class.actionable_resource); end
38
+ def nested_resource; self.class.nested_resource && instance_variable_get(self.class.nested_resource); end
38
39
 
39
- private
40
+ private
40
41
 
41
- def resource_name
42
- self.class.actionable_resource.to_s.gsub('@','').underscore
42
+ def resource_name
43
+ self.class.actionable_resource.to_s.gsub('@','').underscore
44
+ end
43
45
  end
44
46
  end
45
47
 
@@ -50,4 +52,4 @@ require "reactor/controllers/concerns/actions/edit_event"
50
52
  require "reactor/controllers/concerns/actions/create_event"
51
53
  require "reactor/controllers/concerns/actions/update_event"
52
54
  require "reactor/controllers/concerns/actions/destroy_event"
53
- require "reactor/controllers/concerns/actions/show_event"
55
+ require "reactor/controllers/concerns/actions/show_event"
@@ -0,0 +1,2 @@
1
+ # FIXME - these are not properly namespaced. The directories mean nothing
2
+ require "reactor/controllers/concerns/resource_actionable"
@@ -0,0 +1,7 @@
1
+ module Reactor
2
+
3
+ class UnconfiguredWorkerError < StandardError ; end
4
+ class EventHandlerAlreadyDefined < StandardError ; end
5
+ class UndeliverableMailError < StandardError ; end
6
+
7
+ end
data/lib/reactor/event.rb CHANGED
@@ -117,8 +117,8 @@ class Reactor::Event
117
117
 
118
118
  def fire_database_driven_subscribers(data, name)
119
119
  #TODO: support more matching?
120
- Reactor::Subscriber.where(event_name: [name, '*']).each do |subscriber|
121
- Reactor::Subscriber.delay.fire subscriber.id, data
120
+ Reactor::Subscriber.where(event_name: [name, '*']).pluck(:id).each do |model_id|
121
+ Reactor::Workers::DatabaseSubscriberWorker.perform_async model_id, data
122
122
  end
123
123
  end
124
124
 
@@ -1,94 +1,47 @@
1
- module Reactor::Subscribable
2
- extend ActiveSupport::Concern
3
-
4
- class EventHandlerAlreadyDefined < StandardError ; end
5
-
6
- module ClassMethods
7
-
8
- def on_event(*args, &block)
9
- options = args.extract_options!
10
- event, method = args
11
- if subscriber = create_static_subscriber(event, method, options, &block)
12
- (Reactor::SUBSCRIBERS[event.to_s] ||= []).push(subscriber)
1
+ module Reactor
2
+ module Subscribable
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ def on_event(*args, &block)
8
+ options = args.extract_options!
9
+ options[:event_name], options[:action] = args
10
+ options[:action] ||= block
11
+ options[:source] = self
12
+ add_subscription(options)
13
13
  end
14
- end
15
14
 
16
- private
15
+ private
17
16
 
18
- def create_static_subscriber(event, method = nil, options = {}, &block)
19
- worker_class = build_worker_class
20
- handler_name = handler_name(event, options[:handler_name])
21
- check_for_duplicate_handler_name(handler_name)
17
+ def add_subscription(options = {})
18
+ event_name = options[:event_name]
19
+ check_for_duplicate_subscription!(event_name, options[:handler_name_option])
20
+ subscription = Subscription.new(options)
22
21
 
23
- # return if the handler has already been defined (in the case of the class being reloaded)
24
- return if static_subscriber_namespace.const_defined?(handler_name)
25
- name_worker_class worker_class, handler_name
22
+ handler_names << subscription
23
+ handler_names.uniq!
26
24
 
27
- worker_class.tap do |k|
28
- k.source = self
29
- k.method = method || block
30
- k.delay = options[:delay] || 0
31
- k.in_memory = options[:in_memory]
32
- k.dont_perform = Reactor.test_mode?
25
+ Reactor.add_subscriber(event_name, subscription.worker_class)
33
26
  end
34
- end
35
-
36
- def handler_name(event, handler_name_option = nil)
37
- return handler_name_option.to_s.camelize if handler_name_option
38
- "#{event == '*' ? 'Wildcard': event.to_s.camelize}Handler"
39
- end
40
-
41
- def event_handler_names
42
- @event_handler_names ||= []
43
- end
44
-
45
- def build_worker_class
46
- Class.new do
47
- include Sidekiq::Worker
48
27
 
49
- class_attribute :method, :delay, :source, :in_memory, :dont_perform
50
-
51
- def perform(data)
52
- return :__perform_aborted__ if dont_perform && !Reactor::TEST_MODE_SUBSCRIBERS.include?(source)
53
- event = Reactor::Event.new(data)
54
- if method.is_a?(Symbol)
55
- source.delay_for(delay).send(method, event)
56
- else
57
- method.call(event)
58
- end
59
- end
60
-
61
- def self.perform_where_needed(data)
62
- if in_memory
63
- new.perform(data)
64
- else
65
- perform_async(data)
66
- end
67
- end
28
+ def handler_names
29
+ @handler_names ||= []
68
30
  end
69
- end
70
31
 
71
- def check_for_duplicate_handler_name(handler_name)
72
- if event_handler_names.include?(handler_name)
73
- raise EventHandlerAlreadyDefined.new(
74
- "A Reactor event named #{handler_name} already has been defined on #{static_subscriber_namespace}.
75
- Specify a `:handler_name` option on your subscriber's `on_event` declaration to name this event handler deterministically."
76
- )
32
+ def duplicate_subscription?(handler_name)
33
+ handler_names.include?(handler_name)
77
34
  end
78
- event_handler_names << handler_name
79
- end
80
-
81
- def name_worker_class(klass, handler_name)
82
- static_subscriber_namespace.const_set(handler_name, klass)
83
- end
84
35
 
85
- def static_subscriber_namespace
86
- ns = self.name.demodulize
87
- unless Reactor::StaticSubscribers.const_defined?(ns, false)
88
- Reactor::StaticSubscribers.const_set(ns, Module.new)
36
+ def check_for_duplicate_subscription!(event_name, handler_name_option = nil)
37
+ handler_name = Subscription.build_handler_name(event_name, handler_name_option)
38
+ if duplicate_subscription?(handler_name)
39
+ raise EventHandlerAlreadyDefined.new(
40
+ "A Reactor event named #{handler_name} already has been defined on #{static_subscriber_namespace}.
41
+ Specify a `:handler_name` option on your subscriber's `on_event` declaration to name this event handler deterministically."
42
+ )
43
+ end
89
44
  end
90
-
91
- Reactor::StaticSubscribers.const_get(ns, false)
92
45
  end
93
46
  end
94
47
  end
@@ -1,26 +1,28 @@
1
- class Reactor::Subscriber < ActiveRecord::Base
2
- attr_accessor :event
1
+ module Reactor
2
+ class Subscriber < ActiveRecord::Base
3
+ attr_accessor :event
3
4
 
4
- def event_name=(event)
5
- write_attribute :event_name, event.to_s
6
- end
5
+ def event_name=(event)
6
+ write_attribute :event_name, event.to_s
7
+ end
7
8
 
8
- def fire(data)
9
- self.event = Reactor::Event.new(data)
10
- instance_exec &self.class.on_fire
11
- self
12
- end
9
+ def fire(data)
10
+ self.event = Reactor::Event.new(data)
11
+ instance_exec &self.class.on_fire
12
+ self
13
+ end
13
14
 
14
- class << self
15
- def on_fire(&block)
16
- if block
17
- @fire_block = block
15
+ class << self
16
+ def on_fire(&block)
17
+ if block
18
+ @fire_block = block
19
+ end
20
+ @fire_block
18
21
  end
19
- @fire_block
20
- end
21
22
 
22
- def fire(subscriber_id, data)
23
- Reactor::Subscriber.find(subscriber_id).fire data
23
+ def fire(subscriber_id, data)
24
+ Reactor::Subscriber.find(subscriber_id).fire data.with_indifferent_access
25
+ end
24
26
  end
25
27
  end
26
- end
28
+ end
@@ -0,0 +1,5 @@
1
+ # FIXME - these are not properly namespaced. The directories mean nothing
2
+ require "reactor/models/concerns/publishable"
3
+ require "reactor/models/concerns/subscribable"
4
+ require "reactor/models/concerns/optionally_subclassable"
5
+ require "reactor/models/subscriber"
@@ -0,0 +1,7 @@
1
+ # This module is where named worker classes will live - examples:
2
+ # Reactor::StaticSubscribers::ArbitraryModule::WilcardHandler
3
+ # Reactor::StaticSubscribers::ArbitraryModule::MyEventNameHandler
4
+ module Reactor
5
+ module StaticSubscribers
6
+ end
7
+ end