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
|
@@ -9,7 +9,6 @@ inherit_gem: { rubocop-rails-omakase: rubocop.yml }
|
|
|
9
9
|
|
|
10
10
|
AllCops:
|
|
11
11
|
SuggestExtensions: false
|
|
12
|
-
TargetRubyVersion: 3.3.4
|
|
13
12
|
DisabledByDefault: true
|
|
14
13
|
Exclude:
|
|
15
14
|
- '**/templates/**/*'
|
|
@@ -20,8 +19,11 @@ AllCops:
|
|
|
20
19
|
- 'db/**/*'
|
|
21
20
|
- 'config/**/*'
|
|
22
21
|
- 'script/**/*'
|
|
22
|
+
- 'bin/*'
|
|
23
23
|
- 'public/views/*'
|
|
24
24
|
- 'bin/**/*'
|
|
25
|
+
- 'config/**/*'
|
|
26
|
+
- 'db/**/*'
|
|
25
27
|
- 'tmp/**/*'
|
|
26
28
|
- 'spec/spec_helper.rb'
|
|
27
29
|
- 'spec/rails_helper.rb'
|
|
@@ -1092,9 +1094,6 @@ Style/CommandLiteral:
|
|
|
1092
1094
|
Style/ConstantVisibility:
|
|
1093
1095
|
Enabled: true
|
|
1094
1096
|
|
|
1095
|
-
Style/ClassAndModuleChildren:
|
|
1096
|
-
Enabled: false
|
|
1097
|
-
|
|
1098
1097
|
Style/Documentation:
|
|
1099
1098
|
Enabled: false
|
|
1100
1099
|
|
|
@@ -1134,3 +1133,5 @@ Naming/MethodParameterName:
|
|
|
1134
1133
|
Layout/ClassStructure:
|
|
1135
1134
|
Enabled: true
|
|
1136
1135
|
|
|
1136
|
+
Style/WordArray:
|
|
1137
|
+
EnforcedStyle: brackets
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
# RiderKick Structure Definition for <%= @scope_class %>
|
|
2
|
+
# This file acts as a centralized contract for code generation.
|
|
3
|
+
# Modifying this file and re-running 'rider_kick:scaffold' will update the domain logic.
|
|
4
|
+
|
|
1
5
|
model: <%= @model_class %>
|
|
2
6
|
resource_name: <%= @scope_path %>
|
|
3
|
-
resource_owner_id: <%= @resource_owner_id %>
|
|
4
|
-
|
|
7
|
+
resource_owner_id: <%= @resource_owner_id %> # account_id
|
|
8
|
+
resource_owner: <%= @resource_owner %> # account
|
|
9
|
+
actor: <%= @actor %> # user
|
|
10
|
+
actor_id: <%= @actor_id %> # user_id
|
|
5
11
|
|
|
6
12
|
fields:
|
|
7
13
|
<% @fields.each do |f| -%>
|
|
@@ -11,122 +17,190 @@ fields:
|
|
|
11
17
|
- <%= f %>
|
|
12
18
|
<% end -%>
|
|
13
19
|
|
|
20
|
+
<% if entity_uploader_definitions.empty? -%>
|
|
21
|
+
uploaders: []
|
|
22
|
+
<% else -%>
|
|
14
23
|
uploaders:
|
|
15
|
-
<%
|
|
16
|
-
- <%=
|
|
24
|
+
<% entity_uploader_definitions.each do |uploader_hash| -%>
|
|
25
|
+
- { name: '<%= uploader_hash[:name] %>', type: '<%= uploader_hash[:type] %>' }
|
|
26
|
+
<% end -%>
|
|
17
27
|
<% end -%>
|
|
18
28
|
|
|
29
|
+
<% search_able_fields = arg_settings['search_able'].to_s.split(',').map(&:strip).reject(&:blank?) -%>
|
|
30
|
+
<% if search_able_fields.empty? -%>
|
|
31
|
+
search_able: []
|
|
32
|
+
<% else -%>
|
|
19
33
|
search_able:
|
|
20
|
-
<%
|
|
34
|
+
<% search_able_fields.each do |f| -%>
|
|
21
35
|
- <%= f %>
|
|
22
36
|
<% end -%>
|
|
37
|
+
<% end -%>
|
|
23
38
|
|
|
24
39
|
# ---- Enriched metadata (opsional, untuk tooling/insight) ----
|
|
25
40
|
schema:
|
|
26
|
-
columns:
|
|
41
|
+
columns:
|
|
42
|
+
<% if columns_meta.empty? -%>
|
|
43
|
+
[]
|
|
44
|
+
<% else -%>
|
|
27
45
|
<% columns_meta.each do |c| -%>
|
|
28
|
-
- name: <%= c[:name] %>
|
|
29
|
-
type: <%= c[:type] %>
|
|
30
|
-
sql_type: <%= c[:sql_type] %>
|
|
31
|
-
null: <%= c[:null] %>
|
|
46
|
+
- name: <%= c[:name] %>
|
|
47
|
+
type: <%= c[:type] %>
|
|
48
|
+
sql_type: <%= c[:sql_type] || 'null' %>
|
|
49
|
+
null: <%= c[:null] || 'false' %>
|
|
32
50
|
<% if c[:default].present? -%>
|
|
33
|
-
default: <%= c[:default].inspect %>
|
|
51
|
+
default: <%= c[:default].inspect %>
|
|
34
52
|
<% end -%>
|
|
35
53
|
<% if c[:precision] || c[:scale] -%>
|
|
36
|
-
precision: <%= c[:precision] || 'null' %>
|
|
37
|
-
scale: <%= c[:scale] || 'null' %>
|
|
54
|
+
precision: <%= c[:precision] || 'null' %>
|
|
55
|
+
scale: <%= c[:scale] || 'null' %>
|
|
38
56
|
<% end -%>
|
|
39
57
|
<% if c[:limit] -%>
|
|
40
|
-
limit: <%= c[:limit] %>
|
|
58
|
+
limit: <%= c[:limit] %>
|
|
41
59
|
<% end -%>
|
|
42
60
|
<% end -%>
|
|
43
|
-
|
|
61
|
+
<% end -%>
|
|
62
|
+
foreign_keys:
|
|
44
63
|
<% (fkeys_meta.presence || []).each do |fk| -%>
|
|
45
|
-
- column: <%= fk[:column] %>
|
|
46
|
-
to_table: <%= fk[:to_table] %>
|
|
64
|
+
- column: <%= fk[:column] %>
|
|
65
|
+
to_table: <%= fk[:to_table] %>
|
|
66
|
+
<% end -%>
|
|
67
|
+
<% if fkeys_meta.empty? -%>
|
|
68
|
+
[]
|
|
47
69
|
<% end -%>
|
|
48
|
-
indexes:
|
|
70
|
+
indexes:
|
|
49
71
|
<% (indexes_meta.presence || []).each do |ix| -%>
|
|
50
|
-
- columns: [<%= ix[:columns].join(', ') %>]
|
|
51
|
-
unique: <%= ix[:unique] %>
|
|
72
|
+
- columns: [<%= ix[:columns].join(', ') %>]
|
|
73
|
+
unique: <%= ix[:unique] %>
|
|
52
74
|
<% end -%>
|
|
53
|
-
|
|
75
|
+
<% if indexes_meta.empty? -%>
|
|
76
|
+
[]
|
|
77
|
+
<% end -%>
|
|
78
|
+
enums:
|
|
54
79
|
<% if enums_meta.present? -%>
|
|
55
80
|
<% enums_meta.each do |name, map| -%>
|
|
56
|
-
<%= name %>: <%= map.keys %>
|
|
81
|
+
<%= name %>: <%= map.keys %>
|
|
57
82
|
<% end -%>
|
|
58
83
|
<% else -%>
|
|
59
|
-
{}
|
|
84
|
+
{}
|
|
60
85
|
<% end -%>
|
|
61
86
|
|
|
62
87
|
controllers:
|
|
63
|
-
list_fields:
|
|
88
|
+
list_fields:
|
|
64
89
|
<% @fields.each do |f| -%>
|
|
65
|
-
- <%= f %>
|
|
90
|
+
- <%= f %>
|
|
66
91
|
<% end -%>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
92
|
+
<% if @fields.empty? -%>
|
|
93
|
+
[]
|
|
94
|
+
<% end -%>
|
|
95
|
+
show_fields:
|
|
96
|
+
<% (@columns.map { |c| c[:name] } + @uploaders).uniq.each do |f| -%>
|
|
97
|
+
- <%= f %>
|
|
70
98
|
<% end -%>
|
|
71
|
-
|
|
99
|
+
<% if (@columns.map { |c| c[:name] } + @uploaders).uniq.empty? -%>
|
|
100
|
+
[]
|
|
101
|
+
<% end -%>
|
|
102
|
+
form_fields:
|
|
103
|
+
<% if @fields.empty? && @uploaders.empty? -%>
|
|
104
|
+
[]
|
|
105
|
+
<% else -%>
|
|
72
106
|
<% @fields.each do |f| -%>
|
|
73
|
-
|
|
74
|
-
|
|
107
|
+
<% if @uploaders.include?(f) -%>
|
|
108
|
+
- name: <%= f %>
|
|
109
|
+
type: <%= is_singular?(f) ? 'file' : 'files' %>
|
|
110
|
+
<% else -%>
|
|
111
|
+
- name: <%= f %>
|
|
112
|
+
type: <%= get_column_type(f) %>
|
|
113
|
+
<% end -%>
|
|
75
114
|
<% end -%>
|
|
76
115
|
<% @uploaders.each do |f| -%>
|
|
77
|
-
|
|
78
|
-
|
|
116
|
+
<% unless @fields.include?(f) -%>
|
|
117
|
+
- name: <%= f %>
|
|
118
|
+
type: <%= is_singular?(f) ? 'file' : 'files' %>
|
|
119
|
+
<% end -%>
|
|
120
|
+
<% end -%>
|
|
79
121
|
<% end -%>
|
|
80
122
|
|
|
81
123
|
domains:
|
|
82
|
-
action_list:
|
|
83
|
-
use_case:
|
|
84
|
-
contract:
|
|
85
|
-
<%
|
|
86
|
-
|
|
87
|
-
<%
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
124
|
+
action_list:
|
|
125
|
+
use_case:
|
|
126
|
+
contract:
|
|
127
|
+
<% if contract_lines_for_list.empty? -%>
|
|
128
|
+
[]
|
|
129
|
+
<% else -%>
|
|
130
|
+
<% contract_lines_for_list.each do |line| -%>
|
|
131
|
+
- <%= line %>
|
|
132
|
+
<% end -%>
|
|
133
|
+
<% end -%>
|
|
134
|
+
repository:
|
|
135
|
+
filters:
|
|
136
|
+
<% if repository_list_filters.empty? -%>
|
|
137
|
+
[]
|
|
138
|
+
<% else -%>
|
|
139
|
+
<% repository_list_filters.each do |line| -%>
|
|
140
|
+
- <%= line %>
|
|
141
|
+
<% end -%>
|
|
142
|
+
<% end -%>
|
|
143
|
+
|
|
144
|
+
action_fetch_by_id:
|
|
145
|
+
use_case:
|
|
146
|
+
contract:
|
|
147
|
+
- "required(:id).filled(:string)"
|
|
92
148
|
<% if @resource_owner_id.present? -%>
|
|
93
|
-
- required(:<%= @resource_owner_id %>).filled(:string)
|
|
149
|
+
- "required(:<%= @resource_owner_id %>).filled(:string)"
|
|
150
|
+
<% end -%>
|
|
151
|
+
<% search_able_fields = arg_settings['search_able'].to_s.split(',').map(&:strip).reject(&:blank?) -%>
|
|
152
|
+
<% if search_able_fields.any? -%>
|
|
153
|
+
<% search_able_fields.each do |f| -%>
|
|
154
|
+
# optional search fields: <%= f %>
|
|
155
|
+
<% end -%>
|
|
94
156
|
<% end -%>
|
|
95
157
|
|
|
96
|
-
action_create:
|
|
97
|
-
use_case:
|
|
98
|
-
contract:
|
|
158
|
+
action_create:
|
|
159
|
+
use_case:
|
|
160
|
+
contract:
|
|
99
161
|
<% if @resource_owner_id.present? -%>
|
|
100
|
-
- required(:<%= @resource_owner_id %>).filled(:string)
|
|
162
|
+
- "required(:<%= @resource_owner_id %>).filled(:string)"
|
|
101
163
|
<% end -%>
|
|
164
|
+
<% if contract_lines_for_create.empty? && !@resource_owner_id.present? -%>
|
|
165
|
+
[]
|
|
166
|
+
<% else -%>
|
|
102
167
|
<% contract_lines_for_create.each do |line| -%>
|
|
103
|
-
<%= line %>
|
|
168
|
+
- <%= line %>
|
|
169
|
+
<% end -%>
|
|
104
170
|
<% end -%>
|
|
105
171
|
|
|
106
|
-
action_update:
|
|
107
|
-
use_case:
|
|
108
|
-
contract:
|
|
109
|
-
- required(:id).filled(:string)
|
|
172
|
+
action_update:
|
|
173
|
+
use_case:
|
|
174
|
+
contract:
|
|
175
|
+
- "required(:id).filled(:string)"
|
|
110
176
|
<% if @resource_owner_id.present? -%>
|
|
111
|
-
- required(:<%= @resource_owner_id %>).filled(:string)
|
|
177
|
+
- "required(:<%= @resource_owner_id %>).filled(:string)"
|
|
112
178
|
<% end -%>
|
|
113
179
|
<% contract_lines_for_update.each do |line| -%>
|
|
114
|
-
<%= line %>
|
|
180
|
+
- <%= line %>
|
|
115
181
|
<% end -%>
|
|
116
182
|
|
|
117
|
-
action_destroy:
|
|
118
|
-
use_case:
|
|
119
|
-
contract:
|
|
120
|
-
- required(:id).filled(:string)
|
|
183
|
+
action_destroy:
|
|
184
|
+
use_case:
|
|
185
|
+
contract:
|
|
186
|
+
- "required(:id).filled(:string)"
|
|
121
187
|
<% if @resource_owner_id.present? -%>
|
|
122
|
-
- required(:<%= @resource_owner_id %>).filled(:string)
|
|
188
|
+
- "required(:<%= @resource_owner_id %>).filled(:string)"
|
|
123
189
|
<% end -%>
|
|
124
190
|
|
|
125
191
|
entity:
|
|
126
|
-
skipped_fields:
|
|
127
|
-
- id
|
|
128
|
-
- created_at
|
|
129
|
-
- updated_at
|
|
130
|
-
<% if @columns.map {
|
|
131
|
-
- type
|
|
192
|
+
skipped_fields:
|
|
193
|
+
- id
|
|
194
|
+
- created_at
|
|
195
|
+
- updated_at
|
|
196
|
+
<% if @columns.map { |c| c[:name] }.include?('type') -%>
|
|
197
|
+
- type
|
|
198
|
+
<% end -%>
|
|
199
|
+
db_attributes:
|
|
200
|
+
<% if entity_db_fields.empty? -%>
|
|
201
|
+
[]
|
|
202
|
+
<% else -%>
|
|
203
|
+
<% entity_db_fields.each do |field| -%>
|
|
204
|
+
- <%= field %>
|
|
132
205
|
<% end -%>
|
|
206
|
+
<% end -%>
|
|
@@ -1,25 +1,51 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
class
|
|
4
|
-
acts_as_builder_for_entity
|
|
3
|
+
class <%= domain_class_name %>::Builders::<%= @subject_class %> < RiderKick::Builders::AbstractActiveRecordEntityBuilder
|
|
4
|
+
acts_as_builder_for_entity <%= domain_class_name %>::Entities::<%= @subject_class%>
|
|
5
5
|
|
|
6
6
|
<% if @uploaders.present? -%>
|
|
7
7
|
def attributes_for_entity
|
|
8
8
|
{
|
|
9
|
-
<% @uploaders.each_with_index do |
|
|
10
|
-
<% if
|
|
11
|
-
<%=
|
|
9
|
+
<% @uploaders.each_with_index do |uploader, index| -%>
|
|
10
|
+
<% if uploader.type == 'single' -%>
|
|
11
|
+
<%= uploader.name %>_url: with_<%= uploader.name %>_url(@params)<%= index < @uploaders.length - 1 ? ',' : '' %>
|
|
12
12
|
<% else -%>
|
|
13
|
-
<%=
|
|
13
|
+
<%= uploader.name %>_urls: with_<%= uploader.name %>_urls(@params)<%= index < @uploaders.length - 1 ? ',' : '' %>
|
|
14
14
|
<% end -%>
|
|
15
15
|
<% end -%>
|
|
16
16
|
}
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
private
|
|
19
|
+
private
|
|
20
|
+
<% end -%>
|
|
21
|
+
<%- @uploaders.each do |uploader| -%>
|
|
22
|
+
<%- if uploader.type == 'single' -%>
|
|
23
|
+
# Metode ini akan dipanggil untuk mengisi ':<%= uploader.name %>_url'
|
|
24
|
+
def with_<%= uploader.name %>_url(model)
|
|
25
|
+
return nil unless model.<%= uploader.name %>.attached?
|
|
20
26
|
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
# Anda bisa mengubah logika ini, misal menggunakan Rails.application.routes.url_helpers
|
|
28
|
+
# jika Anda membutuhkan URL yang absolut.
|
|
29
|
+
model.<%= uploader.name %>.url
|
|
30
|
+
rescue StandardError
|
|
31
|
+
nil
|
|
23
32
|
end
|
|
24
|
-
|
|
33
|
+
|
|
34
|
+
<%- else -%>
|
|
35
|
+
# Metode ini akan dipanggil untuk mengisi ':<%= uploader.name %>_urls'
|
|
36
|
+
def with_<%= uploader.name %>_urls(model)
|
|
37
|
+
return [] unless model.<%= uploader.name %>.attached?
|
|
38
|
+
|
|
39
|
+
model.<%= uploader.name %>.map do |attachment|
|
|
40
|
+
# Anda bisa mengubah logika ini juga
|
|
41
|
+
attachment.url
|
|
42
|
+
rescue StandardError
|
|
43
|
+
nil
|
|
44
|
+
end.compact
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
<%- end -%>
|
|
48
|
+
<%- end -%>
|
|
49
|
+
|
|
25
50
|
end
|
|
51
|
+
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rails_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe <%= domain_class_name %>::Builders::<%= @subject_class %>, type: :builder do
|
|
6
|
+
describe '#build' do
|
|
7
|
+
let(:<%= @variable_subject %>) do
|
|
8
|
+
ClassStubber::Model.new(
|
|
9
|
+
'id' => 'test-id-123',
|
|
10
|
+
<%
|
|
11
|
+
# Get uploader field names to exclude from entity_db_fields
|
|
12
|
+
uploader_names = @uploaders.map { |u| u.name.to_s }
|
|
13
|
+
-%>
|
|
14
|
+
<% @entity_db_fields.each do |field| -%>
|
|
15
|
+
<% next if uploader_names.include?(field.to_s) -%>
|
|
16
|
+
<% column_meta = get_column_meta(field) -%>
|
|
17
|
+
<% case column_meta[:type].to_s -%>
|
|
18
|
+
<% when 'datetime', 'timestamp' -%>
|
|
19
|
+
'<%= field %>' => Time.current,
|
|
20
|
+
<% when 'date' -%>
|
|
21
|
+
'<%= field %>' => Date.current,
|
|
22
|
+
<% when 'time' -%>
|
|
23
|
+
'<%= field %>' => Time.current,
|
|
24
|
+
<% when 'boolean' -%>
|
|
25
|
+
'<%= field %>' => true,
|
|
26
|
+
<% when 'integer', 'bigint' -%>
|
|
27
|
+
'<%= field %>' => 123,
|
|
28
|
+
<% when 'decimal', 'float' -%>
|
|
29
|
+
'<%= field %>' => 123.45,
|
|
30
|
+
<% else -%>
|
|
31
|
+
'<%= field %>' => '<%= field %>_value',
|
|
32
|
+
<% end -%>
|
|
33
|
+
<% end -%>
|
|
34
|
+
<% @uploaders.each do |uploader| -%>
|
|
35
|
+
<% if uploader.type == 'single' -%>
|
|
36
|
+
'<%= uploader.name %>' => ClassStubber::ActiveStorageAttachment.new_single('http://example.com/<%= uploader.name %>.jpg'),
|
|
37
|
+
<% else -%>
|
|
38
|
+
'<%= uploader.name %>' => ClassStubber::ActiveStorageAttachment.new_multiple([
|
|
39
|
+
'http://example.com/<%= uploader.name %>_1.jpg',
|
|
40
|
+
'http://example.com/<%= uploader.name %>_2.jpg'
|
|
41
|
+
]),
|
|
42
|
+
<% end -%>
|
|
43
|
+
<% end -%>
|
|
44
|
+
'created_at' => Time.current,
|
|
45
|
+
'updated_at' => Time.current
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
let(:builder) { described_class.new(<%= @variable_subject %>) }
|
|
50
|
+
|
|
51
|
+
it 'builds entity from model' do
|
|
52
|
+
entity = builder.build
|
|
53
|
+
|
|
54
|
+
expect(entity).to be_a(<%= domain_class_name %>::Entities::<%= @subject_class %>)
|
|
55
|
+
expect(entity.id).to eq('test-id-123')
|
|
56
|
+
<% @entity_db_fields.first(2).each do |field| -%>
|
|
57
|
+
<% column_meta = get_column_meta(field) -%>
|
|
58
|
+
<% case column_meta[:type].to_s -%>
|
|
59
|
+
<% when 'datetime', 'timestamp', 'time' -%>
|
|
60
|
+
expect(entity.<%= field %>).to be_a(Time)
|
|
61
|
+
<% when 'date' -%>
|
|
62
|
+
expect(entity.<%= field %>).to be_a(Date)
|
|
63
|
+
<% when 'boolean' -%>
|
|
64
|
+
expect(entity.<%= field %>).to eq(true)
|
|
65
|
+
<% when 'integer', 'bigint' -%>
|
|
66
|
+
expect(entity.<%= field %>).to eq(123)
|
|
67
|
+
<% when 'decimal', 'float' -%>
|
|
68
|
+
expect(entity.<%= field %>).to eq(123.45)
|
|
69
|
+
<% else -%>
|
|
70
|
+
expect(entity.<%= field %>).to eq('<%= field %>_value')
|
|
71
|
+
<% end -%>
|
|
72
|
+
<% end -%>
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'includes all required entity attributes', :aggregate_failures do
|
|
76
|
+
entity = builder.build
|
|
77
|
+
|
|
78
|
+
# Entity must have these attributes (keys must exist, values can be nil for optional)
|
|
79
|
+
expect(entity).to respond_to(:id)
|
|
80
|
+
<% @entity_db_fields.each do |field| -%>
|
|
81
|
+
<% next if uploader_names.include?(field.to_s) -%>
|
|
82
|
+
expect(entity).to respond_to(:<%= field %>)
|
|
83
|
+
<% end -%>
|
|
84
|
+
<% @uploaders.each do |uploader| -%>
|
|
85
|
+
<% if uploader.type == 'single' -%>
|
|
86
|
+
expect(entity).to respond_to(:<%= uploader.name %>_url)
|
|
87
|
+
<% else -%>
|
|
88
|
+
expect(entity).to respond_to(:<%= uploader.name %>_urls)
|
|
89
|
+
<% end -%>
|
|
90
|
+
<% end -%>
|
|
91
|
+
expect(entity).to respond_to(:created_at)
|
|
92
|
+
expect(entity).to respond_to(:updated_at)
|
|
93
|
+
end
|
|
94
|
+
<% if @uploaders.present? -%>
|
|
95
|
+
|
|
96
|
+
describe '#attributes_for_entity' do
|
|
97
|
+
it 'returns hash with uploader attributes', :aggregate_failures do
|
|
98
|
+
attributes = builder.send(:attributes_for_entity)
|
|
99
|
+
|
|
100
|
+
expect(attributes).to be_a(Hash)
|
|
101
|
+
<% @uploaders.each do |uploader| -%>
|
|
102
|
+
<% if uploader.type == 'single' -%>
|
|
103
|
+
expect(attributes).to have_key(:<%= uploader.name %>_url)
|
|
104
|
+
<% else -%>
|
|
105
|
+
expect(attributes).to have_key(:<%= uploader.name %>_urls)
|
|
106
|
+
<% end -%>
|
|
107
|
+
<% end -%>
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it 'generates correct URL attributes', :aggregate_failures do
|
|
111
|
+
attributes = builder.send(:attributes_for_entity)
|
|
112
|
+
|
|
113
|
+
<% @uploaders.each do |uploader| -%>
|
|
114
|
+
<% if uploader.type == 'single' -%>
|
|
115
|
+
expect(attributes[:<%= uploader.name %>_url]).to eq('http://example.com/<%= uploader.name %>.jpg')
|
|
116
|
+
<% else -%>
|
|
117
|
+
expect(attributes[:<%= uploader.name %>_urls]).to be_an(Array)
|
|
118
|
+
expect(attributes[:<%= uploader.name %>_urls].size).to eq(2)
|
|
119
|
+
<% end -%>
|
|
120
|
+
<% end -%>
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
<% end -%>
|
|
124
|
+
|
|
125
|
+
it 'ensures all entity attributes have correct keys and types', :aggregate_failures do
|
|
126
|
+
entity = builder.build
|
|
127
|
+
entity_hash = entity.to_h
|
|
128
|
+
|
|
129
|
+
# All entity attributes must have keys in the hash (source of truth from entity)
|
|
130
|
+
expect(entity_hash).to have_key(:id)
|
|
131
|
+
expect(entity.id).to be_a(String)
|
|
132
|
+
<% @entity_db_fields.each do |field| -%>
|
|
133
|
+
<% next if uploader_names.include?(field.to_s) -%>
|
|
134
|
+
<% column_meta = get_column_meta(field) -%>
|
|
135
|
+
|
|
136
|
+
expect(entity_hash).to have_key(:<%= field %>)
|
|
137
|
+
<% case column_meta[:type].to_s -%>
|
|
138
|
+
<% when 'datetime', 'timestamp', 'time' -%>
|
|
139
|
+
expect(entity.<%= field %>).to be_a(Time) if entity.<%= field %>.present?
|
|
140
|
+
<% when 'date' -%>
|
|
141
|
+
expect(entity.<%= field %>).to be_a(Date) if entity.<%= field %>.present?
|
|
142
|
+
<% when 'boolean' -%>
|
|
143
|
+
expect([TrueClass, FalseClass, NilClass]).to include(entity.<%= field %>.class)
|
|
144
|
+
<% when 'integer', 'bigint' -%>
|
|
145
|
+
expect(entity.<%= field %>).to be_a(Integer) if entity.<%= field %>.present?
|
|
146
|
+
<% when 'decimal', 'float' -%>
|
|
147
|
+
expect(entity.<%= field %>).to be_a(Numeric) if entity.<%= field %>.present?
|
|
148
|
+
<% else -%>
|
|
149
|
+
expect(entity.<%= field %>).to be_a(String).or be_nil
|
|
150
|
+
<% end -%>
|
|
151
|
+
<% end -%>
|
|
152
|
+
<% @uploaders.each do |uploader| -%>
|
|
153
|
+
<% if uploader.type == 'single' -%>
|
|
154
|
+
|
|
155
|
+
expect(entity_hash).to have_key(:<%= uploader.name %>_url)
|
|
156
|
+
expect(entity.<%= uploader.name %>_url).to be_a(String).or be_nil
|
|
157
|
+
<% else -%>
|
|
158
|
+
|
|
159
|
+
expect(entity_hash).to have_key(:<%= uploader.name %>_urls)
|
|
160
|
+
expect(entity.<%= uploader.name %>_urls).to be_a(Array)
|
|
161
|
+
<% end -%>
|
|
162
|
+
<% end -%>
|
|
163
|
+
|
|
164
|
+
expect(entity_hash).to have_key(:created_at)
|
|
165
|
+
expect(entity.created_at).to be_a(Time) if entity.created_at.present?
|
|
166
|
+
|
|
167
|
+
expect(entity_hash).to have_key(:updated_at)
|
|
168
|
+
expect(entity.updated_at).to be_a(Time) if entity.updated_at.present?
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it 'validates entity type schema definitions', :aggregate_failures do
|
|
172
|
+
# Verify entity has correct Dry::Types definitions
|
|
173
|
+
schema = <%= domain_class_name %>::Entities::<%= @subject_class %>.schema
|
|
174
|
+
|
|
175
|
+
# ID must be required (not optional)
|
|
176
|
+
id_key = schema.key(:id)
|
|
177
|
+
expect(id_key.required?).to be true
|
|
178
|
+
# Check if type is not nilable (Constrained means not optional)
|
|
179
|
+
expect(id_key.type.to_s).to match(/Constrained|Strict/)
|
|
180
|
+
<% @entity_db_fields.each do |field| -%>
|
|
181
|
+
<% next if uploader_names.include?(field.to_s) -%>
|
|
182
|
+
<% column_meta = get_column_meta(field) -%>
|
|
183
|
+
|
|
184
|
+
# <%= field %>: <%= column_meta[:null] ? 'optional' : 'required' %>
|
|
185
|
+
<% if column_meta[:null] -%>
|
|
186
|
+
# Optional field - can be nil
|
|
187
|
+
<%= field %>_key = schema.key(:<%= field %>)
|
|
188
|
+
expect(<%= field %>_key.required?).to be false
|
|
189
|
+
<% else -%>
|
|
190
|
+
# Required field - not nilable
|
|
191
|
+
<%= field %>_key = schema.key(:<%= field %>)
|
|
192
|
+
expect(<%= field %>_key.required?).to be true
|
|
193
|
+
expect(<%= field %>_key.type.to_s).to match(/Constrained|Strict/)
|
|
194
|
+
<% end -%>
|
|
195
|
+
<% end -%>
|
|
196
|
+
<% @uploaders.each do |uploader| -%>
|
|
197
|
+
<% if uploader.type == 'single' -%>
|
|
198
|
+
|
|
199
|
+
# <%= uploader.name %>_url: optional (uploader can be nil)
|
|
200
|
+
<%= uploader.name %>_url_key = schema.key(:<%= uploader.name %>_url)
|
|
201
|
+
expect(<%= uploader.name %>_url_key.required?).to be false
|
|
202
|
+
<% else -%>
|
|
203
|
+
|
|
204
|
+
# <%= uploader.name %>_urls: required (but can be empty array)
|
|
205
|
+
<%= uploader.name %>_urls_key = schema.key(:<%= uploader.name %>_urls)
|
|
206
|
+
expect(<%= uploader.name %>_urls_key.required?).to be true
|
|
207
|
+
<% end -%>
|
|
208
|
+
<% end -%>
|
|
209
|
+
|
|
210
|
+
# Timestamps - check their actual definition
|
|
211
|
+
created_at_key = schema.key(:created_at)
|
|
212
|
+
updated_at_key = schema.key(:updated_at)
|
|
213
|
+
|
|
214
|
+
# Verify timestamps exist (they might be optional in some entities)
|
|
215
|
+
expect(schema.keys.map(&:name)).to include(:created_at, :updated_at)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
class
|
|
4
|
-
acts_as_builder_for_entity
|
|
3
|
+
class <%= domain_class_name %>::Builders::Error < RiderKick::Builders::AbstractActiveRecordEntityBuilder
|
|
4
|
+
acts_as_builder_for_entity <%= domain_class_name %>::Entities::Error
|
|
5
5
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
class
|
|
4
|
-
acts_as_builder_for_entity
|
|
3
|
+
class <%= domain_class_name %>::Builders::Pagination < RiderKick::Builders::AbstractActiveRecordEntityBuilder
|
|
4
|
+
acts_as_builder_for_entity <%= domain_class_name %>::Entities::Pagination
|
|
5
5
|
|
|
6
6
|
def attributes_for_entity
|
|
7
7
|
{
|
|
@@ -1,17 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
class
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
class <%= domain_class_name %>::Entities::<%= @subject_class %> < Dry::Struct
|
|
4
|
+
transform_keys(&:to_sym)
|
|
5
|
+
|
|
6
|
+
# Atribut Wajib (selalu ada)
|
|
7
|
+
attribute :id, Types::Strict::String
|
|
8
|
+
<%- @entity_db_fields.reject { |f| f == 'id' }.each do |field| -%>
|
|
9
|
+
<%-
|
|
10
|
+
# Dapatkan tipe data dari pemetaan
|
|
11
|
+
db_type = get_column_type(field).to_s
|
|
12
|
+
entity_type = @entity_type_mapping[db_type] || 'Types::Strict::String' # Fallback
|
|
13
|
+
# Cek nullability dari @columns_meta_hash, BUKAN @model_class.columns_hash
|
|
14
|
+
column_meta = get_column_meta(field) # Menggunakan helper baru
|
|
15
|
+
is_nullable = column_meta[:null] == true
|
|
16
|
+
|
|
17
|
+
# Terapkan .optional jika nullable di DB
|
|
18
|
+
entity_type += ".optional" if is_nullable
|
|
19
|
+
-%>
|
|
20
|
+
attribute :<%= field %>, <%= entity_type %>
|
|
21
|
+
<%- end -%>
|
|
22
|
+
|
|
23
|
+
# Atribut ini diambil dari 'uploaders' di YAML
|
|
24
|
+
<%- @uploaders.each do |uploader| -%>
|
|
25
|
+
<%- if uploader.type == 'single' -%>
|
|
26
|
+
attribute :<%= uploader.name %>_url, Types::Strict::String.optional
|
|
27
|
+
<%- else -%>
|
|
28
|
+
attribute :<%= uploader.name %>_urls, Types::Strict::Array.of(Types::Strict::String).optional
|
|
29
|
+
<%- end -%>
|
|
30
|
+
<%- end -%>
|
|
31
|
+
|
|
32
|
+
# Atribut Opsional (selalu ada)
|
|
33
|
+
attribute? :created_at, Types::Strict::Time.optional
|
|
34
|
+
attribute? :updated_at, Types::Strict::Time.optional
|
|
17
35
|
end
|