bullet_train-super_scaffolding 1.0.28 → 1.0.29

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f442627a03e1aea9a33fd4d046a378d0177649eaffc3c1fef2d77cf6dc738b5b
4
- data.tar.gz: 67a9b22aa08ffe3f99ccd1ff88d1568b2d2d3ff247e53a3e96c96eb80b1a09a0
3
+ metadata.gz: 05b68451045068aa2ec97bb4198826333c702d2af995005b9cf0090e58254ed4
4
+ data.tar.gz: 1ea761bfa6ec36306bedae27ecbb51176fb03ff35581b0c5f66dbcf722f4f69e
5
5
  SHA512:
6
- metadata.gz: ef3e5a25df02bce626e7762b482d019852d3c61ba79096c34d8dbd5bfa63e5e939c8aed3755153d0b926086617b11804868609ac5195cda9d5438c988093707f
7
- data.tar.gz: b618a50a54582ca322650947f3b00b0d9fabc1c0383c17c8c6d265c5ee7eba3a7cab200b963935429c63c2e7c49c9fe78badce0233eb1c50aa76b92f313b1d2d
6
+ metadata.gz: '09dbb3f20dcb25d5f1abab3d5a009686f415799b43575e31738695809a882e3a26e8aa5cdb29951b882c66bd75af3f26abddf8006b053404eb8fafe3038ff5db'
7
+ data.tar.gz: f3b55698e2feb4425bf56d855b82570ec59c7ce51a867b7c447e7386a4c88245534bb54513f638b5b3fd60e2a390d374fd53c6199d0bf761ce5c91ff6186e600
@@ -1,5 +1,5 @@
1
1
  module BulletTrain
2
2
  module SuperScaffolding
3
- VERSION = "1.0.28"
3
+ VERSION = "1.0.29"
4
4
  end
5
5
  end
@@ -137,4 +137,8 @@ class Scaffolding::BlockManipulator
137
137
  end
138
138
  current_line
139
139
  end
140
+
141
+ def block_indentation_size(line_number)
142
+ lines[line_number].scan(/^\s+/).first.size
143
+ end
140
144
  end
@@ -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 = find_namespaces(created_namespaces + [current_namespace], within)
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
- insert_after(["", "namespace :#{child_namespaces.last} do", "end"], find_block_end(scope_within))
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
@@ -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
- else
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 = if type == "date_field"
1039
+ assertion = case type
1040
+ when "date_field"
1034
1041
  "assert_equal Date.parse(tangible_thing_data['#{name}']), tangible_thing.#{name}"
1035
- elsif type == "date_and_time_field"
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
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.28
4
+ version: 1.0.29
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-05-22 00:00:00.000000000 Z
11
+ date: 2022-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: standard
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: spring
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: indefinite_article
57
71
  requirement: !ruby/object:Gem::Requirement