smart_message 0.0.8 → 0.0.9

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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.irbrc +24 -0
  4. data/CHANGELOG.md +96 -0
  5. data/Gemfile.lock +6 -1
  6. data/README.md +289 -15
  7. data/docs/README.md +3 -1
  8. data/docs/addressing.md +119 -13
  9. data/docs/architecture.md +68 -0
  10. data/docs/dead_letter_queue.md +673 -0
  11. data/docs/dispatcher.md +87 -0
  12. data/docs/examples.md +59 -1
  13. data/docs/getting-started.md +8 -1
  14. data/docs/logging.md +382 -326
  15. data/docs/message_filtering.md +451 -0
  16. data/examples/01_point_to_point_orders.rb +54 -53
  17. data/examples/02_publish_subscribe_events.rb +14 -10
  18. data/examples/03_many_to_many_chat.rb +16 -8
  19. data/examples/04_redis_smart_home_iot.rb +20 -10
  20. data/examples/05_proc_handlers.rb +12 -11
  21. data/examples/06_custom_logger_example.rb +95 -100
  22. data/examples/07_error_handling_scenarios.rb +4 -2
  23. data/examples/08_entity_addressing_basic.rb +18 -6
  24. data/examples/08_entity_addressing_with_filtering.rb +27 -9
  25. data/examples/09_dead_letter_queue_demo.rb +559 -0
  26. data/examples/09_regex_filtering_microservices.rb +407 -0
  27. data/examples/10_header_block_configuration.rb +263 -0
  28. data/examples/11_global_configuration_example.rb +219 -0
  29. data/examples/README.md +102 -0
  30. data/examples/dead_letters.jsonl +12 -0
  31. data/examples/performance_metrics/benchmark_results_ractor_20250818_205603.json +135 -0
  32. data/examples/performance_metrics/benchmark_results_ractor_20250818_205831.json +135 -0
  33. data/examples/performance_metrics/benchmark_results_test_20250818_204942.json +130 -0
  34. data/examples/performance_metrics/benchmark_results_threadpool_20250818_204942.json +130 -0
  35. data/examples/performance_metrics/benchmark_results_threadpool_20250818_204959.json +130 -0
  36. data/examples/performance_metrics/benchmark_results_threadpool_20250818_205044.json +130 -0
  37. data/examples/performance_metrics/benchmark_results_threadpool_20250818_205109.json +130 -0
  38. data/examples/performance_metrics/benchmark_results_threadpool_20250818_205252.json +130 -0
  39. data/examples/performance_metrics/benchmark_results_unknown_20250819_172852.json +130 -0
  40. data/examples/performance_metrics/compare_benchmarks.rb +519 -0
  41. data/examples/performance_metrics/dead_letters.jsonl +3100 -0
  42. data/examples/performance_metrics/performance_benchmark.rb +344 -0
  43. data/examples/show_logger.rb +367 -0
  44. data/examples/show_me.rb +145 -0
  45. data/examples/temp.txt +94 -0
  46. data/examples/tmux_chat/bot_agent.rb +4 -2
  47. data/examples/tmux_chat/human_agent.rb +4 -2
  48. data/examples/tmux_chat/room_monitor.rb +4 -2
  49. data/examples/tmux_chat/shared_chat_system.rb +6 -3
  50. data/lib/smart_message/addressing.rb +259 -0
  51. data/lib/smart_message/base.rb +121 -599
  52. data/lib/smart_message/circuit_breaker.rb +2 -1
  53. data/lib/smart_message/configuration.rb +199 -0
  54. data/lib/smart_message/dead_letter_queue.rb +27 -10
  55. data/lib/smart_message/dispatcher.rb +90 -49
  56. data/lib/smart_message/header.rb +5 -0
  57. data/lib/smart_message/logger/base.rb +21 -1
  58. data/lib/smart_message/logger/default.rb +88 -138
  59. data/lib/smart_message/logger/lumberjack.rb +324 -0
  60. data/lib/smart_message/logger/null.rb +81 -0
  61. data/lib/smart_message/logger.rb +17 -9
  62. data/lib/smart_message/messaging.rb +100 -0
  63. data/lib/smart_message/plugins.rb +132 -0
  64. data/lib/smart_message/serializer/base.rb +25 -8
  65. data/lib/smart_message/serializer/json.rb +5 -4
  66. data/lib/smart_message/subscription.rb +193 -0
  67. data/lib/smart_message/transport/base.rb +72 -41
  68. data/lib/smart_message/transport/memory_transport.rb +7 -5
  69. data/lib/smart_message/transport/redis_transport.rb +15 -45
  70. data/lib/smart_message/transport/stdout_transport.rb +18 -8
  71. data/lib/smart_message/transport.rb +1 -34
  72. data/lib/smart_message/utilities.rb +142 -0
  73. data/lib/smart_message/version.rb +1 -1
  74. data/lib/smart_message/versioning.rb +85 -0
  75. data/lib/smart_message/wrapper.rb.bak +132 -0
  76. data/lib/smart_message.rb +74 -28
  77. data/smart_message.gemspec +3 -0
  78. metadata +76 -3
  79. data/lib/smart_message/serializer.rb +0 -10
  80. data/lib/smart_message/wrapper.rb +0 -43
@@ -0,0 +1,407 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/09_regex_filtering_microservices.rb
3
+
4
+ require_relative '../lib/smart_message'
5
+
6
+ # Example: Advanced Regex Filtering for Microservices Architecture
7
+ #
8
+ # This example demonstrates how to use SmartMessage's regex filtering capabilities
9
+ # to build a sophisticated microservices routing system that supports:
10
+ # - Environment-based routing (dev, staging, prod)
11
+ # - Service pattern routing (payment-*, api-*, admin-*)
12
+ # - Mixed exact and pattern matching
13
+ # - Complex multi-criteria filtering
14
+
15
+ puts "šŸ” SmartMessage Regex Filtering Demo"
16
+ puts "=" * 50
17
+
18
+ # Base message class for the microservices ecosystem
19
+ class MicroserviceMessage < SmartMessage::Base
20
+ version 1
21
+
22
+ # Set default 'from' to avoid header requirement issues
23
+ from 'microservice-demo'
24
+
25
+ property :service_id, required: true, description: "Originating service identifier"
26
+ property :message_type, required: true, description: "Type of message being sent"
27
+ property :data, description: "Message payload data"
28
+ property :environment, default: 'dev', description: "Target environment"
29
+ property :timestamp, default: -> { Time.now.iso8601 }, description: "Message timestamp"
30
+
31
+ # Configure with STDOUT transport for demo visibility
32
+ config do
33
+ transport SmartMessage::Transport::StdoutTransport.new(loopback: true)
34
+ serializer SmartMessage::Serializer::JSON.new
35
+ end
36
+ end
37
+
38
+ # Service-specific message types
39
+ class PaymentMessage < MicroserviceMessage
40
+ description "Payment processing and transaction messages"
41
+
42
+ property :transaction_id, required: true
43
+ property :amount, required: true
44
+ property :currency, default: 'USD'
45
+
46
+ def self.process(wrapper)
47
+ header = wrapper._sm_header
48
+ payload = wrapper._sm_payload
49
+ msg_data = JSON.parse(payload)
50
+ puts "šŸ’³ PaymentMessage processed by #{self.name}"
51
+ puts " From: #{header.from} → To: #{header.to}"
52
+ puts " Transaction: #{msg_data['transaction_id']} (#{msg_data['currency']} #{msg_data['amount']})"
53
+ puts " Environment: #{msg_data['environment']}"
54
+ puts
55
+ end
56
+ end
57
+
58
+ class OrderMessage < MicroserviceMessage
59
+ description "Order management and fulfillment messages"
60
+
61
+ property :order_id, required: true
62
+ property :customer_id, required: true
63
+ property :status, default: 'pending'
64
+
65
+ def self.process(wrapper)
66
+ header = wrapper._sm_header
67
+ payload = wrapper._sm_payload
68
+ msg_data = JSON.parse(payload)
69
+ puts "šŸ“¦ OrderMessage processed by #{self.name}"
70
+ puts " From: #{header.from} → To: #{header.to}"
71
+ puts " Order: #{msg_data['order_id']} for customer #{msg_data['customer_id']}"
72
+ puts " Status: #{msg_data['status']}, Environment: #{msg_data['environment']}"
73
+ puts
74
+ end
75
+ end
76
+
77
+ class AlertMessage < MicroserviceMessage
78
+ description "System monitoring and alerting messages"
79
+
80
+ property :alert_level, required: true
81
+ property :component, required: true
82
+ property :description, required: true
83
+
84
+ def self.process(wrapper)
85
+ header = wrapper._sm_header
86
+ payload = wrapper._sm_payload
87
+ msg_data = JSON.parse(payload)
88
+ puts "🚨 AlertMessage processed by #{self.name}"
89
+ puts " From: #{header.from} → To: #{header.to}"
90
+ puts " Level: #{msg_data['alert_level']} - Component: #{msg_data['component']}"
91
+ puts " Description: #{msg_data['description']}"
92
+ puts " Environment: #{msg_data['environment']}"
93
+ puts
94
+ end
95
+ end
96
+
97
+ # Demonstration of different regex filtering patterns
98
+ def demonstrate_filtering_patterns
99
+ puts "\nšŸŽÆ Setting up subscription filters..."
100
+
101
+ # Clear any existing subscriptions
102
+ [PaymentMessage, OrderMessage, AlertMessage].each(&:unsubscribe!)
103
+
104
+ # 1. Environment-based filtering
105
+ puts "\n1ļøāƒ£ Environment-based filtering:"
106
+ puts " - Development services receive dev/staging messages"
107
+ puts " - Production services receive only prod messages"
108
+
109
+ PaymentMessage.subscribe("PaymentMessage.process_dev", to: /^(dev|staging)-.*/)
110
+ PaymentMessage.subscribe("PaymentMessage.process_prod", to: /^prod-.*/)
111
+
112
+ # 2. Service pattern filtering
113
+ puts "\n2ļøāƒ£ Service pattern filtering:"
114
+ puts " - Order services receive messages from payment services"
115
+ puts " - Alert services receive messages from any monitoring system"
116
+
117
+ OrderMessage.subscribe("OrderMessage.process", from: /^payment-.*/)
118
+ AlertMessage.subscribe("AlertMessage.process", from: /^(monitoring|health|system)-.*/)
119
+
120
+ # 3. Mixed exact and pattern matching
121
+ puts "\n3ļøāƒ£ Mixed filtering (exact + patterns):"
122
+ puts " - Specific services + pattern matching"
123
+
124
+ # Alert service receives from admin, plus any system-* services
125
+ AlertMessage.subscribe("AlertMessage.process_admin", from: ['admin', /^system-.*/, 'security'])
126
+
127
+ # 4. Complex multi-criteria filtering
128
+ puts "\n4ļøāƒ£ Complex multi-criteria filtering:"
129
+ puts " - Admin services to production environments only"
130
+
131
+ OrderMessage.subscribe("OrderMessage.process_admin_prod",
132
+ from: /^admin-.*/,
133
+ to: /^prod-.*/)
134
+
135
+ # 5. Broadcast + directed message filtering
136
+ puts "\n5ļøāƒ£ Broadcast + directed filtering:"
137
+ puts " - Receive broadcast messages OR messages directed to api services"
138
+
139
+ PaymentMessage.subscribe("PaymentMessage.process_api",
140
+ broadcast: true,
141
+ to: /^api-.*/)
142
+
143
+ puts "\nāœ… All subscription filters configured!"
144
+ end
145
+
146
+ # Simulate microservices sending messages
147
+ def simulate_microservice_traffic
148
+ puts "\nšŸ“” Simulating microservice message traffic..."
149
+ puts "=" * 50
150
+
151
+ # Sleep between messages for readability
152
+ delay = 0.5
153
+
154
+ # 1. Environment-based routing examples
155
+ puts "\nšŸŒ Environment-based routing examples:"
156
+
157
+ payment_msg = PaymentMessage.new(
158
+ service_id: "payment-core",
159
+ message_type: "transaction_complete",
160
+ transaction_id: "TXN-001",
161
+ amount: 99.99,
162
+ data: { merchant: "Online Store" },
163
+ environment: "dev"
164
+ )
165
+ payment_msg.from('payment-service')
166
+ payment_msg.to('dev-payment-processor')
167
+ payment_msg.publish
168
+ sleep(delay)
169
+
170
+ payment_msg = PaymentMessage.new(
171
+ service_id: "payment-core",
172
+ message_type: "transaction_complete",
173
+ transaction_id: "TXN-002",
174
+ amount: 299.99,
175
+ data: { merchant: "Enterprise Store" },
176
+ environment: "prod"
177
+ )
178
+ payment_msg.from('payment-service')
179
+ payment_msg.to('prod-payment-processor')
180
+ payment_msg.publish
181
+ sleep(delay)
182
+
183
+ # 2. Service pattern routing examples
184
+ puts "\nšŸ”„ Service pattern routing examples:"
185
+
186
+ order_msg = OrderMessage.new(
187
+ service_id: "order-manager",
188
+ message_type: "order_created",
189
+ order_id: "ORD-123",
190
+ customer_id: "CUST-456",
191
+ status: "pending",
192
+ data: { items: ["Widget A", "Widget B"] },
193
+ environment: "prod"
194
+ )
195
+ order_msg.from('payment-gateway') # Matches /^payment-.*/ pattern
196
+ order_msg.to('order-service')
197
+ order_msg.publish
198
+ sleep(delay)
199
+
200
+ # 3. Monitoring and alerting examples
201
+ puts "\nšŸ“Š Monitoring and alerting examples:"
202
+
203
+ alert_msg = AlertMessage.new(
204
+ service_id: "health-checker",
205
+ message_type: "system_alert",
206
+ alert_level: "warning",
207
+ component: "database",
208
+ description: "High connection count detected",
209
+ data: { current_connections: 95, max_connections: 100 },
210
+ environment: "prod"
211
+ )
212
+ alert_msg.from('monitoring-system') # Matches /^monitoring-.*/ pattern
213
+ alert_msg.to('ops-dashboard')
214
+ alert_msg.publish
215
+ sleep(delay)
216
+
217
+ # 4. Mixed filtering examples
218
+ puts "\nšŸŽ­ Mixed filtering examples:"
219
+
220
+ alert_msg = AlertMessage.new(
221
+ service_id: "security-scanner",
222
+ message_type: "security_alert",
223
+ alert_level: "critical",
224
+ component: "authentication",
225
+ description: "Multiple failed login attempts detected",
226
+ data: { attempts: 50, ip: "192.168.1.100" },
227
+ environment: "prod"
228
+ )
229
+ alert_msg.from('admin') # Exact match in mixed array ['admin', /^system-.*/, 'security']
230
+ alert_msg.to('security-dashboard')
231
+ alert_msg.publish
232
+ sleep(delay)
233
+
234
+ alert_msg = AlertMessage.new(
235
+ service_id: "system-monitor",
236
+ message_type: "resource_alert",
237
+ alert_level: "warning",
238
+ component: "memory",
239
+ description: "Memory usage above threshold",
240
+ data: { usage_percent: 85, threshold: 80 },
241
+ environment: "staging"
242
+ )
243
+ alert_msg.from('system-metrics') # Matches /^system-.*/ pattern
244
+ alert_msg.to('ops-dashboard')
245
+ alert_msg.publish
246
+ sleep(delay)
247
+
248
+ # 5. Complex multi-criteria examples
249
+ puts "\nšŸŽÆ Complex multi-criteria examples:"
250
+
251
+ order_msg = OrderMessage.new(
252
+ service_id: "admin-portal",
253
+ message_type: "admin_order_override",
254
+ order_id: "ORD-999",
255
+ customer_id: "ADMIN",
256
+ status: "expedited",
257
+ data: { priority: "high", reason: "VIP customer" },
258
+ environment: "prod"
259
+ )
260
+ order_msg.from('admin-dashboard') # Matches /^admin-.*/ pattern
261
+ order_msg.to('prod-fulfillment') # Matches /^prod-.*/ pattern
262
+ order_msg.publish
263
+ sleep(delay)
264
+
265
+ # 6. Broadcast message examples
266
+ puts "\nšŸ“¢ Broadcast message examples:"
267
+
268
+ payment_msg = PaymentMessage.new(
269
+ service_id: "payment-system",
270
+ message_type: "system_maintenance",
271
+ transaction_id: "MAINT-001",
272
+ amount: 0,
273
+ data: {
274
+ message: "Scheduled maintenance in 30 minutes",
275
+ duration: "2 hours",
276
+ affected_services: ["payment", "billing"]
277
+ },
278
+ environment: "prod"
279
+ )
280
+ payment_msg.from('admin')
281
+ payment_msg.to(nil) # Broadcast message
282
+ payment_msg.publish
283
+ sleep(delay)
284
+
285
+ # 7. Messages that won't match filters
286
+ puts "\nāŒ Examples of messages that won't match filters:"
287
+
288
+ # This won't match any filters (wrong from pattern)
289
+ order_msg = OrderMessage.new(
290
+ service_id: "user-service",
291
+ message_type: "user_action",
292
+ order_id: "ORD-NOFILT",
293
+ customer_id: "USER-123",
294
+ status: "ignored",
295
+ environment: "dev"
296
+ )
297
+ order_msg.from('user-portal') # Doesn't match /^payment-.*/ pattern
298
+ order_msg.to('order-service')
299
+ order_msg.publish
300
+ puts " āš ļø This message won't be processed (wrong sender pattern)"
301
+ sleep(delay)
302
+
303
+ # This won't match the admin-prod filter (wrong environment)
304
+ order_msg = OrderMessage.new(
305
+ service_id: "admin-dev",
306
+ message_type: "test_order",
307
+ order_id: "ORD-TEST",
308
+ customer_id: "TEST-123",
309
+ status: "test",
310
+ environment: "dev"
311
+ )
312
+ order_msg.from('admin-panel') # Matches /^admin-.*/ pattern
313
+ order_msg.to('dev-fulfillment') # Doesn't match /^prod-.*/ pattern
314
+ order_msg.publish
315
+ puts " āš ļø This message won't match admin-prod filter (wrong environment)"
316
+ sleep(delay)
317
+
318
+ puts "\n✨ Message simulation complete!"
319
+ end
320
+
321
+ # Display filter configuration summary
322
+ def display_filter_summary
323
+ puts "\nšŸ“‹ Current Filter Configuration Summary:"
324
+ puts "=" * 50
325
+
326
+ # Get dispatcher to examine subscriptions
327
+ dispatcher = PaymentMessage.transport.instance_variable_get(:@dispatcher)
328
+
329
+ dispatcher.subscribers.each do |message_class, subscriptions|
330
+ puts "\n#{message_class}:"
331
+ subscriptions.each_with_index do |sub, index|
332
+ filters = sub[:filters]
333
+ method = sub[:process_method]
334
+
335
+ puts " #{index + 1}. #{method}"
336
+
337
+ if filters[:from]
338
+ from_desc = filters[:from].map do |f|
339
+ f.is_a?(Regexp) ? f.inspect : "'#{f}'"
340
+ end.join(', ')
341
+ puts " from: [#{from_desc}]"
342
+ end
343
+
344
+ if filters[:to]
345
+ to_desc = filters[:to].map do |f|
346
+ f.is_a?(Regexp) ? f.inspect : "'#{f}'"
347
+ end.join(', ')
348
+ puts " to: [#{to_desc}]"
349
+ end
350
+
351
+ if filters[:broadcast]
352
+ puts " broadcast: #{filters[:broadcast]}"
353
+ end
354
+ end
355
+ end
356
+
357
+ puts "\nšŸ“Š Message Processing Statistics:"
358
+ puts SS.stat.select { |k, v| k.include?('process') }
359
+ end
360
+
361
+ # Main demonstration
362
+ def main
363
+ puts "\nThis example demonstrates SmartMessage's powerful regex filtering capabilities"
364
+ puts "for building sophisticated microservices routing systems.\n"
365
+
366
+ # Setup
367
+ demonstrate_filtering_patterns
368
+
369
+ # Wait a moment for subscriptions to be established
370
+ sleep(1)
371
+
372
+ # Simulate traffic
373
+ simulate_microservice_traffic
374
+
375
+ # Wait for message processing
376
+ sleep(2)
377
+
378
+ # Show results
379
+ display_filter_summary
380
+
381
+ puts "\n" + "=" * 60
382
+ puts "šŸŽ‰ Regex Filtering Demo Complete!"
383
+ puts "=" * 60
384
+
385
+ puts "\nšŸ’” Key Takeaways:"
386
+ puts " • Use regex patterns for flexible service routing"
387
+ puts " • Combine exact matches with patterns in arrays"
388
+ puts " • Environment-based routing with regex patterns"
389
+ puts " • Multi-criteria filtering for complex scenarios"
390
+ puts " • Broadcast + directed message handling"
391
+ puts " • Validation prevents invalid filter types"
392
+ puts "\nšŸ”— See CLAUDE.md and README.md for more filtering examples!"
393
+ end
394
+
395
+ # Handle script execution
396
+ if __FILE__ == $0
397
+ begin
398
+ main
399
+ rescue Interrupt
400
+ puts "\n\nšŸ‘‹ Demo interrupted by user"
401
+ exit(0)
402
+ rescue => e
403
+ puts "\nāŒ Error: #{e.message}"
404
+ puts e.backtrace.first(5).map { |line| " #{line}" }
405
+ exit(1)
406
+ end
407
+ end
@@ -0,0 +1,263 @@
1
+ #!/usr/bin/env ruby
2
+ # examples/10_header_block_configuration.rb
3
+ #
4
+ # Demonstrates the different ways to configure message addressing:
5
+ # - Method 1: Direct class methods (from, to, reply_to)
6
+ # - Method 2: Header block DSL
7
+ # - Method 3: Instance-level overrides
8
+ # - Shortcut accessor methods for addressing
9
+
10
+ require_relative '../lib/smart_message'
11
+
12
+ puts "šŸŽÆ SmartMessage Header Block Configuration Demo"
13
+ puts "=" * 50
14
+
15
+ # =============================================================================
16
+ # Method 1: Direct Class Methods
17
+ # =============================================================================
18
+
19
+ puts "\nšŸ“” Method 1: Direct Class Methods"
20
+ puts "-" * 40
21
+
22
+ class DirectMethodMessage < SmartMessage::Base
23
+ version 1
24
+ description "Configured using direct class methods"
25
+
26
+ # Configure addressing using individual methods
27
+ from 'service-a'
28
+ to 'service-b'
29
+ reply_to 'service-a-callback'
30
+
31
+ property :data, required: true
32
+
33
+ config do
34
+ transport SmartMessage::Transport.create(:stdout)
35
+ serializer SmartMessage::Serializer::JSON.new
36
+ end
37
+ end
38
+
39
+ msg1 = DirectMethodMessage.new(data: "Method 1 test")
40
+ puts "From: #{msg1.from}"
41
+ puts "To: #{msg1.to}"
42
+ puts "Reply-to: #{msg1.reply_to}"
43
+
44
+ # =============================================================================
45
+ # Method 2: Header Block DSL
46
+ # =============================================================================
47
+
48
+ puts "\nšŸ“” Method 2: Header Block DSL"
49
+ puts "-" * 40
50
+
51
+ class HeaderBlockMessage < SmartMessage::Base
52
+ version 1
53
+ description "Configured using header block DSL"
54
+
55
+ # Configure all addressing in a single block
56
+ header do
57
+ from 'service-x'
58
+ to 'service-y'
59
+ reply_to 'service-x-callback'
60
+ end
61
+
62
+ property :data, required: true
63
+
64
+ config do
65
+ transport SmartMessage::Transport.create(:stdout)
66
+ serializer SmartMessage::Serializer::JSON.new
67
+ end
68
+ end
69
+
70
+ msg2 = HeaderBlockMessage.new(data: "Method 2 test")
71
+ puts "From: #{msg2.from}"
72
+ puts "To: #{msg2.to}"
73
+ puts "Reply-to: #{msg2.reply_to}"
74
+
75
+ # =============================================================================
76
+ # Method 3: Mixed Approach
77
+ # =============================================================================
78
+
79
+ puts "\nšŸ“” Method 3: Mixed Approach"
80
+ puts "-" * 40
81
+
82
+ class MixedConfigMessage < SmartMessage::Base
83
+ version 1
84
+ description "Configured using mixed approaches"
85
+
86
+ # Some configuration in header block
87
+ header do
88
+ from 'mixed-service'
89
+ to 'target-service'
90
+ end
91
+
92
+ # Additional configuration outside block
93
+ reply_to 'mixed-callback'
94
+
95
+ property :data, required: true
96
+
97
+ config do
98
+ transport SmartMessage::Transport.create(:stdout)
99
+ serializer SmartMessage::Serializer::JSON.new
100
+ end
101
+ end
102
+
103
+ msg3 = MixedConfigMessage.new(data: "Method 3 test")
104
+ puts "From: #{msg3.from}"
105
+ puts "To: #{msg3.to}"
106
+ puts "Reply-to: #{msg3.reply_to}"
107
+
108
+ # =============================================================================
109
+ # Instance-Level Overrides
110
+ # =============================================================================
111
+
112
+ puts "\nšŸ“” Instance-Level Overrides"
113
+ puts "-" * 40
114
+
115
+ class FlexibleMessage < SmartMessage::Base
116
+ version 1
117
+ description "Demonstrates instance-level addressing overrides"
118
+
119
+ # Default configuration using header block
120
+ header do
121
+ from 'default-sender'
122
+ to 'default-recipient'
123
+ reply_to 'default-callback'
124
+ end
125
+
126
+ property :data, required: true
127
+
128
+ config do
129
+ transport SmartMessage::Transport.create(:stdout)
130
+ serializer SmartMessage::Serializer::JSON.new
131
+ end
132
+ end
133
+
134
+ # Create with defaults
135
+ msg4 = FlexibleMessage.new(data: "Default config")
136
+ puts "\nDefault configuration:"
137
+ puts "From: #{msg4.from}"
138
+ puts "To: #{msg4.to}"
139
+ puts "Reply-to: #{msg4.reply_to}"
140
+
141
+ # Override using method chaining
142
+ msg5 = FlexibleMessage.new(data: "Chained overrides")
143
+ msg5.from('override-sender')
144
+ .to('override-recipient')
145
+ .reply_to('override-callback')
146
+
147
+ puts "\nMethod chaining overrides:"
148
+ puts "From: #{msg5.from}"
149
+ puts "To: #{msg5.to}"
150
+ puts "Reply-to: #{msg5.reply_to}"
151
+
152
+ # Override using setter syntax
153
+ msg6 = FlexibleMessage.new(data: "Setter overrides")
154
+ msg6.from = 'setter-sender'
155
+ msg6.to = 'setter-recipient'
156
+ msg6.reply_to = 'setter-callback'
157
+
158
+ puts "\nSetter syntax overrides:"
159
+ puts "From: #{msg6.from}"
160
+ puts "To: #{msg6.to}"
161
+ puts "Reply-to: #{msg6.reply_to}"
162
+
163
+ # =============================================================================
164
+ # Accessing Addressing Values
165
+ # =============================================================================
166
+
167
+ puts "\nšŸ“” Accessing Addressing Values"
168
+ puts "-" * 40
169
+
170
+ msg7 = FlexibleMessage.new(data: "Access demo")
171
+ msg7.from = 'demo-service'
172
+ msg7.to = 'demo-target'
173
+
174
+ puts "\nThree ways to access addressing:"
175
+
176
+ # Method 1: Shortcut methods (recommended)
177
+ puts "\n1. Shortcut methods:"
178
+ puts " msg.from => #{msg7.from}"
179
+ puts " msg.to => #{msg7.to}"
180
+ puts " msg.reply_to => #{msg7.reply_to}"
181
+
182
+ # Method 2: Via header object
183
+ puts "\n2. Via header object:"
184
+ puts " msg._sm_header.from => #{msg7._sm_header.from}"
185
+ puts " msg._sm_header.to => #{msg7._sm_header.to}"
186
+ puts " msg._sm_header.reply_to => #{msg7._sm_header.reply_to}"
187
+
188
+ # Method 3: Class defaults
189
+ puts "\n3. Class defaults (unchanged by instances):"
190
+ puts " FlexibleMessage.from => #{FlexibleMessage.from}"
191
+ puts " FlexibleMessage.to => #{FlexibleMessage.to}"
192
+ puts " FlexibleMessage.reply_to => #{FlexibleMessage.reply_to}"
193
+
194
+ # =============================================================================
195
+ # Header Synchronization
196
+ # =============================================================================
197
+
198
+ puts "\nšŸ“” Header Synchronization"
199
+ puts "-" * 40
200
+
201
+ msg8 = FlexibleMessage.new(data: "Sync demo")
202
+ puts "\nInitial values:"
203
+ puts "Instance from: #{msg8.from}"
204
+ puts "Header from: #{msg8._sm_header.from}"
205
+
206
+ # Change instance value
207
+ msg8.from = 'new-sender'
208
+ puts "\nAfter changing instance value:"
209
+ puts "Instance from: #{msg8.from}"
210
+ puts "Header from: #{msg8._sm_header.from} (automatically synced)"
211
+
212
+ # Headers stay in sync
213
+ msg8.to = 'new-target'
214
+ puts "\nHeaders stay synchronized:"
215
+ puts "Instance to: #{msg8.to}"
216
+ puts "Header to: #{msg8._sm_header.to}"
217
+
218
+ # =============================================================================
219
+ # Configuration Checks
220
+ # =============================================================================
221
+
222
+ puts "\nšŸ“” Configuration Checks"
223
+ puts "-" * 40
224
+
225
+ class CheckableMessage < SmartMessage::Base
226
+ version 1
227
+
228
+ header do
229
+ from 'check-service'
230
+ # Note: to is not set
231
+ end
232
+
233
+ property :data
234
+
235
+ config do
236
+ transport SmartMessage::Transport.create(:stdout)
237
+ serializer SmartMessage::Serializer::JSON.new
238
+ end
239
+ end
240
+
241
+ # Class-level checks
242
+ puts "\nClass-level configuration checks:"
243
+ puts "from_configured? => #{CheckableMessage.from_configured?}"
244
+ puts "to_configured? => #{CheckableMessage.to_configured?}"
245
+ puts "reply_to_configured? => #{CheckableMessage.reply_to_configured?}"
246
+ puts "to_missing? => #{CheckableMessage.to_missing?}"
247
+
248
+ # Instance-level checks
249
+ msg9 = CheckableMessage.new(data: "Check test")
250
+ msg9.to = 'instance-target'
251
+
252
+ puts "\nInstance-level configuration checks:"
253
+ puts "from_configured? => #{msg9.from_configured?}"
254
+ puts "to_configured? => #{msg9.to_configured?}"
255
+ puts "reply_to_configured? => #{msg9.reply_to_configured?}"
256
+
257
+ # Reset functionality
258
+ msg9.reset_to
259
+ puts "\nAfter reset_to:"
260
+ puts "to_configured? => #{msg9.to_configured?}"
261
+ puts "to value: => #{msg9.to.inspect}"
262
+
263
+ puts "\nāœ… Header Block Configuration Demo Complete!"