servus 0.5.0 → 0.5.2
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/lib/servus/events/emitter.rb +68 -12
- data/lib/servus/testing/matchers.rb +5 -0
- data/lib/servus/version.rb +1 -1
- data/lib/servus.rb +1 -2
- metadata +2 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 15cec1ebe831437428e84374b7b7a83cc34c1f4cbcdc13bfe1c847eca5c1c9b3
|
|
4
|
+
data.tar.gz: 2b371d1069a549fab5af3de5aca80d8be029850cc0c1e3378e7643c742b917dd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a66d2a07c3c564148e612fac96ab22e350c9483938226a495cc7b97b3b96ad979a4dba26b3bc2b5090bb3fc4c3c5016647f186f34cbe93bdc9f8f0f329205572
|
|
7
|
+
data.tar.gz: 56d23b1caac58e6d1c62062b80ecd85bb50784f034709fb5228d742e5de0c76e6a096bf59d45d67d84b0e024e2a0ba7f8f283db2027e543aa5543ad383eee2b3
|
|
@@ -33,12 +33,15 @@ module Servus
|
|
|
33
33
|
# Declares an event that this service will emit.
|
|
34
34
|
#
|
|
35
35
|
# Events are automatically emitted when the service completes with the specified
|
|
36
|
-
# trigger condition (:success, :failure, or :error). Use the `with` option
|
|
37
|
-
# provide a custom payload builder
|
|
36
|
+
# trigger condition (:success, :failure, or :error). Use the `with` option or a
|
|
37
|
+
# block to provide a custom payload builder. Use `if` or `unless` to gate emission
|
|
38
|
+
# on a runtime condition.
|
|
38
39
|
#
|
|
39
40
|
# @param event_name [Symbol] the name of the event to emit
|
|
40
|
-
# @param on [Symbol] when to emit (:success, :failure, or :error)
|
|
41
|
-
# @
|
|
41
|
+
# @param on [Symbol] when to emit (:success, :failure, or :error!)
|
|
42
|
+
# @option options [Symbol, nil] :with instance method name for building the payload
|
|
43
|
+
# @option options [Proc, Symbol, nil] :if condition proc or method name; event only emits when truthy
|
|
44
|
+
# @option options [Proc, Symbol, nil] :unless condition proc or method name; event only emits when falsy
|
|
42
45
|
# @yield [result] optional block for building the payload
|
|
43
46
|
# @yieldparam result [Servus::Support::Response] the service result
|
|
44
47
|
# @yieldreturn [Hash] the event payload
|
|
@@ -67,6 +70,22 @@ module Servus
|
|
|
67
70
|
# end
|
|
68
71
|
# end
|
|
69
72
|
#
|
|
73
|
+
# @example Conditional emission with if: lambda
|
|
74
|
+
# class CreateUser < Servus::Base
|
|
75
|
+
# emits :premium_user_created, on: :success, if: ->(result) { result.data[:plan] == :premium }
|
|
76
|
+
# end
|
|
77
|
+
#
|
|
78
|
+
# @example Conditional emission with unless: method reference
|
|
79
|
+
# class CreateUser < Servus::Base
|
|
80
|
+
# emits :user_created, on: :success, unless: :suppressed?
|
|
81
|
+
#
|
|
82
|
+
# private
|
|
83
|
+
#
|
|
84
|
+
# def suppressed?(result)
|
|
85
|
+
# result.data[:suppressed]
|
|
86
|
+
# end
|
|
87
|
+
# end
|
|
88
|
+
#
|
|
70
89
|
# @note Best Practice: Services should typically emit ONE event per trigger
|
|
71
90
|
# that represents their core concern. Multiple downstream reactions should
|
|
72
91
|
# be coordinated by Event classes, not by emitting multiple events
|
|
@@ -87,7 +106,7 @@ module Servus
|
|
|
87
106
|
#
|
|
88
107
|
# @see Servus::Events::Bus
|
|
89
108
|
# @see Servus::Event
|
|
90
|
-
def emits(event_name, on:,
|
|
109
|
+
def emits(event_name, on:, **options, &block)
|
|
91
110
|
valid_triggers = %i[success failure error!]
|
|
92
111
|
|
|
93
112
|
unless valid_triggers.include?(on)
|
|
@@ -95,10 +114,7 @@ module Servus
|
|
|
95
114
|
end
|
|
96
115
|
|
|
97
116
|
@event_emissions ||= { success: [], failure: [], error!: [] }
|
|
98
|
-
@event_emissions[on] <<
|
|
99
|
-
event_name: event_name,
|
|
100
|
-
payload_builder: block || with
|
|
101
|
-
}
|
|
117
|
+
@event_emissions[on] << build_emission(event_name, options, block)
|
|
102
118
|
end
|
|
103
119
|
|
|
104
120
|
# Returns all event emissions declared for this service.
|
|
@@ -116,6 +132,17 @@ module Servus
|
|
|
116
132
|
def emissions_for(trigger)
|
|
117
133
|
event_emissions[trigger] || []
|
|
118
134
|
end
|
|
135
|
+
|
|
136
|
+
private
|
|
137
|
+
|
|
138
|
+
def build_emission(event_name, options, block)
|
|
139
|
+
{
|
|
140
|
+
event_name: event_name,
|
|
141
|
+
if_condition: options[:if],
|
|
142
|
+
unless_condition: options[:unless],
|
|
143
|
+
payload_builder: block || options[:with]
|
|
144
|
+
}
|
|
145
|
+
end
|
|
119
146
|
end
|
|
120
147
|
|
|
121
148
|
# Emits events for a specific trigger with the given result.
|
|
@@ -126,6 +153,8 @@ module Servus
|
|
|
126
153
|
# @api private
|
|
127
154
|
def emit_events_for(trigger, result)
|
|
128
155
|
self.class.emissions_for(trigger).each do |emission|
|
|
156
|
+
next unless emission_condition_met?(emission, result)
|
|
157
|
+
|
|
129
158
|
payload = build_event_payload(emission, result)
|
|
130
159
|
validate_event_payload!(emission[:event_name], payload)
|
|
131
160
|
Servus::Events::Bus.emit(emission[:event_name], payload)
|
|
@@ -133,7 +162,35 @@ module Servus
|
|
|
133
162
|
end
|
|
134
163
|
|
|
135
164
|
# Instance methods for emitting events during service execution
|
|
136
|
-
|
|
165
|
+
|
|
166
|
+
# Returns true when all declared conditions on the emission pass.
|
|
167
|
+
#
|
|
168
|
+
# @param emission [Hash] the emission configuration
|
|
169
|
+
# @param result [Servus::Support::Response] the service result
|
|
170
|
+
# @return [Boolean]
|
|
171
|
+
# @api private
|
|
172
|
+
def emission_condition_met?(emission, result)
|
|
173
|
+
if_condition = emission[:if_condition]
|
|
174
|
+
unless_condition = emission[:unless_condition]
|
|
175
|
+
|
|
176
|
+
return false if if_condition && !evaluate_emission_condition(if_condition, result)
|
|
177
|
+
return false if unless_condition && evaluate_emission_condition(unless_condition, result)
|
|
178
|
+
|
|
179
|
+
true
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Evaluates a single emission condition — either a Proc/lambda or a Symbol method reference.
|
|
183
|
+
#
|
|
184
|
+
# Both forms receive the result object so conditions can inspect result.data,
|
|
185
|
+
# result.error, result.success?, etc.
|
|
186
|
+
#
|
|
187
|
+
# @param condition [Proc, Symbol] the condition to evaluate
|
|
188
|
+
# @param result [Servus::Support::Response] the service result
|
|
189
|
+
# @return [Object] truthy or falsy value
|
|
190
|
+
# @api private
|
|
191
|
+
def evaluate_emission_condition(condition, result)
|
|
192
|
+
condition.is_a?(Proc) ? instance_exec(result, &condition) : send(condition, result)
|
|
193
|
+
end
|
|
137
194
|
|
|
138
195
|
# Validates the payload against the Event class's schema registered for the event.
|
|
139
196
|
#
|
|
@@ -159,8 +216,7 @@ module Servus
|
|
|
159
216
|
builder = emission[:payload_builder]
|
|
160
217
|
|
|
161
218
|
if builder.is_a?(Proc)
|
|
162
|
-
|
|
163
|
-
builder.call(result)
|
|
219
|
+
instance_exec(result, &builder)
|
|
164
220
|
elsif builder.is_a?(Symbol)
|
|
165
221
|
# Method-based payload builder
|
|
166
222
|
send(builder, result)
|
|
@@ -55,6 +55,11 @@ RSpec::Matchers.define :emit_event do |event_class_or_symbol|
|
|
|
55
55
|
"got: #{@matching_event[:payload].inspect}"
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
|
+
|
|
59
|
+
failure_message_when_negated do
|
|
60
|
+
"expected event :#{@event_name} not to be emitted, but it was.\n" \
|
|
61
|
+
"Payload: #{@matching_event[:payload].inspect}"
|
|
62
|
+
end
|
|
58
63
|
end
|
|
59
64
|
|
|
60
65
|
# Matcher for asserting service invocation
|
data/lib/servus/version.rb
CHANGED
data/lib/servus.rb
CHANGED
metadata
CHANGED
|
@@ -1,29 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: servus
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sebastian Scholl
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
-
- !ruby/object:Gem::Dependency
|
|
14
|
-
name: active_model_serializers
|
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
|
16
|
-
requirements:
|
|
17
|
-
- - "~>"
|
|
18
|
-
- !ruby/object:Gem::Version
|
|
19
|
-
version: 0.10.0
|
|
20
|
-
type: :runtime
|
|
21
|
-
prerelease: false
|
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
-
requirements:
|
|
24
|
-
- - "~>"
|
|
25
|
-
- !ruby/object:Gem::Version
|
|
26
|
-
version: 0.10.0
|
|
27
13
|
- !ruby/object:Gem::Dependency
|
|
28
14
|
name: activesupport
|
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|