better_model 2.1.0 → 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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +96 -13
  3. data/lib/better_model/archivable.rb +203 -91
  4. data/lib/better_model/errors/archivable/already_archived_error.rb +11 -0
  5. data/lib/better_model/errors/archivable/archivable_error.rb +13 -0
  6. data/lib/better_model/errors/archivable/configuration_error.rb +10 -0
  7. data/lib/better_model/errors/archivable/not_archived_error.rb +11 -0
  8. data/lib/better_model/errors/archivable/not_enabled_error.rb +11 -0
  9. data/lib/better_model/errors/better_model_error.rb +9 -0
  10. data/lib/better_model/errors/permissible/configuration_error.rb +9 -0
  11. data/lib/better_model/errors/permissible/permissible_error.rb +13 -0
  12. data/lib/better_model/errors/predicable/configuration_error.rb +9 -0
  13. data/lib/better_model/errors/predicable/predicable_error.rb +13 -0
  14. data/lib/better_model/errors/searchable/configuration_error.rb +9 -0
  15. data/lib/better_model/errors/searchable/invalid_order_error.rb +11 -0
  16. data/lib/better_model/errors/searchable/invalid_pagination_error.rb +11 -0
  17. data/lib/better_model/errors/searchable/invalid_predicate_error.rb +11 -0
  18. data/lib/better_model/errors/searchable/invalid_security_error.rb +11 -0
  19. data/lib/better_model/errors/searchable/searchable_error.rb +13 -0
  20. data/lib/better_model/errors/sortable/configuration_error.rb +10 -0
  21. data/lib/better_model/errors/sortable/sortable_error.rb +13 -0
  22. data/lib/better_model/errors/stateable/check_failed_error.rb +14 -0
  23. data/lib/better_model/errors/stateable/configuration_error.rb +10 -0
  24. data/lib/better_model/errors/stateable/invalid_state_error.rb +11 -0
  25. data/lib/better_model/errors/stateable/invalid_transition_error.rb +11 -0
  26. data/lib/better_model/errors/stateable/not_enabled_error.rb +11 -0
  27. data/lib/better_model/errors/stateable/stateable_error.rb +13 -0
  28. data/lib/better_model/errors/stateable/validation_failed_error.rb +11 -0
  29. data/lib/better_model/errors/statusable/configuration_error.rb +9 -0
  30. data/lib/better_model/errors/statusable/statusable_error.rb +13 -0
  31. data/lib/better_model/errors/taggable/configuration_error.rb +10 -0
  32. data/lib/better_model/errors/taggable/taggable_error.rb +13 -0
  33. data/lib/better_model/errors/traceable/configuration_error.rb +10 -0
  34. data/lib/better_model/errors/traceable/not_enabled_error.rb +11 -0
  35. data/lib/better_model/errors/traceable/traceable_error.rb +13 -0
  36. data/lib/better_model/errors/validatable/configuration_error.rb +10 -0
  37. data/lib/better_model/errors/validatable/not_enabled_error.rb +11 -0
  38. data/lib/better_model/errors/validatable/validatable_error.rb +13 -0
  39. data/lib/better_model/models/state_transition.rb +122 -0
  40. data/lib/better_model/models/version.rb +68 -0
  41. data/lib/better_model/permissible.rb +103 -52
  42. data/lib/better_model/predicable.rb +114 -63
  43. data/lib/better_model/repositable/base_repository.rb +232 -0
  44. data/lib/better_model/repositable.rb +32 -0
  45. data/lib/better_model/searchable.rb +92 -92
  46. data/lib/better_model/sortable.rb +137 -41
  47. data/lib/better_model/stateable/configurator.rb +71 -53
  48. data/lib/better_model/stateable/guard.rb +35 -15
  49. data/lib/better_model/stateable/transition.rb +59 -30
  50. data/lib/better_model/stateable.rb +33 -15
  51. data/lib/better_model/statusable.rb +84 -52
  52. data/lib/better_model/taggable.rb +120 -75
  53. data/lib/better_model/traceable.rb +56 -48
  54. data/lib/better_model/validatable/configurator.rb +49 -172
  55. data/lib/better_model/validatable.rb +88 -113
  56. data/lib/better_model/version.rb +1 -1
  57. data/lib/better_model.rb +42 -5
  58. data/lib/generators/better_model/repository/repository_generator.rb +141 -0
  59. data/lib/generators/better_model/repository/templates/application_repository.rb.tt +21 -0
  60. data/lib/generators/better_model/repository/templates/repository.rb.tt +71 -0
  61. data/lib/generators/better_model/stateable/templates/README +1 -1
  62. metadata +44 -7
  63. data/lib/better_model/state_transition.rb +0 -106
  64. data/lib/better_model/stateable/errors.rb +0 -48
  65. data/lib/better_model/validatable/business_rule_validator.rb +0 -47
  66. data/lib/better_model/validatable/order_validator.rb +0 -77
  67. data/lib/better_model/version_record.rb +0 -66
@@ -2,56 +2,45 @@
2
2
 
3
3
  module BetterModel
4
4
  module Validatable
5
- # Configurator per il DSL di Validatable
5
+ # Configurator for Validatable DSL.
6
6
  #
7
- # Questo configurator permette di definire validazioni in modo dichiarativo
8
- # all'interno del blocco `validatable do...end`.
7
+ # This configurator enables defining validations declaratively
8
+ # within the `validatable do...end` block.
9
9
  #
10
- # Esempio:
10
+ # @example
11
11
  # validatable do
12
- # # Validazioni base
12
+ # # Basic validations
13
13
  # check :title, :content, presence: true
14
14
  # check :email, format: { with: URI::MailTo::EMAIL_REGEXP }
15
15
  #
16
- # # Validazioni condizionali
17
- # validate_if :is_published? do
18
- # check :published_at, presence: true
19
- # check :author_id, presence: true
20
- # end
16
+ # # Complex validations
17
+ # check_complex :valid_pricing
18
+ # check_complex :stock_check
21
19
  #
22
- # # Validazioni condizionali negate
23
- # validate_unless :is_draft? do
24
- # check :reviewer_id, presence: true
25
- # end
26
- #
27
- # # Cross-field validations
28
- # validate_order :starts_at, :before, :ends_at
29
- # validate_order :min_price, :lteq, :max_price
30
- #
31
- # # Business rules
32
- # validate_business_rule :valid_category
33
- # validate_business_rule :author_has_permission, on: :create
34
- #
35
- # # Gruppi di validazioni
20
+ # # Validation groups
36
21
  # validation_group :step1, [:email, :password]
37
22
  # validation_group :step2, [:first_name, :last_name]
38
23
  # end
39
24
  #
25
+ # @api private
40
26
  class Configurator
41
27
  attr_reader :groups
42
28
 
29
+ # Initialize a new Configurator.
30
+ #
31
+ # @param model_class [Class] Model class being configured
43
32
  def initialize(model_class)
44
33
  @model_class = model_class
45
- @conditional_validations = []
46
- @order_validations = []
47
- @business_rules = []
34
+ @complex_validations = []
48
35
  @groups = {}
49
36
  end
50
37
 
51
- # Definisce validazioni standard sui campi
38
+ # Define standard validations on fields.
39
+ #
40
+ # Delegates to ActiveRecord's validates method.
52
41
  #
53
- # @param fields [Array<Symbol>] Nomi dei campi
54
- # @param options [Hash] Opzioni di validazione (presence, format, etc.)
42
+ # @param fields [Array<Symbol>] Field names
43
+ # @param options [Hash] Validation options (presence, format, etc.)
55
44
  #
56
45
  # @example
57
46
  # check :title, :content, presence: true
@@ -59,164 +48,54 @@ module BetterModel
59
48
  # check :age, numericality: { greater_than: 0 }
60
49
  #
61
50
  def check(*fields, **options)
62
- # Se siamo dentro un blocco condizionale, aggiungi alla condizione corrente
63
- if @current_conditional
64
- @current_conditional[:validations] << {
65
- fields: fields,
66
- options: options
67
- }
68
- else
69
- # Altrimenti applica direttamente alla classe
70
- # Questo viene fatto subito, non in apply_validatable_config
71
- @model_class.validates(*fields, **options)
72
- end
73
- end
74
-
75
- # Validazioni condizionali (se condizione è vera)
76
- #
77
- # @param condition [Symbol, Proc] Condizione da verificare
78
- # @yield Blocco con validazioni da applicare se condizione è vera
79
- #
80
- # @example Con simbolo (metodo)
81
- # validate_if :is_published? do
82
- # check :published_at, presence: true
83
- # end
84
- #
85
- # @example Con lambda
86
- # validate_if -> { status == "published" } do
87
- # check :published_at, presence: true
88
- # end
89
- #
90
- def validate_if(condition, &block)
91
- raise ArgumentError, "validate_if requires a block" unless block_given?
92
-
93
- conditional = {
94
- condition: condition,
95
- negate: false,
96
- validations: []
97
- }
98
-
99
- # Set current conditional per catturare le validate dentro il blocco
100
- @current_conditional = conditional
101
- instance_eval(&block)
102
- @current_conditional = nil
103
-
104
- @conditional_validations << conditional
105
- end
106
-
107
- # Validazioni condizionali negate (se condizione è falsa)
108
- #
109
- # @param condition [Symbol, Proc] Condizione da verificare
110
- # @yield Blocco con validazioni da applicare se condizione è falsa
111
- #
112
- # @example
113
- # validate_unless :is_draft? do
114
- # check :reviewer_id, presence: true
115
- # end
116
- #
117
- def validate_unless(condition, &block)
118
- raise ArgumentError, "validate_unless requires a block" unless block_given?
119
-
120
- conditional = {
121
- condition: condition,
122
- negate: true,
123
- validations: []
124
- }
125
-
126
- @current_conditional = conditional
127
- instance_eval(&block)
128
- @current_conditional = nil
129
-
130
- @conditional_validations << conditional
51
+ @model_class.validates(*fields, **options)
131
52
  end
132
53
 
133
- # Validazione di ordine tra campi (cross-field)
134
- #
135
- # Verifica che un campo sia in una relazione d'ordine rispetto ad un altro.
136
- #
137
- # @param first_field [Symbol] Primo campo
138
- # @param comparator [Symbol] Comparatore (:before, :after, :lteq, :gteq)
139
- # @param second_field [Symbol] Secondo campo
140
- # @param options [Hash] Opzioni aggiuntive (on, if, unless, message)
141
- #
142
- # @example Date validation
143
- # validate_order :starts_at, :before, :ends_at
144
- # validate_order :starts_at, :before, :ends_at, message: "must be before end date"
145
- #
146
- # @example Numeric validation
147
- # validate_order :min_price, :lteq, :max_price
148
- # validate_order :discount, :lteq, :price, on: :create
149
- #
150
- # Comparatori supportati:
151
- # - :before - first < second (date/time)
152
- # - :after - first > second (date/time)
153
- # - :lteq - first <= second (numeric)
154
- # - :gteq - first >= second (numeric)
155
- # - :lt - first < second (numeric)
156
- # - :gt - first > second (numeric)
157
- #
158
- def validate_order(first_field, comparator, second_field, **options)
159
- valid_comparators = %i[before after lteq gteq lt gt]
160
- unless valid_comparators.include?(comparator)
161
- raise ArgumentError, "Invalid comparator: #{comparator}. Valid: #{valid_comparators.join(', ')}"
162
- end
163
-
164
- @order_validations << {
165
- first_field: first_field,
166
- comparator: comparator,
167
- second_field: second_field,
168
- options: options
169
- }
170
- end
171
-
172
- # Definisce una business rule custom
54
+ # Use a registered complex validation.
173
55
  #
174
- # Le business rules sono metodi custom che implementano logica di validazione
175
- # complessa che non può essere espressa con validatori standard.
56
+ # Complex validations must be registered first using
57
+ # register_complex_validation in the model.
176
58
  #
177
- # @param rule_name [Symbol] Nome del metodo che implementa la rule
178
- # @param options [Hash] Opzioni (on, if, unless)
59
+ # @param name [Symbol] Name of registered complex validation
60
+ # @raise [ArgumentError] If validation is not registered
179
61
  #
180
62
  # @example
181
- # # Nel configurator:
182
- # validate_business_rule :valid_category
183
- # validate_business_rule :author_has_permission, on: :create
184
- #
185
- # # Nel modello (implementazione):
186
- # def valid_category
187
- # unless Category.exists?(id: category_id)
188
- # errors.add(:category_id, "must be a valid category")
63
+ # # In model (registration):
64
+ # register_complex_validation :valid_pricing do
65
+ # if sale_price.present? && sale_price >= price
66
+ # errors.add(:sale_price, "must be less than regular price")
189
67
  # end
190
68
  # end
191
69
  #
192
- # def author_has_permission
193
- # unless author&.can_create_articles?
194
- # errors.add(:author_id, "does not have permission")
195
- # end
70
+ # # In configurator (usage):
71
+ # validatable do
72
+ # check_complex :valid_pricing
196
73
  # end
197
74
  #
198
- def validate_business_rule(rule_name, **options)
199
- @business_rules << {
200
- name: rule_name,
201
- options: options
202
- }
75
+ def check_complex(name)
76
+ unless @model_class.complex_validation?(name)
77
+ raise ArgumentError, "Unknown complex validation: #{name}. Use register_complex_validation to define it first."
78
+ end
79
+
80
+ @complex_validations << name.to_sym
203
81
  end
204
82
 
205
- # Definisce un gruppo di validazioni
83
+ # Define a validation group.
206
84
  #
207
- # I gruppi permettono di validare solo un sottoinsieme di campi,
208
- # utile per form multi-step o validazioni parziali.
85
+ # Groups allow validating only a subset of fields,
86
+ # useful for multi-step forms or partial validations.
209
87
  #
210
- # @param group_name [Symbol] Nome del gruppo
211
- # @param fields [Array<Symbol>] Campi inclusi nel gruppo
88
+ # @param group_name [Symbol] Group name
89
+ # @param fields [Array<Symbol>] Fields included in group
90
+ # @raise [ArgumentError] If group name is invalid, fields not array, or group already defined
212
91
  #
213
92
  # @example
214
93
  # validation_group :step1, [:email, :password]
215
94
  # validation_group :step2, [:first_name, :last_name]
216
95
  # validation_group :step3, [:address, :city, :zip_code]
217
96
  #
218
- # # Utilizzo:
219
- # user.valid?(:step1) # Valida solo email e password
97
+ # @example Usage
98
+ # user.valid?(:step1) # Validate only email and password
220
99
  # user.errors_for_group(:step1)
221
100
  #
222
101
  def validation_group(group_name, fields)
@@ -230,14 +109,12 @@ module BetterModel
230
109
  }
231
110
  end
232
111
 
233
- # Restituisce la configurazione completa
112
+ # Return complete configuration.
234
113
  #
235
- # @return [Hash] Configurazione con tutte le validazioni
114
+ # @return [Hash] Configuration with all validations
236
115
  def to_h
237
116
  {
238
- conditional_validations: @conditional_validations,
239
- order_validations: @order_validations,
240
- business_rules: @business_rules
117
+ complex_validations: @complex_validations
241
118
  }
242
119
  end
243
120
  end
@@ -1,56 +1,62 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Validatable - Sistema di validazioni dichiarativo per modelli Rails
3
+ require_relative "errors/validatable/validatable_error"
4
+ require_relative "errors/validatable/not_enabled_error"
5
+ require_relative "errors/validatable/configuration_error"
6
+
7
+ # Validatable - Declarative validation system for Rails models.
4
8
  #
5
- # Questo concern permette di definire validazioni in modo dichiarativo e leggibile,
6
- # con supporto per validazioni condizionali, gruppi, cross-field e business rules.
9
+ # This concern enables defining validations declaratively and readably,
10
+ # with support for conditional validations, groups, cross-field, and business rules.
7
11
  #
8
- # APPROCCIO OPT-IN: Le validazioni dichiarative non sono attive automaticamente.
9
- # Devi chiamare esplicitamente `validatable do...end` nel tuo modello.
12
+ # @note OPT-IN APPROACH
13
+ # Declarative validations are not enabled automatically.
14
+ # You must explicitly call `validatable do...end` in your model.
10
15
  #
11
- # Esempio di utilizzo:
16
+ # @example Basic Usage
12
17
  # class Article < ApplicationRecord
13
18
  # include BetterModel
14
19
  #
15
- # # Status (già esistente in Statusable)
20
+ # # Status (from Statusable)
16
21
  # is :draft, -> { status == "draft" }
17
22
  # is :published, -> { status == "published" }
18
23
  #
19
- # # Attiva validatable (opt-in)
20
- # validatable do
21
- # # Validazioni base
22
- # validate :title, :content, presence: true
24
+ # # Register complex validations
25
+ # register_complex_validation :valid_date_range do
26
+ # return if starts_at.blank? || ends_at.blank?
27
+ # errors.add(:starts_at, "must be before end date") if starts_at >= ends_at
28
+ # end
23
29
  #
24
- # # Validazioni condizionali
25
- # validate_if :is_published? do
26
- # validate :published_at, presence: true
27
- # validate :author_id, presence: true
28
- # end
30
+ # # Enable validatable (opt-in)
31
+ # validatable do
32
+ # # Basic validations
33
+ # check :title, :content, presence: true
29
34
  #
30
- # # Cross-field validations
31
- # validate_order :starts_at, :before, :ends_at
35
+ # # Conditional validations (using Rails options)
36
+ # check :published_at, presence: true, if: -> { status == "published" }
37
+ # check :author_id, presence: true, if: :is_published?
32
38
  #
33
- # # Business rules
34
- # validate_business_rule :valid_category
39
+ # # Complex validations for cross-field and business logic
40
+ # check_complex :valid_date_range
35
41
  #
36
- # # Gruppi di validazioni
42
+ # # Validation groups
37
43
  # validation_group :step1, [:email, :password]
38
44
  # validation_group :step2, [:first_name, :last_name]
39
45
  # end
40
46
  # end
41
47
  #
42
- # Utilizzo:
43
- # article.valid? # Tutte le validazioni
44
- # article.valid?(:step1) # Solo gruppo step1
48
+ # @example Validation Usage
49
+ # article.valid? # All validations
50
+ # article.valid?(:step1) # Only step1 group
45
51
  #
46
52
  module BetterModel
47
53
  module Validatable
48
54
  extend ActiveSupport::Concern
49
55
 
50
56
  included do
51
- # Validazione ActiveRecord
57
+ # Validate ActiveRecord inheritance
52
58
  unless ancestors.include?(ActiveRecord::Base)
53
- raise ArgumentError, "BetterModel::Validatable can only be included in ActiveRecord models"
59
+ raise BetterModel::Errors::Validatable::ConfigurationError, "Invalid configuration"
54
60
  end
55
61
 
56
62
  # Configurazione validatable (opt-in)
@@ -58,6 +64,8 @@ module BetterModel
58
64
  class_attribute :validatable_config, default: {}.freeze
59
65
  class_attribute :validatable_groups, default: {}.freeze
60
66
  class_attribute :_validatable_setup_done, default: false
67
+ # Registry dei complex validations custom
68
+ class_attribute :complex_validations_registry, default: {}.freeze
61
69
  end
62
70
 
63
71
  class_methods do
@@ -65,14 +73,12 @@ module BetterModel
65
73
  #
66
74
  # @example Attivazione base
67
75
  # validatable do
68
- # validate :title, presence: true
76
+ # check :title, presence: true
69
77
  # end
70
78
  #
71
79
  # @example Con validazioni condizionali
72
80
  # validatable do
73
- # validate_if :is_published? do
74
- # validate :published_at, presence: true
75
- # end
81
+ # check :published_at, presence: true, if: :is_published?
76
82
  # end
77
83
  #
78
84
  def validatable(&block)
@@ -99,98 +105,71 @@ module BetterModel
99
105
  # Verifica se validatable è attivo
100
106
  #
101
107
  # @return [Boolean]
102
- def validatable_enabled?
103
- validatable_enabled == true
108
+ def validatable_enabled? = validatable_enabled == true
109
+
110
+ # Registra una validazione complessa custom
111
+ #
112
+ # Permette di definire validazioni complesse riutilizzabili che possono combinare
113
+ # più campi o utilizzare logica custom non coperta dalle validazioni standard.
114
+ #
115
+ # @param name [Symbol] il nome della validazione
116
+ # @param block [Proc] il blocco di validazione che verrà eseguito nel contesto dell'istanza
117
+ #
118
+ # @example Validazione complessa base
119
+ # register_complex_validation :valid_pricing do
120
+ # if sale_price.present? && sale_price >= price
121
+ # errors.add(:sale_price, "must be less than regular price")
122
+ # end
123
+ # end
124
+ #
125
+ # @example Con logica multi-campo
126
+ # register_complex_validation :valid_dates do
127
+ # if starts_at.present? && ends_at.present? && starts_at >= ends_at
128
+ # errors.add(:ends_at, "must be after start date")
129
+ # end
130
+ # end
131
+ #
132
+ def register_complex_validation(name, &block)
133
+ unless block_given?
134
+ raise BetterModel::Errors::Validatable::ConfigurationError, "Invalid configuration"
135
+ end
136
+
137
+ # Registra nel registry
138
+ self.complex_validations_registry = complex_validations_registry.merge(name.to_sym => block).freeze
104
139
  end
105
140
 
141
+ # Verifica se una validazione complessa è stata registrata
142
+ #
143
+ # @param name [Symbol] il nome della validazione
144
+ # @return [Boolean]
145
+ def complex_validation?(name) = complex_validations_registry.key?(name.to_sym)
146
+
106
147
  private
107
148
 
108
149
  # Applica le configurazioni di validazione al modello
109
150
  def apply_validatable_config
110
151
  return unless validatable_config.present?
111
152
 
112
- # Apply conditional validations
113
- validatable_config[:conditional_validations]&.each do |conditional|
114
- apply_conditional_validation(conditional)
115
- end
116
-
117
- # Apply order validations
118
- validatable_config[:order_validations]&.each do |order_val|
119
- apply_order_validation(order_val)
120
- end
121
-
122
- # Apply business rules
123
- validatable_config[:business_rules]&.each do |rule|
124
- apply_business_rule(rule)
153
+ # Apply complex validations
154
+ validatable_config[:complex_validations]&.each do |name|
155
+ apply_complex_validation(name)
125
156
  end
126
157
  end
127
158
 
128
- # Applica una validazione condizionale
129
- def apply_conditional_validation(conditional)
130
- condition = conditional[:condition]
131
- negate = conditional[:negate]
132
- validations = conditional[:validations]
159
+ # Applica una validazione complessa
160
+ def apply_complex_validation(name)
161
+ block = complex_validations_registry[name]
162
+ return unless block
133
163
 
134
- # Create a custom validator for this conditional block
164
+ # Crea un validator custom per questa validazione complessa
135
165
  validate do
136
- condition_met = if condition.is_a?(Symbol)
137
- send(condition)
138
- elsif condition.is_a?(Proc)
139
- instance_exec(&condition)
140
- else
141
- raise ArgumentError, "Condition must be a Symbol or Proc"
142
- end
143
-
144
- condition_met = !condition_met if negate
145
-
146
- if condition_met
147
- validations.each do |validation|
148
- apply_validation_in_context(validation)
149
- end
150
- end
166
+ instance_eval(&block)
151
167
  end
152
168
  end
153
-
154
- # Applica una validazione order (cross-field)
155
- def apply_order_validation(order_val)
156
- validates_with BetterModel::Validatable::OrderValidator,
157
- attributes: [ order_val[:first_field] ],
158
- second_field: order_val[:second_field],
159
- comparator: order_val[:comparator],
160
- **order_val[:options]
161
- end
162
-
163
- # Applica una business rule
164
- def apply_business_rule(rule)
165
- validates_with BetterModel::Validatable::BusinessRuleValidator,
166
- rule_name: rule[:name],
167
- **rule[:options]
168
- end
169
169
  end
170
170
 
171
171
  # Metodi di istanza
172
172
 
173
- # Apply a validation in the context of the current instance
174
- def apply_validation_in_context(validation)
175
- fields = validation[:fields]
176
- options = validation[:options]
177
-
178
- fields.each do |field|
179
- options.each do |validator_type, validator_options|
180
- # Prepare validator options
181
- # If validator_options is true, convert to empty hash
182
- # If it's a hash, use as-is
183
- opts = validator_options.is_a?(Hash) ? validator_options : {}
184
-
185
- validator = ActiveModel::Validations.const_get("#{validator_type.to_s.camelize}Validator").new(
186
- attributes: [ field ],
187
- **opts
188
- )
189
- validator.validate(self)
190
- end
191
- end
192
- end
193
-
194
173
  # Override valid? per supportare validation groups
195
174
  #
196
175
  # @param context [Symbol, nil] Context o gruppo di validazione
@@ -210,7 +189,9 @@ module BetterModel
210
189
  # @param group_name [Symbol] Nome del gruppo
211
190
  # @return [Boolean]
212
191
  def validate_group(group_name)
213
- raise ValidatableNotEnabledError unless self.class.validatable_enabled?
192
+ unless self.class.validatable_enabled?
193
+ raise BetterModel::Errors::Validatable::NotEnabledError, "Module is not enabled"
194
+ end
214
195
 
215
196
  group = self.class.validatable_groups[group_name]
216
197
  return false unless group
@@ -231,7 +212,9 @@ module BetterModel
231
212
  # @param group_name [Symbol] Nome del gruppo
232
213
  # @return [ActiveModel::Errors]
233
214
  def errors_for_group(group_name)
234
- raise ValidatableNotEnabledError unless self.class.validatable_enabled?
215
+ unless self.class.validatable_enabled?
216
+ raise BetterModel::Errors::Validatable::NotEnabledError, "Module is not enabled"
217
+ end
235
218
 
236
219
  group = self.class.validatable_groups[group_name]
237
220
  return errors unless group
@@ -259,12 +242,4 @@ module BetterModel
259
242
  end
260
243
  end
261
244
 
262
- # Errori custom
263
- class ValidatableError < StandardError; end
264
-
265
- class ValidatableNotEnabledError < ValidatableError
266
- def initialize(msg = nil)
267
- super(msg || "Validatable is not enabled. Add 'validatable do...end' to your model.")
268
- end
269
- end
270
245
  end
@@ -1,3 +1,3 @@
1
1
  module BetterModel
2
- VERSION = "2.1.0"
2
+ VERSION = "3.0.0"
3
3
  end
data/lib/better_model.rb CHANGED
@@ -1,24 +1,61 @@
1
1
  require "better_model/version"
2
2
  require "better_model/railtie"
3
+
4
+ # Load all error classes first
5
+ require "better_model/errors/better_model_error"
6
+ require "better_model/errors/archivable/archivable_error"
7
+ require "better_model/errors/archivable/already_archived_error"
8
+ require "better_model/errors/archivable/not_archived_error"
9
+ require "better_model/errors/archivable/not_enabled_error"
10
+ require "better_model/errors/validatable/validatable_error"
11
+ require "better_model/errors/validatable/not_enabled_error"
12
+ require "better_model/errors/traceable/traceable_error"
13
+ require "better_model/errors/traceable/not_enabled_error"
14
+ require "better_model/errors/searchable/searchable_error"
15
+ require "better_model/errors/searchable/invalid_predicate_error"
16
+ require "better_model/errors/searchable/invalid_order_error"
17
+ require "better_model/errors/searchable/invalid_pagination_error"
18
+ require "better_model/errors/searchable/invalid_security_error"
19
+ require "better_model/errors/stateable/stateable_error"
20
+ require "better_model/errors/stateable/not_enabled_error"
21
+ require "better_model/errors/stateable/invalid_state_error"
22
+ require "better_model/errors/stateable/invalid_transition_error"
23
+ require "better_model/errors/stateable/check_failed_error"
24
+ require "better_model/errors/stateable/validation_failed_error"
25
+ require "better_model/errors/stateable/configuration_error"
26
+ require "better_model/errors/archivable/configuration_error"
27
+ require "better_model/errors/validatable/configuration_error"
28
+ require "better_model/errors/traceable/configuration_error"
29
+ require "better_model/errors/searchable/configuration_error"
30
+ require "better_model/errors/predicable/predicable_error"
31
+ require "better_model/errors/predicable/configuration_error"
32
+ require "better_model/errors/sortable/sortable_error"
33
+ require "better_model/errors/sortable/configuration_error"
34
+ require "better_model/errors/statusable/statusable_error"
35
+ require "better_model/errors/statusable/configuration_error"
36
+ require "better_model/errors/permissible/permissible_error"
37
+ require "better_model/errors/permissible/configuration_error"
38
+ require "better_model/errors/taggable/taggable_error"
39
+ require "better_model/errors/taggable/configuration_error"
40
+
41
+ # Load modules
3
42
  require "better_model/statusable"
4
43
  require "better_model/permissible"
5
44
  require "better_model/sortable"
6
45
  require "better_model/predicable"
7
46
  require "better_model/searchable"
8
47
  require "better_model/archivable"
9
- require "better_model/version_record"
48
+ require "better_model/models/version"
10
49
  require "better_model/traceable"
11
50
  require "better_model/validatable"
12
51
  require "better_model/validatable/configurator"
13
- require "better_model/validatable/order_validator"
14
- require "better_model/validatable/business_rule_validator"
15
- require "better_model/state_transition"
52
+ require "better_model/models/state_transition"
16
53
  require "better_model/stateable"
17
54
  require "better_model/stateable/configurator"
18
- require "better_model/stateable/errors"
19
55
  require "better_model/stateable/guard"
20
56
  require "better_model/stateable/transition"
21
57
  require "better_model/taggable"
58
+ require "better_model/repositable"
22
59
 
23
60
  module BetterModel
24
61
  extend ActiveSupport::Concern