eventish 0.3.2 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: affdd6406fe05bcc51fa60a0bdd1e894c47412e8d8c347e2f8e4e8ed0d846757
4
- data.tar.gz: 754e24d0338cb7eb4c6eb299371d2880b0b867a85fadb0b604ea3511a8e9ee32
3
+ metadata.gz: 419b6aafd21ffe1e4c9041549dc80b77fe7973975732a44feeac183f28d8f474
4
+ data.tar.gz: 50e7f43233ee05c86c930807677cdee82a21471b6d4f4c4a037ea1062e6f3127
5
5
  SHA512:
6
- metadata.gz: 23e2bd4268d4c28a3691327e499552815fbe05d6ada3e17a887e812ec2666d4f65c8c78ac878d7ef0426403cd61760134a06f7c0d9a07da6c8e73fe440da9da0
7
- data.tar.gz: 530d9dcd90223304e1606cbfe909ccf223d1353d1409a230807b29cf6258fa740228235975f0411484b99886ab961349a84ca73a3a432842090c7b95d69cf713
6
+ metadata.gz: b768c6c9baaac52a7b3bd841569714727a43527d90956881645e17b11afc5be65e14bfec6424d4a877f12d7294dc4a69edaf94a55b62b4da7f9bb133d1d69c41
7
+ data.tar.gz: a272f0d0420ae08b627be7fcb975d7051af6f7662b2089f91b4719a1b97fab70fd3cc7872031fba83ccb8d61881953f08d921476b4918cd9dfff82be05d6272b
data/README.md CHANGED
@@ -1,20 +1,27 @@
1
1
  # Eventish
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/eventish.svg)](https://badge.fury.io/rb/eventish)
4
- [![Specs](https://github.com/blocknotes/eventish/actions/workflows/main.yml/badge.svg)](https://github.com/blocknotes/eventish/actions/workflows/main.yml)
4
+ [![Specs Rails 6](https://github.com/blocknotes/eventish/actions/workflows/rails6.yml/badge.svg)](https://github.com/blocknotes/eventish/actions/workflows/rails6.yml)
5
+ [![Specs Rails 7](https://github.com/blocknotes/eventish/actions/workflows/rails7.yml/badge.svg)](https://github.com/blocknotes/eventish/actions/workflows/rails7.yml)
6
+ [![Linters](https://github.com/blocknotes/eventish/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/eventish/actions/workflows/linters.yml)
5
7
 
6
- Yet another opinionated events library which proposes a simple API to handle... events 🎉
8
+ Yet another events library with a _simple_ API to handle... events :tada:
7
9
 
8
- The main features:
10
+ Main features:
9
11
  - _composable_: just require the components that you need;
10
- - with _adapters_: support ActiveSupport::Notifications for pub/sub events;
11
- - with _async events_: support ActiveJob for background execution;
12
- - with _callbacks_ wrapper: support ActiveRecord.
12
+ - with [adapters](#adapters): support ActiveSupport::Notifications and Wisper for pub/sub events;
13
+ - with [async events](#async-events): support ActiveJob for events background execution;
14
+ - with [callbacks wrapper](#callbacks): support ActiveRecord callbacks.
15
+ - with [plugins](#plugins): a simple logger and a Rails logger are included.
16
+
17
+ Please :star: if you like it.
18
+
19
+ > Do you want to speak by events? Try _eventish_ :smile:
13
20
 
14
21
  ## Install
15
22
 
16
23
  - Add to your Gemfile: `gem 'eventish'` (and execute `bundle`)
17
- - Create an initializer - _config/initializers/eventish.rb_:
24
+ - Create an initializer - ex. _config/initializers/eventish.rb_:
18
25
 
19
26
  ```rb
20
27
  require 'eventish/adapters/active_support'
@@ -38,7 +45,7 @@ Rails.configuration.after_initialize do
38
45
  end
39
46
  ```
40
47
 
41
- - Create some events - _app/events/main/app_loaded_event.rb_:
48
+ - Create some events - ex. _app/events/main/app_loaded_event.rb_:
42
49
 
43
50
  ```rb
44
51
  module Main
@@ -52,9 +59,11 @@ end
52
59
 
53
60
  For a complete example please take a look at the [dummy app](spec/dummy) in the specs.
54
61
 
55
- ### Adatpers
62
+ ### Adapters
56
63
 
57
- Only _ActiveSupport_ is supported for now.
64
+ Used for events subscription and publishing.
65
+
66
+ _ActiveSupport Notification_:
58
67
 
59
68
  ```rb
60
69
  # initializer setup
@@ -65,6 +74,18 @@ Eventish.setup do |config|
65
74
  end
66
75
  ```
67
76
 
77
+ _Wisper_ (NOTE: around callback wrappers are not supported):
78
+
79
+ ```rb
80
+ # initializer setup
81
+ require 'wisper'
82
+ require 'eventish/adapters/wisper'
83
+
84
+ Eventish.setup do |config|
85
+ config.adapter = Eventish::Adapters::Wisper
86
+ end
87
+ ```
88
+
68
89
  ### Simple events
69
90
 
70
91
  Generic events not related to a specific component.
@@ -78,7 +99,7 @@ Rails.configuration.after_initialize do
78
99
  end
79
100
  ```
80
101
 
81
- Sample event - _app/events/main/test_event.rb_:
102
+ Sample event - ex. _app/events/main/test_event.rb_:
82
103
 
83
104
  ```rb
84
105
  module Main
@@ -97,14 +118,20 @@ module Main
97
118
  end
98
119
  ```
99
120
 
100
- Publish the event: `Eventish.publish('some_event')`
121
+ Publish the event with:
122
+
123
+ ```rb
124
+ Eventish.publish('some_event')
125
+ ```
101
126
 
102
127
  ### Async events
103
128
 
104
- Events executed in a background process. Only _ActiveJob_ is supported for now.
129
+ Events executed in a background process.
130
+ Only _ActiveJob_ is supported for now.
105
131
 
106
132
  ```rb
107
133
  # initializer setup
134
+ require 'active_job/railtie'
108
135
  require 'eventish/active_job_event'
109
136
 
110
137
  Rails.configuration.after_initialize do
@@ -112,7 +139,7 @@ Rails.configuration.after_initialize do
112
139
  end
113
140
  ```
114
141
 
115
- Sample event - _app/events/notifications/user_after_save_commit_event.rb_:
142
+ Sample event - ex. _app/events/notifications/user_after_save_commit_event.rb_:
116
143
 
117
144
  ```rb
118
145
  module Notifications
@@ -126,7 +153,7 @@ end
126
153
 
127
154
  ### Callbacks
128
155
 
129
- Only for ActiveRecord, callbacks wrapper are available with the postfix `_event` (ex. `after_commit_event SomeEvent`).
156
+ Wrappers for ActiveRecord callbacks using the postfix `_event` (ex. `after_commit_event SomeEvent`).
130
157
 
131
158
  ```rb
132
159
  # initializer setup
@@ -134,6 +161,7 @@ require 'eventish/active_record/callback'
134
161
  ```
135
162
 
136
163
  ```rb
164
+ # sample model
137
165
  class SomeModel < ActiveRecord::Base
138
166
  extend ::Eventish::ActiveRecord::Callback
139
167
 
@@ -143,6 +171,34 @@ end
143
171
 
144
172
  The related callback will be setup by the wrapper and the specified event class will be invoked accordingly.
145
173
 
174
+ ### Plugins
175
+
176
+ A plugins system is available for custom processing, a logger and a Rails logger are included in the gem.
177
+
178
+ ```rb
179
+ # initializer setup
180
+ require 'eventish/plugins/rails_logger' # without rails_ for a simple stdout logger
181
+
182
+ Eventish.setup do |config|
183
+ config.before_event = [Eventish::Plugins::RailsLogger]
184
+ config.after_event = [Eventish::Plugins::RailsLogger]
185
+ end
186
+ ```
187
+
188
+ A sample plugin:
189
+
190
+ ```rb
191
+ module Eventish::Plugins::RailsLogger
192
+ class << self
193
+ def call(target, _args, event:, hook: nil, &_block)
194
+ Rails.logger.debug "EVENT: #{hook} #{event.class.event_name} on #{target.inspect}"
195
+ end
196
+ end
197
+ end
198
+ ```
199
+
200
+ Plugins can also be configured for single events overriding _before_event_ and _after_event_.
201
+
146
202
  ## Do you like it? Star it!
147
203
 
148
204
  If you use this component just star it. A developer is more motivated to improve a project when there is some interest.
@@ -7,7 +7,10 @@ module Eventish
7
7
  end
8
8
 
9
9
  def perform(target, args)
10
+ self.class.before_event.each { |plugin| plugin.call(target, args, event: self, hook: :before) }
10
11
  call(target, args)
12
+ self.class.after_event.each { |plugin| plugin.call(target, args, event: self, hook: :after) }
13
+ self
11
14
  end
12
15
 
13
16
  class << self
@@ -4,103 +4,126 @@ module Eventish
4
4
  module ActiveRecord
5
5
  module Callback
6
6
  # Init events
7
- def after_initialize_event(event)
8
- after_initialize -> { ::Eventish.publish(event, self) }
7
+ def after_initialize_event(*args)
8
+ event = args.shift
9
+ after_initialize -> { ::Eventish.publish(event, self) }, *args
9
10
  end
10
11
 
11
- def after_find_event(event)
12
- after_find -> { ::Eventish.publish(event, self) }
12
+ def after_find_event(*args)
13
+ event = args.shift
14
+ after_find -> { ::Eventish.publish(event, self) }, *args
13
15
  end
14
16
 
15
17
  # Validation events
16
- def before_validation_event(event)
17
- before_validation -> { ::Eventish.publish(event, self) }
18
+ def before_validation_event(*args)
19
+ event = args.shift
20
+ before_validation -> { ::Eventish.publish(event, self) }, *args
18
21
  end
19
22
 
20
- def after_validation_event(event)
21
- after_validation -> { ::Eventish.publish(event, self) }
23
+ def after_validation_event(*args)
24
+ event = args.shift
25
+ after_validation -> { ::Eventish.publish(event, self) }, *args
22
26
  end
23
27
 
24
28
  # Create events
25
- def before_create_event(event)
26
- before_create -> { ::Eventish.publish(event, self) }
29
+ def before_create_event(*args)
30
+ event = args.shift
31
+ before_create -> { ::Eventish.publish(event, self) }, *args
27
32
  end
28
33
 
29
- def around_create_event(event)
30
- around_create ->(_object, block) { ::Eventish.publish(event, self, block: block) }
34
+ def around_create_event(*args)
35
+ event = args.shift
36
+ around_create ->(_object, block) { ::Eventish.publish(event, self, block: block) }, *args
31
37
  end
32
38
 
33
- def after_create_event(event)
34
- after_create -> { ::Eventish.publish(event, self) }
39
+ def after_create_event(*args)
40
+ event = args.shift
41
+ after_create -> { ::Eventish.publish(event, self) }, *args
35
42
  end
36
43
 
37
44
  # Update events
38
- def before_update_event(event)
39
- before_update -> { ::Eventish.publish(event, self) }
45
+ def before_update_event(*args)
46
+ event = args.shift
47
+ before_update -> { ::Eventish.publish(event, self) }, *args
40
48
  end
41
49
 
42
- def around_update_event(event)
43
- around_update ->(_object, block) { ::Eventish.publish(event, self, block: block) }
50
+ def around_update_event(*args)
51
+ event = args.shift
52
+ around_update ->(_object, block) { ::Eventish.publish(event, self, block: block) }, *args
44
53
  end
45
54
 
46
- def after_update_event(event)
47
- after_update -> { ::Eventish.publish(event, self) }
55
+ def after_update_event(*args)
56
+ event = args.shift
57
+ after_update -> { ::Eventish.publish(event, self) }, *args
48
58
  end
49
59
 
50
60
  # Save events
51
- def before_save_event(event)
52
- before_save -> { ::Eventish.publish(event, self) }
61
+ def before_save_event(*args)
62
+ event = args.shift
63
+ before_save -> { ::Eventish.publish(event, self) }, *args
53
64
  end
54
65
 
55
- def around_save_event(event)
56
- around_save ->(_object, block) { ::Eventish.publish(event, self, block: block) }
66
+ def around_save_event(*args)
67
+ event = args.shift
68
+ around_save ->(_object, block) { ::Eventish.publish(event, self, block: block) }, *args
57
69
  end
58
70
 
59
- def after_save_event(event)
60
- after_save -> { ::Eventish.publish(event, self) }
71
+ def after_save_event(*args)
72
+ event = args.shift
73
+ after_save -> { ::Eventish.publish(event, self) }, *args
61
74
  end
62
75
 
63
76
  # Destroy events
64
- def before_destroy_event(event)
65
- before_destroy -> { ::Eventish.publish(event, self) }
77
+ def before_destroy_event(*args)
78
+ event = args.shift
79
+ before_destroy -> { ::Eventish.publish(event, self) }, *args
66
80
  end
67
81
 
68
- def around_destroy_event(event)
69
- around_destroy ->(_object, block) { ::Eventish.publish(event, self, block: block) }
82
+ def around_destroy_event(*args)
83
+ event = args.shift
84
+ around_destroy ->(_object, block) { ::Eventish.publish(event, self, block: block) }, *args
70
85
  end
71
86
 
72
- def after_destroy_event(event)
73
- after_destroy -> { ::Eventish.publish(event, self) }
87
+ def after_destroy_event(*args)
88
+ event = args.shift
89
+ after_destroy -> { ::Eventish.publish(event, self) }, *args
74
90
  end
75
91
 
76
92
  # Commit events
77
- def after_commit_event(event)
78
- after_commit -> { ::Eventish.publish(event, self) }
93
+ def after_commit_event(*args)
94
+ event = args.shift
95
+ after_commit -> { ::Eventish.publish(event, self) }, *args
79
96
  end
80
97
 
81
- def after_create_commit_event(event)
82
- after_create_commit -> { ::Eventish.publish(event, self) }
98
+ def after_create_commit_event(*args)
99
+ event = args.shift
100
+ after_create_commit -> { ::Eventish.publish(event, self) }, *args
83
101
  end
84
102
 
85
- def after_update_commit_event(event)
86
- after_update_commit -> { ::Eventish.publish(event, self) }
103
+ def after_update_commit_event(*args)
104
+ event = args.shift
105
+ after_update_commit -> { ::Eventish.publish(event, self) }, *args
87
106
  end
88
107
 
89
- def after_save_commit_event(event)
90
- after_save_commit -> { ::Eventish.publish(event, self) }
108
+ def after_save_commit_event(*args)
109
+ event = args.shift
110
+ after_save_commit -> { ::Eventish.publish(event, self) }, *args
91
111
  end
92
112
 
93
- def after_destroy_commit_event(event)
94
- after_destroy_commit -> { ::Eventish.publish(event, self) }
113
+ def after_destroy_commit_event(*args)
114
+ event = args.shift
115
+ after_destroy_commit -> { ::Eventish.publish(event, self) }, *args
95
116
  end
96
117
 
97
- def after_rollback_event(event)
98
- after_rollback -> { ::Eventish.publish(event, self) }
118
+ def after_rollback_event(*args)
119
+ event = args.shift
120
+ after_rollback -> { ::Eventish.publish(event, self) }, *args
99
121
  end
100
122
 
101
123
  # Touch events
102
- def after_touch_event(event)
103
- after_touch -> { ::Eventish.publish(event, self) }
124
+ def after_touch_event(*args)
125
+ event = args.shift
126
+ after_touch -> { ::Eventish.publish(event, self) }, *args
104
127
  end
105
128
  end
106
129
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Eventish
4
- class Adapters
4
+ module Adapters
5
5
  class ActiveSupport
6
6
  class << self
7
7
  def publish(event, target = nil, block: nil)
@@ -15,16 +15,19 @@ module Eventish
15
15
  raise ArgumentError, 'Missing event to subscribe' if event.nil?
16
16
  raise ArgumentError, 'Missing handler for subscription' if handler.nil?
17
17
 
18
- ::ActiveSupport::Notifications.subscribe(event.to_s) do |name, start, finish, id, payload|
18
+ subscriber = ::ActiveSupport::Notifications.subscribe(event.to_s) do |name, start, finish, id, payload|
19
19
  args = { event: name, id: id, start: start, finish: finish }
20
20
  handler.trigger(payload[:target], args, &payload.dig(:options, :block))
21
21
  end
22
+ Eventish.subscribers[event.to_s] = subscriber
23
+ subscriber
22
24
  end
23
25
 
24
26
  def unsubscribe(event)
25
27
  raise ArgumentError, 'Missing event to unsubscribe' if event.nil?
26
28
 
27
29
  ::ActiveSupport::Notifications.unsubscribe(event.to_s)
30
+ Eventish.subscribers.delete(event.to_s)
28
31
  end
29
32
  end
30
33
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eventish
4
+ module Adapters
5
+ class Wisper
6
+ class << self
7
+ include ::Wisper::Publisher
8
+
9
+ def publish(event, target = nil, block: nil)
10
+ raise ArgumentError, 'Missing event to publish' if event.nil?
11
+
12
+ options = block ? { block: block } : {} # TODO: verify block feature
13
+ broadcast(event.to_s, target, options)
14
+ end
15
+
16
+ def subscribe(event, handler)
17
+ raise ArgumentError, 'Missing event to subscribe' if event.nil?
18
+ raise ArgumentError, 'Missing handler for subscription' if handler.nil?
19
+
20
+ ::Wisper.subscribe(handler.new, on: event.to_s, with: :call).tap do |subscriber|
21
+ Eventish.subscribers[event.to_s] = subscriber
22
+ end
23
+ end
24
+
25
+ def unsubscribe(event)
26
+ raise ArgumentError, 'Missing event to unsubscribe' if event.nil?
27
+
28
+ subscriber = Eventish.subscribers[event.to_s]
29
+ ::Wisper.unsubscribe(subscriber)
30
+ Eventish.subscribers.delete(event.to_s)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -6,6 +6,14 @@ module Eventish
6
6
  other&.priority <=> priority
7
7
  end
8
8
 
9
+ def after_event
10
+ Eventish.config.after_event || []
11
+ end
12
+
13
+ def before_event
14
+ Eventish.config.before_event || []
15
+ end
16
+
9
17
  def event_name
10
18
  @event_name ||= to_s
11
19
  end
@@ -19,8 +27,14 @@ module Eventish
19
27
  end
20
28
 
21
29
  def subscribe_all
22
- # iterate the descendants
23
- ObjectSpace.each_object(singleton_class).sort.each(&:subscribe)
30
+ ignore_events = [Eventish::SimpleEvent]
31
+ ignore_events.push(Eventish::ActiveJobEvent) if defined? Eventish::ActiveJobEvent
32
+ events = Eventish.descendants(self).sort
33
+ (events - ignore_events).each(&:subscribe)
34
+ end
35
+
36
+ def unsubscribe
37
+ Eventish.adapter.unsubscribe(event_name)
24
38
  end
25
39
  end
26
40
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eventish
4
+ module Plugins
5
+ class Logger
6
+ class << self
7
+ def call(target, _args, event:, hook: nil, &_block)
8
+ puts "[#{Time.now}] EVENT: #{hook} #{event.class.event_name} on #{target.inspect}"
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Eventish
4
+ module Plugins
5
+ class RailsLogger
6
+ class << self
7
+ def call(target, _args, event:, hook: nil, &_block)
8
+ ::Rails.logger.debug "EVENT: #{hook} #{event.class.event_name} on #{target.inspect}"
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -10,7 +10,11 @@ module Eventish
10
10
  include EventApi
11
11
 
12
12
  def trigger(target, args, &block)
13
- new.call(target, args, &block)
13
+ event = new
14
+ before_event.each { |plugin| plugin.call(target, args, event: event, hook: :before, &block) }
15
+ event.call(target, args, &block)
16
+ after_event.each { |plugin| plugin.call(target, args, event: event, hook: :after, &block) }
17
+ event
14
18
  end
15
19
  end
16
20
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Eventish # :nodoc:
4
- VERSION = '0.3.2'
4
+ VERSION = '0.5.0'
5
5
  end
data/lib/eventish.rb CHANGED
@@ -4,7 +4,7 @@ require_relative 'eventish/event_api'
4
4
  require_relative 'eventish/simple_event'
5
5
 
6
6
  module Eventish
7
- OPTIONS = %i[adapter].freeze
7
+ OPTIONS = %i[adapter after_event before_event].freeze
8
8
 
9
9
  AdapterError = Class.new(StandardError)
10
10
 
@@ -18,6 +18,17 @@ module Eventish
18
18
  @options ||= Struct.new(*OPTIONS).new # rubocop:disable Naming/MemoizedInstanceVariableName
19
19
  end
20
20
 
21
+ # From Rails 6.0
22
+ def descendants(klass)
23
+ descendants = []
24
+ ObjectSpace.each_object(klass.singleton_class) do |k|
25
+ next if k.singleton_class?
26
+
27
+ descendants.unshift k unless k == self
28
+ end
29
+ descendants
30
+ end
31
+
21
32
  def publish(event_name, target = nil, block: nil)
22
33
  config.adapter&.publish(event_name, target, block: block)
23
34
  end
@@ -29,4 +40,8 @@ module Eventish
29
40
 
30
41
  @options
31
42
  end
43
+
44
+ def subscribers
45
+ @subscribers ||= {}
46
+ end
32
47
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eventish
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mattia Roccoberton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-20 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-05-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: appraisal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.4'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.4'
13
27
  description: A simple and composable event library
14
28
  email: mat@blocknot.es
15
29
  executables: []
@@ -22,7 +36,10 @@ files:
22
36
  - lib/eventish/active_job_event.rb
23
37
  - lib/eventish/active_record/callback.rb
24
38
  - lib/eventish/adapters/active_support.rb
39
+ - lib/eventish/adapters/wisper.rb
25
40
  - lib/eventish/event_api.rb
41
+ - lib/eventish/plugins/logger.rb
42
+ - lib/eventish/plugins/rails_logger.rb
26
43
  - lib/eventish/simple_event.rb
27
44
  - lib/eventish/version.rb
28
45
  homepage: https://github.com/blocknotes/eventish