easy_talk 1.0.4 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # EasyTalk
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/easy_talk.svg)](https://badge.fury.io/rb/easy_talk)
4
+ [![Ruby](https://github.com/sergiobayona/easy_talk/actions/workflows/dev-build.yml/badge.svg)](https://github.com/sergiobayona/easy_talk/actions/workflows/dev-build.yml)
5
+
3
6
  ## Introduction
4
7
 
5
8
  ### What is EasyTalk?
@@ -7,10 +10,12 @@ EasyTalk is a Ruby library that simplifies defining and generating JSON Schema.
7
10
 
8
11
  ### Key Features
9
12
  * **Intuitive Schema Definition**: Use Ruby classes and methods to define JSON Schema documents easily.
10
- * **Works for plain Ruby classes and ActiveRecord models**: Integrate with existing code or build from scratch.
13
+ * **Automatic ActiveModel Validations**: Schema constraints automatically generate corresponding ActiveModel validations (configurable).
14
+ * **Works for plain Ruby classes and ActiveModel classes**: Integrate with existing code or build from scratch.
11
15
  * **LLM Function Support**: Ideal for integrating with Large Language Models (LLMs) such as OpenAI's GPT series. EasyTalk enables you to effortlessly create JSON Schema documents describing the inputs and outputs of LLM function calls.
12
16
  * **Schema Composition**: Define EasyTalk models and reference them in other EasyTalk models to create complex schemas.
13
- * **Validation**: Write validations using ActiveModel's validations.
17
+ * **Enhanced Model Integration**: Automatic instantiation of nested EasyTalk models from hash attributes.
18
+ * **Flexible Configuration**: Global and per-model configuration options for fine-tuned control.
14
19
 
15
20
  ### Use Cases
16
21
  - API request/response validation
@@ -26,8 +31,39 @@ Inspired by Python's Pydantic library, EasyTalk brings similar functionality to
26
31
 
27
32
  ### Requirements
28
33
  - Ruby 3.2 or higher
29
- - ActiveModel 7.0 or higher
30
- - ActiveSupport 7.0 or higher
34
+
35
+ ### Version 2.0.0 Breaking Changes
36
+
37
+ ⚠️ **IMPORTANT**: Version 2.0.0 includes breaking changes. Please review before upgrading:
38
+
39
+ - **Removed**: Block-style nested object definitions (using `Hash do ... end`)
40
+ - **Migration**: Use class references instead of inline Hash definitions
41
+
42
+ ```ruby
43
+ # ❌ No longer supported (v1.x style)
44
+ define_schema do
45
+ property :address, Hash do
46
+ property :street, String
47
+ property :city, String
48
+ end
49
+ end
50
+
51
+ # ✅ New approach (v2.x style)
52
+ class Address
53
+ include EasyTalk::Model
54
+ define_schema do
55
+ property :street, String
56
+ property :city, String
57
+ end
58
+ end
59
+
60
+ class User
61
+ include EasyTalk::Model
62
+ define_schema do
63
+ property :address, Address # Reference the class directly
64
+ end
65
+ end
66
+ ```
31
67
 
32
68
  ### Installation Steps
33
69
  Add EasyTalk to your application's Gemfile:
@@ -109,10 +145,11 @@ Creating and validating an instance of your model:
109
145
 
110
146
  ```ruby
111
147
  user = User.new(name: "John Doe", email: "john@example.com", age: 25)
112
- user.valid? # => true
148
+ user.valid? # => true (automatically validates based on schema constraints)
113
149
 
114
150
  user.age = 17
115
- user.valid? # => false
151
+ user.valid? # => false (violates minimum: 18 constraint)
152
+ user.errors[:age] # => ["must be greater than or equal to 18"]
116
153
  ```
117
154
 
118
155
  ## Core Concepts
@@ -143,7 +180,6 @@ EasyTalk supports standard Ruby types directly:
143
180
  - `Float`: Floating-point numbers
144
181
  - `Date`: Date values
145
182
  - `DateTime`: Date and time values
146
- - `Hash`: Object/dictionary values
147
183
 
148
184
  #### Sorbet-Style Types
149
185
  For complex types, EasyTalk uses Sorbet-style type notation:
@@ -184,25 +220,57 @@ end
184
220
 
185
221
  In this example, `name` is required but `middle_name` is optional.
186
222
 
187
- ### Schema Validation
188
- EasyTalk models include ActiveModel validations. You can validate your models using the standard ActiveModel validation methods:
223
+ ### Automatic Validation Generation
224
+ EasyTalk automatically generates ActiveModel validations from your schema constraints. This feature is enabled by default but can be configured:
225
+
226
+ ```ruby
227
+ class User
228
+ include EasyTalk::Model
229
+
230
+ define_schema do
231
+ property :name, String, min_length: 2, max_length: 50
232
+ property :email, String, format: "email"
233
+ property :age, Integer, minimum: 18, maximum: 120
234
+ property :status, String, enum: ["active", "inactive", "pending"]
235
+ end
236
+ # Validations are automatically generated:
237
+ # validates :name, presence: true, length: { minimum: 2, maximum: 50 }
238
+ # validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
239
+ # validates :age, presence: true, numericality: { greater_than_or_equal_to: 18, less_than_or_equal_to: 120 }
240
+ # validates :status, presence: true, inclusion: { in: ["active", "inactive", "pending"] }
241
+ end
242
+
243
+ user = User.new(name: "Jo", email: "invalid-email", age: 17)
244
+ user.valid? # => false
245
+ user.errors.full_messages
246
+ # => ["Name is too short (minimum is 2 characters)",
247
+ # "Email is invalid",
248
+ # "Age must be greater than or equal to 18"]
249
+ ```
250
+
251
+ ### Manual Validation Overrides
252
+ You can still add manual validations alongside automatic ones:
189
253
 
190
254
  ```ruby
191
255
  class User
192
256
  include EasyTalk::Model
193
257
 
194
- validates :name, presence: true
195
- validates :age, numericality: { greater_than_or_equal_to: 18 }
258
+ # Custom validation in addition to automatic ones
259
+ validates :email, uniqueness: true
260
+ validate :complex_business_rule
196
261
 
197
262
  define_schema do
198
263
  property :name, String
264
+ property :email, String, format: "email"
199
265
  property :age, Integer, minimum: 18
200
266
  end
267
+
268
+ private
269
+
270
+ def complex_business_rule
271
+ # Custom validation logic
272
+ end
201
273
  end
202
-
203
- user = User.new(name: "John", age: 17)
204
- user.valid? # => false
205
- user.errors.full_messages # => ["Age must be greater than or equal to 18"]
206
274
  ```
207
275
 
208
276
  ## Defining Schemas
@@ -230,16 +298,6 @@ property :name, String, description: "The person's name", title: "Full Name"
230
298
  property :age, Integer, minimum: 0, maximum: 120, description: "The person's age"
231
299
  ```
232
300
 
233
- ### Nested Objects
234
- You can define nested objects using a block:
235
-
236
- ```ruby
237
- property :email, Hash do
238
- property :address, String, format: "email"
239
- property :verified, T::Boolean
240
- end
241
- ```
242
-
243
301
  ### Arrays and Collections
244
302
  Arrays can be defined using the `T::Array` type:
245
303
 
@@ -254,22 +312,38 @@ You can also define arrays of complex types:
254
312
  property :addresses, T::Array[Address], description: "List of addresses"
255
313
  ```
256
314
 
257
- ### Constraints and Validations
258
- Constraints can be added to properties and are used for schema generation:
315
+ ### Constraints and Automatic Validations
316
+ Constraints are added to properties and are used for both schema generation and automatic validation generation:
259
317
 
260
318
  ```ruby
261
- property :name, String, min_length: 2, max_length: 50
262
- property :email, String, format: "email"
263
- property :category, String, enum: ["A", "B", "C"], default: "A"
319
+ define_schema do
320
+ property :name, String, min_length: 2, max_length: 50
321
+ property :email, String, format: "email"
322
+ property :category, String, enum: ["A", "B", "C"]
323
+ property :score, Float, minimum: 0.0, maximum: 100.0
324
+ property :tags, T::Array[String], min_items: 1, max_items: 10
325
+ end
326
+ # Automatically generates equivalent ActiveModel validations:
327
+ # validates :name, presence: true, length: { minimum: 2, maximum: 50 }
328
+ # validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
329
+ # validates :category, presence: true, inclusion: { in: ["A", "B", "C"] }
330
+ # validates :score, presence: true, numericality: { greater_than_or_equal_to: 0.0, less_than_or_equal_to: 100.0 }
331
+ # validates :tags, presence: true, length: { minimum: 1, maximum: 10 }
264
332
  ```
265
333
 
266
- For validation, you can use ActiveModel validations:
334
+ ### Supported Constraint-to-Validation Mappings
267
335
 
268
- ```ruby
269
- validates :name, presence: true, length: { minimum: 2, maximum: 50 }
270
- validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
271
- validates :category, inclusion: { in: ["A", "B", "C"] }
272
- ```
336
+ | Constraint | Validation Generated |
337
+ |------------|---------------------|
338
+ | `min_length`, `max_length` | `length: { minimum: X, maximum: Y }` |
339
+ | `minimum`, `maximum` | `numericality: { greater_than_or_equal_to: X, less_than_or_equal_to: Y }` |
340
+ | `format: "email"` | `format: { with: URI::MailTo::EMAIL_REGEXP }` |
341
+ | `format: "url"` or `format: "uri"` | `format: { with: URI::regexp }` |
342
+ | `pattern: /regex/` | `format: { with: /regex/ }` |
343
+ | `enum: [...]` | `inclusion: { in: [...] }` |
344
+ | `min_items`, `max_items` (arrays) | `length: { minimum: X, maximum: Y }` |
345
+ | `optional: true` | Skips presence validation |
346
+ | `T.nilable(Type)` | Allows nil values, skips presence validation |
273
347
 
274
348
  ### Additional Properties
275
349
  By default, EasyTalk models do not allow additional properties beyond those defined in the schema. You can change this behavior using the `additional_properties` keyword:
@@ -373,20 +447,21 @@ end
373
447
 
374
448
  ## ActiveModel Integration
375
449
 
376
- ### Validations
377
- EasyTalk models include ActiveModel validations:
450
+ ### Enhanced Validation System
451
+ EasyTalk models include comprehensive ActiveModel validation support with automatic generation:
378
452
 
379
453
  ```ruby
380
454
  class User
381
455
  include EasyTalk::Model
382
456
 
383
- validates :age, comparison: { greater_than: 21 }
384
- validates :height, presence: true, numericality: { greater_than: 0 }
457
+ # Manual validations work alongside automatic ones
458
+ validates :age, comparison: { greater_than: 21 } # Additional business rule
459
+ validates :height, numericality: { greater_than: 0 } # Overrides auto-validation
385
460
 
386
461
  define_schema do
387
- property :name, String
388
- property :age, Integer
389
- property :height, Float
462
+ property :name, String, min_length: 2 # Auto-generates presence + length validations
463
+ property :age, Integer, minimum: 18 # Auto-generates presence + numericality validations
464
+ property :height, Float # Auto-generates presence validation (overridden above)
390
465
  end
391
466
  end
392
467
  ```
@@ -395,10 +470,11 @@ end
395
470
  You can access validation errors using the standard ActiveModel methods:
396
471
 
397
472
  ```ruby
398
- user = User.new(name: "Jim", age: 18, height: -5.9)
473
+ user = User.new(name: "J", age: 18, height: -5.9)
399
474
  user.valid? # => false
400
- user.errors[:age] # => ["must be greater than 21"]
401
- user.errors[:height] # => ["must be greater than 0"]
475
+ user.errors[:name] # => ["is too short (minimum is 2 characters)"]
476
+ user.errors[:age] # => ["must be greater than 21"] # Custom validation
477
+ user.errors[:height] # => ["must be greater than 0"] # Overridden validation
402
478
  ```
403
479
 
404
480
  ### Model Attributes
@@ -411,123 +487,35 @@ user.age = 30
411
487
  puts user.name # => "John"
412
488
  ```
413
489
 
414
- You can also initialize a model with a hash of attributes:
490
+ You can also initialize a model with a hash of attributes, including nested EasyTalk models:
415
491
 
416
492
  ```ruby
417
493
  user = User.new(name: "John", age: 30, height: 5.9)
418
- ```
419
-
420
- ## ActiveRecord Integration
421
-
422
- ### Automatic Schema Generation
423
- For ActiveRecord models, EasyTalk automatically generates a schema based on the database columns:
424
-
425
- ```ruby
426
- class Product < ActiveRecord::Base
427
- include EasyTalk::Model
428
- end
429
- ```
430
-
431
- This will create a schema with properties for each column in the `products` table.
432
494
 
433
- ### Enhancing Generated Schemas
434
- You can enhance the auto-generated schema with the `enhance_schema` method:
435
-
436
- ```ruby
437
- class Product < ActiveRecord::Base
438
- include EasyTalk::Model
439
-
440
- enhance_schema({
441
- title: "Retail Product",
442
- description: "A product available for purchase",
443
- properties: {
444
- name: {
445
- description: "Product display name",
446
- title: "Product Name"
447
- },
448
- price: {
449
- description: "Retail price in USD"
450
- }
451
- }
452
- })
453
- end
454
- ```
455
-
456
- ### Column Exclusion Options
457
- EasyTalk provides several ways to exclude columns from your JSON schema:
458
-
459
- #### 1. Global Configuration
460
-
461
- ```ruby
462
- EasyTalk.configure do |config|
463
- # Exclude specific columns by name from all models
464
- config.excluded_columns = [:created_at, :updated_at, :deleted_at]
465
-
466
- # Exclude all foreign key columns (columns ending with '_id')
467
- config.exclude_foreign_keys = true # Default: false
468
-
469
- # Exclude all primary key columns ('id')
470
- config.exclude_primary_key = true # Default: true
471
-
472
- # Exclude timestamp columns ('created_at', 'updated_at')
473
- config.exclude_timestamps = true # Default: true
474
-
475
- # Exclude all association properties
476
- config.exclude_associations = true # Default: false
477
- end
478
- ```
479
-
480
- #### 2. Model-Specific Column Ignoring
481
-
482
- ```ruby
483
- class Product < ActiveRecord::Base
484
- include EasyTalk::Model
485
-
486
- enhance_schema({
487
- ignore: [:internal_ref_id, :legacy_code] # Model-specific exclusions
488
- })
489
- end
490
- ```
491
-
492
- ### Virtual Properties
493
- You can add properties that don't exist as database columns:
494
-
495
- ```ruby
496
- class Product < ActiveRecord::Base
495
+ # NEW in v2.0.0: Automatic nested model instantiation
496
+ class Address
497
497
  include EasyTalk::Model
498
-
499
- enhance_schema({
500
- properties: {
501
- full_details: {
502
- virtual: true,
503
- type: :string,
504
- description: "Complete product information"
505
- }
506
- }
507
- })
498
+ define_schema do
499
+ property :street, String
500
+ property :city, String
501
+ end
508
502
  end
509
- ```
510
503
 
511
- ### Associations and Foreign Keys
512
- By default, EasyTalk includes your model's associations in the schema:
513
-
514
- ```ruby
515
- class Product < ActiveRecord::Base
504
+ class User
516
505
  include EasyTalk::Model
517
- belongs_to :category
518
- has_many :reviews
506
+ define_schema do
507
+ property :name, String
508
+ property :address, Address
509
+ end
519
510
  end
520
- ```
521
-
522
- This will include `category` (as an object) and `reviews` (as an array) in the schema.
523
-
524
- You can control this behavior with configuration:
525
511
 
526
- ```ruby
527
- EasyTalk.configure do |config|
528
- config.exclude_associations = true # Don't include associations
529
- config.exclude_foreign_keys = true # Don't include foreign key columns
530
- end
512
+ # Hash attributes automatically instantiate nested models
513
+ user = User.new(
514
+ name: "John",
515
+ address: { street: "123 Main St", city: "Boston" }
516
+ )
517
+ user.address.class # => Address (automatically instantiated)
518
+ user.address.street # => "123 Main St"
531
519
  ```
532
520
 
533
521
  ## Advanced Features
@@ -597,79 +585,99 @@ You can configure EasyTalk globally:
597
585
 
598
586
  ```ruby
599
587
  EasyTalk.configure do |config|
600
- config.excluded_columns = [:created_at, :updated_at, :deleted_at]
601
- config.exclude_foreign_keys = true
602
- config.exclude_primary_key = true
603
- config.exclude_timestamps = true
604
- config.exclude_associations = false
605
- config.default_additional_properties = false
588
+ # Schema behavior options
589
+ config.default_additional_properties = false # Control additional properties on all models
590
+ config.nilable_is_optional = false # Makes T.nilable properties also optional
591
+ config.auto_validations = true # Automatically generate ActiveModel validations
606
592
  end
607
593
  ```
608
594
 
609
- ### Per-Model Configuration
610
- Some settings can be configured per model:
595
+ ### Automatic Validation Configuration
596
+ The new `auto_validations` option (enabled by default) automatically generates ActiveModel validations from your schema constraints:
611
597
 
612
598
  ```ruby
613
- class Product < ActiveRecord::Base
599
+ # Disable automatic validations globally
600
+ EasyTalk.configure do |config|
601
+ config.auto_validations = false
602
+ end
603
+
604
+ # Now you must manually define validations
605
+ class User
614
606
  include EasyTalk::Model
615
607
 
616
- enhance_schema({
617
- additionalProperties: true,
618
- ignore: [:internal_ref_id, :legacy_code]
619
- })
608
+ validates :name, presence: true, length: { minimum: 2 }
609
+ validates :age, presence: true, numericality: { greater_than_or_equal_to: 18 }
610
+
611
+ define_schema do
612
+ property :name, String, min_length: 2
613
+ property :age, Integer, minimum: 18
614
+ end
620
615
  end
621
616
  ```
622
617
 
623
- ### Exclusion Rules
624
- Columns are excluded based on the following rules (in order of precedence):
625
-
626
- 1. Explicitly listed in `excluded_columns` global setting
627
- 2. Listed in the model's `schema_enhancements[:ignore]` array
628
- 3. Is a primary key when `exclude_primary_key` is true (default)
629
- 4. Is a timestamp column when `exclude_timestamps` is true (default)
630
- 5. Matches a foreign key pattern when `exclude_foreign_keys` is true
631
-
632
- ### Customizing Output
633
- You can customize the JSON Schema output by enhancing the schema:
618
+ ### Per-Model Configuration
619
+ You can configure additional properties for individual models:
634
620
 
635
621
  ```ruby
636
- class User < ActiveRecord::Base
622
+ class User
637
623
  include EasyTalk::Model
638
624
 
639
- enhance_schema({
640
- title: "User Account",
641
- description: "User account information",
642
- properties: {
643
- name: {
644
- title: "Full Name",
645
- description: "User's full name"
646
- }
647
- }
648
- })
625
+ define_schema do
626
+ title "User"
627
+ additional_properties true # Allow arbitrary additional properties on this model
628
+ property :name, String
629
+ property :email, String, format: "email"
630
+ end
649
631
  end
650
632
  ```
651
633
 
652
634
  ## Examples
653
635
 
654
- ### User Registration
636
+ ### User Registration (with Auto-Validations)
655
637
 
656
638
  ```ruby
657
639
  class User
658
640
  include EasyTalk::Model
659
641
 
660
- validates :name, :email, :password, presence: true
661
- validates :password, length: { minimum: 8 }
662
- validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
642
+ # Additional custom validations beyond automatic ones
643
+ validates :email, uniqueness: true
644
+ validates :password, confirmation: true
663
645
 
664
646
  define_schema do
665
647
  title "User Registration"
666
648
  description "User registration information"
667
- property :name, String, description: "User's full name"
649
+ property :name, String, min_length: 2, max_length: 100, description: "User's full name"
668
650
  property :email, String, format: "email", description: "User's email address"
669
- property :password, String, min_length: 8, description: "User's password"
670
- property :notify, T::Boolean, default: true, description: "Whether to send notifications"
651
+ property :password, String, min_length: 8, max_length: 128, description: "User's password"
652
+ property :notify, T::Boolean, optional: true, description: "Whether to send notifications"
671
653
  end
654
+ # Auto-generated validations:
655
+ # validates :name, presence: true, length: { minimum: 2, maximum: 100 }
656
+ # validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
657
+ # validates :password, presence: true, length: { minimum: 8, maximum: 128 }
658
+ # validates :notify, inclusion: { in: [true, false] } - only if present (optional: true)
672
659
  end
660
+
661
+ # Usage with automatic validation
662
+ user = User.new(
663
+ name: "John Doe",
664
+ email: "john@example.com",
665
+ password: "secretpassword123",
666
+ notify: true
667
+ )
668
+ user.valid? # => true (assuming email is unique)
669
+
670
+ # Invalid data triggers auto-generated validations
671
+ invalid_user = User.new(
672
+ name: "J", # Too short
673
+ email: "invalid-email", # Invalid format
674
+ password: "123" # Too short
675
+ )
676
+ invalid_user.valid? # => false
677
+ invalid_user.errors.full_messages
678
+ # => ["Name is too short (minimum is 2 characters)",
679
+ # "Email is invalid",
680
+ # "Password is too short (minimum is 8 characters)"]
673
681
  ```
674
682
 
675
683
  ### Payment Processing
@@ -852,13 +860,16 @@ property :status, String, enum: ["active", "inactive", "pending"]
852
860
 
853
861
  ### Best Practices
854
862
 
855
- 1. Define clear property names and descriptions
856
- 2. Use appropriate types for each property
857
- 3. Add validations for important business rules
858
- 4. Keep schemas focused and modular
859
- 5. Reuse models when appropriate
860
- 6. Use explicit types instead of relying on inference
861
- 7. Test your schemas with sample data
863
+ 1. **Define clear property names and descriptions** for better documentation
864
+ 2. **Use appropriate types** for each property with proper constraints
865
+ 3. **Leverage automatic validations** by defining schema constraints instead of manual validations
866
+ 4. **Keep schemas focused and modular** - extract nested objects to separate classes
867
+ 5. **Reuse models when appropriate** instead of duplicating schema definitions
868
+ 6. **Use explicit types** instead of relying on inference
869
+ 7. **Test your schemas with sample data** to ensure validations work as expected
870
+ 8. **Configure auto-validations globally** to maintain consistency across your application
871
+ 9. **Use nullable_optional_property** for fields that can be omitted or null
872
+ 10. **Document breaking changes** when updating schema definitions
862
873
 
863
874
  # Nullable vs Optional Properties in EasyTalk
864
875
 
@@ -983,14 +994,6 @@ class UserProfile
983
994
 
984
995
  # Optional and nullable (can be omitted, can be null if present)
985
996
  nullable_optional_property :bio, String
986
-
987
- # Nested object with mixed property types
988
- property :address, Hash do
989
- property :street, String # Required
990
- property :city, String # Required
991
- property :state, String, optional: true # Optional
992
- nullable_optional_property :zip, String # Optional and nullable
993
- end
994
997
  end
995
998
  end
996
999
  ```
@@ -1041,6 +1044,102 @@ We recommend updating your schema definitions to explicitly declare which proper
1041
1044
  | `property :p, String, optional: true` | No | No | `{ "properties": { "p": { "type": "string" } } }` |
1042
1045
  | `nullable_optional_property :p, String` | No | Yes | `{ "properties": { "p": { "type": ["string", "null"] } } }` |
1043
1046
 
1047
+ ## Migration Guide from v1.x to v2.0
1048
+
1049
+ ### Breaking Changes Summary
1050
+
1051
+ 1. **Removed Block-Style Sub-Schemas**: Hash-based nested definitions are no longer supported
1052
+ 2. **Enhanced Validation System**: Automatic validation generation is now enabled by default
1053
+ 3. **Improved Model Initialization**: Better support for nested model instantiation
1054
+
1055
+ ### Migration Steps
1056
+
1057
+ #### 1. Replace Hash-based Nested Schemas
1058
+
1059
+ ```ruby
1060
+ # OLD (v1.x) - No longer works
1061
+ class User
1062
+ include EasyTalk::Model
1063
+ define_schema do
1064
+ property :address, Hash do
1065
+ property :street, String
1066
+ property :city, String
1067
+ end
1068
+ end
1069
+ end
1070
+
1071
+ # NEW (v2.x) - Extract to separate classes
1072
+ class Address
1073
+ include EasyTalk::Model
1074
+ define_schema do
1075
+ property :street, String
1076
+ property :city, String
1077
+ end
1078
+ end
1079
+
1080
+ class User
1081
+ include EasyTalk::Model
1082
+ define_schema do
1083
+ property :address, Address
1084
+ end
1085
+ end
1086
+ ```
1087
+
1088
+ #### 2. Review Automatic Validations
1089
+
1090
+ With `auto_validations: true` (default), you may need to remove redundant manual validations:
1091
+
1092
+ ```ruby
1093
+ # OLD (v1.x) - Manual validations required
1094
+ class User
1095
+ include EasyTalk::Model
1096
+
1097
+ validates :name, presence: true, length: { minimum: 2 }
1098
+ validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
1099
+
1100
+ define_schema do
1101
+ property :name, String
1102
+ property :email, String
1103
+ end
1104
+ end
1105
+
1106
+ # NEW (v2.x) - Automatic validations from constraints
1107
+ class User
1108
+ include EasyTalk::Model
1109
+
1110
+ # Only add validations not covered by schema constraints
1111
+ validates :email, uniqueness: true
1112
+
1113
+ define_schema do
1114
+ property :name, String, min_length: 2 # Auto-generates presence + length
1115
+ property :email, String, format: "email" # Auto-generates presence + format
1116
+ end
1117
+ end
1118
+ ```
1119
+
1120
+ #### 3. Configuration Updates
1121
+
1122
+ Review your configuration for new options:
1123
+
1124
+ ```ruby
1125
+ EasyTalk.configure do |config|
1126
+ # New option in v2.0
1127
+ config.auto_validations = true # Enable/disable automatic validation generation
1128
+
1129
+ # Existing options (unchanged)
1130
+ config.nilable_is_optional = false
1131
+ config.default_additional_properties = false
1132
+ # ... other existing config
1133
+ end
1134
+ ```
1135
+
1136
+ ### Compatibility Notes
1137
+
1138
+ - **Ruby Version**: Still requires Ruby 3.2+
1139
+ - **Dependencies**: Core dependencies remain the same
1140
+ - **JSON Schema Output**: No changes to generated schemas
1141
+ - **ActiveModel Integration**: Fully backward compatible
1142
+
1044
1143
  ## Development and Contributing
1045
1144
 
1046
1145
  ### Setting Up the Development Environment
@@ -1059,6 +1158,13 @@ Run the test suite with:
1059
1158
  bundle exec rake spec
1060
1159
  ```
1061
1160
 
1161
+ ### Code Quality
1162
+ Run the linter:
1163
+
1164
+ ```bash
1165
+ bundle exec rubocop
1166
+ ```
1167
+
1062
1168
  ### Contributing Guidelines
1063
1169
  Bug reports and pull requests are welcome on GitHub at https://github.com/sergiobayona/easy_talk.
1064
1170