u-observers 0.7.0 → 2.1.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 +4 -4
- data/.tool-versions +1 -0
- data/.travis.sh +34 -0
- data/.travis.yml +27 -3
- data/Gemfile +31 -5
- data/README.md +392 -11
- data/README.pt-BR.md +426 -0
- data/lib/micro/observers.rb +3 -23
- data/lib/micro/observers/event.rb +21 -0
- data/lib/micro/observers/event/names.rb +29 -0
- data/lib/micro/observers/for/active_model.rb +36 -0
- data/lib/micro/observers/for/active_record.rb +16 -0
- data/lib/micro/observers/set.rb +178 -0
- data/lib/micro/observers/utils.rb +4 -4
- data/lib/micro/observers/version.rb +1 -1
- data/lib/u-observers/for/active_model.rb +2 -0
- data/lib/u-observers/for/active_record.rb +2 -0
- data/test.sh +11 -0
- data/u-observers.gemspec +5 -1
- metadata +42 -5
- data/lib/micro/observers/events_or_actions.rb +0 -25
- data/lib/micro/observers/manager.rb +0 -93
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Micro
|
4
|
+
module Observers
|
5
|
+
|
6
|
+
class Event
|
7
|
+
require 'micro/observers/event/names'
|
8
|
+
|
9
|
+
attr_reader :name, :subject, :context, :data
|
10
|
+
|
11
|
+
def initialize(name, subject, context, data)
|
12
|
+
@name, @subject = name, subject
|
13
|
+
@context, @data = context, data
|
14
|
+
end
|
15
|
+
|
16
|
+
alias ctx context
|
17
|
+
alias subj subject
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Micro
|
4
|
+
module Observers
|
5
|
+
|
6
|
+
class Event::Names
|
7
|
+
EMPTY_ARRAY = [].freeze
|
8
|
+
|
9
|
+
def self.[](value, default: EMPTY_ARRAY)
|
10
|
+
values = Utils::Arrays.flatten_and_compact(value)
|
11
|
+
|
12
|
+
values.empty? ? default : values
|
13
|
+
end
|
14
|
+
|
15
|
+
NO_EVENTS_MSG = 'no events (expected at least 1)'.freeze
|
16
|
+
|
17
|
+
def self.fetch(value)
|
18
|
+
values = self[value]
|
19
|
+
|
20
|
+
return values unless values.empty?
|
21
|
+
|
22
|
+
raise ArgumentError, NO_EVENTS_MSG
|
23
|
+
end
|
24
|
+
|
25
|
+
private_constant :NO_EVENTS_MSG
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Micro
|
4
|
+
module Observers
|
5
|
+
module For
|
6
|
+
|
7
|
+
module ActiveModel
|
8
|
+
module ClassMethods
|
9
|
+
def notify_observers!(events)
|
10
|
+
proc do |object|
|
11
|
+
object.observers.subject_changed!
|
12
|
+
object.observers.send(:broadcast_if_subject_changed, events)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def notify_observers(*events)
|
17
|
+
notify_observers!(Event::Names.fetch(events))
|
18
|
+
end
|
19
|
+
|
20
|
+
def notify_observers_on(*callback_methods)
|
21
|
+
Utils::Arrays.flatten_and_compact(callback_methods).each do |callback_method|
|
22
|
+
self.public_send(callback_method, ¬ify_observers!([callback_method]))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.included(base)
|
28
|
+
base.extend(ClassMethods)
|
29
|
+
base.send(:private_class_method, :notify_observers!)
|
30
|
+
base.send(:include, ::Micro::Observers)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Micro
|
4
|
+
module Observers
|
5
|
+
module For
|
6
|
+
require 'micro/observers/for/active_model'
|
7
|
+
|
8
|
+
module ActiveRecord
|
9
|
+
def self.included(base)
|
10
|
+
base.send(:include, ::Micro::Observers::For::ActiveModel)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Micro
|
4
|
+
module Observers
|
5
|
+
|
6
|
+
class Set
|
7
|
+
EMPTY_HASH = {}.freeze
|
8
|
+
|
9
|
+
MapSubscriber = -> (observer, options) { [:observer, observer, options[:context]] }
|
10
|
+
|
11
|
+
MapSubscribers = -> (value) do
|
12
|
+
array = Utils::Arrays.flatten_and_compact(value.kind_of?(Array) ? value : [])
|
13
|
+
array.map { |observer| MapSubscriber[observer, EMPTY_HASH] }
|
14
|
+
end
|
15
|
+
|
16
|
+
GetObserver = -> subscriber { subscriber[0] == :observer ? subscriber[1] : subscriber[2][0] }
|
17
|
+
|
18
|
+
EqualTo = -> (observer) { -> subscriber { GetObserver[subscriber] == observer } }
|
19
|
+
|
20
|
+
def self.for(subject)
|
21
|
+
new(subject)
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(subject, subscribers: nil)
|
25
|
+
@subject = subject
|
26
|
+
|
27
|
+
@subject_changed = false
|
28
|
+
|
29
|
+
@subscribers = MapSubscribers.call(subscribers)
|
30
|
+
end
|
31
|
+
|
32
|
+
def count
|
33
|
+
@subscribers.size
|
34
|
+
end
|
35
|
+
|
36
|
+
def none?
|
37
|
+
@subscribers.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
def some?
|
41
|
+
!none?
|
42
|
+
end
|
43
|
+
|
44
|
+
def subject_changed?
|
45
|
+
@subject_changed
|
46
|
+
end
|
47
|
+
|
48
|
+
INVALID_BOOLEAN_MSG = 'expected a boolean (true, false)'.freeze
|
49
|
+
|
50
|
+
def subject_changed(state)
|
51
|
+
return @subject_changed = state if state == true || state == false
|
52
|
+
|
53
|
+
raise ArgumentError, INVALID_BOOLEAN_MSG
|
54
|
+
end
|
55
|
+
|
56
|
+
def subject_changed!
|
57
|
+
subject_changed(true)
|
58
|
+
end
|
59
|
+
|
60
|
+
def included?(observer)
|
61
|
+
@subscribers.any?(&EqualTo[observer])
|
62
|
+
end
|
63
|
+
|
64
|
+
def attach(*args)
|
65
|
+
options = args.last.is_a?(Hash) ? args.pop : EMPTY_HASH
|
66
|
+
|
67
|
+
Utils::Arrays.flatten_and_compact(args).each do |observer|
|
68
|
+
@subscribers << MapSubscriber[observer, options] unless included?(observer)
|
69
|
+
end
|
70
|
+
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
def detach(*args)
|
75
|
+
Utils::Arrays.flatten_and_compact(args).each do |observer|
|
76
|
+
@subscribers.delete_if(&EqualTo[observer])
|
77
|
+
end
|
78
|
+
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
def on(options = EMPTY_HASH)
|
83
|
+
event, callable, with, context = options[:event], options[:call], options[:with], options[:context]
|
84
|
+
|
85
|
+
return self unless event.is_a?(Symbol) && callable.respond_to?(:call)
|
86
|
+
|
87
|
+
@subscribers << [:callable, event, [callable, with, context]] unless included?(callable)
|
88
|
+
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
def notify(*events, data: nil)
|
93
|
+
broadcast_if_subject_changed(Event::Names.fetch(events), data)
|
94
|
+
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
def notify!(*events, data: nil)
|
99
|
+
broadcast(Event::Names.fetch(events), data)
|
100
|
+
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
CALL_EVENT = [:call].freeze
|
105
|
+
|
106
|
+
def call(*events, data: nil)
|
107
|
+
broadcast_if_subject_changed(Event::Names[events, default: CALL_EVENT], data)
|
108
|
+
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
def call!(*events, data: nil)
|
113
|
+
broadcast(Event::Names[events, default: CALL_EVENT], data)
|
114
|
+
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
def inspect
|
119
|
+
subs = @subscribers.empty? ? @subscribers : @subscribers.map(&GetObserver)
|
120
|
+
|
121
|
+
'<#%s @subject=%s @subject_changed=%p @subscribers=%p>' % [self.class, @subject, @subject_changed, subs]
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def broadcast_if_subject_changed(events, data = nil)
|
127
|
+
return unless subject_changed?
|
128
|
+
|
129
|
+
broadcast(events, data)
|
130
|
+
|
131
|
+
subject_changed(false)
|
132
|
+
end
|
133
|
+
|
134
|
+
def broadcast(event_names, data)
|
135
|
+
return if @subscribers.empty?
|
136
|
+
|
137
|
+
event_names.each do |event_name|
|
138
|
+
@subscribers.each do |strategy, observer, context|
|
139
|
+
case strategy
|
140
|
+
when :observer then notify_observer(observer, event_name, context, data)
|
141
|
+
when :callable then notify_callable(observer, event_name, context, data)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def notify_observer(observer, event_name, context, data)
|
148
|
+
return unless observer.respond_to?(event_name)
|
149
|
+
|
150
|
+
handler = observer.is_a?(Proc) ? observer : observer.method(event_name)
|
151
|
+
|
152
|
+
return handler.call(@subject) if handler.arity == 1
|
153
|
+
|
154
|
+
handler.call(@subject, Event.new(event_name, @subject, context, data))
|
155
|
+
end
|
156
|
+
|
157
|
+
def notify_callable(expected_event_name, event_name, opt, data)
|
158
|
+
return if expected_event_name != event_name
|
159
|
+
|
160
|
+
callable, with, context = opt[0], opt[1], opt[2]
|
161
|
+
callable_arg =
|
162
|
+
if with && !with.is_a?(Proc)
|
163
|
+
with
|
164
|
+
else
|
165
|
+
event = Event.new(event_name, @subject, context, data)
|
166
|
+
|
167
|
+
with.is_a?(Proc) ? with.call(event) : event
|
168
|
+
end
|
169
|
+
|
170
|
+
callable.call(callable_arg)
|
171
|
+
end
|
172
|
+
|
173
|
+
private_constant :EMPTY_HASH, :INVALID_BOOLEAN_MSG, :CALL_EVENT
|
174
|
+
private_constant :MapSubscriber, :MapSubscribers, :GetObserver, :EqualTo
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
end
|
@@ -4,10 +4,10 @@ module Micro
|
|
4
4
|
module Observers
|
5
5
|
|
6
6
|
module Utils
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
module Arrays
|
8
|
+
def self.flatten_and_compact(value)
|
9
|
+
Array(value).flatten.tap(&:compact!)
|
10
|
+
end
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
data/test.sh
ADDED
data/u-observers.gemspec
CHANGED
@@ -10,7 +10,6 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.description = %q{Simple and powerful implementation of the observer pattern.}
|
11
11
|
spec.homepage = 'https://github.com/serradura/u-observers'
|
12
12
|
spec.license = 'MIT'
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new('>= 2.2.0')
|
14
13
|
|
15
14
|
spec.metadata['homepage_uri'] = spec.homepage
|
16
15
|
spec.metadata['source_code_uri'] = 'https://github.com/serradura/u-observers'
|
@@ -24,4 +23,9 @@ Gem::Specification.new do |spec|
|
|
24
23
|
spec.bindir = 'exe'
|
25
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
25
|
spec.require_paths = ['lib']
|
26
|
+
|
27
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.2.0')
|
28
|
+
|
29
|
+
spec.add_development_dependency 'bundler'
|
30
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
27
31
|
end
|
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: u-observers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rodrigo Serradura
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
12
|
-
dependencies:
|
11
|
+
date: 2020-10-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '13.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '13.0'
|
13
41
|
description: Simple and powerful implementation of the observer pattern.
|
14
42
|
email:
|
15
43
|
- rodrigo.serradura@gmail.com
|
@@ -18,20 +46,29 @@ extensions: []
|
|
18
46
|
extra_rdoc_files: []
|
19
47
|
files:
|
20
48
|
- ".gitignore"
|
49
|
+
- ".tool-versions"
|
50
|
+
- ".travis.sh"
|
21
51
|
- ".travis.yml"
|
22
52
|
- CODE_OF_CONDUCT.md
|
23
53
|
- Gemfile
|
24
54
|
- LICENSE.txt
|
25
55
|
- README.md
|
56
|
+
- README.pt-BR.md
|
26
57
|
- Rakefile
|
27
58
|
- bin/console
|
28
59
|
- bin/setup
|
29
60
|
- lib/micro/observers.rb
|
30
|
-
- lib/micro/observers/
|
31
|
-
- lib/micro/observers/
|
61
|
+
- lib/micro/observers/event.rb
|
62
|
+
- lib/micro/observers/event/names.rb
|
63
|
+
- lib/micro/observers/for/active_model.rb
|
64
|
+
- lib/micro/observers/for/active_record.rb
|
65
|
+
- lib/micro/observers/set.rb
|
32
66
|
- lib/micro/observers/utils.rb
|
33
67
|
- lib/micro/observers/version.rb
|
34
68
|
- lib/u-observers.rb
|
69
|
+
- lib/u-observers/for/active_model.rb
|
70
|
+
- lib/u-observers/for/active_record.rb
|
71
|
+
- test.sh
|
35
72
|
- u-observers.gemspec
|
36
73
|
homepage: https://github.com/serradura/u-observers
|
37
74
|
licenses:
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Micro
|
4
|
-
module Observers
|
5
|
-
|
6
|
-
module EventsOrActions
|
7
|
-
DEFAULTS = [:call]
|
8
|
-
|
9
|
-
def self.[](value)
|
10
|
-
values = Utils.compact_array(value)
|
11
|
-
|
12
|
-
values.empty? ? DEFAULTS : values
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.fetch_actions(hash)
|
16
|
-
return self[hash[:actions] || hash.fetch(:action)] if hash.is_a?(Hash)
|
17
|
-
|
18
|
-
raise ArgumentError, 'expected a hash with the key :action or :actions'
|
19
|
-
end
|
20
|
-
|
21
|
-
private_constant :DEFAULTS
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|