smart_message 0.0.3 → 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: 8a7c214ec62b411d8f3bbf0925d6547fa135233684ac22483e028ffc76cc6cbe
4
- data.tar.gz: f80ce67e2ea59172a36a8c7b675864c93573bf1f2b94e294124bdf2bbb28ae73
3
+ metadata.gz: 6c388c9738746603d14a57d6c4e04fb7d6e48156c4e571cd82dffd461217e111
4
+ data.tar.gz: 975779de0b52686b8b08baa94070fea52578c86f5fb1a3752aa25cad98a812d7
5
5
  SHA512:
6
- metadata.gz: da70af3b299ef64e94d8cefd87b3bb25b0a50dd3b835d4765a6f26231c65d0fa69b2ccf3d204d8de666aca2e241dcb37e396dcd064aaeae895881885e8c1ea21
7
- data.tar.gz: fd2da658b323102bcb93e73f9b5d0ae843bd6afc7a8f031be7ebc206d89231f3304092d83de79524d7fd337f09a0bafad7b7bfc782e9f7a9820d32568c65e252
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/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_message (0.0.3)
4
+ smart_message (0.0.4)
5
5
  activesupport
6
6
  concurrent-ruby
7
7
  hashie
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/README.md CHANGED
@@ -18,6 +18,7 @@ Welcome to the comprehensive documentation for SmartMessage, a Ruby gem that abs
18
18
  - [Property System](properties.md)
19
19
  - [Transport Layer](transports.md)
20
20
  - [Serializers](serializers.md)
21
+ - [Logging System](logging.md)
21
22
  - [Dispatcher & Routing](dispatcher.md)
22
23
  - [Message Headers](headers.md)
23
24
 
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