signal 0.3.0 → 1.3.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 +5 -5
- data/.github/FUNDING.yml +3 -0
- data/.rubocop.yml +12 -0
- data/.travis.yml +16 -8
- data/Gemfile +3 -1
- data/README.md +87 -41
- data/Rakefile +15 -1
- data/examples/activerecord_model.rb +14 -12
- data/examples/arguments.rb +4 -2
- data/examples/block_context.rb +8 -5
- data/examples/blocks.rb +6 -4
- data/examples/call.rb +23 -0
- data/examples/chain.rb +20 -18
- data/examples/listener.rb +6 -4
- data/lib/signal/{active_record.rb → extensions/active_record.rb} +24 -19
- data/lib/signal/extensions/call.rb +25 -0
- data/lib/signal/listener.rb +4 -1
- data/lib/signal/mock.rb +51 -0
- data/lib/signal/version.rb +3 -1
- data/lib/signal.rb +11 -7
- data/signal.gemspec +30 -17
- metadata +73 -33
- data/.rspec +0 -1
- data/lib/signal/call.rb +0 -21
- data/spec/signal/activerecord_spec.rb +0 -132
- data/spec/signal/call_spec.rb +0 -18
- data/spec/signal/listener_spec.rb +0 -8
- data/spec/signal/signal_spec.rb +0 -123
- data/spec/spec_helper.rb +0 -24
- data/spec/support/callable.rb +0 -10
- data/spec/support/observable.rb +0 -3
- data/spec/support/observable_with_call.rb +0 -13
- data/spec/support/user.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b9b02225af7234c06c7bdca60c54ca2bc5bd7b56760350fb52c603dcfcd9c6fc
|
4
|
+
data.tar.gz: 6ae6ad7189173f3eef745a12b0bba61444a00b6ed6da7680848d8fdfa26c9214
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aba54da3377c2f2eb8eca0d87edc44599dccb195259bf75949008cd17b780f7d2ad9fbce0e54aac6b3e2fd63e0bf61e86f02ad1e02e4bd4b5ba9c6a96baa74c9
|
7
|
+
data.tar.gz: b7be39534802b24399c9d732c7af050447b66ac5fff04abd6ee66f46f54324e6e6f636c2d84b62c0f20c490fc471484d3ee86e6f5faca3b833d5a8d17761fcdf
|
data/.github/FUNDING.yml
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
CHANGED
@@ -1,12 +1,20 @@
|
|
1
1
|
language: ruby
|
2
2
|
cache: bundler
|
3
3
|
sudo: false
|
4
|
-
script: bundle exec
|
4
|
+
script: bundle exec rake
|
5
5
|
rvm:
|
6
|
-
-
|
7
|
-
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
- 2.7.1
|
7
|
+
- 2.6.2
|
8
|
+
before_script:
|
9
|
+
- "curl -L
|
10
|
+
https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64
|
11
|
+
> ./cc-test-reporter"
|
12
|
+
- chmod +x ./cc-test-reporter
|
13
|
+
- "./cc-test-reporter before-build"
|
14
|
+
after_script:
|
15
|
+
- "./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT"
|
16
|
+
notifications:
|
17
|
+
email: false
|
18
|
+
env:
|
19
|
+
global:
|
20
|
+
secure: EmzkOnefLJlsAbh4tKzcdfX9PiwQMNSmWz1aTaieA1C9GJryT2JswBa/eVgU3jDKPhFFdZ5X8K6bf0ArAdDXFMW5+DPQ9nWDOCUH3QuuFTOicyTi16W8HCozbLTg49CdB0kP4iQlA3rdpje/T9zgsTvdNDuBevB90JplHy5Lu6o=
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
# Signal
|
2
2
|
|
3
|
-
[](https://travis-ci.org/fnando/signal)
|
4
4
|
[](https://codeclimate.com/github/fnando/signal)
|
5
5
|
[](https://codeclimate.com/github/fnando/signal)
|
6
|
+
[](https://rubygems.org/gems/signal)
|
7
|
+
[](https://rubygems.org/gems/signal)
|
6
8
|
|
7
|
-
A simple observer implementation on POROs (Plain Old Ruby Object) and
|
9
|
+
A simple observer implementation on POROs (Plain Old Ruby Object) and
|
10
|
+
ActiveRecord objects.
|
8
11
|
|
9
12
|
## Installation
|
10
13
|
|
@@ -28,7 +31,8 @@ You can use Signal with PORO (Plain Old Ruby Object) and ActiveRecord.
|
|
28
31
|
|
29
32
|
### Plain Ruby
|
30
33
|
|
31
|
-
All you have to do is including the `Signal` module. Then you can add listeners
|
34
|
+
All you have to do is including the `Signal` module. Then you can add listeners
|
35
|
+
and trigger events.
|
32
36
|
|
33
37
|
```ruby
|
34
38
|
class Status
|
@@ -49,7 +53,8 @@ status.ready!
|
|
49
53
|
#=> After the ready event!
|
50
54
|
```
|
51
55
|
|
52
|
-
You can also pass objects that implement methods like `before_*`, `on_*` and
|
56
|
+
You can also pass objects that implement methods like `before_*`, `on_*` and
|
57
|
+
`after_*`.
|
53
58
|
|
54
59
|
```ruby
|
55
60
|
class MyListener
|
@@ -74,7 +79,9 @@ Status.new
|
|
74
79
|
#=> After the ready event!
|
75
80
|
```
|
76
81
|
|
77
|
-
Executed blocks don't switch context. You always have to emit the object you're
|
82
|
+
Executed blocks don't switch context. You always have to emit the object you're
|
83
|
+
interested in. The follow example uses `emit(:output, self)` to send the
|
84
|
+
`Contact` instance to all listeners.
|
78
85
|
|
79
86
|
```ruby
|
80
87
|
class Contact
|
@@ -119,11 +126,12 @@ Arguments.new
|
|
119
126
|
|
120
127
|
### ActiveRecord
|
121
128
|
|
122
|
-
You can use Signal with ActiveRecord, which will give you some default events
|
129
|
+
You can use Signal with ActiveRecord, which will give you some default events
|
130
|
+
like `:create`, `:update`, `:remove` and `:validation`.
|
123
131
|
|
124
132
|
```ruby
|
125
133
|
class Thing < ActiveRecord::Base
|
126
|
-
include Signal
|
134
|
+
include Signal.active_record
|
127
135
|
|
128
136
|
validates_presence_of :name
|
129
137
|
end
|
@@ -151,22 +159,23 @@ thing.destroy
|
|
151
159
|
|
152
160
|
These are the available events:
|
153
161
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
162
|
+
- `before(:create)`: triggered before creating the record (record is valid).
|
163
|
+
- `on(:create)`: triggered after `before(:create)` event.
|
164
|
+
- `after(:create)`: triggered after the `on(:create)` event.
|
165
|
+
- `before(:update)`: triggered before updating the record (record is valid).
|
166
|
+
- `on(:update)`: triggered when the `before(:update)` event.
|
167
|
+
- `after(:update)`: triggered after the `on(:update)` event.
|
168
|
+
- `before(:remove)`: triggered before removing the record.
|
169
|
+
- `on(:remove)`: triggered after the `before(:remove)`.
|
170
|
+
- `after(:remove)`: triggered after the `on(:remove)` event.
|
171
|
+
- `before(:validation)`: triggered before validating record.
|
172
|
+
- `on(:validation)`: triggered when record is invalid.
|
173
|
+
- `after(:validation)`: triggered after validating record.
|
166
174
|
|
167
175
|
### Inside Rails
|
168
176
|
|
169
|
-
Although there's no special code for Rails, here's just an example of how you
|
177
|
+
Although there's no special code for Rails, here's just an example of how you
|
178
|
+
can use it:
|
170
179
|
|
171
180
|
```ruby
|
172
181
|
class UsersController < ApplicationController
|
@@ -197,7 +206,10 @@ end
|
|
197
206
|
|
198
207
|
### Signal::Call
|
199
208
|
|
200
|
-
You can include `Signal
|
209
|
+
You can include `Signal.call` instead, so you can have a common interface for
|
210
|
+
your observable object. This will add the `.call()` method to the target class,
|
211
|
+
which will delegate attributes to the observable's `initialize` method and call
|
212
|
+
its `call` method.
|
201
213
|
|
202
214
|
```ruby
|
203
215
|
class Contact
|
@@ -219,7 +231,43 @@ Contact.call('John', 'john@example.com') do |o|
|
|
219
231
|
end
|
220
232
|
```
|
221
233
|
|
222
|
-
Notice that you don't have to explicit call the instance's `call` method;
|
234
|
+
Notice that you don't have to explicit call the instance's `call` method;
|
235
|
+
`Contact.call` will initialize the object with all the provided parameters and
|
236
|
+
call `Contact#call` after the block has been executed.
|
237
|
+
|
238
|
+
### Testing
|
239
|
+
|
240
|
+
`Signal::Mock` can be helpful for most test situations where you don't want to
|
241
|
+
bring other mock libraries.
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
require "signal/mock"
|
245
|
+
|
246
|
+
class SomeTest < Minitest::Test
|
247
|
+
def test_some_test
|
248
|
+
mock = Signal::Mock.new
|
249
|
+
|
250
|
+
# Using listener
|
251
|
+
sum = Sum.new
|
252
|
+
sum.add_listener(mock)
|
253
|
+
|
254
|
+
# Calling `mock.on(event_name)` is required because
|
255
|
+
# the handler doesn't receive the event name, just the
|
256
|
+
# arguments.
|
257
|
+
sum = Sum.new
|
258
|
+
sum.on(:result, &mock.on(:result))
|
259
|
+
|
260
|
+
# Using with Signal.call
|
261
|
+
Sum.call(1, 2, &mock)
|
262
|
+
|
263
|
+
assert mock.received?(:result)
|
264
|
+
assert mock.received?(:result, times: 1)
|
265
|
+
assert mock.received?(:result, with: [3])
|
266
|
+
assert mock.received?(:result, with: ->(result) { result == 3 } )
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
```
|
223
271
|
|
224
272
|
## Contributing
|
225
273
|
|
@@ -231,25 +279,23 @@ Notice that you don't have to explicit call the instance's `call` method; `Conta
|
|
231
279
|
|
232
280
|
## License
|
233
281
|
|
234
|
-
Copyright (c) 2013
|
282
|
+
Copyright (c) 2013 Nando Vieira
|
235
283
|
|
236
284
|
MIT License
|
237
285
|
|
238
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
255
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
286
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
287
|
+
this software and associated documentation files (the "Software"), to deal in
|
288
|
+
the Software without restriction, including without limitation the rights to
|
289
|
+
use, copy, modify, merge, publish, distribute, sub-license, and/or sell copies
|
290
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
291
|
+
so, subject to the following conditions:
|
292
|
+
|
293
|
+
The above copyright notice and this permission notice shall be included in all
|
294
|
+
copies or substantial portions of the Software.
|
295
|
+
|
296
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
297
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
298
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
299
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
300
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
301
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -1 +1,15 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rake/testtask"
|
5
|
+
require "rubocop/rake_task"
|
6
|
+
|
7
|
+
Rake::TestTask.new(:test) do |t|
|
8
|
+
t.libs << "test"
|
9
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
10
|
+
t.warning = false
|
11
|
+
end
|
12
|
+
|
13
|
+
RuboCop::RakeTask.new
|
14
|
+
|
15
|
+
task default: %i[test rubocop]
|
@@ -1,13 +1,15 @@
|
|
1
|
-
|
2
|
-
require 'signal'
|
3
|
-
require 'active_record'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
})
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
4
|
+
require "signal"
|
5
|
+
require "active_record"
|
9
6
|
|
10
|
-
ActiveRecord::
|
7
|
+
ActiveRecord::Base.establish_connection(
|
8
|
+
adapter: "sqlite3",
|
9
|
+
database: ":memory:"
|
10
|
+
)
|
11
|
+
|
12
|
+
ActiveRecord::Schema.define(version: 0) do
|
11
13
|
create_table :things do |t|
|
12
14
|
t.string :name
|
13
15
|
t.timestamps null: false
|
@@ -20,7 +22,7 @@ class Thing < ActiveRecord::Base
|
|
20
22
|
validates_presence_of :name
|
21
23
|
end
|
22
24
|
|
23
|
-
thing = Thing.new(:
|
25
|
+
thing = Thing.new(name: "Stuff")
|
24
26
|
thing.on(:create) {|model| puts model.updated_at, model.name }
|
25
27
|
thing.on(:update) {|model| puts model.updated_at, model.name }
|
26
28
|
thing.on(:remove) {|model| puts model.destroyed? }
|
@@ -30,12 +32,12 @@ thing.save!
|
|
30
32
|
#=> 2013-01-26 10:32:39 -0200
|
31
33
|
#=> Stuff
|
32
34
|
|
33
|
-
thing.update_attributes(:
|
35
|
+
thing.update_attributes(name: "Updated stuff")
|
34
36
|
#=> 2013-01-26 10:33:11 -0200
|
35
37
|
#=> Updated stuff
|
36
38
|
|
37
|
-
thing.update_attributes(:
|
38
|
-
#=> [
|
39
|
+
thing.update_attributes(name: nil)
|
40
|
+
#=> ["Name can"t be blank"]
|
39
41
|
|
40
42
|
thing.destroy
|
41
43
|
#=> true
|
data/examples/arguments.rb
CHANGED
data/examples/block_context.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
4
|
+
require "signal"
|
3
5
|
|
4
6
|
class Contact
|
5
7
|
include Signal
|
@@ -7,7 +9,8 @@ class Contact
|
|
7
9
|
attr_reader :name, :email
|
8
10
|
|
9
11
|
def initialize(name, email)
|
10
|
-
@name
|
12
|
+
@name = name
|
13
|
+
@email = email
|
11
14
|
end
|
12
15
|
|
13
16
|
def output!
|
@@ -15,6 +18,6 @@ class Contact
|
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
18
|
-
contact = Contact.new(
|
19
|
-
contact.on(:output) {|
|
21
|
+
contact = Contact.new("John Doe", "john@example.org")
|
22
|
+
contact.on(:output) {|c| puts c.name, c.email }
|
20
23
|
contact.output!
|
data/examples/blocks.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
4
|
+
require "signal"
|
3
5
|
|
4
6
|
class Status
|
5
7
|
include Signal
|
@@ -10,7 +12,7 @@ class Status
|
|
10
12
|
end
|
11
13
|
|
12
14
|
status = Status.new
|
13
|
-
status.before(:ready) { puts
|
15
|
+
status.before(:ready) { puts "Before the ready event!" }
|
14
16
|
status.on(:ready) { puts "I'm ready!" }
|
15
|
-
status.after(:ready) { puts
|
17
|
+
status.after(:ready) { puts "After the ready event!" }
|
16
18
|
status.ready!
|
data/examples/call.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
4
|
+
require "signal"
|
5
|
+
|
6
|
+
class Contact
|
7
|
+
include Signal.call
|
8
|
+
|
9
|
+
attr_reader :name, :email
|
10
|
+
|
11
|
+
def initialize(name, email)
|
12
|
+
@name = name
|
13
|
+
@email = email
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
emit(:output, self)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Contact.call("John", "john@example.com") do |o|
|
22
|
+
o.on(:output) {|contact| puts contact.name }
|
23
|
+
end
|
data/examples/chain.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
|
2
|
-
require 'signal'
|
3
|
-
require 'active_record'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
})
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
4
|
+
require "signal"
|
5
|
+
require "active_record"
|
9
6
|
|
10
|
-
ActiveRecord::
|
7
|
+
ActiveRecord::Base.establish_connection(
|
8
|
+
adapter: "sqlite3",
|
9
|
+
database: ":memory:"
|
10
|
+
)
|
11
|
+
|
12
|
+
ActiveRecord::Schema.define(version: 0) do
|
11
13
|
create_table :things do |t|
|
12
14
|
t.string :name
|
13
15
|
t.timestamps null: false
|
@@ -15,14 +17,14 @@ ActiveRecord::Schema.define(:version => 0) do
|
|
15
17
|
end
|
16
18
|
|
17
19
|
class Thing < ActiveRecord::Base
|
18
|
-
include Signal
|
20
|
+
include Signal.active_record
|
19
21
|
|
20
22
|
validates_presence_of :name
|
21
23
|
end
|
22
24
|
|
23
25
|
class MyListener
|
24
|
-
[
|
25
|
-
class_eval <<-RUBY
|
26
|
+
%i[validation update create remove].each do |type|
|
27
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
26
28
|
def before_#{type}(thing); puts __method__; end
|
27
29
|
def on_#{type}(thing); puts __method__; end
|
28
30
|
def after_#{type}(thing); puts __method__; end
|
@@ -31,26 +33,26 @@ class MyListener
|
|
31
33
|
end
|
32
34
|
|
33
35
|
puts "\n=== Creating valid record"
|
34
|
-
thing = Thing.new(:
|
36
|
+
thing = Thing.new(name: "Stuff")
|
35
37
|
thing.listeners << MyListener.new
|
36
38
|
thing.save
|
37
39
|
|
38
40
|
puts "\n=== Creating invalid record"
|
39
|
-
thing = Thing.new(:
|
41
|
+
thing = Thing.new(name: nil)
|
40
42
|
thing.listeners << MyListener.new
|
41
43
|
thing.save
|
42
44
|
|
43
45
|
puts "\n=== Updating valid record"
|
44
|
-
thing = Thing.create(:
|
46
|
+
thing = Thing.create(name: "Stuff")
|
45
47
|
thing.listeners << MyListener.new
|
46
|
-
thing.update_attributes(:
|
48
|
+
thing.update_attributes(name: "Updated stuff")
|
47
49
|
|
48
50
|
puts "\n=== Updating invalid record"
|
49
|
-
thing = Thing.create!(:
|
51
|
+
thing = Thing.create!(name: "Stuff")
|
50
52
|
thing.listeners << MyListener.new
|
51
|
-
thing.update_attributes(:
|
53
|
+
thing.update_attributes(name: nil)
|
52
54
|
|
53
55
|
puts "\n=== Removing record"
|
54
|
-
thing = Thing.create(:
|
56
|
+
thing = Thing.create(name: "Stuff")
|
55
57
|
thing.listeners << MyListener.new
|
56
58
|
thing.destroy
|
data/examples/listener.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
4
|
+
require "signal"
|
3
5
|
|
4
6
|
class Status
|
5
7
|
include Signal
|
@@ -11,7 +13,7 @@ end
|
|
11
13
|
|
12
14
|
class MyListener
|
13
15
|
def before_ready
|
14
|
-
puts
|
16
|
+
puts "Before the ready event!"
|
15
17
|
end
|
16
18
|
|
17
19
|
def on_ready
|
@@ -19,7 +21,7 @@ class MyListener
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def after_ready
|
22
|
-
puts
|
24
|
+
puts "After the ready event!"
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
@@ -1,29 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Signal
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
4
|
+
def self.active_record
|
5
|
+
Extensions::ActiveRecord
|
6
|
+
end
|
7
|
+
|
8
|
+
module Extensions
|
9
|
+
module ActiveRecord
|
10
|
+
def self.included(base)
|
11
|
+
base.class_eval do
|
12
|
+
include Signal
|
13
|
+
|
14
|
+
around_create :around_create_signal
|
15
|
+
around_save :around_save_signal
|
16
|
+
around_destroy :around_destroy_signal
|
17
|
+
before_validation :before_validation_signal
|
18
|
+
after_validation :after_validation_signal
|
19
|
+
end
|
13
20
|
end
|
14
|
-
end
|
15
21
|
|
16
|
-
|
17
|
-
private
|
18
|
-
def around_create_signal
|
22
|
+
private def around_create_signal
|
19
23
|
emit_signal(:before, :create, self)
|
20
24
|
yield
|
21
25
|
return unless persisted?
|
26
|
+
|
22
27
|
emit_signal(:on, :create, self)
|
23
28
|
emit_signal(:after, :create, self)
|
24
29
|
end
|
25
30
|
|
26
|
-
def around_save_signal
|
31
|
+
private def around_save_signal
|
27
32
|
if new_record?
|
28
33
|
yield
|
29
34
|
return
|
@@ -35,18 +40,18 @@ module Signal
|
|
35
40
|
emit_signal(:after, :update, self)
|
36
41
|
end
|
37
42
|
|
38
|
-
def around_destroy_signal
|
43
|
+
private def around_destroy_signal
|
39
44
|
emit_signal(:before, :remove, self)
|
40
45
|
yield
|
41
46
|
emit_signal(:on, :remove, self)
|
42
47
|
emit_signal(:after, :remove, self)
|
43
48
|
end
|
44
49
|
|
45
|
-
def before_validation_signal
|
50
|
+
private def before_validation_signal
|
46
51
|
emit_signal(:before, :validation, self)
|
47
52
|
end
|
48
53
|
|
49
|
-
def after_validation_signal
|
54
|
+
private def after_validation_signal
|
50
55
|
emit_signal(:on, :validation, self) if errors.any?
|
51
56
|
emit_signal(:after, :validation, self)
|
52
57
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Signal
|
4
|
+
def self.call
|
5
|
+
Extensions::Call
|
6
|
+
end
|
7
|
+
|
8
|
+
module Extensions
|
9
|
+
module Call
|
10
|
+
def self.included(target)
|
11
|
+
target.include(Signal)
|
12
|
+
target.extend(ClassMethods)
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def call(*args, **kwargs)
|
17
|
+
new(*args, **kwargs).tap do |instance|
|
18
|
+
yield(instance) if block_given?
|
19
|
+
instance.call
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/signal/listener.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Signal
|
2
4
|
class Listener
|
3
5
|
def initialize(context, type, event, &block)
|
@@ -10,6 +12,7 @@ module Signal
|
|
10
12
|
|
11
13
|
def method_missing(method_name, *args)
|
12
14
|
return super unless respond_to_missing?(method_name, false)
|
15
|
+
|
13
16
|
@block.call(*args)
|
14
17
|
end
|
15
18
|
|
@@ -17,7 +20,7 @@ module Signal
|
|
17
20
|
"<#{self.class} event: #{@event_method}>"
|
18
21
|
end
|
19
22
|
|
20
|
-
def respond_to_missing?(method_name,
|
23
|
+
def respond_to_missing?(method_name, _include_private)
|
21
24
|
method_name == @event_method
|
22
25
|
end
|
23
26
|
end
|