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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +629 -25
  3. data/lib/generators/rider_kick/USAGE +2 -0
  4. data/lib/generators/rider_kick/base_generator.rb +190 -0
  5. data/lib/generators/rider_kick/clean_arch_generator.rb +235 -45
  6. data/lib/generators/rider_kick/clean_arch_generator_engine_spec.rb +359 -0
  7. data/lib/generators/rider_kick/clean_arch_generator_factory_bot_spec.rb +131 -0
  8. data/lib/generators/rider_kick/entity_type_mapping_spec.rb +22 -13
  9. data/lib/generators/rider_kick/errors.rb +42 -0
  10. data/lib/generators/rider_kick/factory_generator.rb +238 -0
  11. data/lib/generators/rider_kick/factory_generator_spec.rb +175 -0
  12. data/lib/generators/rider_kick/repositories_contract_spec.rb +95 -22
  13. data/lib/generators/rider_kick/scaffold_generator.rb +377 -62
  14. data/lib/generators/rider_kick/scaffold_generator_builder_uploaders_spec.rb +119 -14
  15. data/lib/generators/rider_kick/scaffold_generator_conditional_filtering_spec.rb +820 -0
  16. data/lib/generators/rider_kick/scaffold_generator_contracts_spec.rb +37 -10
  17. data/lib/generators/rider_kick/scaffold_generator_contracts_with_scope_spec.rb +40 -11
  18. data/lib/generators/rider_kick/scaffold_generator_engine_spec.rb +221 -0
  19. data/lib/generators/rider_kick/scaffold_generator_idempotent_spec.rb +38 -13
  20. data/lib/generators/rider_kick/scaffold_generator_list_spec_format_spec.rb +153 -0
  21. data/lib/generators/rider_kick/scaffold_generator_rspec_spec.rb +347 -0
  22. data/lib/generators/rider_kick/scaffold_generator_success_spec.rb +31 -12
  23. data/lib/generators/rider_kick/scaffold_generator_with_scope_spec.rb +32 -11
  24. data/lib/generators/rider_kick/structure_generator.rb +154 -43
  25. data/lib/generators/rider_kick/structure_generator_comprehensive_spec.rb +598 -0
  26. data/lib/generators/rider_kick/structure_generator_engine_spec.rb +279 -0
  27. data/lib/generators/rider_kick/structure_generator_spec.rb +3 -3
  28. data/lib/generators/rider_kick/structure_generator_success_spec.rb +33 -5
  29. data/lib/generators/rider_kick/structure_generator_unit_spec.rb +2202 -0
  30. data/lib/generators/rider_kick/templates/.rubocop.yml +5 -4
  31. data/lib/generators/rider_kick/templates/config/initializers/version.rb.tt +1 -1
  32. data/lib/generators/rider_kick/templates/db/migrate/20220613145533_init_database.rb +1 -1
  33. data/lib/generators/rider_kick/templates/db/structures/example.yaml.tt +140 -66
  34. data/lib/generators/rider_kick/templates/domains/core/builders/builder.rb.tt +36 -10
  35. data/lib/generators/rider_kick/templates/domains/core/builders/builder_spec.rb.tt +219 -0
  36. data/lib/generators/rider_kick/templates/domains/core/builders/error.rb.tt +2 -2
  37. data/lib/generators/rider_kick/templates/domains/core/builders/pagination.rb.tt +2 -2
  38. data/lib/generators/rider_kick/templates/domains/core/entities/entity.rb.tt +32 -14
  39. data/lib/generators/rider_kick/templates/domains/core/entities/error.rb.tt +1 -1
  40. data/lib/generators/rider_kick/templates/domains/core/entities/pagination.rb.tt +1 -1
  41. data/lib/generators/rider_kick/templates/domains/core/repositories/abstract_repository.rb.tt +4 -4
  42. data/lib/generators/rider_kick/templates/domains/core/repositories/create.rb.tt +2 -2
  43. data/lib/generators/rider_kick/templates/domains/core/repositories/create_spec.rb.tt +78 -0
  44. data/lib/generators/rider_kick/templates/domains/core/repositories/destroy.rb.tt +2 -2
  45. data/lib/generators/rider_kick/templates/domains/core/repositories/destroy_spec.rb.tt +88 -0
  46. data/lib/generators/rider_kick/templates/domains/core/repositories/fetch_by_id.rb.tt +3 -3
  47. data/lib/generators/rider_kick/templates/domains/core/repositories/fetch_by_id_spec.rb.tt +62 -0
  48. data/lib/generators/rider_kick/templates/domains/core/repositories/list.rb.tt +13 -8
  49. data/lib/generators/rider_kick/templates/domains/core/repositories/list_spec.rb.tt +190 -0
  50. data/lib/generators/rider_kick/templates/domains/core/repositories/update.rb.tt +4 -4
  51. data/lib/generators/rider_kick/templates/domains/core/repositories/update_spec.rb.tt +119 -0
  52. data/lib/generators/rider_kick/templates/domains/core/use_cases/contract/default.rb.tt +1 -1
  53. data/lib/generators/rider_kick/templates/domains/core/use_cases/contract/pagination.rb.tt +1 -1
  54. data/lib/generators/rider_kick/templates/domains/core/use_cases/create.rb.tt +3 -7
  55. data/lib/generators/rider_kick/templates/domains/core/use_cases/create_spec.rb.tt +71 -0
  56. data/lib/generators/rider_kick/templates/domains/core/use_cases/destroy.rb.tt +3 -7
  57. data/lib/generators/rider_kick/templates/domains/core/use_cases/destroy_spec.rb.tt +62 -0
  58. data/lib/generators/rider_kick/templates/domains/core/use_cases/fetch_by_id.rb.tt +3 -7
  59. data/lib/generators/rider_kick/templates/domains/core/use_cases/fetch_by_id_spec.rb.tt +62 -0
  60. data/lib/generators/rider_kick/templates/domains/core/use_cases/get_version.rb.tt +2 -2
  61. data/lib/generators/rider_kick/templates/domains/core/use_cases/list.rb.tt +3 -7
  62. data/lib/generators/rider_kick/templates/domains/core/use_cases/list_spec.rb.tt +64 -0
  63. data/lib/generators/rider_kick/templates/domains/core/use_cases/update.rb.tt +3 -7
  64. data/lib/generators/rider_kick/templates/domains/core/use_cases/update_spec.rb.tt +73 -0
  65. data/lib/generators/rider_kick/templates/domains/core/utils/abstract_utils.rb.tt +3 -3
  66. data/lib/generators/rider_kick/templates/domains/core/utils/request_methods.rb.tt +1 -1
  67. data/lib/generators/rider_kick/templates/env.development +1 -1
  68. data/lib/generators/rider_kick/templates/env.production +1 -1
  69. data/lib/generators/rider_kick/templates/env.test +1 -1
  70. data/lib/generators/rider_kick/templates/models/{application_record.rb → application_record.rb.tt} +3 -1
  71. data/lib/generators/rider_kick/templates/models/model_spec.rb.tt +68 -0
  72. data/lib/generators/rider_kick/templates/spec/factories/.gitkeep +19 -0
  73. data/lib/generators/rider_kick/templates/spec/factories/factory.rb.tt +8 -0
  74. data/lib/generators/rider_kick/templates/spec/rails_helper.rb +2 -0
  75. data/lib/generators/rider_kick/templates/spec/support/class_stubber.rb +148 -0
  76. data/lib/generators/rider_kick/templates/spec/support/factory_bot.rb +34 -0
  77. data/lib/generators/rider_kick/templates/spec/support/faker.rb +61 -0
  78. data/lib/rider-kick.rb +8 -6
  79. data/lib/rider_kick/builders/abstract_active_record_entity_builder_spec.rb +644 -0
  80. data/lib/rider_kick/configuration.rb +238 -0
  81. data/lib/rider_kick/configuration_engine_spec.rb +377 -0
  82. data/lib/rider_kick/entities/failure_details.rb +1 -1
  83. data/lib/rider_kick/entities/failure_details_spec.rb +1 -1
  84. data/lib/rider_kick/matchers/use_case_result.rb +1 -1
  85. data/lib/rider_kick/use_cases/abstract_use_case.rb +1 -1
  86. data/lib/rider_kick/version.rb +1 -1
  87. metadata +129 -8
  88. data/CHANGELOG.md +0 -5
@@ -0,0 +1,347 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+ require 'tmpdir'
5
+ require 'active_support/inflector'
6
+
7
+ require 'fileutils'
8
+ require 'generators/rider_kick/scaffold_generator'
9
+
10
+ RSpec.describe 'rider_kick:scaffold generator (RSpec generation)' do
11
+ let(:klass) { RiderKick::ScaffoldGenerator }
12
+
13
+ it 'menghasilkan spec files untuk use_cases, repositories, builder, dan entity' do
14
+ Dir.mktmpdir do |dir|
15
+ Dir.chdir(dir) do
16
+ # 1) siapkan kerangka clean-arch minimal
17
+ FileUtils.mkdir_p(RiderKick.configuration.domains_path)
18
+ FileUtils.mkdir_p('app/models/models')
19
+ FileUtils.mkdir_p('spec/models/models')
20
+ FileUtils.mkdir_p('db/structures')
21
+
22
+ # 2) stub namespace & model + metadata kolom
23
+ Object.send(:remove_const, :Models) if Object.const_defined?(:Models)
24
+ Object.send(:remove_const, :Column) if Object.const_defined?(:Column)
25
+ module Models; end
26
+
27
+ Column = Struct.new(:name, :type, :sql_type, :null, :default, :precision, :scale, :limit)
28
+ class Models::Product
29
+ def self.columns
30
+ [
31
+ Column.new('id', :uuid, nil, false, nil, nil, nil, nil),
32
+ Column.new('name', :string, nil, false, nil, nil, nil, 255),
33
+ Column.new('price', :decimal, nil, false, nil, 10, 2, nil),
34
+ Column.new('description', :text, nil, true, nil, nil, nil, nil),
35
+ Column.new('created_at', :datetime, nil, false, nil, nil, nil, nil),
36
+ Column.new('updated_at', :datetime, nil, false, nil, nil, nil, nil)
37
+ ]
38
+ end
39
+
40
+ def self.columns_hash
41
+ columns.to_h { |c| [c.name.to_s, Struct.new(:type).new(c.type)] }
42
+ end
43
+
44
+ def self.column_names
45
+ columns.map { |c| c.name.to_s }
46
+ end
47
+ end
48
+
49
+ # 3) file model untuk inject
50
+ File.write('app/models/models/product.rb', <<~RUBY)
51
+ class Models::Product < ApplicationRecord
52
+ end
53
+ RUBY
54
+
55
+ # 4) YAML struktur dengan uploaders
56
+ File.write('db/structures/products_structure.yaml', <<~YAML)
57
+ model: Models::Product
58
+ resource_name: products
59
+ actor: user
60
+ resource_owner_id: account_id
61
+ resource_owner: account
62
+ uploaders:
63
+ - { name: 'image', type: 'single' }
64
+ - { name: 'documents', type: 'multiple' }
65
+ search_able: []
66
+ domains:
67
+ action_list:
68
+ use_case:
69
+ contract: []
70
+ repository:
71
+ filters: []
72
+ action_fetch_by_id:
73
+ use_case:
74
+ contract:
75
+ - "required(:id).filled(:string)"
76
+ action_create:
77
+ use_case:
78
+ contract:
79
+ - "required(:name).filled(:string)"
80
+ - "required(:price).filled(:decimal)"
81
+ action_update:
82
+ use_case:
83
+ contract:
84
+ - "optional(:name).maybe(:string)"
85
+ - "optional(:price).maybe(:decimal)"
86
+ action_destroy:
87
+ use_case:
88
+ contract: []
89
+ entity:
90
+ db_attributes:
91
+ - name
92
+ - price
93
+ - description
94
+ YAML
95
+
96
+ # 5) jalankan generator
97
+ instance = klass.new(['products'])
98
+ instance.generate_use_case
99
+
100
+ # 6) verifikasi artefak code files
101
+ ['user_create_product', 'user_update_product', 'user_list_product', 'user_destroy_product', 'user_fetch_product_by_id'].each do |uc|
102
+ expect(File).to exist(File.join(RiderKick.configuration.domains_path + '/use_cases/products', "#{uc}.rb")), "Expected use case file #{uc}.rb to exist"
103
+ end
104
+
105
+ ['create_product', 'update_product', 'list_product', 'destroy_product', 'fetch_product_by_id'].each do |repo|
106
+ expect(File).to exist(File.join(RiderKick.configuration.domains_path + '/repositories/products', "#{repo}.rb")), "Expected repository file #{repo}.rb to exist"
107
+ end
108
+
109
+ expect(File).to exist(RiderKick.configuration.domains_path + '/builders/product.rb'), 'Expected builder file to exist'
110
+ expect(File).to exist(RiderKick.configuration.domains_path + '/entities/product.rb'), 'Expected entity file to exist'
111
+
112
+ # 7) VERIFIKASI SPEC FILES - INI YANG BARU!
113
+
114
+ # Use case specs
115
+ ['user_create_product', 'user_update_product', 'user_list_product', 'user_destroy_product', 'user_fetch_product_by_id'].each do |uc|
116
+ spec_file = File.join(RiderKick.configuration.domains_path + '/use_cases/products', "#{uc}_spec.rb")
117
+ expect(File).to exist(spec_file), "Expected use case spec file #{uc}_spec.rb to exist"
118
+
119
+ # Verifikasi konten spec file
120
+ spec_content = File.read(spec_file)
121
+ expect(spec_content).to include('require \'rails_helper\'')
122
+ expect(spec_content).to include('RSpec.describe')
123
+ expect(spec_content).to include('describe \'#call\'')
124
+ expect(spec_content).to include('context \'when parameters are valid\'')
125
+ end
126
+
127
+ # Repository specs
128
+ ['create_product', 'update_product', 'list_product', 'destroy_product', 'fetch_product_by_id'].each do |repo|
129
+ spec_file = File.join(RiderKick.configuration.domains_path + '/repositories/products', "#{repo}_spec.rb")
130
+ expect(File).to exist(spec_file), "Expected repository spec file #{repo}_spec.rb to exist"
131
+
132
+ # Verifikasi konten spec file
133
+ spec_content = File.read(spec_file)
134
+ expect(spec_content).to include('require \'rails_helper\'')
135
+ expect(spec_content).to include('RSpec.describe')
136
+ expect(spec_content).to include('describe \'#call\'')
137
+
138
+ # Only check Hashie::Mash for create, update, destroy, fetch_by_id (list uses simple hash)
139
+ if ['create_product', 'update_product', 'destroy_product', 'fetch_product_by_id'].include?(repo)
140
+ expect(spec_content).to include('Hashie::Mash.new')
141
+ end
142
+
143
+ # Verify error mocking for create, update, destroy (but not list or fetch_by_id)
144
+ if ['create_product', 'update_product', 'destroy_product'].include?(repo)
145
+ expect(spec_content).to include('let(:error_messages)')
146
+ expect(spec_content).to include('let(:active_model_errors)')
147
+ expect(spec_content).to include('allow(errors).to receive(:each)')
148
+ expect(spec_content).to include('double(as_json:')
149
+ expect(spec_content).to include("'options' => { 'message' => 'must be valid format' }")
150
+ end
151
+ end
152
+
153
+ # Builder spec (covers entity validation too)
154
+ builder_spec = RiderKick.configuration.domains_path + '/builders/product_spec.rb'
155
+ expect(File).to exist(builder_spec), 'Expected builder spec file to exist'
156
+
157
+ # Model spec (sekarang sejajar dengan model di app/models/models/)
158
+ model_spec = 'app/models/models/product_spec.rb'
159
+ expect(File).to exist(model_spec), 'Expected model spec file to exist'
160
+
161
+ model_spec_content = File.read(model_spec)
162
+ expect(model_spec_content).to include('require \'rails_helper\'')
163
+ expect(model_spec_content).to include('RSpec.describe Models::Product')
164
+ expect(model_spec_content).to include('describe \'Active Storage attachments\'')
165
+ expect(model_spec_content).to include('image') # single uploader
166
+ expect(model_spec_content).to include('documents') # multiple uploader
167
+ expect(model_spec_content).to include('has one image attached')
168
+ expect(model_spec_content).to include('has many documents attached')
169
+ expect(model_spec_content).to include('describe \'database columns\'')
170
+
171
+ builder_spec_content = File.read(builder_spec)
172
+ expect(builder_spec_content).to include('require \'rails_helper\'')
173
+ expect(builder_spec_content).to include('RSpec.describe Core::Builders::Product')
174
+ expect(builder_spec_content).to include('describe \'#build\'')
175
+ expect(builder_spec_content).to include('image') # uploader single
176
+ expect(builder_spec_content).to include('documents') # uploader multiple
177
+
178
+ # Verify builder spec includes comprehensive entity validation tests
179
+ expect(builder_spec_content).to include('includes all required entity attributes')
180
+ expect(builder_spec_content).to include('describe \'#attributes_for_entity\'') # uploader method test
181
+ expect(builder_spec_content).to include('ensures all entity attributes have correct keys and types')
182
+ expect(builder_spec_content).to include('validates entity type schema definitions') # Dry::Types schema validation
183
+ end
184
+ end
185
+ end
186
+
187
+ it 'menghasilkan spec files dengan resource_owner_id' do
188
+ Dir.mktmpdir do |dir|
189
+ Dir.chdir(dir) do
190
+ # Setup
191
+ FileUtils.mkdir_p(RiderKick.configuration.domains_path)
192
+ FileUtils.mkdir_p('app/models/models')
193
+ FileUtils.mkdir_p('db/structures')
194
+
195
+ # Stub model
196
+ Object.send(:remove_const, :Models) if Object.const_defined?(:Models)
197
+ Object.send(:remove_const, :Column) if Object.const_defined?(:Column)
198
+ module Models; end
199
+
200
+ Column = Struct.new(:name, :type, :sql_type, :null, :default, :precision, :scale, :limit)
201
+ class Models::Task
202
+ def self.columns
203
+ [
204
+ Column.new('id', :uuid),
205
+ Column.new('account_id', :string),
206
+ Column.new('title', :string),
207
+ Column.new('created_at', :datetime),
208
+ Column.new('updated_at', :datetime)
209
+ ]
210
+ end
211
+
212
+ def self.columns_hash
213
+ columns.to_h { |c| [c.name.to_s, Struct.new(:type).new(c.type)] }
214
+ end
215
+
216
+ def self.column_names
217
+ columns.map { |c| c.name.to_s }
218
+ end
219
+ end
220
+
221
+ File.write('app/models/models/task.rb', <<~RUBY)
222
+ class Models::Task < ApplicationRecord
223
+ end
224
+ RUBY
225
+
226
+ File.write('db/structures/tasks_structure.yaml', <<~YAML)
227
+ model: Models::Task
228
+ resource_name: tasks
229
+ actor: user
230
+ resource_owner_id: account_id
231
+ resource_owner: account
232
+ uploaders: []
233
+ search_able: []
234
+ domains:
235
+ action_list:
236
+ use_case:
237
+ contract: []
238
+ repository:
239
+ filters: []
240
+ action_fetch_by_id:
241
+ use_case:
242
+ contract:
243
+ - "required(:id).filled(:string)"
244
+ - "required(:account_id).filled(:string)"
245
+ action_create:
246
+ use_case:
247
+ contract:
248
+ - "required(:account_id).filled(:string)"
249
+ - "required(:title).filled(:string)"
250
+ action_update:
251
+ use_case:
252
+ contract:
253
+ - "required(:account_id).filled(:string)"
254
+ - "optional(:title).maybe(:string)"
255
+ action_destroy:
256
+ use_case:
257
+ contract:
258
+ - "required(:account_id).filled(:string)"
259
+ entity:
260
+ db_attributes:
261
+ - account_id
262
+ - title
263
+ YAML
264
+
265
+ # Run generator
266
+ instance = klass.new(['tasks'])
267
+ instance.generate_use_case
268
+
269
+ # Verifikasi spec files include resource_owner_id
270
+ spec_file = File.join(RiderKick.configuration.domains_path + '/use_cases/tasks', 'user_create_task_spec.rb')
271
+ expect(File).to exist(spec_file)
272
+
273
+ spec_content = File.read(spec_file)
274
+ expect(spec_content).to include('account_id')
275
+ end
276
+ end
277
+ end
278
+
279
+ it 'spec files berada sejajar dengan code files' do
280
+ Dir.mktmpdir do |dir|
281
+ Dir.chdir(dir) do
282
+ # Setup minimal
283
+ FileUtils.mkdir_p(RiderKick.configuration.domains_path)
284
+ FileUtils.mkdir_p('app/models/models')
285
+ FileUtils.mkdir_p('db/structures')
286
+
287
+ Object.send(:remove_const, :Models) if Object.const_defined?(:Models)
288
+ Object.send(:remove_const, :Column) if Object.const_defined?(:Column)
289
+ module Models; end
290
+
291
+ Column = Struct.new(:name, :type, :sql_type, :null, :default, :precision, :scale, :limit)
292
+ class Models::Item
293
+ def self.columns
294
+ [Column.new('id', :uuid), Column.new('name', :string)]
295
+ end
296
+
297
+ def self.columns_hash
298
+ columns.to_h { |c| [c.name.to_s, Struct.new(:type).new(c.type)] }
299
+ end
300
+
301
+ def self.column_names
302
+ columns.map { |c| c.name.to_s }
303
+ end
304
+ end
305
+
306
+ File.write('app/models/models/item.rb', "class Models::Item < ApplicationRecord; end\n")
307
+ File.write('db/structures/items_structure.yaml', <<~YAML)
308
+ model: Models::Item
309
+ resource_name: items
310
+ actor: user
311
+ resource_owner_id: account_id
312
+ resource_owner: account
313
+ uploaders: []
314
+ search_able: []
315
+ domains:
316
+ action_list: { use_case: { contract: [] }, repository: { filters: [] } }
317
+ action_fetch_by_id: { use_case: { contract: [] } }
318
+ action_create: { use_case: { contract: [] } }
319
+ action_update: { use_case: { contract: [] } }
320
+ action_destroy: { use_case: { contract: [] } }
321
+ entity: { db_attributes: [name] }
322
+ YAML
323
+
324
+ instance = klass.new(['items'])
325
+ instance.generate_use_case
326
+
327
+ # Verifikasi lokasi file spec sejajar dengan code files
328
+ use_case_dir = File.join(RiderKick.configuration.domains_path + '/use_cases/items')
329
+ expect(File).to exist(File.join(use_case_dir, 'user_create_item.rb'))
330
+ expect(File).to exist(File.join(use_case_dir, 'user_create_item_spec.rb'))
331
+
332
+ repository_dir = File.join(RiderKick.configuration.domains_path + '/repositories/items')
333
+ expect(File).to exist(File.join(repository_dir, 'create_item.rb'))
334
+ expect(File).to exist(File.join(repository_dir, 'create_item_spec.rb'))
335
+
336
+ builders_dir = RiderKick.configuration.domains_path + '/builders'
337
+ expect(File).to exist(File.join(builders_dir, 'item.rb'))
338
+ expect(File).to exist(File.join(builders_dir, 'item_spec.rb'))
339
+
340
+ # Entity spec is NOT generated - builder spec covers entity validation
341
+ entities_dir = RiderKick.configuration.domains_path + '/entities'
342
+ expect(File).to exist(File.join(entities_dir, 'item.rb'))
343
+ expect(File).not_to exist(File.join(entities_dir, 'item_spec.rb'))
344
+ end
345
+ end
346
+ end
347
+ end
@@ -3,7 +3,7 @@
3
3
  require 'rails/generators'
4
4
  require 'tmpdir'
5
5
  require 'active_support/inflector'
6
- require 'ostruct'
6
+
7
7
  require 'fileutils'
8
8
  require 'generators/rider_kick/scaffold_generator'
9
9
 
@@ -14,14 +14,33 @@ RSpec.describe 'rider_kick:scaffold generator (success)' do
14
14
  Dir.mktmpdir do |dir|
15
15
  Dir.chdir(dir) do
16
16
  # 1) siapkan kerangka clean-arch minimal
17
- FileUtils.mkdir_p('app/domains/core/use_cases')
18
- FileUtils.mkdir_p('app/domains/core/repositories')
19
- FileUtils.mkdir_p('app/domains/core/builders')
20
- FileUtils.mkdir_p('app/domains/core/entities')
17
+ FileUtils.mkdir_p(RiderKick.configuration.domains_path)
21
18
  FileUtils.mkdir_p('app/models/models')
22
19
  FileUtils.mkdir_p('db/structures')
23
20
 
24
21
  # 2) stub namespace & model + metadata kolom
22
+ Object.send(:remove_const, :Models) if Object.const_defined?(:Models)
23
+ Object.send(:remove_const, :Column) if Object.const_defined?(:Column)
24
+ module Models; end
25
+
26
+ Column = Struct.new(:name, :type, :sql_type, :null, :default, :precision, :scale, :limit)
27
+ class Models::User
28
+ def self.columns
29
+ [
30
+ Column.new('id', :uuid),
31
+ Column.new('created_at', :datetime),
32
+ Column.new('updated_at', :datetime)
33
+ ]
34
+ end
35
+
36
+ def self.columns_hash
37
+ columns.to_h { |c| [c.name.to_s, Struct.new(:type).new(c.type)] }
38
+ end
39
+
40
+ def self.column_names
41
+ columns.map { |c| c.name.to_s }
42
+ end
43
+ end
25
44
 
26
45
  # 3) file model untuk inject (hanya dipakai jika uploaders ada)
27
46
  File.write('app/models/models/user.rb', <<~RUBY)
@@ -54,7 +73,7 @@ RSpec.describe 'rider_kick:scaffold generator (success)' do
54
73
  use_case:
55
74
  contract: []
56
75
  entity:
57
- skipped_fields:
76
+ db_attributes:
58
77
  - id
59
78
  - created_at
60
79
  - updated_at
@@ -66,16 +85,16 @@ RSpec.describe 'rider_kick:scaffold generator (success)' do
66
85
 
67
86
  # 6) verifikasi artefak
68
87
  # use_cases (tanpa route scope): app/domains/core/use_cases/users/<use_case>.rb
69
- %w[owner_create_user owner_update_user owner_list_user owner_destroy_user owner_fetch_user_by_id].each do |uc|
70
- expect(File).to exist(File.join('app/domains/core/use_cases/users', "#{uc}.rb"))
88
+ ['owner_create_user', 'owner_update_user', 'owner_list_user', 'owner_destroy_user', 'owner_fetch_user_by_id'].each do |uc|
89
+ expect(File).to exist(File.join(RiderKick.configuration.domains_path + '/use_cases/users', "#{uc}.rb"))
71
90
  end
72
91
  # repositories: app/domains/core/repositories/users/<repo>.rb
73
- %w[create_user update_user list_user destroy_user fetch_user_by_id].each do |repo|
74
- expect(File).to exist(File.join('app/domains/core/repositories/users', "#{repo}.rb"))
92
+ ['create_user', 'update_user', 'list_user', 'destroy_user', 'fetch_user_by_id'].each do |repo|
93
+ expect(File).to exist(File.join(RiderKick.configuration.domains_path + '/repositories/users', "#{repo}.rb"))
75
94
  end
76
95
  # builder & entity
77
- expect(File).to exist('app/domains/core/builders/user.rb')
78
- expect(File).to exist('app/domains/core/entities/user.rb')
96
+ expect(File).to exist(RiderKick.configuration.domains_path + '/builders/user.rb')
97
+ expect(File).to exist(RiderKick.configuration.domains_path + '/entities/user.rb')
79
98
  end
80
99
  end
81
100
  end
@@ -3,7 +3,7 @@
3
3
  require 'rails/generators'
4
4
  require 'tmpdir'
5
5
  require 'active_support/inflector'
6
- require 'ostruct'
6
+
7
7
  require 'fileutils'
8
8
  require 'generators/rider_kick/scaffold_generator'
9
9
 
@@ -13,13 +13,34 @@ RSpec.describe 'rider_kick:scaffold generator (with scope)' do
13
13
  it 'meletakkan use_cases di folder route scope yang benar' do
14
14
  Dir.mktmpdir do |dir|
15
15
  Dir.chdir(dir) do
16
- FileUtils.mkdir_p('app/domains/core/use_cases')
17
- FileUtils.mkdir_p('app/domains/core/repositories')
18
- FileUtils.mkdir_p('app/domains/core/builders')
19
- FileUtils.mkdir_p('app/domains/core/entities')
16
+ FileUtils.mkdir_p(RiderKick.configuration.domains_path)
20
17
  FileUtils.mkdir_p('app/models/models')
21
18
  FileUtils.mkdir_p('db/structures')
22
19
 
20
+ # Stub model classes
21
+ Object.send(:remove_const, :Models) if Object.const_defined?(:Models)
22
+ Object.send(:remove_const, :Column) if Object.const_defined?(:Column)
23
+ module Models; end
24
+
25
+ Column = Struct.new(:name, :type, :sql_type, :null, :default, :precision, :scale, :limit)
26
+ class Models::User
27
+ def self.columns
28
+ [
29
+ Column.new('id', :uuid),
30
+ Column.new('created_at', :datetime),
31
+ Column.new('updated_at', :datetime)
32
+ ]
33
+ end
34
+
35
+ def self.columns_hash
36
+ columns.to_h { |c| [c.name.to_s, Struct.new(:type).new(c.type)] }
37
+ end
38
+
39
+ def self.column_names
40
+ columns.map { |c| c.name.to_s }
41
+ end
42
+ end
43
+
23
44
  File.write('app/models/models/user.rb', "class Models::User < ApplicationRecord; end\n")
24
45
 
25
46
  File.write('db/structures/users_structure.yaml', <<~YAML)
@@ -33,21 +54,21 @@ RSpec.describe 'rider_kick:scaffold generator (with scope)' do
33
54
  action_create: { use_case: { contract: [] } },
34
55
  action_update: { use_case: { contract: [] } },
35
56
  action_destroy: { use_case: { contract: [] } } }
36
- entity: { skipped_fields: [id, created_at, updated_at] }
57
+ entity: { db_attributes: [id, created_at, updated_at] }
37
58
  YAML
38
59
 
39
60
  # jalankan dengan token scope:dashboard (Thor hash-arg)
40
61
  instance = klass.new(['users', 'scope:dashboard'])
41
62
  instance.generate_use_case
42
63
 
43
- # use_cases berada di app/domains/core/use_cases/dashboard/users/...
44
- path = 'app/domains/core/use_cases/dashboard/users'
45
- %w[owner_create_user owner_update_user owner_list_user owner_destroy_user owner_fetch_user_by_id].each do |uc|
64
+ # use_cases berada di app/domains/use_cases/dashboard/users/...
65
+ path = RiderKick.configuration.domains_path + '/use_cases/dashboard/users'
66
+ ['owner_create_user', 'owner_update_user', 'owner_list_user', 'owner_destroy_user', 'owner_fetch_user_by_id'].each do |uc|
46
67
  expect(File).to exist(File.join(path, "#{uc}.rb"))
47
68
  end
48
69
  # repositories tetap di .../repositories/users
49
- %w[create_user update_user list_user destroy_user fetch_user_by_id].each do |repo|
50
- expect(File).to exist(File.join('app/domains/core/repositories/users', "#{repo}.rb"))
70
+ ['create_user', 'update_user', 'list_user', 'destroy_user', 'fetch_user_by_id'].each do |repo|
71
+ expect(File).to exist(File.join(RiderKick.configuration.domains_path + '/repositories/users', "#{repo}.rb"))
51
72
  end
52
73
  end
53
74
  end