smart_domain 0.1.0 → 0.1.2

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +65 -0
  3. data/CHANGELOG.md +6 -8
  4. data/README.md +52 -0
  5. data/Rakefile +3 -3
  6. data/lib/generators/{active_domain → smart_domain}/domain/domain_generator.rb +16 -16
  7. data/lib/generators/{active_domain → smart_domain}/domain/templates/events/created_event.rb.tt +1 -1
  8. data/lib/generators/{active_domain → smart_domain}/domain/templates/events/deleted_event.rb.tt +1 -1
  9. data/lib/generators/{active_domain → smart_domain}/domain/templates/events/updated_event.rb.tt +2 -2
  10. data/lib/generators/{active_domain → smart_domain}/domain/templates/service.rb.tt +5 -5
  11. data/lib/generators/{active_domain → smart_domain}/domain/templates/setup.rb.tt +4 -4
  12. data/lib/generators/{active_domain → smart_domain}/install/install_generator.rb +13 -13
  13. data/lib/smart_domain/configuration.rb +1 -1
  14. data/lib/smart_domain/domain/exceptions.rb +2 -2
  15. data/lib/smart_domain/domain/service.rb +1 -1
  16. data/lib/smart_domain/event/adapters/memory.rb +24 -9
  17. data/lib/smart_domain/event/base.rb +26 -13
  18. data/lib/smart_domain/event/handler.rb +5 -3
  19. data/lib/smart_domain/event/mixins.rb +11 -1
  20. data/lib/smart_domain/event/registration.rb +4 -4
  21. data/lib/smart_domain/generators/domain_generator.rb +1 -1
  22. data/lib/smart_domain/generators/install_generator.rb +1 -1
  23. data/lib/smart_domain/handlers/audit_handler.rb +22 -24
  24. data/lib/smart_domain/handlers/metrics_handler.rb +8 -1
  25. data/lib/smart_domain/integration/active_record.rb +6 -8
  26. data/lib/smart_domain/railtie.rb +24 -24
  27. data/lib/smart_domain/tasks/domains.rake +18 -14
  28. data/lib/smart_domain/version.rb +1 -1
  29. data/lib/smart_domain.rb +20 -20
  30. data/smart_domain.gemspec +26 -25
  31. metadata +32 -43
  32. data/examples/blog_app/.kamal/hooks/docker-setup.sample +0 -3
  33. data/examples/blog_app/.kamal/hooks/post-app-boot.sample +0 -3
  34. data/examples/blog_app/.kamal/hooks/post-deploy.sample +0 -14
  35. data/examples/blog_app/.kamal/hooks/post-proxy-reboot.sample +0 -3
  36. data/examples/blog_app/.kamal/hooks/pre-app-boot.sample +0 -3
  37. data/examples/blog_app/.kamal/hooks/pre-build.sample +0 -51
  38. data/examples/blog_app/.kamal/hooks/pre-connect.sample +0 -47
  39. data/examples/blog_app/.kamal/hooks/pre-deploy.sample +0 -122
  40. data/examples/blog_app/.kamal/hooks/pre-proxy-reboot.sample +0 -3
  41. data/examples/blog_app/.kamal/secrets +0 -20
  42. data/examples/blog_app/bin/kamal +0 -27
  43. data/examples/blog_app/config/deploy.yml +0 -120
  44. data/examples/blog_app/config/master.key +0 -1
  45. /data/examples/blog_app/config/initializers/{active_domain.rb → smart_domain.rb} +0 -0
  46. /data/lib/generators/{active_domain → smart_domain}/domain/templates/policy.rb.tt +0 -0
  47. /data/lib/generators/{active_domain → smart_domain}/install/templates/README +0 -0
  48. /data/lib/generators/{active_domain → smart_domain}/install/templates/application_event.rb +0 -0
  49. /data/lib/generators/{active_domain → smart_domain}/install/templates/application_policy.rb +0 -0
  50. /data/lib/generators/{active_domain → smart_domain}/install/templates/application_service.rb +0 -0
  51. /data/lib/generators/{active_domain → smart_domain}/install/templates/initializer.rb +0 -0
@@ -37,7 +37,7 @@ module SmartDomain
37
37
  # @param event [SmartDomain::Event::Base] Event to handle
38
38
  # @raise [NotImplementedError] If not implemented by subclass
39
39
  def handle(event)
40
- raise NotImplementedError, "#{self.class.name} must implement #handle(event)"
40
+ raise NotImplementedError, 'Subclasses must implement #handle(event)'
41
41
  end
42
42
 
43
43
  # Check if this handler can handle a specific event type
@@ -48,7 +48,7 @@ module SmartDomain
48
48
  # @param event_type [String] Event type to check
49
49
  # @return [Boolean] True if handler can handle this event type
50
50
  def can_handle?(event_type)
51
- raise NotImplementedError, "#{self.class.name} must implement #can_handle?(event_type)"
51
+ raise NotImplementedError, 'Subclasses must implement #can_handle?(event_type)'
52
52
  end
53
53
 
54
54
  # Handle event asynchronously using ActiveJob
@@ -58,12 +58,14 @@ module SmartDomain
58
58
  #
59
59
  # @param event [SmartDomain::Event::Base] Event to handle
60
60
  # @raise [RuntimeError] If ActiveJob is not loaded
61
+ # @raise [ValidationError] If event is invalid
61
62
  def handle_async(event)
62
63
  unless defined?(ActiveJob)
63
64
  raise "ActiveJob is required for async event handling. Please require 'active_job' in your application."
64
65
  end
65
66
 
66
- event.validate!
67
+ raise ValidationError, "Event validation failed: #{event.errors.full_messages.join(', ')}" unless event.valid?
68
+
67
69
  HandlerJob.perform_later(self.class.name, event.to_h)
68
70
  end
69
71
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/concern"
3
+ require 'active_support/concern'
4
4
 
5
5
  module SmartDomain
6
6
  module Event
@@ -89,6 +89,14 @@ module SmartDomain
89
89
  attribute :changed_fields, default: -> { [] }
90
90
  attribute :old_values, default: -> { {} }
91
91
  attribute :new_values, default: -> { {} }
92
+
93
+ validate :changed_fields_must_not_be_empty
94
+
95
+ private
96
+
97
+ def changed_fields_must_not_be_empty
98
+ errors.add(:changed_fields, "can't be blank") if changed_fields.blank? || changed_fields.empty?
99
+ end
92
100
  end
93
101
 
94
102
  # Helper to extract changes from an ActiveRecord model
@@ -150,6 +158,8 @@ module SmartDomain
150
158
 
151
159
  included do
152
160
  attribute :reason, :string
161
+
162
+ validates :reason, presence: true
153
163
  end
154
164
  end
155
165
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../handlers/audit_handler"
4
- require_relative "../handlers/metrics_handler"
3
+ require_relative '../handlers/audit_handler'
4
+ require_relative '../handlers/metrics_handler'
5
5
 
6
6
  module SmartDomain
7
7
  module Event
@@ -86,8 +86,8 @@ module SmartDomain
86
86
  # Log what was registered
87
87
  if include_audit || include_metrics
88
88
  handlers_registered = []
89
- handlers_registered << "audit" if include_audit
90
- handlers_registered << "metrics" if include_metrics
89
+ handlers_registered << 'audit' if include_audit
90
+ handlers_registered << 'metrics' if include_metrics
91
91
 
92
92
  logger.info "[SmartDomain::Registration] Standard handlers registered for #{domain} domain: " \
93
93
  "#{handlers_registered.join(', ')} (#{events.size} events)"
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Load the domain generator
4
- require_relative "../../generators/smart_domain/domain/domain_generator"
4
+ require_relative '../../generators/smart_domain/domain/domain_generator'
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Load the install generator
4
- require_relative "../../generators/smart_domain/install/install_generator"
4
+ require_relative '../../generators/smart_domain/install/install_generator'
@@ -41,7 +41,7 @@ module SmartDomain
41
41
  # @param event_type [String] Event type to check
42
42
  # @return [Boolean] True if event belongs to this domain
43
43
  def can_handle?(event_type)
44
- return true if @domain == "*"
44
+ return true if @domain == '*'
45
45
 
46
46
  event_type.start_with?("#{@domain}.")
47
47
  end
@@ -49,7 +49,7 @@ module SmartDomain
49
49
  # Handle audit logging for an event
50
50
  # @param event [SmartDomain::Event::Base] Event to audit
51
51
  def handle(event)
52
- action = event.event_type.split(".").last
52
+ action = event.event_type.split('.').last
53
53
 
54
54
  # 1. Log to Rails logger (structured)
55
55
  log_audit_event(event, action)
@@ -117,17 +117,15 @@ module SmartDomain
117
117
  return unless defined?(AuditEvent)
118
118
 
119
119
  AuditEvent.create!(
120
- event_type: event.event_type.upcase.tr(".", "_"),
121
- event_category: map_event_category(event.event_type),
122
- user_id: extract_actor_id(event),
120
+ event_id: event.event_id,
121
+ event_type: event.event_type,
122
+ aggregate_id: event.aggregate_id,
123
+ aggregate_type: event.aggregate_type,
123
124
  organization_id: event.organization_id,
124
- ip_address: extract_ip_address(event),
125
- user_agent: extract_user_agent(event),
126
- old_values: extract_old_values(event),
127
- new_values: extract_new_values(event),
128
- occurred_at: event.occurred_at,
125
+ category: map_event_category(event.event_type),
129
126
  risk_level: assess_risk_level(event.event_type),
130
- compliance_flags: build_compliance_flags(event)
127
+ event_data: event.to_h,
128
+ occurred_at: event.occurred_at
131
129
  )
132
130
  rescue StandardError => e
133
131
  @logger.warn "[SmartDomain::AuditHandler] Failed to write to audit table: #{e.message}"
@@ -138,14 +136,14 @@ module SmartDomain
138
136
  # @return [String] Audit category
139
137
  def map_event_category(event_type)
140
138
  case event_type
141
- when /^auth\./
142
- "authentication"
139
+ when /^auth\.|logged_in|logged_out|login|logout|authenticated|password/
140
+ 'authentication'
143
141
  when /accessed|viewed|patient\./
144
- "data_access"
142
+ 'data_access'
145
143
  when /created|updated|deleted|assigned|removed/
146
- "admin_action"
144
+ 'admin_action'
147
145
  else
148
- "system_event"
146
+ 'system_event'
149
147
  end
150
148
  end
151
149
 
@@ -155,11 +153,11 @@ module SmartDomain
155
153
  def assess_risk_level(event_type)
156
154
  case event_type
157
155
  when /suspended|deleted|revoked|failed|rejected/
158
- "HIGH"
156
+ 'HIGH'
159
157
  when /updated|changed|assigned/
160
- "MEDIUM"
158
+ 'MEDIUM'
161
159
  else
162
- "LOW"
160
+ 'LOW'
163
161
  end
164
162
  end
165
163
 
@@ -167,35 +165,35 @@ module SmartDomain
167
165
  # @param event [SmartDomain::Event::Base] Event
168
166
  # @return [String, nil] Actor ID
169
167
  def extract_actor_id(event)
170
- event.try(:actor_id) || event.attributes["actor_id"]
168
+ event.try(:actor_id) || event.attributes['actor_id']
171
169
  end
172
170
 
173
171
  # Extract ip_address from event (SecurityContextMixin)
174
172
  # @param event [SmartDomain::Event::Base] Event
175
173
  # @return [String, nil] IP address
176
174
  def extract_ip_address(event)
177
- event.try(:ip_address) || event.attributes["ip_address"]
175
+ event.try(:ip_address) || event.attributes['ip_address']
178
176
  end
179
177
 
180
178
  # Extract user_agent from event (SecurityContextMixin)
181
179
  # @param event [SmartDomain::Event::Base] Event
182
180
  # @return [String, nil] User agent
183
181
  def extract_user_agent(event)
184
- event.try(:user_agent) || event.attributes["user_agent"]
182
+ event.try(:user_agent) || event.attributes['user_agent']
185
183
  end
186
184
 
187
185
  # Extract old_values from event (ChangeTrackingMixin)
188
186
  # @param event [SmartDomain::Event::Base] Event
189
187
  # @return [Hash, nil] Old values
190
188
  def extract_old_values(event)
191
- event.try(:old_values) || event.attributes["old_values"]
189
+ event.try(:old_values) || event.attributes['old_values']
192
190
  end
193
191
 
194
192
  # Extract new_values from event (ChangeTrackingMixin)
195
193
  # @param event [SmartDomain::Event::Base] Event
196
194
  # @return [Hash, nil] New values
197
195
  def extract_new_values(event)
198
- event.try(:new_values) || event.attributes["new_values"]
196
+ event.try(:new_values) || event.attributes['new_values']
199
197
  end
200
198
 
201
199
  # Build compliance flags for audit record
@@ -36,7 +36,7 @@ module SmartDomain
36
36
  # @param event_type [String] Event type to check
37
37
  # @return [Boolean] True if event belongs to this domain
38
38
  def can_handle?(event_type)
39
- return true if @domain == "*"
39
+ return true if @domain == '*'
40
40
 
41
41
  event_type.start_with?("#{@domain}.")
42
42
  end
@@ -47,7 +47,14 @@ module SmartDomain
47
47
  metric_name = build_metric_name(event)
48
48
  tags = build_metric_tags(event)
49
49
 
50
+ # Emit counter metric
50
51
  emit_metric(metric_name, tags)
52
+
53
+ # Emit timing metric if duration is present
54
+ if event.respond_to?(:duration) && event.duration
55
+ timing_name = "#{metric_name}.duration"
56
+ emit_metric(timing_name, tags.merge(duration_ms: event.duration))
57
+ end
51
58
  rescue StandardError => e
52
59
  # Never fail on metrics handler errors
53
60
  @logger.warn "[SmartDomain::MetricsHandler] Metrics collection failed: #{e.message}"
@@ -145,14 +145,12 @@ module SmartDomain
145
145
  return if @pending_domain_events.blank?
146
146
 
147
147
  @pending_domain_events.each do |event|
148
- begin
149
- SmartDomain::Event.bus.publish(event)
150
- rescue StandardError => e
151
- # Log error but don't raise (events should be fire-and-forget)
152
- logger = defined?(Rails) ? Rails.logger : Logger.new($stdout)
153
- logger.error "[SmartDomain] Failed to publish event: #{e.message}"
154
- logger.error e.backtrace.join("\n")
155
- end
148
+ SmartDomain::Event.bus.publish(event)
149
+ rescue StandardError => e
150
+ # Log error but don't raise (events should be fire-and-forget)
151
+ logger = defined?(Rails) ? Rails.logger : Logger.new($stdout)
152
+ logger.error "[SmartDomain] Failed to publish event: #{e.message}"
153
+ logger.error e.backtrace.join("\n")
156
154
  end
157
155
 
158
156
  clear_domain_events
@@ -12,8 +12,8 @@ module SmartDomain
12
12
 
13
13
  # Add generators to load path
14
14
  generators do
15
- require_relative "generators/install_generator"
16
- require_relative "generators/domain_generator"
15
+ require_relative 'generators/install_generator'
16
+ require_relative 'generators/domain_generator'
17
17
  end
18
18
 
19
19
  # Configuration hook
@@ -27,35 +27,35 @@ module SmartDomain
27
27
 
28
28
  # Rake tasks
29
29
  rake_tasks do
30
- load "smart_domain/tasks/domains.rake"
30
+ load 'smart_domain/tasks/domains.rake'
31
31
  end
32
32
 
33
- private
34
-
35
33
  # Load all domain setup files
36
34
  def self.load_domain_setups
37
- setup_files = Dir[Rails.root.join("app/domains/**/setup.rb")]
35
+ setup_files = Dir[Rails.root.join('app/domains/**/setup.rb')]
38
36
 
39
37
  setup_files.each do |setup_file|
40
- begin
41
- require setup_file
42
-
43
- # Extract domain module name from path
44
- # e.g., app/domains/user_management/setup.rb -> UserManagement
45
- domain_path = setup_file.gsub(Rails.root.join("app/domains/").to_s, "")
46
- domain_name = domain_path.split("/").first.camelize
47
-
48
- # Call setup! method if defined
49
- domain_module = domain_name.constantize rescue nil
50
- if domain_module && domain_module.respond_to?(:setup!)
51
- domain_module.setup!
52
- Rails.logger.info "[SmartDomain] Loaded domain: #{domain_name}"
53
- end
54
- rescue StandardError => e
55
- Rails.logger.error "[SmartDomain] Failed to load domain setup: #{setup_file}"
56
- Rails.logger.error e.message
57
- Rails.logger.error e.backtrace.join("\n")
38
+ require setup_file
39
+
40
+ # Extract domain module name from path
41
+ # e.g., app/domains/user_management/setup.rb -> UserManagement
42
+ domain_path = setup_file.gsub(Rails.root.join('app/domains/').to_s, '')
43
+ domain_name = domain_path.split('/').first.camelize
44
+
45
+ # Call setup! method if defined
46
+ domain_module = begin
47
+ domain_name.constantize
48
+ rescue StandardError
49
+ nil
50
+ end
51
+ if domain_module.respond_to?(:setup!)
52
+ domain_module.setup!
53
+ Rails.logger.info "[SmartDomain] Loaded domain: #{domain_name}"
58
54
  end
55
+ rescue StandardError => e
56
+ Rails.logger.error "[SmartDomain] Failed to load domain setup: #{setup_file}"
57
+ Rails.logger.error e.message
58
+ Rails.logger.error e.backtrace.join("\n")
59
59
  end
60
60
  end
61
61
  end
@@ -1,43 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  namespace :active_domain do
4
- desc "List all registered domains"
4
+ desc 'List all registered domains'
5
5
  task domains: :environment do
6
- setup_files = Dir[Rails.root.join("app/domains/**/setup.rb")]
6
+ setup_files = Dir[Rails.root.join('app/domains/**/setup.rb')]
7
7
 
8
8
  if setup_files.empty?
9
- puts "No domains found in app/domains/"
10
- puts "Generate your first domain with: rails generate active_domain:domain User"
9
+ puts 'No domains found in app/domains/'
10
+ puts 'Generate your first domain with: rails generate active_domain:domain User'
11
11
  else
12
- puts "Registered domains:"
12
+ puts 'Registered domains:'
13
13
  setup_files.each do |setup_file|
14
- domain_path = setup_file.gsub(Rails.root.join("app/domains/").to_s, "")
15
- domain_name = domain_path.split("/").first
14
+ domain_path = setup_file.gsub(Rails.root.join('app/domains/').to_s, '')
15
+ domain_name = domain_path.split('/').first
16
16
  puts " - #{domain_name}"
17
17
  end
18
18
  puts "\nTotal: #{setup_files.size} domain(s)"
19
19
  end
20
20
  end
21
21
 
22
- desc "Reload all domain setups"
22
+ desc 'Reload all domain setups'
23
23
  task reload: :environment do
24
- setup_files = Dir[Rails.root.join("app/domains/**/setup.rb")]
24
+ setup_files = Dir[Rails.root.join('app/domains/**/setup.rb')]
25
25
 
26
26
  puts "Reloading #{setup_files.size} domain(s)..."
27
27
 
28
28
  setup_files.each do |setup_file|
29
29
  load setup_file
30
30
 
31
- domain_path = setup_file.gsub(Rails.root.join("app/domains/").to_s, "")
32
- domain_name = domain_path.split("/").first.camelize
31
+ domain_path = setup_file.gsub(Rails.root.join('app/domains/').to_s, '')
32
+ domain_name = domain_path.split('/').first.camelize
33
33
 
34
- domain_module = domain_name.constantize rescue nil
35
- if domain_module && domain_module.respond_to?(:setup!)
34
+ domain_module = begin
35
+ domain_name.constantize
36
+ rescue StandardError
37
+ nil
38
+ end
39
+ if domain_module.respond_to?(:setup!)
36
40
  domain_module.setup!
37
41
  puts " ✓ #{domain_name}"
38
42
  end
39
43
  end
40
44
 
41
- puts "Done!"
45
+ puts 'Done!'
42
46
  end
43
47
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SmartDomain
4
- VERSION = "0.1.0"
4
+ VERSION = '0.1.2'
5
5
  end
data/lib/smart_domain.rb CHANGED
@@ -1,38 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_model"
4
- require "active_support"
5
- require "active_support/core_ext"
6
- require "active_record"
7
- require "logger"
3
+ require 'active_model'
4
+ require 'active_support'
5
+ require 'active_support/core_ext'
6
+ require 'active_record'
7
+ require 'logger'
8
8
 
9
- require_relative "smart_domain/version"
10
- require_relative "smart_domain/configuration"
9
+ require_relative 'smart_domain/version'
10
+ require_relative 'smart_domain/configuration'
11
11
 
12
12
  # Event system
13
- require_relative "smart_domain/event/base"
14
- require_relative "smart_domain/event/mixins"
15
- require_relative "smart_domain/event/handler"
16
- require_relative "smart_domain/event/adapters/memory"
13
+ require_relative 'smart_domain/event/base'
14
+ require_relative 'smart_domain/event/mixins'
15
+ require_relative 'smart_domain/event/handler'
16
+ require_relative 'smart_domain/event/adapters/memory'
17
17
 
18
18
  # Handlers
19
- require_relative "smart_domain/handlers/audit_handler"
20
- require_relative "smart_domain/handlers/metrics_handler"
19
+ require_relative 'smart_domain/handlers/audit_handler'
20
+ require_relative 'smart_domain/handlers/metrics_handler'
21
21
 
22
22
  # Event registration
23
- require_relative "smart_domain/event/registration"
23
+ require_relative 'smart_domain/event/registration'
24
24
 
25
25
  # Domain patterns
26
- require_relative "smart_domain/domain/exceptions"
27
- require_relative "smart_domain/domain/policy"
28
- require_relative "smart_domain/domain/service"
26
+ require_relative 'smart_domain/domain/exceptions'
27
+ require_relative 'smart_domain/domain/policy'
28
+ require_relative 'smart_domain/domain/service'
29
29
 
30
30
  # Rails integration
31
- require_relative "smart_domain/integration/active_record"
32
- require_relative "smart_domain/integration/multi_tenancy"
31
+ require_relative 'smart_domain/integration/active_record'
32
+ require_relative 'smart_domain/integration/multi_tenancy'
33
33
 
34
34
  # Railtie (loads automatically if Rails is present)
35
- require_relative "smart_domain/railtie" if defined?(Rails::Railtie)
35
+ require_relative 'smart_domain/railtie' if defined?(Rails::Railtie)
36
36
 
37
37
  # SmartDomain - Domain-Driven Design and Event-Driven Architecture for Rails
38
38
  #
data/smart_domain.gemspec CHANGED
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "lib/smart_domain/version"
3
+ require_relative 'lib/smart_domain/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = "smart_domain"
6
+ spec.name = 'smart_domain'
7
7
  spec.version = SmartDomain::VERSION
8
- spec.authors = ["Rachid Al Maach"]
9
- spec.email = ["rachid@qraft.nl"]
8
+ spec.authors = ['Rachid Al Maach']
9
+ spec.email = ['rachid@qraft.nl']
10
10
 
11
- spec.summary = "Smart Domain-Driven Design and Event-Driven Architecture for Rails"
11
+ spec.summary = 'Smart Domain-Driven Design and Event-Driven Architecture for Rails'
12
12
  spec.description = <<~DESC
13
13
  SmartDomain brings battle-tested DDD/EDA patterns to Rails applications.
14
14
  Inspired by the Aeyes healthcare platform, it provides domain events,
@@ -16,13 +16,14 @@ Gem::Specification.new do |spec|
16
16
  Features 70% boilerplate reduction through intelligent event handling and
17
17
  AI-augmented development patterns.
18
18
  DESC
19
- spec.homepage = "https://github.com/rachid/smart_domain"
20
- spec.license = "MIT"
21
- spec.required_ruby_version = ">= 3.0.0"
19
+ spec.homepage = 'https://github.com/rachid/smart_domain'
20
+ spec.license = 'MIT'
21
+ spec.required_ruby_version = '>= 3.0.0'
22
22
 
23
- spec.metadata["homepage_uri"] = spec.homepage
24
- spec.metadata["source_code_uri"] = "https://github.com/rachid/smart_domain"
25
- spec.metadata["changelog_uri"] = "https://github.com/rachid/smart_domain/blob/main/CHANGELOG.md"
23
+ spec.metadata['homepage_uri'] = spec.homepage
24
+ spec.metadata['source_code_uri'] = 'https://github.com/rachid/smart_domain'
25
+ spec.metadata['changelog_uri'] = 'https://github.com/rachid/smart_domain/blob/main/CHANGELOG.md'
26
+ spec.metadata['rubygems_mfa_required'] = 'true'
26
27
 
27
28
  spec.files = Dir.chdir(__dir__) do
28
29
  `git ls-files -z`.split("\x0").reject do |f|
@@ -31,23 +32,23 @@ Gem::Specification.new do |spec|
31
32
  end
32
33
  end
33
34
 
34
- spec.bindir = "exe"
35
+ spec.bindir = 'exe'
35
36
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
36
- spec.require_paths = ["lib"]
37
+ spec.require_paths = ['lib']
37
38
 
38
39
  # Core dependencies
39
- spec.add_dependency "rails", ">= 7.0"
40
- spec.add_dependency "activemodel", ">= 7.0"
41
- spec.add_dependency "activesupport", ">= 7.0"
42
- spec.add_dependency "activerecord", ">= 7.0"
40
+ spec.add_dependency 'activemodel', '>= 7.0'
41
+ spec.add_dependency 'activerecord', '>= 7.0'
42
+ spec.add_dependency 'activesupport', '>= 7.0'
43
+ spec.add_dependency 'rails', '>= 7.0'
43
44
 
44
45
  # Development dependencies
45
- spec.add_development_dependency "rspec", "~> 3.12"
46
- spec.add_development_dependency "rspec-rails", "~> 6.0"
47
- spec.add_development_dependency "factory_bot_rails", "~> 6.2"
48
- spec.add_development_dependency "faker", "~> 3.2"
49
- spec.add_development_dependency "rubocop", "~> 1.50"
50
- spec.add_development_dependency "rubocop-rails", "~> 2.19"
51
- spec.add_development_dependency "rubocop-rspec", "~> 2.20"
52
- spec.add_development_dependency "sqlite3", ">= 2.1"
46
+ spec.add_development_dependency 'factory_bot_rails', '~> 6.2'
47
+ spec.add_development_dependency 'faker', '~> 3.2'
48
+ spec.add_development_dependency 'rspec', '~> 3.12'
49
+ spec.add_development_dependency 'rspec-rails', '~> 6.0'
50
+ spec.add_development_dependency 'rubocop', '~> 1.50'
51
+ spec.add_development_dependency 'rubocop-rails', '~> 2.19'
52
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.20'
53
+ spec.add_development_dependency 'sqlite3', '>= 2.1'
53
54
  end