rails-code-generator 0.1.1 → 0.1.3
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/lib/generators/rails_code_generator/resources/resources_generator.rb +4 -0
- data/lib/generators/rails_code_generator/resources/templates/bulk/create_spec.rb.tt +2 -1
- data/lib/generators/rails_code_generator/resources/templates/bulk/update_spec.rb.tt +2 -2
- data/lib/generators/rails_code_generator/resources/templates/shared/factory.rb.tt +7 -0
- data/lib/generators/rails_code_generator/resources/templates/shared/normalizer.rb.tt +1 -1
- data/lib/generators/rails_code_generator/resources/templates/single/create_spec.rb.tt +2 -1
- data/lib/generators/rails_code_generator/resources/templates/single/update_spec.rb.tt +2 -2
- data/lib/rails/code/generator/model_attributes.rb +131 -3
- data/lib/rails/code/generator/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a58785634e9cb4a0e9ea51de9e3feed6953434eda056000455672489d3220b4f
|
|
4
|
+
data.tar.gz: d52276ce775667bb11a6802d5ee12a389587c0a29e2e42020503b276f242f90d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 97f6426558b8e1ddc60c35af5c931a1e12e628abdb7ca73cbd8641818242958e7179a9e8809e0d65c7d82e90d36e16a1a8654c5379c225cffaddc9f4a3561bfd
|
|
7
|
+
data.tar.gz: 88383886534fdc4954d7bf5b1a7291460324da0d1efec697879df8a7653d9ead08320b538e332471cbe9ac745c8cd294e71a3981459a98e40af4ae8db8b6c262
|
|
@@ -35,6 +35,10 @@ module RailsCodeGenerator
|
|
|
35
35
|
template "shared/normalizer.rb", File.join("app/normalizers", "#{table_name}_normalizer.rb")
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
def create_factory
|
|
39
|
+
template "shared/factory.rb", File.join("spec/factories", "#{singular_name}.rb")
|
|
40
|
+
end
|
|
41
|
+
|
|
38
42
|
def create_request_specs
|
|
39
43
|
template "shared/index_spec.rb", File.join("spec/requests", table_name, "index_spec.rb")
|
|
40
44
|
template "shared/show_spec.rb", File.join("spec/requests", table_name, "show_spec.rb")
|
|
@@ -5,12 +5,13 @@ require "rails_helper"
|
|
|
5
5
|
RSpec.describe "[POST] /<%= route_path %>", type: :request do
|
|
6
6
|
Given(:path) { "/<%= route_path %>" }
|
|
7
7
|
Given(:user) { create :user }
|
|
8
|
+
<%= request_spec_association_givens %>
|
|
8
9
|
|
|
9
10
|
context "with valid params" do
|
|
10
11
|
Given(:params) {
|
|
11
12
|
{
|
|
12
13
|
<%= table_name %>: {
|
|
13
|
-
|
|
14
|
+
<%= request_params_attributes_list %>
|
|
14
15
|
},
|
|
15
16
|
}.to_json
|
|
16
17
|
}
|
|
@@ -6,12 +6,13 @@ RSpec.describe "[PATCH] /<%= route_path %>/:id", type: :request do
|
|
|
6
6
|
Given(:path) { "/<%= route_path %>/" + <%= singular_name %>.id.to_s }
|
|
7
7
|
Given(:<%= singular_name %>) { create :<%= singular_name %> }
|
|
8
8
|
Given(:user) { create :user }
|
|
9
|
+
<%= request_spec_association_givens %>
|
|
9
10
|
|
|
10
11
|
context "with authenticated user & valid params" do
|
|
11
12
|
Given(:params) {
|
|
12
13
|
{
|
|
13
14
|
<%= table_name %>: {
|
|
14
|
-
|
|
15
|
+
<%= request_params_attributes_list %>
|
|
15
16
|
},
|
|
16
17
|
}.to_json
|
|
17
18
|
}
|
|
@@ -21,6 +22,5 @@ RSpec.describe "[PATCH] /<%= route_path %>/:id", type: :request do
|
|
|
21
22
|
Then { expect(response).to be_successful }
|
|
22
23
|
And { expect(response_body[:data]).not_to be_empty }
|
|
23
24
|
And { expect(response_body[:errors]).to be_empty }
|
|
24
|
-
And { expect(response_body.dig(:data, :name)).to eq "Changed <%= singular_name %> name" }
|
|
25
25
|
end
|
|
26
26
|
end
|
|
@@ -5,12 +5,13 @@ require "rails_helper"
|
|
|
5
5
|
RSpec.describe "[POST] /<%= route_path %>", type: :request do
|
|
6
6
|
Given(:path) { "/<%= route_path %>" }
|
|
7
7
|
Given(:user) { create :user }
|
|
8
|
+
<%= request_spec_association_givens %>
|
|
8
9
|
|
|
9
10
|
context "with valid params" do
|
|
10
11
|
Given(:params) {
|
|
11
12
|
{
|
|
12
13
|
<%= singular_name %>: {
|
|
13
|
-
|
|
14
|
+
<%= request_params_attributes_list %>
|
|
14
15
|
},
|
|
15
16
|
}.to_json
|
|
16
17
|
}
|
|
@@ -6,12 +6,13 @@ RSpec.describe "[PATCH] /<%= route_path %>/:id", type: :request do
|
|
|
6
6
|
Given(:path) { "/<%= route_path %>/#{<%= singular_name %>.id}" }
|
|
7
7
|
Given(:<%= singular_name %>) { create :<%= singular_name %> }
|
|
8
8
|
Given(:user) { create :user }
|
|
9
|
+
<%= request_spec_association_givens %>
|
|
9
10
|
|
|
10
11
|
context "with authenticated user & valid params" do
|
|
11
12
|
Given(:params) {
|
|
12
13
|
{
|
|
13
14
|
<%= singular_name %>: {
|
|
14
|
-
|
|
15
|
+
<%= request_params_attributes_list %>
|
|
15
16
|
},
|
|
16
17
|
}.to_json
|
|
17
18
|
}
|
|
@@ -21,6 +22,5 @@ RSpec.describe "[PATCH] /<%= route_path %>/:id", type: :request do
|
|
|
21
22
|
Then { expect(response).to be_successful }
|
|
22
23
|
And { expect(response_body[:data]).not_to be_empty }
|
|
23
24
|
And { expect(response_body[:errors]).to be_empty }
|
|
24
|
-
And { expect(response_body.dig(:data, :name)).to eq "Changed <%= singular_name %> name" }
|
|
25
25
|
end
|
|
26
26
|
end
|
|
@@ -5,6 +5,7 @@ module Rails
|
|
|
5
5
|
module Generator
|
|
6
6
|
module ModelAttributes
|
|
7
7
|
EXCLUDED_COLUMNS = %w[id created_at updated_at].freeze
|
|
8
|
+
AUTH_USER_ASSOCIATION = "user"
|
|
8
9
|
|
|
9
10
|
DRY_TYPE_MAP = {
|
|
10
11
|
"string" => :string,
|
|
@@ -24,6 +25,24 @@ module Rails
|
|
|
24
25
|
"uuid" => :string,
|
|
25
26
|
}.freeze
|
|
26
27
|
|
|
28
|
+
FAKER_EXPRESSION_MAP = {
|
|
29
|
+
"string" => "Faker::Lorem.word",
|
|
30
|
+
"text" => "Faker::Lorem.paragraph",
|
|
31
|
+
"citext" => "Faker::Lorem.word",
|
|
32
|
+
"integer" => "Faker::Number.number(digits: 5)",
|
|
33
|
+
"bigint" => "Faker::Number.number(digits: 5)",
|
|
34
|
+
"float" => "Faker::Number.decimal(l_digits: 2).to_f",
|
|
35
|
+
"decimal" => "Faker::Number.decimal(l_digits: 2)",
|
|
36
|
+
"boolean" => "Faker::Boolean.boolean",
|
|
37
|
+
"date" => "Faker::Date.forward(days: 30)",
|
|
38
|
+
"datetime" => "Faker::Time.forward(days: 30)",
|
|
39
|
+
"timestamp" => "Faker::Time.forward(days: 30)",
|
|
40
|
+
"timestamptz" => "Faker::Time.forward(days: 30)",
|
|
41
|
+
"json" => "{}",
|
|
42
|
+
"jsonb" => "{}",
|
|
43
|
+
"uuid" => "Faker::Internet.uuid",
|
|
44
|
+
}.freeze
|
|
45
|
+
|
|
27
46
|
def model_attributes
|
|
28
47
|
@model_attributes ||= fetch_model_attributes
|
|
29
48
|
end
|
|
@@ -34,8 +53,9 @@ module Rails
|
|
|
34
53
|
format_symbol_list(names)
|
|
35
54
|
end
|
|
36
55
|
|
|
37
|
-
def normalizer_attributes_list
|
|
56
|
+
def normalizer_attributes_list(include_id: false)
|
|
38
57
|
names = model_attribute_names
|
|
58
|
+
names = [:id, *names] if include_id
|
|
39
59
|
return " # TODO: add attributes" if names.empty?
|
|
40
60
|
|
|
41
61
|
format_symbol_list(names, indent: 4)
|
|
@@ -47,12 +67,60 @@ module Rails
|
|
|
47
67
|
model_attributes.map { |attribute| validator_line_for(attribute) }.join("\n")
|
|
48
68
|
end
|
|
49
69
|
|
|
70
|
+
def request_params_attributes_list(indent: 10)
|
|
71
|
+
padding = " " * indent
|
|
72
|
+
return "#{padding}# TODO: add attributes" if model_attributes.empty?
|
|
73
|
+
|
|
74
|
+
model_attributes.map { |attribute| "#{padding}#{attribute[:name]}: #{param_expression_for(attribute)}," }.join("\n")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def request_spec_association_givens
|
|
78
|
+
associations_for_givens.map { |association|
|
|
79
|
+
" Given(:#{association[:name]}) { create :#{association[:factory]} }"
|
|
80
|
+
}.join("\n")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def factory_definition_body
|
|
84
|
+
lines = factory_association_lines + factory_attribute_lines
|
|
85
|
+
return " # TODO: add attributes" if lines.empty?
|
|
86
|
+
|
|
87
|
+
lines.join("\n")
|
|
88
|
+
end
|
|
89
|
+
|
|
50
90
|
private
|
|
51
91
|
|
|
52
92
|
def model_attribute_names
|
|
53
93
|
model_attributes.map { |attribute| attribute[:name].to_sym }
|
|
54
94
|
end
|
|
55
95
|
|
|
96
|
+
def model_associations
|
|
97
|
+
model_attributes.filter_map { |attribute| attribute[:association] }
|
|
98
|
+
.uniq { |association| association[:name] }
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def associations_for_givens
|
|
102
|
+
model_associations.reject { |association| association[:name] == AUTH_USER_ASSOCIATION }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def factory_association_lines
|
|
106
|
+
model_associations.map { |association|
|
|
107
|
+
" association :#{association[:name]}, factory: :#{association[:factory]}"
|
|
108
|
+
}
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def factory_attribute_lines
|
|
112
|
+
attributes = model_attributes.reject { |attribute| attribute[:association] }
|
|
113
|
+
return [] if attributes.empty?
|
|
114
|
+
|
|
115
|
+
width = attributes.map { |attribute| attribute[:name].length }.max
|
|
116
|
+
|
|
117
|
+
attributes.map { |attribute|
|
|
118
|
+
name = attribute[:name].ljust(width)
|
|
119
|
+
expression = FAKER_EXPRESSION_MAP.fetch(attribute[:type], "Faker::Lorem.word")
|
|
120
|
+
" #{name} { #{expression} }"
|
|
121
|
+
}
|
|
122
|
+
end
|
|
123
|
+
|
|
56
124
|
def format_symbol_list(names, indent: 6)
|
|
57
125
|
padding = " " * indent
|
|
58
126
|
names.map { |name| "#{padding}:#{name}," }.join("\n")
|
|
@@ -69,21 +137,81 @@ module Rails
|
|
|
69
137
|
end
|
|
70
138
|
end
|
|
71
139
|
|
|
140
|
+
def param_expression_for(attribute)
|
|
141
|
+
association = attribute[:association]
|
|
142
|
+
return "#{association[:name]}.id" if association
|
|
143
|
+
|
|
144
|
+
FAKER_EXPRESSION_MAP.fetch(attribute[:type], "Faker::Lorem.word")
|
|
145
|
+
end
|
|
146
|
+
|
|
72
147
|
def fetch_model_attributes
|
|
73
148
|
klass = class_name.constantize
|
|
74
149
|
return [] unless klass.respond_to?(:columns)
|
|
75
150
|
|
|
151
|
+
associations_by_fk, polymorphic_fks = belongs_to_association_maps(klass)
|
|
152
|
+
|
|
76
153
|
klass.columns.filter_map do |column|
|
|
77
154
|
next if EXCLUDED_COLUMNS.include?(column.name)
|
|
78
155
|
|
|
156
|
+
type = column.type.to_s
|
|
157
|
+
|
|
79
158
|
{
|
|
80
159
|
name: column.name,
|
|
81
|
-
|
|
82
|
-
|
|
160
|
+
type: type,
|
|
161
|
+
dry_type: DRY_TYPE_MAP[type],
|
|
162
|
+
association: association_for_column(column.name, associations_by_fk, polymorphic_fks),
|
|
163
|
+
}.compact
|
|
83
164
|
end
|
|
84
165
|
rescue StandardError
|
|
85
166
|
[]
|
|
86
167
|
end
|
|
168
|
+
|
|
169
|
+
def belongs_to_association_maps(klass)
|
|
170
|
+
return [{}, []] unless klass.respond_to?(:reflect_on_all_associations)
|
|
171
|
+
|
|
172
|
+
associations_by_fk = {}
|
|
173
|
+
polymorphic_fks = []
|
|
174
|
+
|
|
175
|
+
klass.reflect_on_all_associations(:belongs_to).each do |reflection|
|
|
176
|
+
foreign_key = reflection.foreign_key.to_s
|
|
177
|
+
|
|
178
|
+
if reflection.options[:polymorphic]
|
|
179
|
+
polymorphic_fks << foreign_key
|
|
180
|
+
next
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
associations_by_fk[foreign_key] = {
|
|
184
|
+
name: reflection.name.to_s,
|
|
185
|
+
factory: factory_name_for(reflection),
|
|
186
|
+
}
|
|
187
|
+
rescue StandardError
|
|
188
|
+
next
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
[associations_by_fk, polymorphic_fks]
|
|
192
|
+
rescue StandardError
|
|
193
|
+
[{}, []]
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def factory_name_for(reflection)
|
|
197
|
+
reflection.klass.model_name.singular
|
|
198
|
+
rescue StandardError
|
|
199
|
+
reflection.name.to_s
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def association_for_column(column_name, associations_by_fk, polymorphic_fks)
|
|
203
|
+
return if polymorphic_fks.include?(column_name)
|
|
204
|
+
return associations_by_fk[column_name] if associations_by_fk.key?(column_name)
|
|
205
|
+
return unless column_name.end_with?("_id")
|
|
206
|
+
|
|
207
|
+
association_name = column_name.delete_suffix("_id")
|
|
208
|
+
return if association_name.empty?
|
|
209
|
+
|
|
210
|
+
{
|
|
211
|
+
name: association_name,
|
|
212
|
+
factory: association_name,
|
|
213
|
+
}
|
|
214
|
+
end
|
|
87
215
|
end
|
|
88
216
|
end
|
|
89
217
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails-code-generator
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michael Sweat
|
|
@@ -48,6 +48,7 @@ files:
|
|
|
48
48
|
- lib/generators/rails_code_generator/resources/templates/bulk/update.rb.tt
|
|
49
49
|
- lib/generators/rails_code_generator/resources/templates/bulk/update_spec.rb.tt
|
|
50
50
|
- lib/generators/rails_code_generator/resources/templates/bulk/update_validator.rb.tt
|
|
51
|
+
- lib/generators/rails_code_generator/resources/templates/shared/factory.rb.tt
|
|
51
52
|
- lib/generators/rails_code_generator/resources/templates/shared/index_spec.rb.tt
|
|
52
53
|
- lib/generators/rails_code_generator/resources/templates/shared/normalizer.rb.tt
|
|
53
54
|
- lib/generators/rails_code_generator/resources/templates/shared/show_spec.rb.tt
|