rider-kick 0.0.13 → 0.0.14
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 +4 -4
- data/README.md +629 -25
- data/lib/generators/rider_kick/USAGE +2 -0
- data/lib/generators/rider_kick/base_generator.rb +190 -0
- data/lib/generators/rider_kick/clean_arch_generator.rb +235 -45
- data/lib/generators/rider_kick/clean_arch_generator_engine_spec.rb +359 -0
- data/lib/generators/rider_kick/clean_arch_generator_factory_bot_spec.rb +131 -0
- data/lib/generators/rider_kick/entity_type_mapping_spec.rb +22 -13
- data/lib/generators/rider_kick/errors.rb +42 -0
- data/lib/generators/rider_kick/factory_generator.rb +238 -0
- data/lib/generators/rider_kick/factory_generator_spec.rb +175 -0
- data/lib/generators/rider_kick/repositories_contract_spec.rb +95 -22
- data/lib/generators/rider_kick/scaffold_generator.rb +377 -62
- data/lib/generators/rider_kick/scaffold_generator_builder_uploaders_spec.rb +119 -14
- data/lib/generators/rider_kick/scaffold_generator_conditional_filtering_spec.rb +820 -0
- data/lib/generators/rider_kick/scaffold_generator_contracts_spec.rb +37 -10
- data/lib/generators/rider_kick/scaffold_generator_contracts_with_scope_spec.rb +40 -11
- data/lib/generators/rider_kick/scaffold_generator_engine_spec.rb +221 -0
- data/lib/generators/rider_kick/scaffold_generator_idempotent_spec.rb +38 -13
- data/lib/generators/rider_kick/scaffold_generator_list_spec_format_spec.rb +153 -0
- data/lib/generators/rider_kick/scaffold_generator_rspec_spec.rb +347 -0
- data/lib/generators/rider_kick/scaffold_generator_success_spec.rb +31 -12
- data/lib/generators/rider_kick/scaffold_generator_with_scope_spec.rb +32 -11
- data/lib/generators/rider_kick/structure_generator.rb +154 -43
- data/lib/generators/rider_kick/structure_generator_comprehensive_spec.rb +598 -0
- data/lib/generators/rider_kick/structure_generator_engine_spec.rb +279 -0
- data/lib/generators/rider_kick/structure_generator_spec.rb +3 -3
- data/lib/generators/rider_kick/structure_generator_success_spec.rb +33 -5
- data/lib/generators/rider_kick/structure_generator_unit_spec.rb +2202 -0
- data/lib/generators/rider_kick/templates/.rubocop.yml +5 -4
- data/lib/generators/rider_kick/templates/config/initializers/version.rb.tt +1 -1
- data/lib/generators/rider_kick/templates/db/migrate/20220613145533_init_database.rb +1 -1
- data/lib/generators/rider_kick/templates/db/structures/example.yaml.tt +140 -66
- data/lib/generators/rider_kick/templates/domains/core/builders/builder.rb.tt +36 -10
- data/lib/generators/rider_kick/templates/domains/core/builders/builder_spec.rb.tt +219 -0
- data/lib/generators/rider_kick/templates/domains/core/builders/error.rb.tt +2 -2
- data/lib/generators/rider_kick/templates/domains/core/builders/pagination.rb.tt +2 -2
- data/lib/generators/rider_kick/templates/domains/core/entities/entity.rb.tt +32 -14
- data/lib/generators/rider_kick/templates/domains/core/entities/error.rb.tt +1 -1
- data/lib/generators/rider_kick/templates/domains/core/entities/pagination.rb.tt +1 -1
- data/lib/generators/rider_kick/templates/domains/core/repositories/abstract_repository.rb.tt +4 -4
- data/lib/generators/rider_kick/templates/domains/core/repositories/create.rb.tt +2 -2
- data/lib/generators/rider_kick/templates/domains/core/repositories/create_spec.rb.tt +78 -0
- data/lib/generators/rider_kick/templates/domains/core/repositories/destroy.rb.tt +2 -2
- data/lib/generators/rider_kick/templates/domains/core/repositories/destroy_spec.rb.tt +88 -0
- data/lib/generators/rider_kick/templates/domains/core/repositories/fetch_by_id.rb.tt +3 -3
- data/lib/generators/rider_kick/templates/domains/core/repositories/fetch_by_id_spec.rb.tt +62 -0
- data/lib/generators/rider_kick/templates/domains/core/repositories/list.rb.tt +13 -8
- data/lib/generators/rider_kick/templates/domains/core/repositories/list_spec.rb.tt +190 -0
- data/lib/generators/rider_kick/templates/domains/core/repositories/update.rb.tt +4 -4
- data/lib/generators/rider_kick/templates/domains/core/repositories/update_spec.rb.tt +119 -0
- data/lib/generators/rider_kick/templates/domains/core/use_cases/contract/default.rb.tt +1 -1
- data/lib/generators/rider_kick/templates/domains/core/use_cases/contract/pagination.rb.tt +1 -1
- data/lib/generators/rider_kick/templates/domains/core/use_cases/create.rb.tt +3 -7
- data/lib/generators/rider_kick/templates/domains/core/use_cases/create_spec.rb.tt +71 -0
- data/lib/generators/rider_kick/templates/domains/core/use_cases/destroy.rb.tt +3 -7
- data/lib/generators/rider_kick/templates/domains/core/use_cases/destroy_spec.rb.tt +62 -0
- data/lib/generators/rider_kick/templates/domains/core/use_cases/fetch_by_id.rb.tt +3 -7
- data/lib/generators/rider_kick/templates/domains/core/use_cases/fetch_by_id_spec.rb.tt +62 -0
- data/lib/generators/rider_kick/templates/domains/core/use_cases/get_version.rb.tt +2 -2
- data/lib/generators/rider_kick/templates/domains/core/use_cases/list.rb.tt +3 -7
- data/lib/generators/rider_kick/templates/domains/core/use_cases/list_spec.rb.tt +64 -0
- data/lib/generators/rider_kick/templates/domains/core/use_cases/update.rb.tt +3 -7
- data/lib/generators/rider_kick/templates/domains/core/use_cases/update_spec.rb.tt +73 -0
- data/lib/generators/rider_kick/templates/domains/core/utils/abstract_utils.rb.tt +3 -3
- data/lib/generators/rider_kick/templates/domains/core/utils/request_methods.rb.tt +1 -1
- data/lib/generators/rider_kick/templates/env.development +1 -1
- data/lib/generators/rider_kick/templates/env.production +1 -1
- data/lib/generators/rider_kick/templates/env.test +1 -1
- data/lib/generators/rider_kick/templates/models/{application_record.rb → application_record.rb.tt} +3 -1
- data/lib/generators/rider_kick/templates/models/model_spec.rb.tt +68 -0
- data/lib/generators/rider_kick/templates/spec/factories/.gitkeep +19 -0
- data/lib/generators/rider_kick/templates/spec/factories/factory.rb.tt +8 -0
- data/lib/generators/rider_kick/templates/spec/rails_helper.rb +2 -0
- data/lib/generators/rider_kick/templates/spec/support/class_stubber.rb +148 -0
- data/lib/generators/rider_kick/templates/spec/support/factory_bot.rb +34 -0
- data/lib/generators/rider_kick/templates/spec/support/faker.rb +61 -0
- data/lib/rider-kick.rb +8 -6
- data/lib/rider_kick/builders/abstract_active_record_entity_builder_spec.rb +644 -0
- data/lib/rider_kick/configuration.rb +238 -0
- data/lib/rider_kick/configuration_engine_spec.rb +377 -0
- data/lib/rider_kick/entities/failure_details.rb +1 -1
- data/lib/rider_kick/entities/failure_details_spec.rb +1 -1
- data/lib/rider_kick/matchers/use_case_result.rb +1 -1
- data/lib/rider_kick/use_cases/abstract_use_case.rb +1 -1
- data/lib/rider_kick/version.rb +1 -1
- metadata +129 -8
- data/CHANGELOG.md +0 -5
|
@@ -7,3 +7,5 @@ Example:
|
|
|
7
7
|
bin/rails generate rider_kick:clean_arch --setup
|
|
8
8
|
bin/rails generate rider_kick:structure Models::User actor:owner uploaders:asset,images
|
|
9
9
|
bin/rails generate rider_kick:scaffold users scope:dashboard
|
|
10
|
+
bin/rails generate rider_kick:factory Models::Article scope:core
|
|
11
|
+
bin/rails generate rider_kick:factory Models::Article scope:core --static
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
require 'active_support/inflector'
|
|
5
|
+
require 'active_support/core_ext/object/blank'
|
|
6
|
+
require 'yaml'
|
|
7
|
+
require_relative 'errors'
|
|
8
|
+
require_relative '../../rider-kick'
|
|
9
|
+
|
|
10
|
+
module RiderKick
|
|
11
|
+
class BaseGenerator < Rails::Generators::Base
|
|
12
|
+
protected
|
|
13
|
+
|
|
14
|
+
def template_path_for(template_name)
|
|
15
|
+
# Check for custom template path first
|
|
16
|
+
custom_path = RiderKick.configuration.template_path
|
|
17
|
+
if custom_path && Dir.exist?(custom_path)
|
|
18
|
+
custom_template_path = File.join(custom_path, template_name)
|
|
19
|
+
return custom_template_path if File.exist?(custom_template_path)
|
|
20
|
+
end
|
|
21
|
+
# Fallback to default template path
|
|
22
|
+
File.join(self.class.source_root, template_name)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def configure_engine
|
|
26
|
+
if options[:engine].present?
|
|
27
|
+
RiderKick.configuration.engine_name = options[:engine]
|
|
28
|
+
# Jika --engine dispecify, selalu ada scope engine nya
|
|
29
|
+
engine_prefix = options[:engine].underscore
|
|
30
|
+
domain_part = options[:domain] || ''
|
|
31
|
+
RiderKick.configuration.domain_scope = domain_part.empty? ? engine_prefix + '/' : engine_prefix + '/' + domain_part
|
|
32
|
+
say "Using engine: #{RiderKick.configuration.engine_name}", :green
|
|
33
|
+
say "Using domain scope: #{RiderKick.configuration.domain_scope}", :green
|
|
34
|
+
elsif options[:domain].present?
|
|
35
|
+
# Jika hanya --domain yang dispecify, gunakan konfigurasi existing
|
|
36
|
+
RiderKick.configuration.domain_scope = options[:domain]
|
|
37
|
+
say "Using domain scope: #{RiderKick.configuration.domain_scope}", :blue
|
|
38
|
+
else
|
|
39
|
+
# Jika tidak ada options, pertahankan konfigurasi existing
|
|
40
|
+
# Hanya tampilkan pesan jika belum pernah di-set
|
|
41
|
+
unless @engine_configured
|
|
42
|
+
if RiderKick.configuration.engine_name
|
|
43
|
+
say "Using engine: #{RiderKick.configuration.engine_name}", :green
|
|
44
|
+
say "Using domain scope: #{RiderKick.configuration.domain_scope}", :green
|
|
45
|
+
else
|
|
46
|
+
say 'Using main app (no engine specified)', :blue
|
|
47
|
+
say "Using domain scope: #{RiderKick.configuration.domain_scope}", :blue
|
|
48
|
+
end
|
|
49
|
+
@engine_configured = true
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def validate_file_exists!(path, context = '')
|
|
55
|
+
unless File.exist?(path)
|
|
56
|
+
error_message = "File not found: #{path}"
|
|
57
|
+
error_message += " (#{context})" if context.present?
|
|
58
|
+
raise FileNotFoundError.new(error_message, file_path: path, context: context)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def validate_yaml_format!(file_path)
|
|
63
|
+
validate_file_exists!(file_path, 'YAML validation')
|
|
64
|
+
begin
|
|
65
|
+
YAML.load_file(file_path)
|
|
66
|
+
rescue Psych::SyntaxError => e
|
|
67
|
+
raise YamlFormatError.new(
|
|
68
|
+
"Invalid YAML format in #{file_path}: #{e.message}",
|
|
69
|
+
file_path: file_path,
|
|
70
|
+
yaml_error: e.message
|
|
71
|
+
)
|
|
72
|
+
rescue => e
|
|
73
|
+
raise YamlFormatError.new(
|
|
74
|
+
"Error reading YAML file #{file_path}: #{e.message}",
|
|
75
|
+
file_path: file_path,
|
|
76
|
+
error: e.message
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def validate_model_exists!(model_name)
|
|
82
|
+
# Try to constantize the model name
|
|
83
|
+
# This will raise NameError if the model doesn't exist
|
|
84
|
+
|
|
85
|
+
model_name.constantize
|
|
86
|
+
rescue NameError => e
|
|
87
|
+
# Try to load the model file if it exists (for test scenarios where file exists but not loaded)
|
|
88
|
+
model_path = find_model_file(model_name)
|
|
89
|
+
if model_path && File.exist?(model_path)
|
|
90
|
+
# Try loading the file
|
|
91
|
+
begin
|
|
92
|
+
load model_path
|
|
93
|
+
model_name.constantize
|
|
94
|
+
rescue => load_error
|
|
95
|
+
# If loading also fails, raise the original error
|
|
96
|
+
raise ModelNotFoundError.new(
|
|
97
|
+
"Model #{model_name} not found. Make sure the model exists and is valid.",
|
|
98
|
+
model_name: model_name,
|
|
99
|
+
original_error: e.message,
|
|
100
|
+
load_error: load_error.message
|
|
101
|
+
)
|
|
102
|
+
end
|
|
103
|
+
else
|
|
104
|
+
# Model file doesn't exist, raise error
|
|
105
|
+
raise ModelNotFoundError.new(
|
|
106
|
+
"Model #{model_name} not found. Make sure the model exists.",
|
|
107
|
+
model_name: model_name,
|
|
108
|
+
original_error: e.message
|
|
109
|
+
)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def find_model_file(model_name)
|
|
114
|
+
# Convert model name to file path
|
|
115
|
+
# Models::User -> app/models/models/user.rb or engines/.../app/models/.../user.rb
|
|
116
|
+
parts = model_name.split('::')
|
|
117
|
+
return nil if parts.empty?
|
|
118
|
+
|
|
119
|
+
file_name = parts.last.underscore + '.rb'
|
|
120
|
+
|
|
121
|
+
# Check main app models path first
|
|
122
|
+
main_path = File.join(RiderKick.configuration.models_path, file_name)
|
|
123
|
+
return main_path if File.exist?(main_path)
|
|
124
|
+
|
|
125
|
+
# Check engine models path if engine is set
|
|
126
|
+
if RiderKick.configuration.engine_name
|
|
127
|
+
engine_path = File.join(
|
|
128
|
+
'engines',
|
|
129
|
+
RiderKick.configuration.engine_name.underscore,
|
|
130
|
+
'app/models',
|
|
131
|
+
RiderKick.configuration.engine_name.underscore,
|
|
132
|
+
'models',
|
|
133
|
+
file_name
|
|
134
|
+
)
|
|
135
|
+
return engine_path if File.exist?(engine_path)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
nil
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def validate_domains_path!
|
|
142
|
+
unless Dir.exist?(RiderKick.configuration.domains_path)
|
|
143
|
+
raise ValidationError.new(
|
|
144
|
+
'Clean architecture structure not found. Run: bin/rails generate rider_kick:clean_arch --setup',
|
|
145
|
+
domains_path: RiderKick.configuration.domains_path
|
|
146
|
+
)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def detect_engine_name
|
|
151
|
+
# Detect engine dari struktur file system
|
|
152
|
+
# Cek apakah ada lib/<name>/engine.rb
|
|
153
|
+
return nil unless Dir.exist?('lib')
|
|
154
|
+
|
|
155
|
+
engines = []
|
|
156
|
+
Dir.glob('lib/*/engine.rb').each do |engine_file|
|
|
157
|
+
engine_name = File.basename(File.dirname(engine_file))
|
|
158
|
+
engines << engine_name.camelize if File.exist?(engine_file)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Jika hanya ada satu engine, return itu
|
|
162
|
+
return engines.first if engines.length == 1
|
|
163
|
+
|
|
164
|
+
# Jika ada multiple engines, return nil (user harus specify via --engine option)
|
|
165
|
+
# Atau cek dari gem name di gemspec (fallback)
|
|
166
|
+
gemspec_files = Dir.glob('*.gemspec')
|
|
167
|
+
unless gemspec_files.empty?
|
|
168
|
+
gemspec_content = File.read(gemspec_files.first)
|
|
169
|
+
if gemspec_content =~ /\.name\s*=\s*["']([^"']+)["']/
|
|
170
|
+
gem_name = Regexp.last_match(1)
|
|
171
|
+
# Extract engine name dari gem name (e.g., "my_app-core" -> "Core")
|
|
172
|
+
engine_name = gem_name.split(/[-_]/).last.camelize
|
|
173
|
+
return engine_name if Dir.exist?("lib/#{engine_name.underscore}") && engines.include?(engine_name)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
nil
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def detect_domains_path
|
|
181
|
+
if RiderKick.configuration.engine_name
|
|
182
|
+
# Engine: engines/<engine_name>/app/domains/<domain_scope>
|
|
183
|
+
File.join('engines', RiderKick.configuration.engine_name.underscore, 'app/domains', RiderKick.configuration.domain_scope)
|
|
184
|
+
else
|
|
185
|
+
# Main app: app/domains/<domain_scope>
|
|
186
|
+
File.join('app/domains', RiderKick.configuration.domain_scope)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -1,64 +1,146 @@
|
|
|
1
|
+
require_relative 'base_generator'
|
|
2
|
+
require_relative '../../rider-kick'
|
|
3
|
+
|
|
1
4
|
module RiderKick
|
|
2
|
-
class CleanArchGenerator <
|
|
5
|
+
class CleanArchGenerator < BaseGenerator
|
|
3
6
|
source_root File.expand_path('templates', __dir__)
|
|
4
7
|
|
|
5
8
|
class_option :setup, type: :boolean, default: false, desc: 'Setup domain structure'
|
|
9
|
+
class_option :engine, type: :string, default: nil, desc: 'Specify engine name (e.g., Core, Admin)'
|
|
10
|
+
class_option :domain, type: :string, default: '', desc: 'Specify domain scope (e.g., core/, admin/, api/v1/)'
|
|
6
11
|
|
|
7
12
|
def validate_setup_option
|
|
8
|
-
|
|
13
|
+
# Jika --engine dispecify, maka --setup otomatis dianggap true
|
|
14
|
+
return if options.engine.present?
|
|
15
|
+
|
|
16
|
+
unless options.setup
|
|
17
|
+
raise ValidationError.new(
|
|
18
|
+
'The --setup option must be specified to create the domain structure.',
|
|
19
|
+
suggestion: 'Run: bin/rails generate rider_kick:clean_arch --setup'
|
|
20
|
+
)
|
|
21
|
+
end
|
|
9
22
|
end
|
|
10
23
|
|
|
11
24
|
def create_gem_dependencies
|
|
12
|
-
|
|
13
|
-
|
|
25
|
+
if options[:engine].present?
|
|
26
|
+
# Untuk engine, tambahkan ke Gemfile engine
|
|
27
|
+
engine_gemfile_path = "engines/#{options[:engine].downcase}/Gemfile"
|
|
28
|
+
append_to_file(engine_gemfile_path, gem_dependencies)
|
|
29
|
+
say "Gems added to #{engine_gemfile_path}", :green
|
|
30
|
+
else
|
|
31
|
+
# Untuk main app, tambahkan ke Gemfile host
|
|
32
|
+
append_to_file('Gemfile', gem_dependencies)
|
|
33
|
+
say 'Gems added to Gemfile', :green
|
|
34
|
+
end
|
|
14
35
|
end
|
|
15
36
|
|
|
16
37
|
def setup_configuration
|
|
38
|
+
configure_engine
|
|
17
39
|
setup_domain_structure
|
|
18
40
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
41
|
+
if options[:engine].present?
|
|
42
|
+
# Untuk engine, hanya setup yang relevan
|
|
43
|
+
setup_init_migration
|
|
44
|
+
setup_models
|
|
45
|
+
setup_engine_generators
|
|
46
|
+
else
|
|
47
|
+
# Untuk main app, setup semua
|
|
48
|
+
setup_initializers
|
|
49
|
+
setup_dotenv
|
|
50
|
+
setup_gitignore
|
|
51
|
+
setup_rubocop
|
|
52
|
+
setup_init_migration
|
|
53
|
+
setup_models
|
|
54
|
+
setup_application_config
|
|
55
|
+
# setup_active_storage
|
|
56
|
+
setup_rspec
|
|
57
|
+
setup_readme
|
|
58
|
+
end
|
|
28
59
|
end
|
|
29
60
|
|
|
30
61
|
private
|
|
31
62
|
|
|
63
|
+
def domain_class_name
|
|
64
|
+
# Convert domain scope to class name
|
|
65
|
+
# Engine: "<Engine>" for ApplicationRecord, "<Engine>::<Domain>" for other classes
|
|
66
|
+
# Main app: "" for ApplicationRecord, "<AppName>" for root domain, "<Domain>" for scoped domain
|
|
67
|
+
scope = RiderKick.configuration.domain_scope.chomp('/')
|
|
68
|
+
|
|
69
|
+
if RiderKick.configuration.engine_name.present?
|
|
70
|
+
# Engine context: domain_scope always starts with engine name
|
|
71
|
+
engine_prefix = RiderKick.configuration.engine_name.to_s.camelize
|
|
72
|
+
engine_underscored = RiderKick.configuration.engine_name.to_s.underscore
|
|
73
|
+
|
|
74
|
+
if scope == engine_underscored
|
|
75
|
+
# Default engine domain: engines/my_engine/app/domains/my_engine/
|
|
76
|
+
engine_prefix
|
|
77
|
+
else
|
|
78
|
+
# Engine with sub-domain: engines/my_engine/app/domains/my_engine/admin/
|
|
79
|
+
# Remove engine prefix from scope and create namespace
|
|
80
|
+
sub_scope = scope.sub(/^#{engine_underscored}\//, '')
|
|
81
|
+
if sub_scope.empty?
|
|
82
|
+
engine_prefix
|
|
83
|
+
else
|
|
84
|
+
"#{engine_prefix}::#{sub_scope.split('/').map(&:camelize).join('::')}"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
elsif scope.empty?
|
|
88
|
+
# Main app context
|
|
89
|
+
# Root domain in main app: use application name
|
|
90
|
+
begin
|
|
91
|
+
Rails.application&.class&.module_parent_name || 'MyApp'
|
|
92
|
+
rescue
|
|
93
|
+
'MyApp' # Fallback for test environment
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
# Scoped domain in main app: use domain name only
|
|
97
|
+
scope.split('/').map(&:camelize).join('::')
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def domain_class_name_for_application_record
|
|
102
|
+
# Special method for ApplicationRecord class names
|
|
103
|
+
# Engine: "<Engine>" (will become EngineApplicationRecord)
|
|
104
|
+
# Main app: "" (will become ApplicationRecord)
|
|
105
|
+
if RiderKick.configuration.engine_name.present?
|
|
106
|
+
# Engine context: use engine name
|
|
107
|
+
RiderKick.configuration.engine_name.to_s.camelize
|
|
108
|
+
else
|
|
109
|
+
# Main app context: empty string for ApplicationRecord
|
|
110
|
+
''
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
32
114
|
def setup_active_storage
|
|
33
115
|
run 'rails active_storage:install'
|
|
34
116
|
run 'rails db:migrate'
|
|
35
117
|
end
|
|
36
118
|
|
|
37
119
|
def setup_domain_structure
|
|
38
|
-
empty_directory File.join(
|
|
39
|
-
empty_directory File.join(
|
|
40
|
-
empty_directory File.join(
|
|
41
|
-
empty_directory File.join(
|
|
42
|
-
empty_directory File.join(
|
|
120
|
+
empty_directory File.join(RiderKick.configuration.domains_path, 'use_cases/contract')
|
|
121
|
+
empty_directory File.join(RiderKick.configuration.domains_path, 'repositories')
|
|
122
|
+
empty_directory File.join(RiderKick.configuration.domains_path, 'builders')
|
|
123
|
+
empty_directory File.join(RiderKick.configuration.domains_path, 'entities')
|
|
124
|
+
empty_directory File.join(RiderKick.configuration.domains_path, 'utils')
|
|
43
125
|
|
|
44
126
|
# then
|
|
45
127
|
copy_domain_file
|
|
46
128
|
end
|
|
47
129
|
|
|
48
130
|
def copy_domain_file
|
|
49
|
-
template 'domains/core/use_cases/contract/pagination.rb.tt', File.join(
|
|
50
|
-
template 'domains/core/use_cases/contract/default.rb.tt', File.join(
|
|
51
|
-
template 'domains/core/use_cases/get_version.rb.tt', File.join(
|
|
131
|
+
template 'domains/core/use_cases/contract/pagination.rb.tt', File.join(RiderKick.configuration.domains_path, 'use_cases/contract', 'pagination.rb')
|
|
132
|
+
template 'domains/core/use_cases/contract/default.rb.tt', File.join(RiderKick.configuration.domains_path, 'use_cases/contract', 'default.rb')
|
|
133
|
+
template 'domains/core/use_cases/get_version.rb.tt', File.join(RiderKick.configuration.domains_path, 'use_cases', 'get_version.rb')
|
|
52
134
|
|
|
53
|
-
template 'domains/core/builders/error.rb.tt', File.join(
|
|
54
|
-
template 'domains/core/builders/pagination.rb.tt', File.join(
|
|
135
|
+
template 'domains/core/builders/error.rb.tt', File.join(RiderKick.configuration.domains_path, 'builders', 'error.rb')
|
|
136
|
+
template 'domains/core/builders/pagination.rb.tt', File.join(RiderKick.configuration.domains_path, 'builders', 'pagination.rb')
|
|
55
137
|
|
|
56
|
-
template 'domains/core/entities/error.rb.tt', File.join(
|
|
57
|
-
template 'domains/core/entities/pagination.rb.tt', File.join(
|
|
138
|
+
template 'domains/core/entities/error.rb.tt', File.join(RiderKick.configuration.domains_path, 'entities', 'error.rb')
|
|
139
|
+
template 'domains/core/entities/pagination.rb.tt', File.join(RiderKick.configuration.domains_path, 'entities', 'pagination.rb')
|
|
58
140
|
|
|
59
|
-
template 'domains/core/repositories/abstract_repository.rb.tt', File.join(
|
|
60
|
-
template 'domains/core/utils/abstract_utils.rb.tt', File.join(
|
|
61
|
-
template 'domains/core/utils/request_methods.rb.tt', File.join(
|
|
141
|
+
template 'domains/core/repositories/abstract_repository.rb.tt', File.join(RiderKick.configuration.domains_path, 'repositories', 'abstract_repository.rb')
|
|
142
|
+
template 'domains/core/utils/abstract_utils.rb.tt', File.join(RiderKick.configuration.domains_path, 'utils', 'abstract_utils.rb')
|
|
143
|
+
template 'domains/core/utils/request_methods.rb.tt', File.join(RiderKick.configuration.domains_path, 'utils', 'request_methods.rb')
|
|
62
144
|
end
|
|
63
145
|
|
|
64
146
|
def setup_initializers
|
|
@@ -89,7 +171,18 @@ module RiderKick
|
|
|
89
171
|
end
|
|
90
172
|
|
|
91
173
|
def setup_init_migration
|
|
92
|
-
|
|
174
|
+
if options[:engine].present?
|
|
175
|
+
# Untuk engine, buat migration dan structures directory di engine directory
|
|
176
|
+
engine_migrate_path = "engines/#{options[:engine].downcase}/db/migrate"
|
|
177
|
+
engine_structures_path = "engines/#{options[:engine].downcase}/db/structures"
|
|
178
|
+
empty_directory engine_migrate_path unless Dir.exist?(engine_migrate_path)
|
|
179
|
+
empty_directory engine_structures_path unless Dir.exist?(engine_structures_path)
|
|
180
|
+
template 'db/migrate/20220613145533_init_database.rb', File.join(engine_migrate_path, '20220613145533_init_database.rb')
|
|
181
|
+
else
|
|
182
|
+
# Untuk main app, buat di root db/migrate dan db/structures
|
|
183
|
+
template 'db/migrate/20220613145533_init_database.rb', File.join('db/migrate/20220613145533_init_database.rb')
|
|
184
|
+
empty_directory 'db/structures' unless Dir.exist?('db/structures')
|
|
185
|
+
end
|
|
93
186
|
end
|
|
94
187
|
|
|
95
188
|
# Helper untuk menyalin initializers
|
|
@@ -102,8 +195,21 @@ module RiderKick
|
|
|
102
195
|
end
|
|
103
196
|
|
|
104
197
|
def setup_models
|
|
105
|
-
|
|
106
|
-
|
|
198
|
+
if options[:engine].present?
|
|
199
|
+
# Untuk engine, buat application_record.rb di engine directory
|
|
200
|
+
engine_models_path = "engines/#{options[:engine].downcase}/app/models/#{options[:engine].downcase}"
|
|
201
|
+
empty_directory engine_models_path unless Dir.exist?(engine_models_path)
|
|
202
|
+
template 'models/application_record.rb', File.join(engine_models_path, 'application_record.rb')
|
|
203
|
+
else
|
|
204
|
+
# Untuk main app, buat di root app/models
|
|
205
|
+
template 'models/application_record.rb', File.join('app/models/application_record.rb')
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Untuk engine, models path akan di engines/<engine_name>/app/models/<engine_name>/models
|
|
209
|
+
# Untuk main app, models path akan di app/models/models
|
|
210
|
+
models_dir = RiderKick.configuration.models_path
|
|
211
|
+
empty_directory models_dir unless Dir.exist?(models_dir)
|
|
212
|
+
template 'models/models.rb', File.join(models_dir, 'models.rb')
|
|
107
213
|
end
|
|
108
214
|
|
|
109
215
|
def copy_env_development
|
|
@@ -114,16 +220,13 @@ module RiderKick
|
|
|
114
220
|
end
|
|
115
221
|
|
|
116
222
|
def gem_dependencies
|
|
117
|
-
inject_into_file 'Gemfile', after: "group :development, :test do\n" do
|
|
118
|
-
<<-CONFIG
|
|
119
|
-
|
|
120
|
-
gem "rspec-rails"
|
|
121
|
-
gem "factory_bot_rails"
|
|
122
|
-
gem "shoulda-matchers"
|
|
123
|
-
CONFIG
|
|
124
|
-
end
|
|
125
|
-
|
|
126
223
|
<<~RUBY
|
|
224
|
+
group :development, :test do
|
|
225
|
+
gem "rspec-rails"
|
|
226
|
+
gem "factory_bot_rails"
|
|
227
|
+
gem "faker"
|
|
228
|
+
gem "shoulda-matchers"
|
|
229
|
+
end
|
|
127
230
|
|
|
128
231
|
# Env Variables
|
|
129
232
|
gem 'dotenv-rails'
|
|
@@ -132,11 +235,14 @@ module RiderKick
|
|
|
132
235
|
gem 'hashie'
|
|
133
236
|
|
|
134
237
|
# uploading
|
|
135
|
-
gem 'image_processing'
|
|
238
|
+
gem 'image_processing'
|
|
136
239
|
gem 'ruby-vips'
|
|
137
240
|
|
|
138
241
|
# pagination
|
|
139
|
-
gem 'pagy'
|
|
242
|
+
gem 'pagy'
|
|
243
|
+
|
|
244
|
+
# models validation
|
|
245
|
+
gem 'schema_validations'
|
|
140
246
|
RUBY
|
|
141
247
|
end
|
|
142
248
|
|
|
@@ -148,12 +254,96 @@ module RiderKick
|
|
|
148
254
|
template '.rspec', File.join('.rspec')
|
|
149
255
|
template 'spec/support/repository_stubber.rb', File.join('spec/support/repository_stubber.rb')
|
|
150
256
|
template 'spec/support/file_stuber.rb', File.join('spec/support/file_stuber.rb')
|
|
151
|
-
|
|
257
|
+
template 'spec/support/class_stubber.rb', File.join('spec/support/class_stubber.rb')
|
|
258
|
+
say 'Mengonfigurasi FactoryBot dan Faker...'
|
|
259
|
+
setup_factory_bot
|
|
152
260
|
template 'spec/rails_helper.rb', File.join('spec/rails_helper.rb')
|
|
153
261
|
end
|
|
154
262
|
|
|
155
|
-
def
|
|
156
|
-
|
|
263
|
+
def setup_factory_bot
|
|
264
|
+
# Create factories directory structure
|
|
265
|
+
empty_directory 'spec/factories'
|
|
266
|
+
|
|
267
|
+
# Create FactoryBot support file
|
|
268
|
+
template 'spec/support/factory_bot.rb', File.join('spec/support/factory_bot.rb')
|
|
269
|
+
|
|
270
|
+
# Create Faker support file
|
|
271
|
+
template 'spec/support/faker.rb', File.join('spec/support/faker.rb')
|
|
272
|
+
|
|
273
|
+
# Create example factories file
|
|
274
|
+
template 'spec/factories/.gitkeep', File.join('spec/factories/.gitkeep')
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def setup_application_config
|
|
278
|
+
application_config_path = 'config/application.rb'
|
|
279
|
+
|
|
280
|
+
# Check if file exists
|
|
281
|
+
unless File.exist?(application_config_path)
|
|
282
|
+
say "File #{application_config_path} not found, skipping application config setup", :yellow
|
|
283
|
+
return
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# Check if config already exists
|
|
287
|
+
application_content = File.read(application_config_path)
|
|
288
|
+
if application_content.include?("config.paths['db/migrate']")
|
|
289
|
+
say "Migration paths config already exists in #{application_config_path}", :green
|
|
290
|
+
return
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Find the class Application block and inject config after class definition
|
|
294
|
+
# Look for pattern: class Application < Rails::Application
|
|
295
|
+
if /class\s+Application\s+<\s+Rails::Application/.match?(application_content)
|
|
296
|
+
# Try to inject right after class definition line
|
|
297
|
+
inject_into_file application_config_path, after: /class\s+Application\s+<\s+Rails::Application\s*\n/ do
|
|
298
|
+
<<~RUBY
|
|
299
|
+
# Load migrations from engines
|
|
300
|
+
config.paths['db/migrate'] << './**/db/migrate'
|
|
301
|
+
|
|
302
|
+
RUBY
|
|
303
|
+
end
|
|
304
|
+
say "Added migration paths config to #{application_config_path}", :green
|
|
305
|
+
else
|
|
306
|
+
say "Could not find Application class in #{application_config_path}, skipping", :yellow
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def setup_engine_generators
|
|
311
|
+
engine_name_underscore = options[:engine].downcase
|
|
312
|
+
options[:engine].camelize
|
|
313
|
+
engine_rb_path = "engines/#{engine_name_underscore}/lib/#{engine_name_underscore}/engine.rb"
|
|
314
|
+
|
|
315
|
+
# Check if file exists
|
|
316
|
+
unless File.exist?(engine_rb_path)
|
|
317
|
+
say "File #{engine_rb_path} not found, skipping engine generators config setup", :yellow
|
|
318
|
+
return
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Check if config already exists
|
|
322
|
+
engine_content = File.read(engine_rb_path)
|
|
323
|
+
if engine_content.include?('config.generators do |generate|')
|
|
324
|
+
say "Generator config already exists in #{engine_rb_path}", :green
|
|
325
|
+
return
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# Find the engine class definition and inject config inside it
|
|
329
|
+
# Look for pattern: class Engine < Rails::Engine (inside module)
|
|
330
|
+
if /class\s+Engine\s+<\s+::Rails::Engine/.match?(engine_content)
|
|
331
|
+
# Try to inject right after the class definition line
|
|
332
|
+
inject_into_file engine_rb_path, after: /class\s+Engine\s+<\s+::Rails::Engine\s*\n/ do
|
|
333
|
+
<<~RUBY
|
|
334
|
+
config.generators do |generate|
|
|
335
|
+
generate.orm :active_record, primary_key_type: :uuid
|
|
336
|
+
generate.assets = false
|
|
337
|
+
generate.helper = false
|
|
338
|
+
generate.test_framework nil
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
RUBY
|
|
342
|
+
end
|
|
343
|
+
say "Added generator config to #{engine_rb_path}", :green
|
|
344
|
+
else
|
|
345
|
+
say "Could not find Engine class in #{engine_rb_path}, skipping", :yellow
|
|
346
|
+
end
|
|
157
347
|
end
|
|
158
348
|
end
|
|
159
349
|
end
|