eventish 0.3.2 → 0.5.0

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