reactor 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
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