bullet_train-super_scaffolding 1.0.27 → 1.0.30
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/bullet_train/super_scaffolding/version.rb +1 -1
- data/lib/scaffolding/block_manipulator.rb +4 -0
- data/lib/scaffolding/routes_file_manipulator.rb +66 -14
- data/lib/scaffolding/script.rb +6 -0
- data/lib/scaffolding/transformer.rb +24 -4
- data/lib/scaffolding.rb +19 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ade9510dad6e37f1400c6d5a934f76aadd00dcf0f8d31ee4bf94a22b335db337
|
4
|
+
data.tar.gz: 8c6cbfd05ae88e622ba92cdbe0b7692c5d543c272fd17ed244ec039c77b0155c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 175dfb1b7ba5d85c3d6f50910b96b9759f6b850f747a848a87d66afc865b6fd58f917fc9ea78d43d601f80a9366ff6517bb67850c2c26ddea48cf0d3f9d53822
|
7
|
+
data.tar.gz: b52ffae0b1fd6cb1bc67c053f53b89bacd9ef6165a59d034fd6b67603c3cfd7eba0a8a8896bd47a5e7923da9d1ec708626622a69e8c074addd961f4e4cf635d6
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class Scaffolding::RoutesFileManipulator
|
2
|
-
attr_accessor :child, :parent, :lines, :transformer_options
|
2
|
+
attr_accessor :child, :parent, :lines, :transformer_options, :block_manipulator
|
3
3
|
|
4
4
|
def initialize(filename, child, parent, transformer_options = {})
|
5
5
|
self.child = child
|
@@ -7,6 +7,7 @@ class Scaffolding::RoutesFileManipulator
|
|
7
7
|
@filename = filename
|
8
8
|
self.lines = File.readlines(@filename)
|
9
9
|
self.transformer_options = transformer_options
|
10
|
+
self.block_manipulator = Scaffolding::BlockManipulator.new(@filename)
|
10
11
|
end
|
11
12
|
|
12
13
|
def child_parts
|
@@ -141,7 +142,12 @@ class Scaffolding::RoutesFileManipulator
|
|
141
142
|
current_namespace = nil
|
142
143
|
while namespaces.any?
|
143
144
|
current_namespace = namespaces.shift
|
144
|
-
namespace_lines =
|
145
|
+
namespace_lines = if within.nil?
|
146
|
+
find_namespaces(created_namespaces + [current_namespace], within)
|
147
|
+
else
|
148
|
+
scope_namespace_to_parent(current_namespace, within)
|
149
|
+
end
|
150
|
+
|
145
151
|
unless namespace_lines[current_namespace]
|
146
152
|
lines_to_add = ["namespace :#{current_namespace} do", "end"]
|
147
153
|
if created_namespaces.any?
|
@@ -156,6 +162,35 @@ class Scaffolding::RoutesFileManipulator
|
|
156
162
|
namespace_lines ? namespace_lines[current_namespace] : nil
|
157
163
|
end
|
158
164
|
|
165
|
+
# Since it's possible for multiple namespaces to exist on different levels,
|
166
|
+
# We scope the namespace we're trying to scaffold to its proper parent before processing it.
|
167
|
+
#
|
168
|
+
# i.e:
|
169
|
+
# Parent: Insight => Child: Personality::CharacterTrait
|
170
|
+
# Parent: Team => Child: Personality::Disposition
|
171
|
+
# In this case, the :personality namespace under :insights should be
|
172
|
+
# ignored when Super Scaffolding Personality::Dispositon.
|
173
|
+
#
|
174
|
+
# resources do :insights do
|
175
|
+
# namespace :personality do
|
176
|
+
# resources :character_traits
|
177
|
+
# end
|
178
|
+
# end
|
179
|
+
#
|
180
|
+
# namespace :personality do
|
181
|
+
# resources :dispositions
|
182
|
+
# end
|
183
|
+
#
|
184
|
+
# In this case, Personality::CharacterTrait is under Team just like Personality::Disposition,
|
185
|
+
# but Personality::CharacterTrait's DIRECT parent is Insight so we shouldn't scaffold its routes there.
|
186
|
+
def scope_namespace_to_parent(namespace, within)
|
187
|
+
namespace_block_start = namespace_blocks_directly_under_parent(within).map do |namespace_block|
|
188
|
+
namespace_line_number = namespace_block.begin
|
189
|
+
namespace_line_number if lines[namespace_line_number].match?(/ +namespace :#{namespace}/)
|
190
|
+
end.compact
|
191
|
+
namespace_block_start.present? ? {namespace => namespace_block_start} : {}
|
192
|
+
end
|
193
|
+
|
159
194
|
def find(needle, within = nil)
|
160
195
|
lines_within(within).each_with_index do |line, line_number|
|
161
196
|
return (within + (within ? 1 : 0) + line_number) if line.match?(needle)
|
@@ -220,6 +255,8 @@ class Scaffolding::RoutesFileManipulator
|
|
220
255
|
result
|
221
256
|
end
|
222
257
|
|
258
|
+
# Finds namespace blocks no matter how many levels deep they are nested in resource blocks, etc.
|
259
|
+
# However, will not find namespace blocks inside namespace blocks.
|
223
260
|
def top_level_namespace_block_lines(within)
|
224
261
|
local_namespace_blocks = []
|
225
262
|
lines_within(within).each do |line|
|
@@ -253,6 +290,24 @@ class Scaffolding::RoutesFileManipulator
|
|
253
290
|
local_namespace_blocks
|
254
291
|
end
|
255
292
|
|
293
|
+
# Whereas top_level_namespace_block_lines grabs all namespace blocks that
|
294
|
+
# appear first no matter how many resource blocks they're nested in,
|
295
|
+
# this method grabs namespace blocks that are only indented one level deep.
|
296
|
+
def namespace_blocks_directly_under_parent(within)
|
297
|
+
blocks = []
|
298
|
+
if lines[within].match?(/do$/)
|
299
|
+
parent_indentation_size = block_manipulator.block_indentation_size(within)
|
300
|
+
within_block_end = find_block_end(within)
|
301
|
+
within.upto(within_block_end) do |line_number|
|
302
|
+
if lines[line_number].match?(/^#{" " * (parent_indentation_size + 2)}namespace/)
|
303
|
+
namespace_block_lines = line_number..find_block_end(line_number)
|
304
|
+
blocks << namespace_block_lines
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
blocks
|
309
|
+
end
|
310
|
+
|
256
311
|
def find_or_create_resource_block(parts, options = {})
|
257
312
|
find_or_create_resource(parts, options)
|
258
313
|
find_or_convert_resource_block(parts.last, options)
|
@@ -300,7 +355,6 @@ class Scaffolding::RoutesFileManipulator
|
|
300
355
|
child_namespaces, child_resource, parent_namespaces, parent_resource = divergent_parts
|
301
356
|
|
302
357
|
within = find_or_create_namespaces(base_namespaces)
|
303
|
-
within = find_or_create_namespaces(common_namespaces, within) if common_namespaces.any?
|
304
358
|
|
305
359
|
# e.g. Project and Projects::Deliverable
|
306
360
|
if parent_namespaces.empty? && child_namespaces.one? && parent_resource == child_namespaces.first
|
@@ -326,33 +380,31 @@ class Scaffolding::RoutesFileManipulator
|
|
326
380
|
# resources :deliverables, except: collection_actions
|
327
381
|
# end
|
328
382
|
|
383
|
+
# We want to see if there are any namespaces one level above the parent itself,
|
384
|
+
# because namespaces with the same name as the resource can exist on the same level.
|
385
|
+
parent_block_start = find_block_parent(parent_within)
|
386
|
+
namespace_line_within = find_or_create_namespaces(child_namespaces, parent_block_start)
|
387
|
+
find_or_create_resource([child_resource], options: "except: collection_actions", within: namespace_line_within)
|
329
388
|
unless find_namespaces(child_namespaces, within)[child_namespaces.last]
|
330
|
-
|
331
|
-
unless find_namespaces(child_namespaces, within)[child_namespaces.last]
|
332
|
-
raise "tried to insert `namespace :#{child_namespaces.last}` but it seems we failed"
|
333
|
-
end
|
389
|
+
raise "tried to insert `namespace :#{child_namespaces.last}` but it seems we failed"
|
334
390
|
end
|
335
391
|
|
336
|
-
find_or_create_resource(child_namespaces + [child_resource], options: "except: collection_actions", within: within)
|
337
|
-
|
338
392
|
# e.g. Projects::Deliverable and Objective Under It, Abstract::Concept and Concrete::Thing
|
339
393
|
elsif parent_namespaces.any?
|
340
394
|
|
341
395
|
# namespace :projects do
|
342
396
|
# resources :deliverables
|
343
397
|
# end
|
344
|
-
|
398
|
+
top_parent_namespace = find_namespaces(parent_namespaces, within)[parent_namespaces.first]
|
399
|
+
find_or_create_resource(child_namespaces + [child_resource], within: top_parent_namespace)
|
400
|
+
|
345
401
|
# resources :projects_deliverables, path: 'projects/deliverables' do
|
346
402
|
# resources :objectives
|
347
403
|
# end
|
348
|
-
|
349
|
-
find_resource(parent_namespaces + [parent_resource], within: within)
|
350
|
-
top_parent_namespace = find_namespaces(parent_namespaces, within)[parent_namespaces.first]
|
351
404
|
block_parent_within = find_block_parent(top_parent_namespace)
|
352
405
|
parent_namespaces_and_resource = (parent_namespaces + [parent_resource]).join("_")
|
353
406
|
parent_within = find_or_create_resource_block([parent_namespaces_and_resource], options: "path: '#{parent_namespaces_and_resource.tr("_", "/")}'", within: block_parent_within)
|
354
407
|
find_or_create_resource(child_namespaces + [child_resource], within: parent_within)
|
355
|
-
|
356
408
|
else
|
357
409
|
|
358
410
|
begin
|
data/lib/scaffolding/script.rb
CHANGED
@@ -37,6 +37,12 @@ def check_required_options_for_attributes(scaffolding_type, attributes, child, p
|
|
37
37
|
name = parts.shift
|
38
38
|
type = parts.join(":")
|
39
39
|
|
40
|
+
unless Scaffolding.valid_attribute_type?(type)
|
41
|
+
raise "You have entered an invalid attribute type: #{type}. General data types are used when creating new models, but Bullet Train " +
|
42
|
+
"uses field partials when Super Scaffolding, i.e. - `name:text_field` as opposed to `name:string`. " +
|
43
|
+
"Please refer to the Field Partial documentation to view which attribute types are available."
|
44
|
+
end
|
45
|
+
|
40
46
|
# extract any options they passed in with the field.
|
41
47
|
type, attribute_options = type.scan(/^(.*){(.*)}/).first || type
|
42
48
|
|
@@ -655,8 +655,14 @@ class Scaffolding::Transformer
|
|
655
655
|
"email"
|
656
656
|
when "color_picker"
|
657
657
|
"code"
|
658
|
-
|
658
|
+
when "text_field"
|
659
|
+
"text"
|
660
|
+
when "text_area"
|
661
|
+
"text"
|
662
|
+
when "file_field"
|
659
663
|
"text"
|
664
|
+
else
|
665
|
+
raise "Invalid attribute type: #{type}."
|
660
666
|
end
|
661
667
|
|
662
668
|
cell_attributes = if boolean_buttons
|
@@ -1030,10 +1036,14 @@ class Scaffolding::Transformer
|
|
1030
1036
|
scaffold_add_line_to_file("./app/views/account/scaffolding/completely_concrete/tangible_things/_tangible_thing.json.jbuilder", ":#{name},", RUBY_NEW_FIELDS_HOOK, prepend: true, suppress_could_not_find: true)
|
1031
1037
|
scaffold_add_line_to_file("./app/serializers/api/v1/scaffolding/completely_concrete/tangible_thing_serializer.rb", ":#{name},", RUBY_NEW_FIELDS_HOOK, prepend: true)
|
1032
1038
|
|
1033
|
-
assertion =
|
1039
|
+
assertion = case type
|
1040
|
+
when "date_field"
|
1034
1041
|
"assert_equal Date.parse(tangible_thing_data['#{name}']), tangible_thing.#{name}"
|
1035
|
-
|
1042
|
+
when "date_and_time_field"
|
1036
1043
|
"assert_equal DateTime.parse(tangible_thing_data['#{name}']), tangible_thing.#{name}"
|
1044
|
+
when "file_field"
|
1045
|
+
# TODO: If we want to use Cloudinary to handle our files, we should make sure we're getting a URL.
|
1046
|
+
"assert_equal tangible_thing_data['#{name}']['record']['id'], tangible_thing.#{name}.record.id"
|
1037
1047
|
else
|
1038
1048
|
"assert_equal tangible_thing_data['#{name}'], tangible_thing.#{name}"
|
1039
1049
|
end
|
@@ -1276,10 +1286,20 @@ class Scaffolding::Transformer
|
|
1276
1286
|
else
|
1277
1287
|
transform_string("association :absolutely_abstract_creative_concept, factory: :scaffolding_absolutely_abstract_creative_concept")
|
1278
1288
|
end
|
1289
|
+
|
1279
1290
|
scaffold_replace_line_in_file("./test/factories/scaffolding/completely_concrete/tangible_things.rb", content, "absolutely_abstract_creative_concept { nil }")
|
1280
1291
|
|
1281
1292
|
add_has_many_association
|
1282
1293
|
|
1294
|
+
# Adds file attachment to factory
|
1295
|
+
attributes.each do |attribute|
|
1296
|
+
attribute_name, partial_type = attribute.split(":")
|
1297
|
+
if partial_type == "file_field"
|
1298
|
+
content = "#{attribute_name} { Rack::Test::UploadedFile.new(\"test/support/foo.txt\") }"
|
1299
|
+
scaffold_replace_line_in_file("./test/factories/scaffolding/completely_concrete/tangible_things.rb", content, "#{attribute_name} { nil }")
|
1300
|
+
end
|
1301
|
+
end
|
1302
|
+
|
1283
1303
|
if class_names_transformer.belongs_to_needs_class_definition?
|
1284
1304
|
scaffold_replace_line_in_file("./app/models/scaffolding/completely_concrete/tangible_thing.rb", transform_string("belongs_to :absolutely_abstract_creative_concept, class_name: \"Scaffolding::AbsolutelyAbstract::CreativeConcept\"\n"), transform_string("belongs_to :absolutely_abstract_creative_concept\n"))
|
1285
1305
|
end
|
@@ -1430,6 +1450,6 @@ class Scaffolding::Transformer
|
|
1430
1450
|
|
1431
1451
|
add_additional_step :yellow, transform_string("If you would like the table view you've just generated to reactively update when a Tangible Thing is updated on the server, please edit `app/models/scaffolding/absolutely_abstract/creative_concept.rb`, locate the `has_many :completely_concrete_tangible_things`, and add `enable_updates: true` to it.")
|
1432
1452
|
|
1433
|
-
restart_server
|
1453
|
+
restart_server unless ENV["CI"].present?
|
1434
1454
|
end
|
1435
1455
|
end
|
data/lib/scaffolding.rb
CHANGED
@@ -1,2 +1,21 @@
|
|
1
1
|
module Scaffolding
|
2
|
+
def self.valid_attribute_type?(type)
|
3
|
+
[
|
4
|
+
"boolean",
|
5
|
+
"button",
|
6
|
+
"cloudinary_image",
|
7
|
+
"color_picker",
|
8
|
+
"date_and_time_field",
|
9
|
+
"date_field",
|
10
|
+
"email_field",
|
11
|
+
"file_field",
|
12
|
+
"options",
|
13
|
+
"password_field",
|
14
|
+
"phone_field",
|
15
|
+
"super_select",
|
16
|
+
"text_area",
|
17
|
+
"text_field",
|
18
|
+
"trix_editor"
|
19
|
+
].include?(type.gsub(/{.*}/, "")) # Pop off curly brackets such as `super_select{class_name=Membership}`
|
20
|
+
end
|
2
21
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bullet_train-super_scaffolding
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.30
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Culver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: standard
|