servus 0.1.5 → 0.2.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.
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Servus
4
+ module Support
5
+ # Resolves message templates with interpolation support.
6
+ #
7
+ # Handles multiple template formats:
8
+ # - String: Static or with %{key} / %<key>s interpolation
9
+ # - Symbol: I18n key lookup with fallback
10
+ # - Hash: Inline translations keyed by locale
11
+ # - Proc: Dynamic template evaluated at runtime
12
+ #
13
+ # @example Basic string interpolation
14
+ # resolver = MessageResolver.new(
15
+ # template: 'Hello, %<name>s!',
16
+ # data: { name: 'World' }
17
+ # )
18
+ # resolver.resolve # => "Hello, World!"
19
+ #
20
+ # @example With I18n symbol
21
+ # resolver = MessageResolver.new(template: :greeting)
22
+ # resolver.resolve # => I18n.t('greeting') or "Greeting" fallback
23
+ #
24
+ # @example With inline translations
25
+ # resolver = MessageResolver.new(
26
+ # template: { en: 'Hello', es: 'Hola' }
27
+ # )
28
+ # resolver.resolve # => "Hello" (or "Hola" if I18n.locale == :es)
29
+ #
30
+ # @example With proc and context
31
+ # resolver = MessageResolver.new(
32
+ # template: -> { "Balance: #{balance}" }
33
+ # )
34
+ # resolver.resolve(context: account) # => "Balance: 100"
35
+ #
36
+ class MessageResolver
37
+ # @return [String, Symbol, Hash, Proc, nil] the message template
38
+ attr_reader :template
39
+
40
+ # @return [Hash, Proc, nil] the interpolation data or data-providing block
41
+ attr_reader :data
42
+
43
+ # @return [String, nil] the I18n scope prefix for symbol templates
44
+ attr_reader :i18n_scope
45
+
46
+ # Creates a new message resolver.
47
+ #
48
+ # @param template [String, Symbol, Hash, Proc, nil] the message template
49
+ # @param data [Hash, Proc, nil] interpolation data or block returning data
50
+ # @param i18n_scope [String] prefix for I18n lookups (default: nil)
51
+ def initialize(template:, data: nil, i18n_scope: nil)
52
+ @template = template
53
+ @data = data
54
+ @i18n_scope = i18n_scope
55
+ end
56
+
57
+ # Resolves the template to a final string.
58
+ #
59
+ # @param context [Object, nil] object for evaluating Proc templates/data blocks
60
+ # @return [String] the resolved and interpolated message
61
+ def resolve(context: nil)
62
+ resolved_template = resolve_template(context)
63
+ resolved_data = resolve_data(context)
64
+
65
+ interpolate(resolved_template, resolved_data)
66
+ end
67
+
68
+ private
69
+
70
+ # Resolves the template to a string based on its type.
71
+ #
72
+ # @param context [Object, nil] evaluation context for Proc templates
73
+ # @return [String] the resolved template string
74
+ def resolve_template(context)
75
+ case template
76
+ when Symbol then resolve_i18n_template
77
+ when Proc then resolve_proc_template(context)
78
+ when Hash then resolve_locale_template
79
+ else template.to_s
80
+ end
81
+ end
82
+
83
+ # Resolves I18n symbol template with fallback.
84
+ #
85
+ # @return [String] the translated string or humanized fallback
86
+ def resolve_i18n_template
87
+ key = build_i18n_key
88
+ fallback = humanize_symbol(template)
89
+
90
+ if defined?(I18n)
91
+ I18n.t(key, default: fallback)
92
+ else
93
+ fallback
94
+ end
95
+ end
96
+
97
+ # Builds the full I18n key from template and scope.
98
+ #
99
+ # @return [String, Symbol] the I18n lookup key
100
+ def build_i18n_key
101
+ return template if template.to_s.include?('.')
102
+ return template unless i18n_scope
103
+
104
+ "#{i18n_scope}.#{template}"
105
+ end
106
+
107
+ # Converts a symbol to a human-readable string.
108
+ #
109
+ # @param sym [Symbol] the symbol to humanize
110
+ # @return [String] humanized string
111
+ def humanize_symbol(sym)
112
+ sym.to_s.tr('_', ' ').capitalize
113
+ end
114
+
115
+ # Evaluates a Proc template in the given context.
116
+ #
117
+ # @param context [Object, nil] the evaluation context
118
+ # @return [String] the proc result as string
119
+ def resolve_proc_template(context)
120
+ result = context ? context.instance_exec(&template) : template.call
121
+ result.to_s
122
+ end
123
+
124
+ # Resolves a Hash template by current locale.
125
+ #
126
+ # @return [String] the localized string
127
+ def resolve_locale_template
128
+ locale = current_locale
129
+ (template[locale] || template[:en] || template.values.first).to_s
130
+ end
131
+
132
+ # Returns the current I18n locale or :en.
133
+ #
134
+ # @return [Symbol] the current locale
135
+ def current_locale
136
+ defined?(I18n) ? I18n.locale : :en
137
+ end
138
+
139
+ # Resolves data to a Hash for interpolation.
140
+ #
141
+ # @param context [Object, nil] evaluation context for Proc data
142
+ # @return [Hash] the interpolation data
143
+ def resolve_data(context)
144
+ case data
145
+ when Proc then context ? context.instance_exec(&data) : data.call
146
+ when Hash then data
147
+ else {}
148
+ end
149
+ end
150
+
151
+ # Interpolates data into the template string.
152
+ #
153
+ # @param template_str [String] the template with placeholders
154
+ # @param data_hash [Hash] the interpolation data
155
+ # @return [String] the interpolated string
156
+ def interpolate(template_str, data_hash)
157
+ return template_str if data_hash.empty?
158
+
159
+ template_str % data_hash
160
+ rescue KeyError, ArgumentError => e
161
+ warn "MessageResolver interpolation failed: #{e.message}"
162
+ template_str
163
+ end
164
+ end
165
+ end
166
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Servus
4
- VERSION = '0.1.5'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/servus.rb CHANGED
@@ -24,6 +24,7 @@ require_relative 'servus/support/response'
24
24
  require_relative 'servus/support/validator'
25
25
  require_relative 'servus/support/errors'
26
26
  require_relative 'servus/support/rescuer'
27
+ require_relative 'servus/support/message_resolver'
27
28
 
28
29
  # Events
29
30
  require_relative 'servus/events/errors'
@@ -31,6 +32,10 @@ require_relative 'servus/events/bus'
31
32
  require_relative 'servus/events/emitter'
32
33
  require_relative 'servus/event_handler'
33
34
 
35
+ # Guards (guards.rb loads defaults based on config)
36
+ require_relative 'servus/guard'
37
+ require_relative 'servus/guards'
38
+
34
39
  # Core
35
40
  require_relative 'servus/version'
36
41
  require_relative 'servus/base'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: servus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Scholl
@@ -88,21 +88,16 @@ files:
88
88
  - LICENSE.txt
89
89
  - READme.md
90
90
  - Rakefile
91
- - builds/servus-0.0.1.gem
92
- - builds/servus-0.1.1.gem
93
- - builds/servus-0.1.2.gem
94
- - builds/servus-0.1.3.gem
95
- - builds/servus-0.1.4.gem
96
- - builds/servus-0.1.5.gem
97
91
  - docs/core/1_overview.md
98
92
  - docs/core/2_architecture.md
99
93
  - docs/core/3_service_objects.md
100
- - docs/current_focus.md
101
94
  - docs/features/1_schema_validation.md
102
95
  - docs/features/2_error_handling.md
103
96
  - docs/features/3_async_execution.md
104
97
  - docs/features/4_logging.md
105
98
  - docs/features/5_event_bus.md
99
+ - docs/features/6_guards.md
100
+ - docs/features/guards_naming_convention.md
106
101
  - docs/guides/1_common_patterns.md
107
102
  - docs/guides/2_migration_guide.md
108
103
  - docs/integration/1_configuration.md
@@ -189,6 +184,9 @@ files:
189
184
  - lib/generators/servus/event_handler/event_handler_generator.rb
190
185
  - lib/generators/servus/event_handler/templates/handler.rb.erb
191
186
  - lib/generators/servus/event_handler/templates/handler_spec.rb.erb
187
+ - lib/generators/servus/guard/guard_generator.rb
188
+ - lib/generators/servus/guard/templates/guard.rb.erb
189
+ - lib/generators/servus/guard/templates/guard_spec.rb.erb
192
190
  - lib/generators/servus/service/service_generator.rb
193
191
  - lib/generators/servus/service/templates/arguments.json.erb
194
192
  - lib/generators/servus/service/templates/result.json.erb
@@ -205,10 +203,17 @@ files:
205
203
  - lib/servus/extensions/async/errors.rb
206
204
  - lib/servus/extensions/async/ext.rb
207
205
  - lib/servus/extensions/async/job.rb
206
+ - lib/servus/guard.rb
207
+ - lib/servus/guards.rb
208
+ - lib/servus/guards/falsey_guard.rb
209
+ - lib/servus/guards/presence_guard.rb
210
+ - lib/servus/guards/state_guard.rb
211
+ - lib/servus/guards/truthy_guard.rb
208
212
  - lib/servus/helpers/controller_helpers.rb
209
213
  - lib/servus/railtie.rb
210
214
  - lib/servus/support/errors.rb
211
215
  - lib/servus/support/logger.rb
216
+ - lib/servus/support/message_resolver.rb
212
217
  - lib/servus/support/rescuer.rb
213
218
  - lib/servus/support/response.rb
214
219
  - lib/servus/support/validator.rb
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file