smart_message 0.0.5 → 0.0.7
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/CHANGELOG.md +122 -0
- data/Gemfile.lock +9 -1
- data/README.md +58 -4
- data/docs/README.md +1 -0
- data/docs/addressing.md +364 -0
- data/docs/getting-started.md +38 -0
- data/examples/01_point_to_point_orders.rb +4 -2
- data/examples/02_publish_subscribe_events.rb +2 -1
- data/examples/03_many_to_many_chat.rb +10 -5
- data/examples/04_redis_smart_home_iot.rb +32 -16
- data/examples/05_proc_handlers.rb +3 -2
- data/examples/06_custom_logger_example.rb +13 -7
- data/examples/07_error_handling_scenarios.rb +26 -15
- data/examples/08_entity_addressing_basic.rb +373 -0
- data/examples/08_entity_addressing_with_filtering.rb +430 -0
- data/examples/README.md +68 -0
- data/examples/tmux_chat/bot_agent.rb +2 -1
- data/examples/tmux_chat/shared_chat_system.rb +4 -2
- data/lib/smart_message/base.rb +204 -12
- data/lib/smart_message/circuit_breaker.rb +227 -0
- data/lib/smart_message/dispatcher.rb +189 -20
- data/lib/smart_message/header.rb +14 -0
- data/lib/smart_message/serializer/base.rb +77 -4
- data/lib/smart_message/serializer/json.rb +2 -2
- data/lib/smart_message/transport/base.rb +141 -4
- data/lib/smart_message/transport/memory_transport.rb +1 -1
- data/lib/smart_message/transport/redis_transport.rb +45 -15
- data/lib/smart_message/transport/stdout_transport.rb +1 -1
- data/lib/smart_message/version.rb +1 -1
- data/lib/smart_message.rb +1 -0
- data/smart_message.gemspec +1 -0
- metadata +19 -1
data/docs/getting-started.md
CHANGED
@@ -40,6 +40,11 @@ class WelcomeMessage < SmartMessage::Base
|
|
40
40
|
# Add a description for the message class
|
41
41
|
description "Welcomes new users after successful signup"
|
42
42
|
|
43
|
+
# Configure entity addressing
|
44
|
+
from 'user-service' # Required: identifies sender
|
45
|
+
to 'notification-service' # Optional: specific recipient
|
46
|
+
reply_to 'user-service' # Optional: where responses go
|
47
|
+
|
43
48
|
# Define message properties
|
44
49
|
property :user_name
|
45
50
|
property :email
|
@@ -153,6 +158,9 @@ puts message._sm_header.uuid # Unique identifier
|
|
153
158
|
puts message._sm_header.message_class # "WelcomeMessage"
|
154
159
|
puts message._sm_header.published_at # Timestamp when published
|
155
160
|
puts message._sm_header.publisher_pid # Process ID of publisher
|
161
|
+
puts message._sm_header.from # 'user-service'
|
162
|
+
puts message._sm_header.to # 'notification-service'
|
163
|
+
puts message._sm_header.reply_to # 'user-service'
|
156
164
|
```
|
157
165
|
|
158
166
|
### Transports
|
@@ -222,6 +230,36 @@ OrderMessage.subscribe("OrderService.process_order")
|
|
222
230
|
- **Proc**: Reusable handlers that work across multiple message types
|
223
231
|
- **Method**: Complex business logic organized in service classes
|
224
232
|
|
233
|
+
### Entity Addressing
|
234
|
+
|
235
|
+
SmartMessage supports entity-to-entity addressing for sophisticated messaging patterns:
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
# Point-to-point messaging
|
239
|
+
class PaymentMessage < SmartMessage::Base
|
240
|
+
from 'payment-service' # Required: sender identity
|
241
|
+
to 'bank-gateway' # Optional: specific recipient
|
242
|
+
reply_to 'payment-service' # Optional: where responses go
|
243
|
+
|
244
|
+
property :amount, required: true
|
245
|
+
end
|
246
|
+
|
247
|
+
# Broadcast messaging (no 'to' field)
|
248
|
+
class AnnouncementMessage < SmartMessage::Base
|
249
|
+
from 'admin-service' # Required sender
|
250
|
+
# No 'to' = broadcast to all subscribers
|
251
|
+
|
252
|
+
property :message, required: true
|
253
|
+
end
|
254
|
+
|
255
|
+
# Instance-level addressing override
|
256
|
+
payment = PaymentMessage.new(amount: 100.00)
|
257
|
+
payment.to('backup-gateway') # Override destination
|
258
|
+
payment.publish
|
259
|
+
```
|
260
|
+
|
261
|
+
For more details, see [Entity Addressing](addressing.md).
|
262
|
+
|
225
263
|
## Next Steps
|
226
264
|
|
227
265
|
Now that you have the basics working, explore:
|
@@ -92,7 +92,8 @@ class OrderService
|
|
92
92
|
customer_id: customer_id,
|
93
93
|
amount: amount,
|
94
94
|
payment_method: payment_method,
|
95
|
-
items: items
|
95
|
+
items: items,
|
96
|
+
from: 'OrderService'
|
96
97
|
)
|
97
98
|
|
98
99
|
puts "🏪 OrderService: Sending order to payment processing..."
|
@@ -132,7 +133,8 @@ class PaymentService
|
|
132
133
|
payment_id: payment_id,
|
133
134
|
status: success ? 'success' : 'failed',
|
134
135
|
message: success ? 'Payment processed successfully' : 'Insufficient funds',
|
135
|
-
processed_at: Time.now.iso8601
|
136
|
+
processed_at: Time.now.iso8601,
|
137
|
+
from: 'PaymentService'
|
136
138
|
)
|
137
139
|
|
138
140
|
puts "💳 PaymentService: Sending payment response..."
|
@@ -164,7 +164,8 @@ class HumanChatAgent
|
|
164
164
|
message_type: 'user',
|
165
165
|
timestamp: Time.now.iso8601,
|
166
166
|
mentions: mentions,
|
167
|
-
metadata: { client: 'human_agent' }
|
167
|
+
metadata: { client: 'human_agent' },
|
168
|
+
from: @user_id
|
168
169
|
)
|
169
170
|
|
170
171
|
message.publish
|
@@ -228,7 +229,8 @@ class HumanChatAgent
|
|
228
229
|
user_id: @user_id,
|
229
230
|
command: command,
|
230
231
|
parameters: parameters,
|
231
|
-
timestamp: Time.now.iso8601
|
232
|
+
timestamp: Time.now.iso8601,
|
233
|
+
from: @user_id
|
232
234
|
)
|
233
235
|
|
234
236
|
bot_command.publish
|
@@ -259,7 +261,8 @@ class HumanChatAgent
|
|
259
261
|
notification_type: notification_type,
|
260
262
|
content: content,
|
261
263
|
timestamp: Time.now.iso8601,
|
262
|
-
metadata: { triggered_by: @user_id }
|
264
|
+
metadata: { triggered_by: @user_id },
|
265
|
+
from: @user_id
|
263
266
|
)
|
264
267
|
|
265
268
|
notification.publish
|
@@ -444,7 +447,8 @@ class BotAgent
|
|
444
447
|
message_type: 'bot',
|
445
448
|
timestamp: Time.now.iso8601,
|
446
449
|
mentions: [],
|
447
|
-
metadata: { bot_type: 'service_bot' }
|
450
|
+
metadata: { bot_type: 'service_bot' },
|
451
|
+
from: @bot_id
|
448
452
|
)
|
449
453
|
|
450
454
|
message.publish
|
@@ -480,7 +484,8 @@ class RoomManager
|
|
480
484
|
notification_type: 'room_created',
|
481
485
|
content: "Room '#{name}' was created",
|
482
486
|
timestamp: Time.now.iso8601,
|
483
|
-
metadata: { description: description }
|
487
|
+
metadata: { description: description },
|
488
|
+
from: 'RoomManager'
|
484
489
|
)
|
485
490
|
|
486
491
|
notification.publish
|
@@ -234,7 +234,7 @@ class SmartThermostat
|
|
234
234
|
@battery_level -= 0.1 if rand < 0.1 # Occasional battery drain
|
235
235
|
|
236
236
|
# Publish sensor data
|
237
|
-
SensorDataMessage.new(
|
237
|
+
sensor_msg = SensorDataMessage.new(
|
238
238
|
device_id: @device_id,
|
239
239
|
device_type: 'thermostat',
|
240
240
|
location: @location,
|
@@ -242,8 +242,11 @@ class SmartThermostat
|
|
242
242
|
value: @current_temp.round(1),
|
243
243
|
unit: 'celsius',
|
244
244
|
timestamp: Time.now.iso8601,
|
245
|
-
battery_level: @battery_level.round(1)
|
246
|
-
|
245
|
+
battery_level: @battery_level.round(1),
|
246
|
+
from: @device_id
|
247
|
+
)
|
248
|
+
puts "🌡️ #{@device_id}: Publishing temperature #{@current_temp.round(1)}°C"
|
249
|
+
sensor_msg.publish
|
247
250
|
|
248
251
|
# Check for alerts
|
249
252
|
if @current_temp > 28.0
|
@@ -255,7 +258,8 @@ class SmartThermostat
|
|
255
258
|
location: @location,
|
256
259
|
message: "Temperature too high: #{@current_temp.round(1)}°C",
|
257
260
|
timestamp: Time.now.iso8601,
|
258
|
-
requires_action: true
|
261
|
+
requires_action: true,
|
262
|
+
from: @device_id
|
259
263
|
).publish
|
260
264
|
end
|
261
265
|
|
@@ -325,7 +329,8 @@ class SecurityCamera
|
|
325
329
|
value: true,
|
326
330
|
unit: 'boolean',
|
327
331
|
timestamp: Time.now.iso8601,
|
328
|
-
battery_level: @battery_level.round(1)
|
332
|
+
battery_level: @battery_level.round(1),
|
333
|
+
from: @device_id
|
329
334
|
).publish
|
330
335
|
|
331
336
|
# Send security alert
|
@@ -337,7 +342,8 @@ class SecurityCamera
|
|
337
342
|
location: @location,
|
338
343
|
message: "Motion detected in #{@location}",
|
339
344
|
timestamp: Time.now.iso8601,
|
340
|
-
requires_action: false
|
345
|
+
requires_action: false,
|
346
|
+
from: @device_id
|
341
347
|
).publish
|
342
348
|
|
343
349
|
# Auto-start recording
|
@@ -346,7 +352,8 @@ class SecurityCamera
|
|
346
352
|
command: 'start_recording',
|
347
353
|
parameters: { duration: 30 },
|
348
354
|
requested_by: 'motion_detector',
|
349
|
-
timestamp: Time.now.iso8601
|
355
|
+
timestamp: Time.now.iso8601,
|
356
|
+
from: @device_id
|
350
357
|
).publish
|
351
358
|
|
352
359
|
elsif !motion_detected && @motion_detected
|
@@ -361,7 +368,8 @@ class SecurityCamera
|
|
361
368
|
value: false,
|
362
369
|
unit: 'boolean',
|
363
370
|
timestamp: Time.now.iso8601,
|
364
|
-
battery_level: @battery_level.round(1)
|
371
|
+
battery_level: @battery_level.round(1),
|
372
|
+
from: @device_id
|
365
373
|
).publish
|
366
374
|
end
|
367
375
|
|
@@ -424,7 +432,8 @@ class SmartDoorLock
|
|
424
432
|
value: @locked ? 'locked' : 'unlocked',
|
425
433
|
unit: 'string',
|
426
434
|
timestamp: Time.now.iso8601,
|
427
|
-
battery_level: @battery_level.round(1)
|
435
|
+
battery_level: @battery_level.round(1),
|
436
|
+
from: @device_id
|
428
437
|
).publish
|
429
438
|
|
430
439
|
# Check for low battery
|
@@ -437,7 +446,8 @@ class SmartDoorLock
|
|
437
446
|
location: @location,
|
438
447
|
message: "Door lock battery low: #{@battery_level.round(1)}%",
|
439
448
|
timestamp: Time.now.iso8601,
|
440
|
-
requires_action: true
|
449
|
+
requires_action: true,
|
450
|
+
from: @device_id
|
441
451
|
).publish
|
442
452
|
end
|
443
453
|
|
@@ -528,7 +538,8 @@ class IoTDashboard
|
|
528
538
|
summary_stats: {
|
529
539
|
total_devices: @@devices.size,
|
530
540
|
avg_battery: @@devices.values.map { |d| d[:battery_level] || 100 }.sum / [@@devices.size, 1].max
|
531
|
-
}
|
541
|
+
},
|
542
|
+
from: 'IoTDashboard'
|
532
543
|
).publish
|
533
544
|
end
|
534
545
|
end
|
@@ -592,13 +603,16 @@ class SmartHomeDemo
|
|
592
603
|
puts "\n🎛️ Sending some manual commands..."
|
593
604
|
sleep(2)
|
594
605
|
|
595
|
-
DeviceCommandMessage.new(
|
606
|
+
cmd_msg = DeviceCommandMessage.new(
|
596
607
|
device_id: "THERM-001",
|
597
608
|
command: "set_temperature",
|
598
609
|
parameters: { target: 24.0 },
|
599
610
|
requested_by: "mobile_app",
|
600
|
-
timestamp: Time.now.iso8601
|
601
|
-
|
611
|
+
timestamp: Time.now.iso8601,
|
612
|
+
from: 'SmartHomeDemo'
|
613
|
+
)
|
614
|
+
puts "🎛️ Publishing command: set_temperature for THERM-001"
|
615
|
+
cmd_msg.publish
|
602
616
|
|
603
617
|
sleep(3)
|
604
618
|
|
@@ -607,7 +621,8 @@ class SmartHomeDemo
|
|
607
621
|
command: "start_recording",
|
608
622
|
parameters: { duration: 60 },
|
609
623
|
requested_by: "security_schedule",
|
610
|
-
timestamp: Time.now.iso8601
|
624
|
+
timestamp: Time.now.iso8601,
|
625
|
+
from: 'SmartHomeDemo'
|
611
626
|
).publish
|
612
627
|
|
613
628
|
sleep(2)
|
@@ -617,7 +632,8 @@ class SmartHomeDemo
|
|
617
632
|
command: "get_status",
|
618
633
|
parameters: {},
|
619
634
|
requested_by: "mobile_app",
|
620
|
-
timestamp: Time.now.iso8601
|
635
|
+
timestamp: Time.now.iso8601,
|
636
|
+
from: 'SmartHomeDemo'
|
621
637
|
).publish
|
622
638
|
|
623
639
|
puts "\n⏳ Monitoring for 30 seconds (watch the Redis channels!)..."
|
@@ -137,7 +137,7 @@ notifications = [
|
|
137
137
|
notifications.each_with_index do |notification_data, index|
|
138
138
|
puts "\n📤 Publishing notification #{index + 1}: #{notification_data[:title]}"
|
139
139
|
|
140
|
-
notification = NotificationMessage.new(**notification_data)
|
140
|
+
notification = NotificationMessage.new(**notification_data, from: 'ProcHandlerDemo')
|
141
141
|
notification.publish
|
142
142
|
|
143
143
|
# Give time for all handlers to process
|
@@ -161,7 +161,8 @@ error_notification = NotificationMessage.new(
|
|
161
161
|
title: 'Another Error',
|
162
162
|
message: 'This error won\'t trigger the block handler',
|
163
163
|
user_id: 'test_user',
|
164
|
-
timestamp: Time.now.iso8601
|
164
|
+
timestamp: Time.now.iso8601,
|
165
|
+
from: 'ProcHandlerDemo'
|
165
166
|
)
|
166
167
|
|
167
168
|
error_notification.publish
|
@@ -470,7 +470,7 @@ class PriorityOrderService
|
|
470
470
|
|
471
471
|
def process_priority_order(order_data)
|
472
472
|
# Create message with instance-level logger override
|
473
|
-
message = OrderProcessingMessage.new(**order_data)
|
473
|
+
message = OrderProcessingMessage.new(**order_data, from: 'PriorityOrderService')
|
474
474
|
|
475
475
|
# Override the logger at instance level
|
476
476
|
message.logger(@priority_logger)
|
@@ -506,7 +506,8 @@ class LoggerDemo
|
|
506
506
|
DefaultLoggerMessage.subscribe
|
507
507
|
default_msg = DefaultLoggerMessage.new(
|
508
508
|
message: "Testing the built-in default logger",
|
509
|
-
level: "info"
|
509
|
+
level: "info",
|
510
|
+
from: 'LoggerDemo'
|
510
511
|
)
|
511
512
|
default_msg.publish
|
512
513
|
sleep(0.5)
|
@@ -518,7 +519,8 @@ class LoggerDemo
|
|
518
519
|
customer_id: "CUST-123",
|
519
520
|
amount: 99.99,
|
520
521
|
status: "pending",
|
521
|
-
items: ["Widget A", "Widget B"]
|
522
|
+
items: ["Widget A", "Widget B"],
|
523
|
+
from: 'LoggerDemo'
|
522
524
|
)
|
523
525
|
order1.publish
|
524
526
|
sleep(0.5)
|
@@ -529,7 +531,8 @@ class LoggerDemo
|
|
529
531
|
recipient: "customer@example.com",
|
530
532
|
subject: "Order Confirmation",
|
531
533
|
body: "Your order has been received",
|
532
|
-
priority: "normal"
|
534
|
+
priority: "normal",
|
535
|
+
from: 'LoggerDemo'
|
533
536
|
)
|
534
537
|
notification.publish
|
535
538
|
sleep(0.5)
|
@@ -542,7 +545,8 @@ class LoggerDemo
|
|
542
545
|
customer_id: "VIP-456",
|
543
546
|
amount: 299.99,
|
544
547
|
status: "urgent",
|
545
|
-
items: ["Premium Widget", "Express Shipping"]
|
548
|
+
items: ["Premium Widget", "Express Shipping"],
|
549
|
+
from: 'PriorityOrderService'
|
546
550
|
)
|
547
551
|
sleep(0.5)
|
548
552
|
|
@@ -555,7 +559,8 @@ class LoggerDemo
|
|
555
559
|
# Create and send a message - watch for the Ruby logger output
|
556
560
|
msg = StandardLoggerMessage.new(
|
557
561
|
content: "Testing with Ruby's standard logger",
|
558
|
-
level: "info"
|
562
|
+
level: "info",
|
563
|
+
from: 'LoggerDemo'
|
559
564
|
)
|
560
565
|
|
561
566
|
# The logger will output to STDOUT using Ruby's standard format
|
@@ -573,7 +578,8 @@ class LoggerDemo
|
|
573
578
|
order_id: nil, # This might cause issues
|
574
579
|
customer_id: "ERROR-TEST",
|
575
580
|
amount: "invalid_amount",
|
576
|
-
status: "error_demo"
|
581
|
+
status: "error_demo",
|
582
|
+
from: 'LoggerDemo'
|
577
583
|
)
|
578
584
|
|
579
585
|
# Simulate an error during processing
|
@@ -167,7 +167,8 @@ class ErrorDemonstrator
|
|
167
167
|
missing_user_id = UserRegistrationMessage.new(
|
168
168
|
email: "john@example.com",
|
169
169
|
age: 25,
|
170
|
-
username: "johndoe"
|
170
|
+
username: "johndoe",
|
171
|
+
from: 'ErrorDemonstrator'
|
171
172
|
)
|
172
173
|
puts "❌ ERROR: Should have failed but didn't!"
|
173
174
|
rescue => e
|
@@ -181,7 +182,8 @@ class ErrorDemonstrator
|
|
181
182
|
begin
|
182
183
|
missing_multiple = UserRegistrationMessage.new(
|
183
184
|
user_id: "USER-123",
|
184
|
-
username: "johndoe"
|
185
|
+
username: "johndoe",
|
186
|
+
from: 'ErrorDemonstrator'
|
185
187
|
)
|
186
188
|
puts "❌ ERROR: Should have failed but didn't!"
|
187
189
|
rescue => e
|
@@ -197,7 +199,8 @@ class ErrorDemonstrator
|
|
197
199
|
user_id: "USER-123",
|
198
200
|
email: "john@example.com",
|
199
201
|
age: 25,
|
200
|
-
username: "johndoe"
|
202
|
+
username: "johndoe",
|
203
|
+
from: 'ErrorDemonstrator'
|
201
204
|
)
|
202
205
|
puts "✅ Message created successfully"
|
203
206
|
puts " User: #{valid_user.username} (#{valid_user.email})"
|
@@ -227,7 +230,8 @@ class ErrorDemonstrator
|
|
227
230
|
user_id: "USER-124",
|
228
231
|
email: "not-an-email", # Invalid format
|
229
232
|
age: 25,
|
230
|
-
username: "janedoe"
|
233
|
+
username: "janedoe",
|
234
|
+
from: 'ErrorDemonstrator'
|
231
235
|
)
|
232
236
|
puts " Message created, now validating..."
|
233
237
|
invalid_email.validate! # Explicitly trigger validation
|
@@ -245,7 +249,8 @@ class ErrorDemonstrator
|
|
245
249
|
user_id: "USER-125",
|
246
250
|
email: "kid@example.com",
|
247
251
|
age: 10, # Too young (< 13)
|
248
|
-
username: "kiduser"
|
252
|
+
username: "kiduser",
|
253
|
+
from: 'ErrorDemonstrator'
|
249
254
|
)
|
250
255
|
puts " Message created, now validating..."
|
251
256
|
invalid_age.validate! # Explicitly trigger validation
|
@@ -263,7 +268,8 @@ class ErrorDemonstrator
|
|
263
268
|
user_id: "USER-126",
|
264
269
|
email: "user@example.com",
|
265
270
|
age: 30,
|
266
|
-
username: "user@123!" # Contains invalid characters
|
271
|
+
username: "user@123!", # Contains invalid characters
|
272
|
+
from: 'ErrorDemonstrator'
|
267
273
|
)
|
268
274
|
puts " Message created, now validating..."
|
269
275
|
invalid_username.validate! # Explicitly trigger validation
|
@@ -282,7 +288,8 @@ class ErrorDemonstrator
|
|
282
288
|
email: "user@example.com",
|
283
289
|
age: 30,
|
284
290
|
username: "validuser",
|
285
|
-
subscription_type: "platinum" # Not in allowed list
|
291
|
+
subscription_type: "platinum", # Not in allowed list
|
292
|
+
from: 'ErrorDemonstrator'
|
286
293
|
)
|
287
294
|
puts " Message created, now validating..."
|
288
295
|
invalid_subscription.validate! # Explicitly trigger validation
|
@@ -301,7 +308,8 @@ class ErrorDemonstrator
|
|
301
308
|
email: "valid@example.com",
|
302
309
|
age: 25,
|
303
310
|
username: "validuser123",
|
304
|
-
subscription_type: "premium"
|
311
|
+
subscription_type: "premium",
|
312
|
+
from: 'ErrorDemonstrator'
|
305
313
|
)
|
306
314
|
puts " Message created, now validating..."
|
307
315
|
valid_user.validate! # Explicitly trigger validation
|
@@ -339,7 +347,8 @@ class ErrorDemonstrator
|
|
339
347
|
user_id: "USER-V1-001",
|
340
348
|
email: "v1user@example.com",
|
341
349
|
age: 28,
|
342
|
-
username: "v1user"
|
350
|
+
username: "v1user",
|
351
|
+
from: 'ErrorDemonstrator'
|
343
352
|
)
|
344
353
|
puts "✅ V1 Message created (version #{v1_message._sm_header.version})"
|
345
354
|
v1_message.publish
|
@@ -356,7 +365,8 @@ class ErrorDemonstrator
|
|
356
365
|
email: "v2user@example.com",
|
357
366
|
age: 32,
|
358
367
|
username: "v2user",
|
359
|
-
phone_number: "+1234567890"
|
368
|
+
phone_number: "+1234567890",
|
369
|
+
from: 'ErrorDemonstrator'
|
360
370
|
)
|
361
371
|
puts "✅ V2 Message created (version #{v2_message._sm_header.version})"
|
362
372
|
v2_message.publish
|
@@ -374,7 +384,8 @@ class ErrorDemonstrator
|
|
374
384
|
user_id: "USER-MISMATCH-001",
|
375
385
|
email: "mismatch@example.com",
|
376
386
|
age: 35,
|
377
|
-
username: "mismatchuser"
|
387
|
+
username: "mismatchuser",
|
388
|
+
from: 'ErrorDemonstrator'
|
378
389
|
)
|
379
390
|
|
380
391
|
puts "✅ Original message created with version #{version_mismatch_message._sm_header.version}"
|
@@ -396,8 +407,8 @@ class ErrorDemonstrator
|
|
396
407
|
|
397
408
|
# Test Case 4: Show version information
|
398
409
|
puts "📊 Test Case 3D: Version information display"
|
399
|
-
v1_msg = UserRegistrationMessage.new(user_id: "INFO-V1", email: "info@example.com", age: 25, username: "infouser")
|
400
|
-
v2_msg = UserRegistrationMessageV2.new(user_id: "INFO-V2", email: "info@example.com", age: 25, username: "infouser", phone_number: "+1234567890")
|
410
|
+
v1_msg = UserRegistrationMessage.new(user_id: "INFO-V1", email: "info@example.com", age: 25, username: "infouser", from: 'ErrorDemonstrator')
|
411
|
+
v2_msg = UserRegistrationMessageV2.new(user_id: "INFO-V2", email: "info@example.com", age: 25, username: "infouser", phone_number: "+1234567890", from: 'ErrorDemonstrator')
|
401
412
|
|
402
413
|
puts "📋 Version Information:"
|
403
414
|
puts " UserRegistrationMessage (V1):"
|
@@ -424,7 +435,7 @@ class ErrorDemonstrator
|
|
424
435
|
puts "Expected: Ideally should report all missing fields"
|
425
436
|
puts "Actual Hashie::Dash behavior:"
|
426
437
|
begin
|
427
|
-
message = MultiRequiredMessage.new(optional_field: "present")
|
438
|
+
message = MultiRequiredMessage.new(optional_field: "present", from: 'ErrorDemonstrator')
|
428
439
|
puts "❌ ERROR: Should have failed but didn't!"
|
429
440
|
rescue => e
|
430
441
|
puts "✅ Error caught: #{e.class.name}"
|
@@ -443,7 +454,7 @@ class ErrorDemonstrator
|
|
443
454
|
test_data.each_with_index do |test_case, index|
|
444
455
|
puts " #{index + 1}. #{test_case[:name]}:"
|
445
456
|
begin
|
446
|
-
message = MultiRequiredMessage.new(test_case[:data])
|
457
|
+
message = MultiRequiredMessage.new(test_case[:data].merge(from: 'ErrorDemonstrator'))
|
447
458
|
puts " ✅ Success: Message created"
|
448
459
|
rescue => e
|
449
460
|
field_name = e.message.match(/property '([^']+)'/)[1] rescue 'unknown'
|