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
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
require 'tmpdir'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'generators/rider_kick/clean_arch_generator'
|
|
7
|
+
|
|
8
|
+
RSpec.describe 'rider_kick:clean_arch generator with engine option' do
|
|
9
|
+
let(:klass) { RiderKick::CleanArchGenerator }
|
|
10
|
+
|
|
11
|
+
context 'without --engine option (main app)' do
|
|
12
|
+
it 'uses main app models path when no engine specified' do
|
|
13
|
+
Dir.mktmpdir do |dir|
|
|
14
|
+
Dir.chdir(dir) do
|
|
15
|
+
FileUtils.mkdir_p('config')
|
|
16
|
+
File.write('Gemfile', "source 'https://rubygems.org'\n")
|
|
17
|
+
|
|
18
|
+
# Reset configuration untuk test
|
|
19
|
+
RiderKick.configuration.engine_name = nil
|
|
20
|
+
|
|
21
|
+
instance = klass.new([])
|
|
22
|
+
opts = double('options', setup: true)
|
|
23
|
+
allow(opts).to receive(:[]).and_return(nil)
|
|
24
|
+
allow(opts).to receive(:[]).with(:engine).and_return(nil)
|
|
25
|
+
allow(opts).to receive(:[]).with(:quiet).and_return(false)
|
|
26
|
+
allow(instance).to receive(:options).and_return(opts)
|
|
27
|
+
|
|
28
|
+
# Hanya test setup_domain_structure yang relevan dengan engine configuration
|
|
29
|
+
allow(instance).to receive(:copy_domain_file) # Skip template yang memerlukan Rails
|
|
30
|
+
allow(instance).to receive(:setup_initializers) # Skip initializers yang memerlukan Rails
|
|
31
|
+
allow(instance).to receive(:setup_dotenv)
|
|
32
|
+
allow(instance).to receive(:setup_gitignore)
|
|
33
|
+
allow(instance).to receive(:setup_rubocop)
|
|
34
|
+
allow(instance).to receive(:setup_init_migration)
|
|
35
|
+
allow(instance).to receive(:setup_active_storage)
|
|
36
|
+
allow(instance).to receive(:setup_rspec)
|
|
37
|
+
allow(instance).to receive(:setup_readme)
|
|
38
|
+
allow(instance).to receive(:create_gem_dependencies)
|
|
39
|
+
allow(instance).to receive(:run)
|
|
40
|
+
|
|
41
|
+
instance.setup_configuration
|
|
42
|
+
|
|
43
|
+
# Verifikasi models_path menggunakan main app
|
|
44
|
+
expect(RiderKick.configuration.models_path).to eq('app/models/models')
|
|
45
|
+
expect(RiderKick.configuration.engine_name).to be_nil
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context 'with --engine option' do
|
|
52
|
+
it 'uses engine models path when engine specified' do
|
|
53
|
+
Dir.mktmpdir do |dir|
|
|
54
|
+
Dir.chdir(dir) do
|
|
55
|
+
FileUtils.mkdir_p('config')
|
|
56
|
+
File.write('Gemfile', "source 'https://rubygems.org'\n")
|
|
57
|
+
|
|
58
|
+
# Reset configuration untuk test
|
|
59
|
+
RiderKick.configuration.engine_name = nil
|
|
60
|
+
|
|
61
|
+
instance = klass.new([])
|
|
62
|
+
opts = double('options', setup: true)
|
|
63
|
+
allow(opts).to receive(:[]).and_return(nil)
|
|
64
|
+
allow(opts).to receive(:[]).with(:engine).and_return('Core')
|
|
65
|
+
allow(opts).to receive(:[]).with(:quiet).and_return(false)
|
|
66
|
+
allow(instance).to receive(:options).and_return(opts)
|
|
67
|
+
|
|
68
|
+
# Hanya test setup_domain_structure yang relevan dengan engine configuration
|
|
69
|
+
allow(instance).to receive(:copy_domain_file) # Skip template yang memerlukan Rails
|
|
70
|
+
allow(instance).to receive(:setup_initializers) # Skip initializers yang memerlukan Rails
|
|
71
|
+
allow(instance).to receive(:setup_dotenv)
|
|
72
|
+
allow(instance).to receive(:setup_gitignore)
|
|
73
|
+
allow(instance).to receive(:setup_rubocop)
|
|
74
|
+
allow(instance).to receive(:setup_init_migration)
|
|
75
|
+
allow(instance).to receive(:setup_active_storage)
|
|
76
|
+
allow(instance).to receive(:setup_rspec)
|
|
77
|
+
allow(instance).to receive(:setup_readme)
|
|
78
|
+
allow(instance).to receive(:create_gem_dependencies)
|
|
79
|
+
allow(instance).to receive(:run)
|
|
80
|
+
|
|
81
|
+
instance.setup_configuration
|
|
82
|
+
|
|
83
|
+
# Verifikasi models_path menggunakan engine
|
|
84
|
+
expect(RiderKick.configuration.models_path).to eq('engines/core/app/models/core/models')
|
|
85
|
+
expect(RiderKick.configuration.engine_name).to eq('Core')
|
|
86
|
+
expect(RiderKick.configuration.domain_scope).to eq('core/')
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'creates models directory with correct engine path' do
|
|
92
|
+
Dir.mktmpdir do |dir|
|
|
93
|
+
Dir.chdir(dir) do
|
|
94
|
+
FileUtils.mkdir_p('config')
|
|
95
|
+
File.write('Gemfile', "source 'https://rubygems.org'\n")
|
|
96
|
+
|
|
97
|
+
# Reset configuration untuk test
|
|
98
|
+
RiderKick.configuration.engine_name = nil
|
|
99
|
+
|
|
100
|
+
instance = klass.new([])
|
|
101
|
+
opts = double('options', setup: true)
|
|
102
|
+
allow(opts).to receive(:[]).and_return(nil)
|
|
103
|
+
allow(opts).to receive(:[]).with(:engine).and_return('Admin')
|
|
104
|
+
allow(opts).to receive(:[]).with(:quiet).and_return(false)
|
|
105
|
+
allow(instance).to receive(:options).and_return(opts)
|
|
106
|
+
|
|
107
|
+
# Hanya test setup_domain_structure yang relevan dengan engine configuration
|
|
108
|
+
allow(instance).to receive(:copy_domain_file) # Skip template yang memerlukan Rails
|
|
109
|
+
allow(instance).to receive(:setup_initializers) # Skip initializers yang memerlukan Rails
|
|
110
|
+
allow(instance).to receive(:setup_dotenv)
|
|
111
|
+
allow(instance).to receive(:setup_gitignore)
|
|
112
|
+
allow(instance).to receive(:setup_rubocop)
|
|
113
|
+
allow(instance).to receive(:setup_init_migration)
|
|
114
|
+
allow(instance).to receive(:setup_active_storage)
|
|
115
|
+
allow(instance).to receive(:setup_rspec)
|
|
116
|
+
allow(instance).to receive(:setup_readme)
|
|
117
|
+
allow(instance).to receive(:create_gem_dependencies)
|
|
118
|
+
allow(instance).to receive(:run)
|
|
119
|
+
|
|
120
|
+
instance.setup_configuration
|
|
121
|
+
|
|
122
|
+
# Verifikasi directory models dibuat dengan path engine
|
|
123
|
+
expect(Dir.exist?('engines/admin/app/models/admin')).to be true
|
|
124
|
+
expect(RiderKick.configuration.models_path).to eq('engines/admin/app/models/admin/models')
|
|
125
|
+
expect(RiderKick.configuration.domain_scope).to eq('admin/')
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
context 'domain scope default behavior' do
|
|
132
|
+
it 'uses empty domain scope as default' do
|
|
133
|
+
Dir.mktmpdir do |dir|
|
|
134
|
+
Dir.chdir(dir) do
|
|
135
|
+
# Reset configuration to defaults
|
|
136
|
+
RiderKick.configuration.engine_name = nil
|
|
137
|
+
RiderKick.configuration.domain_scope = ''
|
|
138
|
+
|
|
139
|
+
# Mock the domain_class_name method to return predictable result
|
|
140
|
+
generator = klass.new([])
|
|
141
|
+
allow(generator).to receive(:domain_class_name).and_return('MyApp')
|
|
142
|
+
|
|
143
|
+
expect(RiderKick.configuration.domain_scope).to eq('')
|
|
144
|
+
expect(RiderKick.configuration.domains_path).to eq('app/domains/')
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it 'generates class names with app name for empty domain scope in main app' do
|
|
150
|
+
Dir.mktmpdir do |dir|
|
|
151
|
+
Dir.chdir(dir) do
|
|
152
|
+
# Create minimal Rails app structure for testing
|
|
153
|
+
FileUtils.mkdir_p('app/domains')
|
|
154
|
+
|
|
155
|
+
# Reset configuration
|
|
156
|
+
RiderKick.configuration.engine_name = nil
|
|
157
|
+
RiderKick.configuration.domain_scope = ''
|
|
158
|
+
|
|
159
|
+
instance = klass.new([])
|
|
160
|
+
opts = double('options', setup: true)
|
|
161
|
+
allow(opts).to receive(:[]).and_return(nil)
|
|
162
|
+
allow(opts).to receive(:[]).with(:engine).and_return(nil)
|
|
163
|
+
allow(opts).to receive(:[]).with(:quiet).and_return(false)
|
|
164
|
+
allow(instance).to receive(:options).and_return(opts)
|
|
165
|
+
|
|
166
|
+
# Mock methods to avoid actual file generation
|
|
167
|
+
allow(instance).to receive(:setup_domain_structure)
|
|
168
|
+
allow(instance).to receive(:setup_initializers)
|
|
169
|
+
allow(instance).to receive(:setup_dotenv)
|
|
170
|
+
allow(instance).to receive(:setup_gitignore)
|
|
171
|
+
allow(instance).to receive(:setup_rubocop)
|
|
172
|
+
allow(instance).to receive(:setup_active_storage)
|
|
173
|
+
allow(instance).to receive(:setup_rspec)
|
|
174
|
+
allow(instance).to receive(:setup_readme)
|
|
175
|
+
allow(instance).to receive(:create_gem_dependencies)
|
|
176
|
+
allow(instance).to receive(:setup_init_migration)
|
|
177
|
+
allow(instance).to receive(:setup_models)
|
|
178
|
+
allow(instance).to receive(:say)
|
|
179
|
+
|
|
180
|
+
# Test domain_class_name method
|
|
181
|
+
expect(instance.send(:domain_class_name)).to eq('MyApp')
|
|
182
|
+
|
|
183
|
+
# Test configuration paths
|
|
184
|
+
expect(RiderKick.configuration.domains_path).to eq('app/domains/')
|
|
185
|
+
expect(RiderKick.configuration.models_path).to eq('app/models/models')
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it 'generates class names with engine name for engine with default domain scope' do
|
|
191
|
+
Dir.mktmpdir do |dir|
|
|
192
|
+
Dir.chdir(dir) do
|
|
193
|
+
# Create minimal engine structure for testing
|
|
194
|
+
FileUtils.mkdir_p('engines/admin/lib/admin/engine.rb')
|
|
195
|
+
|
|
196
|
+
# Reset configuration
|
|
197
|
+
RiderKick.configuration.engine_name = 'Admin'
|
|
198
|
+
RiderKick.configuration.domain_scope = 'admin/' # Engine-prefixed domain scope
|
|
199
|
+
|
|
200
|
+
instance = klass.new([])
|
|
201
|
+
opts = double('options', setup: true)
|
|
202
|
+
allow(opts).to receive(:[]).and_return(nil)
|
|
203
|
+
allow(opts).to receive(:[]).with(:engine).and_return('Admin')
|
|
204
|
+
allow(opts).to receive(:[]).with(:quiet).and_return(false)
|
|
205
|
+
allow(instance).to receive(:options).and_return(opts)
|
|
206
|
+
|
|
207
|
+
# Mock methods to avoid actual file generation
|
|
208
|
+
allow(instance).to receive(:setup_domain_structure)
|
|
209
|
+
allow(instance).to receive(:setup_initializers)
|
|
210
|
+
allow(instance).to receive(:setup_dotenv)
|
|
211
|
+
allow(instance).to receive(:setup_gitignore)
|
|
212
|
+
allow(instance).to receive(:setup_rubocop)
|
|
213
|
+
allow(instance).to receive(:setup_active_storage)
|
|
214
|
+
allow(instance).to receive(:setup_rspec)
|
|
215
|
+
allow(instance).to receive(:setup_readme)
|
|
216
|
+
allow(instance).to receive(:create_gem_dependencies)
|
|
217
|
+
allow(instance).to receive(:setup_init_migration)
|
|
218
|
+
allow(instance).to receive(:setup_models)
|
|
219
|
+
allow(instance).to receive(:say)
|
|
220
|
+
|
|
221
|
+
# Test domain_class_name method for engine with empty domain scope
|
|
222
|
+
expect(instance.send(:domain_class_name)).to eq('Admin')
|
|
223
|
+
|
|
224
|
+
# Test configuration paths
|
|
225
|
+
expect(RiderKick.configuration.domains_path).to eq('engines/admin/app/domains/admin/')
|
|
226
|
+
expect(RiderKick.configuration.models_path).to eq('engines/admin/app/models/admin/models')
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
it 'generates class names with engine and domain for scoped domain in engine' do
|
|
232
|
+
Dir.mktmpdir do |dir|
|
|
233
|
+
Dir.chdir(dir) do
|
|
234
|
+
# Create minimal engine structure for testing
|
|
235
|
+
FileUtils.mkdir_p('engines/admin/lib/admin/engine.rb')
|
|
236
|
+
|
|
237
|
+
# Reset configuration
|
|
238
|
+
RiderKick.configuration.engine_name = 'Admin'
|
|
239
|
+
RiderKick.configuration.domain_scope = 'admin/core/' # Engine-prefixed
|
|
240
|
+
|
|
241
|
+
instance = klass.new([])
|
|
242
|
+
opts = double('options', setup: true)
|
|
243
|
+
allow(opts).to receive(:[]).and_return(nil)
|
|
244
|
+
allow(opts).to receive(:[]).with(:engine).and_return('Admin')
|
|
245
|
+
allow(opts).to receive(:[]).with(:domain).and_return('core/')
|
|
246
|
+
allow(opts).to receive(:[]).with(:quiet).and_return(false)
|
|
247
|
+
allow(instance).to receive(:options).and_return(opts)
|
|
248
|
+
|
|
249
|
+
# Mock methods to avoid actual file generation
|
|
250
|
+
allow(instance).to receive(:setup_domain_structure)
|
|
251
|
+
allow(instance).to receive(:setup_initializers)
|
|
252
|
+
allow(instance).to receive(:setup_dotenv)
|
|
253
|
+
allow(instance).to receive(:setup_gitignore)
|
|
254
|
+
allow(instance).to receive(:setup_rubocop)
|
|
255
|
+
allow(instance).to receive(:setup_active_storage)
|
|
256
|
+
allow(instance).to receive(:setup_rspec)
|
|
257
|
+
allow(instance).to receive(:setup_readme)
|
|
258
|
+
allow(instance).to receive(:create_gem_dependencies)
|
|
259
|
+
allow(instance).to receive(:setup_init_migration)
|
|
260
|
+
allow(instance).to receive(:setup_models)
|
|
261
|
+
allow(instance).to receive(:say)
|
|
262
|
+
|
|
263
|
+
# Test domain_class_name method for engine with domain
|
|
264
|
+
expect(instance.send(:domain_class_name)).to eq('Admin::Core')
|
|
265
|
+
|
|
266
|
+
# Test domain_class_name_for_application_record method
|
|
267
|
+
expect(instance.send(:domain_class_name_for_application_record)).to eq('Admin')
|
|
268
|
+
|
|
269
|
+
# Test configuration paths - when both engine and domain specified, structure goes to engine domains
|
|
270
|
+
expect(RiderKick.configuration.domains_path).to eq('engines/admin/app/domains/admin/core/')
|
|
271
|
+
expect(RiderKick.configuration.models_path).to eq('engines/admin/app/models/admin/models')
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
it 'creates domains structure in engine when both engine and domain are specified during setup' do
|
|
277
|
+
Dir.mktmpdir do |dir|
|
|
278
|
+
Dir.chdir(dir) do
|
|
279
|
+
# Create minimal Rails app structure for testing
|
|
280
|
+
FileUtils.mkdir_p('app/domains')
|
|
281
|
+
|
|
282
|
+
# Reset configuration
|
|
283
|
+
RiderKick.configuration.engine_name = 'MyEngine'
|
|
284
|
+
RiderKick.configuration.domain_scope = 'admin/'
|
|
285
|
+
|
|
286
|
+
instance = klass.new([])
|
|
287
|
+
opts = double('options', setup: true)
|
|
288
|
+
allow(opts).to receive(:[]).and_return(nil)
|
|
289
|
+
allow(opts).to receive(:[]).with(:engine).and_return('MyEngine')
|
|
290
|
+
allow(opts).to receive(:[]).with(:domain).and_return('admin/')
|
|
291
|
+
allow(opts).to receive(:[]).with(:quiet).and_return(false)
|
|
292
|
+
allow(instance).to receive(:options).and_return(opts)
|
|
293
|
+
|
|
294
|
+
# Mock methods to avoid actual file generation
|
|
295
|
+
allow(instance).to receive(:setup_domain_structure)
|
|
296
|
+
allow(instance).to receive(:setup_initializers)
|
|
297
|
+
allow(instance).to receive(:setup_dotenv)
|
|
298
|
+
allow(instance).to receive(:setup_gitignore)
|
|
299
|
+
allow(instance).to receive(:setup_rubocop)
|
|
300
|
+
allow(instance).to receive(:setup_active_storage)
|
|
301
|
+
allow(instance).to receive(:setup_rspec)
|
|
302
|
+
allow(instance).to receive(:setup_readme)
|
|
303
|
+
allow(instance).to receive(:create_gem_dependencies)
|
|
304
|
+
allow(instance).to receive(:setup_init_migration)
|
|
305
|
+
allow(instance).to receive(:setup_models)
|
|
306
|
+
allow(instance).to receive(:say)
|
|
307
|
+
|
|
308
|
+
# Test domain_class_name method for engine with domain
|
|
309
|
+
expect(instance.send(:domain_class_name)).to eq('MyEngine::Admin')
|
|
310
|
+
|
|
311
|
+
# Test configuration paths - should create structure in engine domains
|
|
312
|
+
expect(RiderKick.configuration.domains_path).to eq('engines/my_engine/app/domains/admin/')
|
|
313
|
+
expect(RiderKick.configuration.models_path).to eq('engines/my_engine/app/models/my_engine/models')
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
it 'generates ApplicationRecord class name for main app' do
|
|
319
|
+
Dir.mktmpdir do |dir|
|
|
320
|
+
Dir.chdir(dir) do
|
|
321
|
+
# Create minimal Rails app structure for testing
|
|
322
|
+
FileUtils.mkdir_p('app/domains')
|
|
323
|
+
|
|
324
|
+
# Reset configuration
|
|
325
|
+
RiderKick.configuration.engine_name = nil
|
|
326
|
+
RiderKick.configuration.domain_scope = ''
|
|
327
|
+
|
|
328
|
+
instance = klass.new([])
|
|
329
|
+
opts = double('options', setup: true)
|
|
330
|
+
allow(opts).to receive(:[]).and_return(nil)
|
|
331
|
+
allow(opts).to receive(:[]).with(:engine).and_return(nil)
|
|
332
|
+
allow(opts).to receive(:[]).with(:quiet).and_return(false)
|
|
333
|
+
allow(instance).to receive(:options).and_return(opts)
|
|
334
|
+
|
|
335
|
+
# Mock methods to avoid actual file generation
|
|
336
|
+
allow(instance).to receive(:setup_domain_structure)
|
|
337
|
+
allow(instance).to receive(:setup_initializers)
|
|
338
|
+
allow(instance).to receive(:setup_dotenv)
|
|
339
|
+
allow(instance).to receive(:setup_gitignore)
|
|
340
|
+
allow(instance).to receive(:setup_rubocop)
|
|
341
|
+
allow(instance).to receive(:setup_active_storage)
|
|
342
|
+
allow(instance).to receive(:setup_rspec)
|
|
343
|
+
allow(instance).to receive(:setup_readme)
|
|
344
|
+
allow(instance).to receive(:create_gem_dependencies)
|
|
345
|
+
allow(instance).to receive(:setup_init_migration)
|
|
346
|
+
allow(instance).to receive(:setup_models)
|
|
347
|
+
allow(instance).to receive(:say)
|
|
348
|
+
|
|
349
|
+
# Test domain_class_name_for_application_record method for main app
|
|
350
|
+
expect(instance.send(:domain_class_name_for_application_record)).to eq('')
|
|
351
|
+
|
|
352
|
+
# Test configuration paths
|
|
353
|
+
expect(RiderKick.configuration.domains_path).to eq('app/domains/')
|
|
354
|
+
expect(RiderKick.configuration.models_path).to eq('app/models/models')
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails/generators'
|
|
4
|
+
require 'tmpdir'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
require 'generators/rider_kick/clean_arch_generator'
|
|
7
|
+
|
|
8
|
+
RSpec.describe 'rider_kick:clean_arch generator (FactoryBot & Faker setup)' do
|
|
9
|
+
let(:klass) { RiderKick::CleanArchGenerator }
|
|
10
|
+
|
|
11
|
+
it 'sets up FactoryBot and Faker with proper directory structure and configuration' do
|
|
12
|
+
Dir.mktmpdir do |dir|
|
|
13
|
+
Dir.chdir(dir) do
|
|
14
|
+
# Setup minimal Rails structure
|
|
15
|
+
FileUtils.mkdir_p('config')
|
|
16
|
+
FileUtils.mkdir_p('spec')
|
|
17
|
+
File.write('Gemfile', "source 'https://rubygems.org'\n")
|
|
18
|
+
|
|
19
|
+
instance = klass.new([])
|
|
20
|
+
opts = double('options', setup: true)
|
|
21
|
+
allow(opts).to receive(:[]).and_return(nil)
|
|
22
|
+
allow(opts).to receive(:[]).with(:setup).and_return(true)
|
|
23
|
+
allow(opts).to receive(:[]).with(:engine).and_return(nil)
|
|
24
|
+
allow(opts).to receive(:[]).with(:quiet).and_return(false)
|
|
25
|
+
allow(instance).to receive(:options).and_return(opts)
|
|
26
|
+
|
|
27
|
+
# Skip other setup methods
|
|
28
|
+
allow(instance).to receive(:copy_domain_file)
|
|
29
|
+
allow(instance).to receive(:setup_initializers)
|
|
30
|
+
allow(instance).to receive(:setup_dotenv)
|
|
31
|
+
allow(instance).to receive(:setup_gitignore)
|
|
32
|
+
allow(instance).to receive(:setup_rubocop)
|
|
33
|
+
allow(instance).to receive(:setup_init_migration)
|
|
34
|
+
allow(instance).to receive(:setup_models)
|
|
35
|
+
allow(instance).to receive(:setup_active_storage)
|
|
36
|
+
allow(instance).to receive(:setup_readme)
|
|
37
|
+
allow(instance).to receive(:run)
|
|
38
|
+
|
|
39
|
+
# Call setup methods
|
|
40
|
+
instance.send(:setup_domain_structure)
|
|
41
|
+
instance.send(:setup_rspec)
|
|
42
|
+
|
|
43
|
+
# Verify FactoryBot directory structure
|
|
44
|
+
expect(Dir.exist?('spec/factories')).to be true
|
|
45
|
+
|
|
46
|
+
# Verify FactoryBot support file
|
|
47
|
+
factory_bot_support = 'spec/support/factory_bot.rb'
|
|
48
|
+
expect(File.exist?(factory_bot_support)).to be true
|
|
49
|
+
|
|
50
|
+
factory_bot_content = File.read(factory_bot_support)
|
|
51
|
+
expect(factory_bot_content).to include('FactoryBot::Syntax::Methods')
|
|
52
|
+
expect(factory_bot_content).to include('config.include FactoryBot::Syntax::Methods')
|
|
53
|
+
expect(factory_bot_content).to include('sequence :email')
|
|
54
|
+
expect(factory_bot_content).to include('sequence :uuid')
|
|
55
|
+
|
|
56
|
+
# Verify Faker support file
|
|
57
|
+
faker_support = 'spec/support/faker.rb'
|
|
58
|
+
expect(File.exist?(faker_support)).to be true
|
|
59
|
+
|
|
60
|
+
faker_content = File.read(faker_support)
|
|
61
|
+
expect(faker_content).to include('Faker::Config')
|
|
62
|
+
expect(faker_content).to include('module FakerHelpers')
|
|
63
|
+
expect(faker_content).to include('def self.random_phone')
|
|
64
|
+
expect(faker_content).to include('def self.random_address')
|
|
65
|
+
expect(faker_content).to include('def self.random_url')
|
|
66
|
+
expect(faker_content).to include('config.include FakerHelpers')
|
|
67
|
+
|
|
68
|
+
# Verify .gitkeep file
|
|
69
|
+
gitkeep = 'spec/factories/.gitkeep'
|
|
70
|
+
expect(File.exist?(gitkeep)).to be true
|
|
71
|
+
|
|
72
|
+
gitkeep_content = File.read(gitkeep)
|
|
73
|
+
expect(gitkeep_content).to include('FactoryBot.define')
|
|
74
|
+
expect(gitkeep_content).to include('Example:')
|
|
75
|
+
|
|
76
|
+
# Verify rails_helper includes
|
|
77
|
+
rails_helper = 'spec/rails_helper.rb'
|
|
78
|
+
expect(File.exist?(rails_helper)).to be true
|
|
79
|
+
|
|
80
|
+
rails_helper_content = File.read(rails_helper)
|
|
81
|
+
expect(rails_helper_content).to include("Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }")
|
|
82
|
+
expect(rails_helper_content).to include('config.include FactoryBot::Syntax::Methods')
|
|
83
|
+
expect(rails_helper_content).to include('config.include FakerHelpers')
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'generates Gemfile with correct dependencies' do
|
|
89
|
+
Dir.mktmpdir do |dir|
|
|
90
|
+
Dir.chdir(dir) do
|
|
91
|
+
FileUtils.mkdir_p('config')
|
|
92
|
+
File.write('Gemfile', <<~GEMFILE)
|
|
93
|
+
source 'https://rubygems.org'
|
|
94
|
+
|
|
95
|
+
group :development, :test do
|
|
96
|
+
end
|
|
97
|
+
GEMFILE
|
|
98
|
+
|
|
99
|
+
instance = klass.new([])
|
|
100
|
+
opts = double('options', setup: true)
|
|
101
|
+
allow(opts).to receive(:[]).and_return(nil)
|
|
102
|
+
allow(opts).to receive(:[]).with(:setup).and_return(true)
|
|
103
|
+
allow(opts).to receive(:[]).with(:engine).and_return(nil)
|
|
104
|
+
allow(opts).to receive(:[]).with(:quiet).and_return(false)
|
|
105
|
+
allow(instance).to receive(:options).and_return(opts)
|
|
106
|
+
|
|
107
|
+
# Skip validation and other setup methods
|
|
108
|
+
allow(instance).to receive(:validate_setup_option)
|
|
109
|
+
allow(instance).to receive(:setup_configuration)
|
|
110
|
+
allow(instance).to receive(:run)
|
|
111
|
+
|
|
112
|
+
# Only run create_gem_dependencies
|
|
113
|
+
instance.create_gem_dependencies
|
|
114
|
+
|
|
115
|
+
gemfile_content = File.read('Gemfile')
|
|
116
|
+
|
|
117
|
+
# Verify gems are added in correct group
|
|
118
|
+
expect(gemfile_content).to include('group :development, :test do')
|
|
119
|
+
expect(gemfile_content).to include('gem "rspec-rails"')
|
|
120
|
+
expect(gemfile_content).to include('gem "factory_bot_rails"')
|
|
121
|
+
expect(gemfile_content).to include('gem "faker"')
|
|
122
|
+
expect(gemfile_content).to include('gem "shoulda-matchers"')
|
|
123
|
+
|
|
124
|
+
# Verify other gems
|
|
125
|
+
expect(gemfile_content).to include("gem 'dotenv-rails'")
|
|
126
|
+
expect(gemfile_content).to include("gem 'hashie'")
|
|
127
|
+
expect(gemfile_content).to include("gem 'pagy'")
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -4,22 +4,26 @@
|
|
|
4
4
|
require 'rails/generators'
|
|
5
5
|
require 'tmpdir'
|
|
6
6
|
require 'fileutils'
|
|
7
|
-
require 'ostruct'
|
|
8
7
|
require 'generators/rider_kick/scaffold_generator'
|
|
9
8
|
|
|
10
9
|
RSpec.describe 'entity type mapping' do
|
|
11
10
|
let(:klass) { RiderKick::ScaffoldGenerator }
|
|
12
11
|
|
|
13
12
|
it 'memetakan kolom ke Types::Strict yang benar' do
|
|
13
|
+
# Store original configuration
|
|
14
|
+
original_engine = RiderKick.configuration.engine_name
|
|
15
|
+
original_domain = RiderKick.configuration.domain_scope
|
|
16
|
+
|
|
14
17
|
Dir.mktmpdir do |dir|
|
|
15
18
|
Dir.chdir(dir) do
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
# Reset configuration for this test
|
|
20
|
+
RiderKick.configuration.engine_name = nil
|
|
21
|
+
RiderKick.configuration.domain_scope = 'core/'
|
|
22
|
+
|
|
23
|
+
FileUtils.mkdir_p [
|
|
24
|
+
RiderKick.configuration.domains_path,
|
|
25
|
+
'app/models/models',
|
|
26
|
+
'db/structures'
|
|
23
27
|
]
|
|
24
28
|
|
|
25
29
|
# pakai stub shared Models::User dari spec/support (sudah auto-require)
|
|
@@ -28,7 +32,9 @@ RSpec.describe 'entity type mapping' do
|
|
|
28
32
|
model: Models::User
|
|
29
33
|
resource_name: users
|
|
30
34
|
actor: owner
|
|
31
|
-
|
|
35
|
+
resource_owner_id: account_id
|
|
36
|
+
resource_owner: account
|
|
37
|
+
uploaders: [{ name: 'avatar', type: 'single' }]
|
|
32
38
|
search_able: []
|
|
33
39
|
domains:
|
|
34
40
|
action_list: { use_case: { contract: [] } }
|
|
@@ -36,17 +42,20 @@ RSpec.describe 'entity type mapping' do
|
|
|
36
42
|
action_create: { use_case: { contract: [] } }
|
|
37
43
|
action_update: { use_case: { contract: [] } }
|
|
38
44
|
action_destroy: { use_case: { contract: [] } }
|
|
39
|
-
|
|
45
|
+
entity: { db_attributes: ['id', 'name', 'price', 'created_at', 'updated_at'] }
|
|
40
46
|
YAML
|
|
41
47
|
|
|
42
48
|
klass.new(['users']).generate_use_case
|
|
43
49
|
|
|
44
|
-
entity = File.read('
|
|
45
|
-
# harapannya: string,
|
|
50
|
+
entity = File.read(RiderKick.configuration.domains_path + '/entities/user.rb')
|
|
51
|
+
# harapannya: string, datetime dipetakan ke Strict
|
|
46
52
|
expect(entity).to match(/Types::Strict::String/)
|
|
47
|
-
expect(entity).to match(/Types::Strict::Decimal|Types::Coercible::Decimal/)
|
|
48
53
|
expect(entity).to match(/Types::Strict::Time|Types::Strict::Date|Types::Strict::DateTime/)
|
|
49
54
|
end
|
|
55
|
+
ensure
|
|
56
|
+
# Restore original configuration
|
|
57
|
+
RiderKick.configuration.engine_name = original_engine
|
|
58
|
+
RiderKick.configuration.domain_scope = original_domain
|
|
50
59
|
end
|
|
51
60
|
end
|
|
52
61
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RiderKick
|
|
4
|
+
# Base error class for all generator errors
|
|
5
|
+
class GeneratorError < StandardError
|
|
6
|
+
attr_reader :context
|
|
7
|
+
|
|
8
|
+
def initialize(message, context = {})
|
|
9
|
+
super(message)
|
|
10
|
+
@context = context
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_s
|
|
14
|
+
if @context.any?
|
|
15
|
+
context_str = @context.map { |k, v| "#{k}: #{v}" }.join(', ')
|
|
16
|
+
"#{super} (#{context_str})"
|
|
17
|
+
else
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Error raised when validation fails
|
|
24
|
+
class ValidationError < GeneratorError
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Error raised when configuration is invalid
|
|
28
|
+
class ConfigurationError < GeneratorError
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Error raised when a model is not found
|
|
32
|
+
class ModelNotFoundError < GeneratorError
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Error raised when a file is not found
|
|
36
|
+
class FileNotFoundError < GeneratorError
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Error raised when YAML format is invalid
|
|
40
|
+
class YamlFormatError < GeneratorError
|
|
41
|
+
end
|
|
42
|
+
end
|