smart_message 0.0.4 → 0.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de5fce8e9cb793850301df5fdb9ad8a6954cf3a481cadc2deb625c373706723a
4
- data.tar.gz: 0cc8067011377f0d574bc7f9bf1168ac2176fad7c7981cbd43f708e622a98fa0
3
+ metadata.gz: 6c388c9738746603d14a57d6c4e04fb7d6e48156c4e571cd82dffd461217e111
4
+ data.tar.gz: 975779de0b52686b8b08baa94070fea52578c86f5fb1a3752aa25cad98a812d7
5
5
  SHA512:
6
- metadata.gz: bf7d1fc90d41bdbd3a8661f1f3e294915d29f267a68c13869926a4f829a00338f3878b03e14f26a7ccc9b248dc55b566e9988cb67aca7f6de596b94a51b5e885
7
- data.tar.gz: 51c784d4183fe12862ff9250389a57233718604442e50303cdb941265971978e291fe7c3c1fec92509e6fa32bcc67b6b2fe8813b3cc1d06fa9d1f16645b181f3
6
+ metadata.gz: b425fa9d66a2716394a1dc695b8ba82c9acc9c82dc616fc00cf8eeab2639a7833640e71240969614f31836ee0d325ae8980fa4f4d266e6961dfd6a8971172420
7
+ data.tar.gz: 711381ff80115a8582551fc58f22630c9c103c24d46f04b1edc54b87d41fd181d80a0f730cc6d14a000ec3b5478330062385edb6e5344fe1e541559e82652c97
data/CHANGELOG.md CHANGED
@@ -7,6 +7,57 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.0.5] 2025-08-18
11
+
12
+ ### Added
13
+ - **Enhanced Description DSL**: Extended class-level `description` method with automatic defaults
14
+ - Classes without explicit descriptions now automatically get `"ClassName is a SmartMessage"` default
15
+ - Instance method `message.description` provides access to class description
16
+ - Backward compatible with existing description implementations
17
+ - Improves developer experience by eliminating nil description values
18
+ - **Comprehensive Error Handling Example** (`examples/07_error_handling_scenarios.rb`)
19
+ - Demonstrates missing required property validation with detailed error messages
20
+ - Shows custom property validation failures with multiple validation types (regex, range, enum, proc)
21
+ - Illustrates version mismatch detection between message classes and headers
22
+ - **NEW**: Documents Hashie::Dash limitation where only first missing required property is reported
23
+ - Provides educational content about SmartMessage's robust validation framework
24
+ - Includes suggestions for potential improvements to multi-property validation
25
+ - **Complete Property Documentation**: All examples now include comprehensive descriptions
26
+ - Message class descriptions added to all example programs (01-06 + tmux_chat)
27
+ - Individual property descriptions added with detailed explanations of purpose and format
28
+ - Enhanced readability and educational value of all demonstration code
29
+ - Consistent documentation patterns across all messaging scenarios
30
+
31
+ ### Fixed
32
+ - **Critical: Infinite Loop Bug in Chat Examples**
33
+ - Fixed infinite message loops in `examples/03_many_to_many_chat.rb` and `examples/tmux_chat/bot_agent.rb`
34
+ - **Root Cause**: Bots responding to other bots' messages containing trigger keywords ("hello", "hi")
35
+ - **Solution**: Added `return if chat_data['message_type'] == 'bot'` to prevent bot-to-bot responses
36
+ - Examples now terminate properly without requiring manual intervention
37
+ - Maintains proper bot functionality for human interactions and explicit commands
38
+ - **Example Termination**: Chat examples now shutdown cleanly without hanging indefinitely
39
+
40
+ ### Changed
41
+ - **Enhanced Documentation Coverage**
42
+ - Updated README.md with comprehensive description DSL documentation
43
+ - Enhanced `docs/properties.md` with updated class description behavior and default handling
44
+ - Updated `docs/getting-started.md`, `docs/architecture.md`, and `docs/examples.md` with description examples
45
+ - All documentation now demonstrates proper message and property description usage
46
+ - **Improved Example Educational Value**
47
+ - All example programs enhanced with descriptive class and property documentation
48
+ - Better demonstration of SmartMessage's self-documenting capabilities
49
+ - Examples serve as both functional demonstrations and documentation references
50
+
51
+ ### Documentation
52
+ - **Hashie::Dash Limitation Discovery**: Documented important framework limitation in error handling example
53
+ - Only first missing required property reported during validation failures
54
+ - Provides clear explanation of incremental error discovery behavior
55
+ - Suggests potential solutions for improved multi-property validation
56
+ - **Comprehensive Description System**: Complete documentation of message documentation capabilities
57
+ - Class-level description DSL with automatic defaults
58
+ - Property-level descriptions with usage patterns
59
+ - Integration with existing SmartMessage validation and introspection systems
60
+
10
61
  ## [0.0.2] - 2025-08-17
11
62
 
12
63
  ### Added
data/README.md CHANGED
@@ -9,6 +9,9 @@ SmartMessage is a message abstraction framework that decouples business logic fr
9
9
 
10
10
  - **Transport Abstraction**: Plugin architecture supporting multiple message transports (Redis, RabbitMQ, Kafka, etc.)
11
11
  - **Serialization Flexibility**: Pluggable serialization formats (JSON, MessagePack, etc.)
12
+ - **Schema Versioning**: Built-in version management with automatic compatibility validation
13
+ - **Comprehensive Validation**: Property validation with custom error messages and automatic validation before publishing
14
+ - **Message Documentation**: Built-in documentation support for message classes and properties with automatic defaults
12
15
  - **Flexible Message Handlers**: Multiple subscription patterns - default methods, custom methods, blocks, procs, and lambdas
13
16
  - **Dual-Level Configuration**: Class and instance-level plugin overrides for gateway patterns
14
17
  - **Concurrent Processing**: Thread-safe message routing using `Concurrent::CachedThreadPool`
@@ -38,10 +41,35 @@ Or install it yourself as:
38
41
 
39
42
  ```ruby
40
43
  class OrderMessage < SmartMessage::Base
41
- property :order_id, description: "Unique order identifier"
42
- property :customer_id, description: "Customer's unique ID"
43
- property :amount, description: "Total order amount in dollars"
44
- property :items, description: "Array of ordered items"
44
+ # Declare schema version for compatibility tracking
45
+ version 2
46
+
47
+ # Add a description for the message class
48
+ description "Represents customer order data for processing and fulfillment"
49
+
50
+ # Required properties with validation
51
+ property :order_id,
52
+ required: true,
53
+ message: "Order ID is required",
54
+ validate: ->(v) { v.is_a?(String) && v.length > 0 },
55
+ validation_message: "Order ID must be a non-empty string",
56
+ description: "Unique order identifier"
57
+
58
+ property :customer_id,
59
+ required: true,
60
+ message: "Customer ID is required",
61
+ description: "Customer's unique ID"
62
+
63
+ property :amount,
64
+ required: true,
65
+ message: "Amount is required",
66
+ validate: ->(v) { v.is_a?(Numeric) && v > 0 },
67
+ validation_message: "Amount must be a positive number",
68
+ description: "Total order amount in dollars"
69
+
70
+ property :items,
71
+ default: [],
72
+ description: "Array of ordered items"
45
73
 
46
74
  # Configure transport and serializer at class level
47
75
  config do
@@ -74,7 +102,7 @@ end
74
102
  ### 2. Publish Messages
75
103
 
76
104
  ```ruby
77
- # Create and publish a message
105
+ # Create and publish a message (automatically validated before publishing)
78
106
  order = OrderMessage.new(
79
107
  order_id: "ORD-123",
80
108
  customer_id: "CUST-456",
@@ -82,7 +110,16 @@ order = OrderMessage.new(
82
110
  items: ["Widget A", "Widget B"]
83
111
  )
84
112
 
85
- order.publish
113
+ # Message is automatically validated before publishing
114
+ order.publish # Validates all properties, header, and version compatibility
115
+
116
+ # Or validate manually
117
+ if order.valid?
118
+ order.publish
119
+ else
120
+ errors = order.validation_errors
121
+ errors.each { |err| puts "#{err[:property]}: #{err[:message]}" }
122
+ end
86
123
  ```
87
124
 
88
125
  ### 3. Subscribe to Messages
@@ -287,13 +324,211 @@ end
287
324
 
288
325
  1. **Definition**: Create message class inheriting from `SmartMessage::Base`
289
326
  2. **Configuration**: Set transport, serializer, and logger plugins
290
- 3. **Publishing**: Message instance is encoded and sent through transport
291
- 4. **Subscription**: Message classes register handlers with dispatcher for processing
327
+ 3. **Validation**: Messages are automatically validated before publishing (properties, header, version compatibility)
328
+ 4. **Publishing**: Message instance is encoded and sent through transport
329
+ 5. **Subscription**: Message classes register handlers with dispatcher for processing
292
330
  - Default handlers (`self.process` method)
293
331
  - Custom method handlers (`"ClassName.method_name"`)
294
332
  - Block handlers (`subscribe do |h,p|...end`)
295
333
  - Proc/Lambda handlers (`subscribe(proc {...})`)
296
- 5. **Processing**: Received messages are decoded and routed to registered handlers
334
+ 6. **Processing**: Received messages are decoded and routed to registered handlers
335
+
336
+ ## Schema Versioning and Validation
337
+
338
+ SmartMessage includes comprehensive validation and versioning capabilities to ensure message integrity and schema evolution support.
339
+
340
+ ### Version Declaration
341
+
342
+ Declare your message schema version using the `version` class method:
343
+
344
+ ```ruby
345
+ class OrderMessage < SmartMessage::Base
346
+ version 2 # Schema version 2
347
+
348
+ property :order_id, required: true
349
+ property :customer_email # Added in version 2
350
+ end
351
+ ```
352
+
353
+ ### Property Validation
354
+
355
+ Properties support multiple validation types with custom error messages:
356
+
357
+ ```ruby
358
+ class UserMessage < SmartMessage::Base
359
+ version 1
360
+
361
+ # Required field validation (Hashie built-in)
362
+ property :user_id,
363
+ required: true,
364
+ message: "User ID is required and cannot be blank"
365
+
366
+ # Custom validation with lambda
367
+ property :age,
368
+ validate: ->(v) { v.is_a?(Integer) && v.between?(1, 120) },
369
+ validation_message: "Age must be an integer between 1 and 120"
370
+
371
+ # Email validation with regex
372
+ property :email,
373
+ validate: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i,
374
+ validation_message: "Must be a valid email address"
375
+
376
+ # Inclusion validation with array
377
+ property :status,
378
+ validate: ['active', 'inactive', 'pending'],
379
+ validation_message: "Status must be active, inactive, or pending"
380
+ end
381
+ ```
382
+
383
+ ### Validation Methods
384
+
385
+ All message instances include validation methods:
386
+
387
+ ```ruby
388
+ user = UserMessage.new(user_id: "123", age: 25)
389
+
390
+ # Validate entire message (properties + header + version)
391
+ user.validate! # Raises SmartMessage::Errors::ValidationError on failure
392
+ user.valid? # Returns true/false
393
+
394
+ # Get detailed validation errors
395
+ errors = user.validation_errors
396
+ errors.each do |error|
397
+ puts "#{error[:source]}.#{error[:property]}: #{error[:message]}"
398
+ # Example output:
399
+ # message.age: Age must be an integer between 1 and 120
400
+ # header.version: Header version must be a positive integer
401
+ # version_mismatch.version: Expected version 1, got: 2
402
+ end
403
+ ```
404
+
405
+ ### Automatic Validation
406
+
407
+ Messages are automatically validated during publishing:
408
+
409
+ ```ruby
410
+ # This will raise ValidationError if invalid
411
+ message = UserMessage.new(user_id: "", age: 150)
412
+ message.publish # Automatically validates before publishing
413
+ ```
414
+
415
+ ### Version Compatibility
416
+
417
+ The framework automatically validates version compatibility:
418
+
419
+ ```ruby
420
+ class V2Message < SmartMessage::Base
421
+ version 2
422
+ property :data
423
+ end
424
+
425
+ message = V2Message.new(data: "test")
426
+ # Header automatically gets version: 2
427
+
428
+ # Simulate version mismatch (e.g., from older message)
429
+ message._sm_header.version = 1
430
+ message.validate! # Raises: "V2Message expects version 2, but header has version 1"
431
+ ```
432
+
433
+ ### Supported Validation Types
434
+
435
+ - **Proc/Lambda**: `validate: ->(v) { v.length > 5 }`
436
+ - **Regexp**: `validate: /\A[a-z]+\z/`
437
+ - **Class**: `validate: String` (type checking)
438
+ - **Array**: `validate: ['red', 'green', 'blue']` (inclusion)
439
+ - **Range**: `validate: (1..100)` (range checking)
440
+ - **Symbol**: `validate: :custom_validator_method`
441
+
442
+ ## Message Documentation
443
+
444
+ SmartMessage provides built-in documentation capabilities for both message classes and their properties.
445
+
446
+ ### Class-Level Descriptions
447
+
448
+ Use the `description` DSL method to document what your message class represents:
449
+
450
+ ```ruby
451
+ class OrderMessage < SmartMessage::Base
452
+ description "Represents customer order data for processing and fulfillment"
453
+
454
+ property :order_id, required: true
455
+ property :amount, required: true
456
+ end
457
+
458
+ class UserMessage < SmartMessage::Base
459
+ description "Handles user management operations including registration and updates"
460
+
461
+ property :user_id, required: true
462
+ property :email, required: true
463
+ end
464
+
465
+ # Access descriptions
466
+ puts OrderMessage.description
467
+ # => "Represents customer order data for processing and fulfillment"
468
+
469
+ puts UserMessage.description
470
+ # => "Handles user management operations including registration and updates"
471
+
472
+ # Instance access to class description
473
+ order = OrderMessage.new(order_id: "123", amount: 99.99)
474
+ puts order.description
475
+ # => "Represents customer order data for processing and fulfillment"
476
+ ```
477
+
478
+ ### Default Descriptions
479
+
480
+ Classes without explicit descriptions automatically get a default description:
481
+
482
+ ```ruby
483
+ class MyMessage < SmartMessage::Base
484
+ property :data
485
+ end
486
+
487
+ puts MyMessage.description
488
+ # => "MyMessage is a SmartMessage"
489
+ ```
490
+
491
+ ### Property Documentation
492
+
493
+ Combine class descriptions with property descriptions for comprehensive documentation:
494
+
495
+ ```ruby
496
+ class FullyDocumented < SmartMessage::Base
497
+ description "A fully documented message class for demonstration purposes"
498
+
499
+ property :id,
500
+ description: "Unique identifier for the record"
501
+ property :name,
502
+ description: "Display name for the entity"
503
+ property :status,
504
+ description: "Current processing status",
505
+ validate: ['active', 'inactive', 'pending']
506
+ end
507
+
508
+ # Access all documentation
509
+ puts FullyDocumented.description
510
+ # => "A fully documented message class for demonstration purposes"
511
+
512
+ puts FullyDocumented.property_description(:id)
513
+ # => "Unique identifier for the record"
514
+
515
+ puts FullyDocumented.property_descriptions
516
+ # => {:id=>"Unique identifier for the record", :name=>"Display name for the entity", ...}
517
+ ```
518
+
519
+ ### Documentation in Config Blocks
520
+
521
+ You can also set descriptions within configuration blocks:
522
+
523
+ ```ruby
524
+ class ConfiguredMessage < SmartMessage::Base
525
+ config do
526
+ description "Set within config block"
527
+ transport SmartMessage::Transport.create(:stdout)
528
+ serializer SmartMessage::Serializer::JSON.new
529
+ end
530
+ end
531
+ ```
297
532
 
298
533
  ## Advanced Usage
299
534
 
data/docs/architecture.md CHANGED
@@ -65,6 +65,8 @@ The foundation class that all messages inherit from, built on `Hashie::Dash`.
65
65
 
66
66
  ```ruby
67
67
  class MyMessage < SmartMessage::Base
68
+ description "Handles custom message processing for my application"
69
+
68
70
  property :data
69
71
 
70
72
  config do
data/docs/examples.md CHANGED
@@ -10,6 +10,8 @@ This document provides practical examples of using SmartMessage in real-world sc
10
10
  require 'smart_message'
11
11
 
12
12
  class NotificationMessage < SmartMessage::Base
13
+ description "Sends notifications to users via multiple channels"
14
+
13
15
  property :recipient
14
16
  property :subject
15
17
  property :body
@@ -37,6 +37,9 @@ Let's create a simple message class and see it in action:
37
37
  require 'smart_message'
38
38
 
39
39
  class WelcomeMessage < SmartMessage::Base
40
+ # Add a description for the message class
41
+ description "Welcomes new users after successful signup"
42
+
40
43
  # Define message properties
41
44
  property :user_name
42
45
  property :email
@@ -132,6 +135,8 @@ Messages use Hashie::Dash properties for type-safe attributes:
132
135
 
133
136
  ```ruby
134
137
  class OrderMessage < SmartMessage::Base
138
+ description "Represents customer orders for processing and fulfillment"
139
+
135
140
  property :order_id, required: true
136
141
  property :amount, transform_with: ->(v) { BigDecimal(v.to_s) }
137
142
  property :items, default: []
@@ -175,6 +180,8 @@ SmartMessage supports four types of message handlers to give you flexibility in
175
180
 
176
181
  ```ruby
177
182
  class OrderMessage < SmartMessage::Base
183
+ description "Handles customer order processing and fulfillment"
184
+
178
185
  # Define your message properties
179
186
  property :order_id
180
187
  property :amount
@@ -230,6 +237,8 @@ Now that you have the basics working, explore:
230
237
 
231
238
  ```ruby
232
239
  class NotificationMessage < SmartMessage::Base
240
+ description "Sends notifications to users via email, SMS, or push"
241
+
233
242
  property :recipient
234
243
  property :subject
235
244
  property :body
@@ -271,6 +280,8 @@ NotificationMessage.new(
271
280
 
272
281
  ```ruby
273
282
  class EventMessage < SmartMessage::Base
283
+ description "Logs application events for monitoring and analytics"
284
+
274
285
  property :event_type
275
286
  property :user_id
276
287
  property :data
data/docs/properties.md CHANGED
@@ -4,6 +4,7 @@ The SmartMessage property system builds on Hashie::Dash to provide a robust, dec
4
4
 
5
5
  ## Table of Contents
6
6
  - [Basic Property Definition](#basic-property-definition)
7
+ - [Schema Versioning](#schema-versioning)
7
8
  - [Class-Level Description](#class-level-description)
8
9
  - [Property Options](#property-options)
9
10
  - [Accessing Property Information](#accessing-property-information)
@@ -20,9 +21,115 @@ class MyMessage < SmartMessage::Base
20
21
  end
21
22
  ```
22
23
 
24
+ ## Schema Versioning
25
+
26
+ SmartMessage supports schema versioning to enable message evolution while maintaining compatibility:
27
+
28
+ ```ruby
29
+ class OrderMessage < SmartMessage::Base
30
+ version 2 # Declare schema version
31
+
32
+ property :order_id, required: true
33
+ property :customer_email # Added in version 2
34
+ end
35
+ ```
36
+
37
+ ### Version Management
38
+
39
+ ```ruby
40
+ # Version 1 message
41
+ class V1OrderMessage < SmartMessage::Base
42
+ version 1 # or omit for default version 1
43
+
44
+ property :order_id, required: true
45
+ property :amount, required: true
46
+ end
47
+
48
+ # Version 2 message with additional field
49
+ class V2OrderMessage < SmartMessage::Base
50
+ version 2
51
+
52
+ property :order_id, required: true
53
+ property :amount, required: true
54
+ property :customer_email # New in version 2
55
+ end
56
+
57
+ # Version 3 message with validation
58
+ class V3OrderMessage < SmartMessage::Base
59
+ version 3
60
+
61
+ property :order_id,
62
+ required: true,
63
+ validate: ->(v) { v.is_a?(String) && v.length > 0 }
64
+
65
+ property :amount,
66
+ required: true,
67
+ validate: ->(v) { v.is_a?(Numeric) && v > 0 }
68
+
69
+ property :customer_email,
70
+ validate: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
71
+ end
72
+ ```
73
+
74
+ ### Version Validation
75
+
76
+ The framework automatically validates version compatibility:
77
+
78
+ ```ruby
79
+ message = V2OrderMessage.new(order_id: "123", amount: 99.99)
80
+ # Header automatically gets version: 2
81
+
82
+ # Version validation happens automatically
83
+ message.validate! # Validates message + header + version compatibility
84
+
85
+ # Manual version validation
86
+ message.validate_header_version! # Checks header version matches class version
87
+
88
+ # Check version information
89
+ V2OrderMessage.version # => 2
90
+ V2OrderMessage.expected_header_version # => 2
91
+ message._sm_header.version # => 2
92
+ ```
93
+
94
+ ### Version Evolution Patterns
95
+
96
+ ```ruby
97
+ # Pattern 1: Additive changes (safe)
98
+ class UserMessageV1 < SmartMessage::Base
99
+ version 1
100
+ property :user_id, required: true
101
+ property :name, required: true
102
+ end
103
+
104
+ class UserMessageV2 < SmartMessage::Base
105
+ version 2
106
+ property :user_id, required: true
107
+ property :name, required: true
108
+ property :email # Optional addition - backward compatible
109
+ end
110
+
111
+ # Pattern 2: Field validation evolution
112
+ class ProductMessageV1 < SmartMessage::Base
113
+ version 1
114
+ property :product_id, required: true
115
+ property :price, required: true
116
+ end
117
+
118
+ class ProductMessageV2 < SmartMessage::Base
119
+ version 2
120
+ property :product_id,
121
+ required: true,
122
+ validate: ->(v) { v.is_a?(String) && v.match?(/\APROD-\d+\z/) }
123
+
124
+ property :price,
125
+ required: true,
126
+ validate: ->(v) { v.is_a?(Numeric) && v > 0 }
127
+ end
128
+ ```
129
+
23
130
  ## Class-Level Description
24
131
 
25
- In addition to property-level descriptions, you can add a description for the entire message class:
132
+ In addition to property-level descriptions, you can add a description for the entire message class using the `description` DSL method:
26
133
 
27
134
  ```ruby
28
135
  class OrderMessage < SmartMessage::Base
@@ -35,15 +142,29 @@ end
35
142
  # Access the class description
36
143
  OrderMessage.description # => "Handles order processing and fulfillment workflow"
37
144
 
38
- # Class descriptions can also be set after class definition
145
+ # Instance access to class description
146
+ order = OrderMessage.new(order_id: "123", amount: 9999)
147
+ order.description # => "Handles order processing and fulfillment workflow"
148
+ ```
149
+
150
+ ### Setting Descriptions
151
+
152
+ Class descriptions can be set in multiple ways:
153
+
154
+ ```ruby
155
+ # 1. During class definition
39
156
  class PaymentMessage < SmartMessage::Base
157
+ description "Processes payment transactions"
40
158
  property :payment_id
41
159
  end
42
160
 
43
- PaymentMessage.description "Processes payment transactions"
44
- PaymentMessage.description # => "Processes payment transactions"
161
+ # 2. After class definition
162
+ class RefundMessage < SmartMessage::Base
163
+ property :refund_id
164
+ end
165
+ RefundMessage.description "Handles payment refunds and reversals"
45
166
 
46
- # Can be set within config block
167
+ # 3. Within config block
47
168
  class NotificationMessage < SmartMessage::Base
48
169
  config do
49
170
  description "Sends notifications to users"
@@ -53,13 +174,41 @@ class NotificationMessage < SmartMessage::Base
53
174
  end
54
175
  ```
55
176
 
177
+ ### Default Descriptions
178
+
179
+ Classes without explicit descriptions automatically receive a default description:
180
+
181
+ ```ruby
182
+ class MyMessage < SmartMessage::Base
183
+ property :data
184
+ end
185
+
186
+ MyMessage.description # => "MyMessage is a SmartMessage"
187
+
188
+ # This applies to all unnamed message classes
189
+ class SomeModule::ComplexMessage < SmartMessage::Base
190
+ property :info
191
+ end
192
+
193
+ SomeModule::ComplexMessage.description
194
+ # => "SomeModule::ComplexMessage is a SmartMessage"
195
+ ```
196
+
197
+ ### Use Cases
198
+
56
199
  Class descriptions are useful for:
57
200
  - Documenting the overall purpose of a message class
58
201
  - Providing context for code generation tools
59
202
  - Integration with documentation systems
60
203
  - API documentation generation
204
+ - Dynamic message introspection in gateway applications
61
205
 
62
- Note: Class descriptions are not inherited by subclasses. Each class maintains its own description.
206
+ ### Important Notes
207
+
208
+ - Class descriptions are not inherited by subclasses - each class maintains its own description
209
+ - Setting a description to `nil` will revert to the default description
210
+ - Descriptions are stored as strings and can include multiline content
211
+ - Both class and instance methods are available to access descriptions
63
212
 
64
213
  ## Property Options
65
214
 
@@ -181,7 +330,64 @@ msg.tags # => ['important'] (Array)
181
330
  msg.metadata # => {} (Hash)
182
331
  ```
183
332
 
184
- ### 6. Property Descriptions (SmartMessage Enhancement)
333
+ ### 6. Property Validation (SmartMessage Enhancement)
334
+
335
+ Add custom validation logic to ensure data integrity:
336
+
337
+ ```ruby
338
+ class ValidatedMessage < SmartMessage::Base
339
+ # Lambda validation
340
+ property :age,
341
+ validate: ->(v) { v.is_a?(Integer) && v.between?(1, 120) },
342
+ validation_message: "Age must be an integer between 1 and 120"
343
+
344
+ # Regex validation for email
345
+ property :email,
346
+ validate: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i,
347
+ validation_message: "Must be a valid email address"
348
+
349
+ # Array inclusion validation
350
+ property :status,
351
+ validate: ['active', 'inactive', 'pending'],
352
+ validation_message: "Status must be active, inactive, or pending"
353
+
354
+ # Range validation
355
+ property :score,
356
+ validate: (0..100),
357
+ validation_message: "Score must be between 0 and 100"
358
+
359
+ # Class type validation
360
+ property :created_at,
361
+ validate: Time,
362
+ validation_message: "Must be a Time object"
363
+
364
+ # Symbol method validation
365
+ property :username,
366
+ validate: :valid_username?,
367
+ validation_message: "Username contains invalid characters"
368
+
369
+ private
370
+
371
+ def valid_username?(value)
372
+ value.to_s.match?(/\A[a-zA-Z0-9_]+\z/)
373
+ end
374
+ end
375
+
376
+ # Validation usage
377
+ message = ValidatedMessage.new(age: 25, email: "test@example.com")
378
+
379
+ # Validate entire message
380
+ message.validate! # Raises SmartMessage::Errors::ValidationError on failure
381
+ message.valid? # Returns true/false
382
+
383
+ # Get validation errors
384
+ errors = message.validation_errors
385
+ errors.each do |error|
386
+ puts "#{error[:property]}: #{error[:message]}"
387
+ end
388
+ ```
389
+
390
+ ### 7. Property Descriptions (SmartMessage Enhancement)
185
391
 
186
392
  Add human-readable descriptions to document your properties for dynamic LLM integration:
187
393