bullet_train-super_scaffolding 1.2.9 → 1.2.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 850aff688799324e6aea7b1569259f09160a10401a2f298fec0c81a9ec418658
4
- data.tar.gz: f8fbdf234386a2931731c6e82efdd8fd2ee99f4d627bad2b1fdd07fd3fd32c30
3
+ metadata.gz: 175742fbb3b9512721c4250562fc533f6c43cf630f3c277345d59d61538a3364
4
+ data.tar.gz: 83933564920e87dc260767af664fcba01894f1484d76ed93c8288742705071f1
5
5
  SHA512:
6
- metadata.gz: 671b90bc86112e8babd7d93fc9360257b092498438b4a8f46923ac43d9039f7f0b9f289d340803574162dd2b0e4f31cce98c22bc20ba544ed30f8caace3d14ea
7
- data.tar.gz: 8cc555f6a9f895f67eb6ee2abbae34c109fcce6b75794c5788a5fd45d9bc686c9babd4d5d8ba664d73efc03102ebcbc0eae9f6a048eecca0a0fcc40069b47ff6
6
+ metadata.gz: 5e9a5613d412175f70bd8cdedd9a2aa91cee42a96fefdf0b16ec5862276ef09f0f0f664062b0968d197a5a1b986b7b7f25e154422736f1c3fd5d4026cafe1784
7
+ data.tar.gz: 1d004de2a792cdd6d0d39f65842aa5ef161c4018d681beb5579737c1191b95411bcea4b2adeeb3561c14b34b69b389bcf8dc01025d2f6612b96d6f300445871a
@@ -26,7 +26,7 @@ class Account::Scaffolding::CompletelyConcrete::TangibleThingsController < Accou
26
26
  def create
27
27
  respond_to do |format|
28
28
  if @tangible_thing.save
29
- format.html { redirect_to [:account, @absolutely_abstract_creative_concept, :completely_concrete_tangible_things], notice: I18n.t("scaffolding/completely_concrete/tangible_things.notifications.created") }
29
+ format.html { redirect_to [:account, @tangible_thing], notice: I18n.t("scaffolding/completely_concrete/tangible_things.notifications.created") }
30
30
  format.json { render :show, status: :created, location: [:account, @tangible_thing] }
31
31
  else
32
32
  format.html { render :new, status: :unprocessable_entity }
@@ -1,5 +1,5 @@
1
1
  module BulletTrain
2
2
  module SuperScaffolding
3
- VERSION = "1.2.9"
3
+ VERSION = "1.2.11"
4
4
  end
5
5
  end
@@ -1,209 +1,242 @@
1
1
  require "scaffolding/file_manipulator"
2
2
 
3
- module Scaffolding::BlockManipulator
4
- #
5
- # Wrap a block of ruby code with another block on the outside.
6
- #
7
- # @param [String] `starting` A string to search for at the start of the block. Eg "<%= updates_for context, collection do"
8
- # @param [Array] `with` An array with two String elements. The text that should wrap the block. Eg ["<%= action_model_select_controller do %>", "<% end %>"]
9
- #
10
- def self.wrap_block(starting:, with:, lines:)
11
- with[0] += "\n" unless with[0].match?(/\n$/)
12
- with[1] += "\n" unless with[1].match?(/\n$/)
13
- starting_line = find_block_start(starting_from: starting, lines: lines)
14
- end_line = find_block_end(starting_from: starting_line, lines: lines)
15
-
16
- final = []
17
- block_indent = ""
18
- spacer = " "
19
- lines.each_with_index do |line, index|
20
- line += "\n" unless line.match?(/\n$/)
21
- if index < starting_line
22
- final << line
23
- elsif index == starting_line
24
- block_indent = line.match(/^\s*/).to_s
25
- final << block_indent + with[0]
26
- final << (line.blank? ? "\n" : "#{spacer}#{line}")
27
- elsif index > starting_line && index < end_line
28
- final << (line.blank? ? "\n" : "#{spacer}#{line}")
29
- elsif index == end_line
30
- final << (line.blank? ? "\n" : "#{spacer}#{line}")
31
- final << block_indent + with[1]
32
- else
33
- final << line
3
+ module Scaffolding
4
+ class BlockManipulator
5
+ class << self
6
+ #
7
+ # Wrap a block of ruby code with another block on the outside.
8
+ #
9
+ # @param [String] `starting` A string to search for at the start of the block. Eg "<%= updates_for context, collection do"
10
+ # @param [Array] `with` An array with two String elements. The text that should wrap the block. Eg ["<%= action_model_select_controller do %>", "<% end %>"]
11
+ #
12
+ def wrap_block(starting:, with:, lines:)
13
+ with[0] += "\n" unless with[0].match?(/\n$/)
14
+ with[1] += "\n" unless with[1].match?(/\n$/)
15
+ starting_line = find_block_start(starting_from: starting, lines: lines)
16
+ end_line = find_block_end(starting_from: starting_line, lines: lines)
17
+
18
+ final = []
19
+ block_indent = ""
20
+ spacer = " "
21
+ lines.each_with_index do |line, index|
22
+ line += "\n" unless line.match?(/\n$/)
23
+ if index < starting_line
24
+ final << line
25
+ elsif index == starting_line
26
+ block_indent = line.match(/^\s*/).to_s
27
+ final << block_indent + with[0]
28
+ final << (line.blank? ? "\n" : "#{spacer}#{line}")
29
+ elsif index > starting_line && index < end_line
30
+ final << (line.blank? ? "\n" : "#{spacer}#{line}")
31
+ elsif index == end_line
32
+ final << (line.blank? ? "\n" : "#{spacer}#{line}")
33
+ final << block_indent + with[1]
34
+ else
35
+ final << line
36
+ end
37
+ end
38
+
39
+ lines = final
40
+ unless lines.last.match?(/\n$/)
41
+ lines[-1] += "\n"
42
+ end
43
+ lines
34
44
  end
35
- end
36
45
 
37
- lines = final
38
- unless lines.last.match?(/\n$/)
39
- lines[-1] += "\n"
40
- end
41
- lines
42
- end
46
+ # This method unwraps the block from the perspective of the child.
47
+ #
48
+ # 2.times do
49
+ # 3.times do
50
+ # puts "foo"
51
+ # end
52
+ # end
53
+ #
54
+ # Here we would pass the index of `"3.times do\n"` to
55
+ # `block_start` which would result in removing the outer block.
56
+ def unwrap_block(lines:, block_start:)
57
+ block_start = if block_start.is_a? String
58
+ block_start_line = lines.find { |line| line.match?(block_start) }
59
+ lines.index(block_start_line)
60
+ end
43
61
 
44
- # This method unwraps the block from the perspective of the child.
45
- #
46
- # 2.times do
47
- # 3.times do
48
- # puts "foo"
49
- # end
50
- # end
51
- #
52
- # Here we would pass the index of `"3.times do\n"` to
53
- # `block_start` which would result in removing the outer block.
54
- def self.unwrap_block(lines:, block_start:)
55
- block_start = if block_start.is_a? String
56
- block_start_line = lines.find { |line| line.match?(block_start) }
57
- lines.index(block_start_line)
58
- end
62
+ # Find the proper indices for both child and parent blocks.
63
+ block_parent_start = find_block_parent(block_start, lines)
64
+ block_parent_end = find_block_end(starting_from: block_parent_start, lines: lines)
59
65
 
60
- # Find the proper indices for both child and parent blocks.
61
- block_parent_start = find_block_parent(block_start, lines)
62
- block_parent_end = find_block_end(starting_from: block_parent_start, lines: lines)
66
+ new_lines = shift_block(lines: lines, block_start: block_start)
67
+ new_lines.reject.with_index { |lines, idx| idx == block_parent_start || idx == block_parent_end }
68
+ end
63
69
 
64
- new_lines = shift_block(lines: lines, block_start: block_start)
65
- new_lines.reject.with_index { |lines, idx| idx == block_parent_start || idx == block_parent_end }
66
- end
70
+ def insert(content, lines:, within: nil, after: nil, before: nil, after_block: nil, append: false)
71
+ content = prepare_content_array(content)
67
72
 
68
- def self.insert(content, lines:, within: nil, after: nil, before: nil, after_block: nil, append: false)
69
- # Search for before like we do after, we'll just inject before it.
70
- after ||= before
71
-
72
- # If within is given, find the start and end lines of the block
73
- content += "\n" unless content.match?(/\n$/)
74
- start_line = 0
75
- end_line = lines.count - 1
76
- if within.present?
77
- start_line = find_block_start(starting_from: within, lines: lines)
78
- end_line = find_block_end(starting_from: start_line, lines: lines)
79
- # start_line += 1 # ensure we actually insert the content _within_ the given block
80
- # end_line += 1 if end_line == start_line
81
- end
82
- if after_block.present?
83
- block_start = find_block_start(starting_from: after_block, lines: lines)
84
- block_end = find_block_end(starting_from: block_start, lines: lines)
85
- start_line = block_end
86
- end_line = lines.count - 1
87
- end
88
- index = start_line
89
- match = false
90
- while index < end_line && !match
91
- line = lines[index]
92
- if after.nil? || line.match?(after)
93
- unless append
94
- match = true
95
- # We adjust the injection point if we really wanted to insert before.
96
- lines = insert_line(content, index - (before ? 1 : 0), lines)
73
+ # We initialize the search with the entire file's lines and look for the block below.
74
+ start_line = 0
75
+ end_line = lines.count - 1
76
+
77
+ # Search for before like we do after, we'll just inject before it.
78
+ after ||= before
79
+
80
+ # If within is given, find the start and end lines of the block
81
+ if within.present?
82
+ start_line = find_block_start(starting_from: within, lines: lines)
83
+ end_line = find_block_end(starting_from: start_line, lines: lines)
84
+ # start_line += 1 # ensure we actually insert the content _within_ the given block
85
+ # end_line += 1 if end_line == start_line
97
86
  end
98
- end
99
- index += 1
100
- end
101
87
 
102
- return lines if match
88
+ if after_block.present?
89
+ block_start = find_block_start(starting_from: after_block, lines: lines)
90
+ block_end = find_block_end(starting_from: block_start, lines: lines)
91
+ start_line = block_end
92
+ end_line = lines.count - 1
93
+ end
103
94
 
104
- # Match should always be false here.
105
- if append && !match
106
- lines = insert_line(content, index - 1, lines)
107
- end
108
- lines
109
- end
95
+ index = start_line
96
+ match = false
97
+ while index < end_line && !match
98
+ line = lines[index]
99
+ if after.nil? || line.match?(after)
100
+ unless append
101
+ match = true
102
+ indent = !(before.present? || after.present? || after_block.present?)
103
+
104
+ # We adjust the injection point if we really wanted to insert before.
105
+ lines = insert_lines(content, index - (before ? 1 : 0), lines, indent)
106
+ end
107
+ end
108
+ index += 1
109
+ end
110
110
 
111
- def self.insert_line(content, insert_at_index, lines)
112
- content += "\n" unless content.match?(/\n$/)
113
- final = []
114
- lines.each_with_index do |line, index|
115
- indent = line.match(/^\s*/).to_s
116
- final << line
117
- if index == insert_at_index
118
- final << indent + content
111
+ return lines if match
112
+
113
+ # Match should always be false here.
114
+ if append && !match
115
+ lines = insert_lines(content, index - 1, lines)
116
+ end
117
+ lines
119
118
  end
120
- end
121
- final
122
- end
123
119
 
124
- def self.insert_block(block_content, after_block:, lines:)
125
- block_start = find_block_start(starting_from: after_block, lines: lines)
126
- block_end = find_block_end(starting_from: block_start, lines: lines)
127
- lines = insert_line(block_content[0], block_end, lines)
128
- insert_line(block_content[1], block_end + 1, lines)
129
- end
120
+ def insert_lines(content, insert_at_index, lines, indent)
121
+ final = []
122
+ lines.each_with_index do |line, index|
123
+ indentation = line.match(/^\s*/).to_s
124
+ indentation += "\s" * 2 if indent
125
+
126
+ final << line
127
+ content.each { |new_line| final << indentation + new_line } if index == insert_at_index
128
+ end
129
+ final
130
+ end
130
131
 
131
- def self.find_block_parent(starting_line_number, lines)
132
- return nil unless indentation_of(starting_line_number, lines)
133
- cursor = starting_line_number
134
- while cursor >= 0
135
- unless lines[cursor].match?(/^#{indentation_of(starting_line_number, lines)}/) || !lines[cursor].present?
136
- return cursor
132
+ # TODO: We should eventually replace this with `insert_lines``,
133
+ # I just want to make sure everything doesn't break first.
134
+ def insert_line(content, insert_at_index, lines, indent = true)
135
+ insert_lines(prepare_content_array(content), insert_at_index, lines, indent)
137
136
  end
138
- cursor -= 1
139
- end
140
- nil
141
- end
142
137
 
143
- def self.find_block_start(starting_from:, lines:)
144
- matcher = Regexp.escape(starting_from)
145
- starting_line = 0
138
+ def insert_block(block_content, after_block:, lines:)
139
+ # Since `after_block` must be present for this method to work,
140
+ # the assumption is we never inseart a block inside an empty block, but
141
+ # always after the end of one. For that reason, ident defaults to false.
142
+ indent = false
143
+ block_start = find_block_start(starting_from: after_block, lines: lines)
144
+ block_end = find_block_end(starting_from: block_start, lines: lines)
145
+ lines = insert_line(block_content[0], block_end, lines, indent)
146
+ insert_line(block_content[1], block_end + 1, lines, indent)
147
+ end
146
148
 
147
- lines.each_with_index do |line, index|
148
- if line.match?(matcher)
149
- starting_line = index
150
- break
149
+ def find_block_parent(starting_line_number, lines)
150
+ return nil unless indentation_of(starting_line_number, lines)
151
+ cursor = starting_line_number
152
+ while cursor >= 0
153
+ unless lines[cursor].match?(/^#{indentation_of(starting_line_number, lines)}/) || !lines[cursor].present?
154
+ return cursor
155
+ end
156
+ cursor -= 1
157
+ end
158
+ nil
151
159
  end
152
- end
153
- starting_line
154
- end
155
160
 
156
- def self.find_block_end(starting_from:, lines:)
157
- # This loop was previously in the RoutesFileManipulator.
158
- lines.each_with_index do |line, line_number|
159
- next unless line_number > starting_from
160
- if /^#{indentation_of(starting_from, lines)}end\s*/.match?(line)
161
- return line_number
161
+ def find_block_start(starting_from:, lines:)
162
+ matcher = Regexp.escape(starting_from)
163
+ starting_line = 0
164
+
165
+ lines.each_with_index do |line, index|
166
+ if line.match?(matcher)
167
+ starting_line = index
168
+ break
169
+ end
170
+ end
171
+ starting_line
162
172
  end
163
- end
164
173
 
165
- depth = 0
166
- current_line = starting_from
167
- lines[starting_from..lines.count].each_with_index do |line, index|
168
- current_line = starting_from + index
169
- depth += 1 if line.match?(/\s*<%.+ do .*%>/)
170
- depth += 1 if line.match?(/\s*<% if .*%>/)
171
- depth += 1 if line.match?(/\s*<% unless .*%>/)
172
- depth -= 1 if line.match?(/\s*<%.* end .*%>/)
173
- break current_line if depth == 0
174
- end
175
- current_line
176
- end
174
+ def find_block_end(starting_from:, lines:)
175
+ # This loop was previously in the RoutesFileManipulator.
176
+ lines.each_with_index do |line, line_number|
177
+ next unless line_number > starting_from
178
+ if /^#{indentation_of(starting_from, lines)}end\s*/.match?(line)
179
+ return line_number
180
+ end
181
+ end
177
182
 
178
- # TODO: We shouldn't need this second argument, but since
179
- # we have `lines` here and in the RoutesFileManipulator,
180
- # the lines diverge from one another when we edit them individually.
181
- def self.indentation_of(line_number, lines)
182
- lines[line_number].match(/^( +)/)[1]
183
- rescue
184
- nil
185
- end
183
+ depth = 0
184
+ current_line = starting_from
185
+ lines[starting_from..lines.count].each_with_index do |line, index|
186
+ current_line = starting_from + index
187
+ depth += 1 if line.match?(/\s*<%.+ do .*%>/)
188
+ depth += 1 if line.match?(/\s*<% if .*%>/)
189
+ depth += 1 if line.match?(/\s*<% unless .*%>/)
190
+ depth -= 1 if line.match?(/\s*<%.* end .*%>/)
191
+ break current_line if depth == 0
192
+ end
193
+ current_line
194
+ end
186
195
 
187
- # Shifts the block either to the left or right.
188
- def self.shift_block(lines:, block_start:, direction: :left, amount: 2, shift_contents_only: false)
189
- block_start = lines.index(block_start) if block_start.is_a? String
190
- block_range = (block_start..(find_block_end(starting_from: block_start, lines: lines)))
191
- block_range = (block_range.first + 1)..(block_range.last - 1) if shift_contents_only
192
- new_lines = []
193
-
194
- lines.each_with_index do |line, line_number|
195
- if block_range.cover?(line_number)
196
- # If we're shifting a block to the left, we want to safeguard
197
- # the String so it doesn't delete any excess characters.
198
- if direction == :left
199
- amount.times { line = line.gsub(/^\s/, "") }
200
- elsif direction == :right
201
- line = "\s" * amount + line
196
+ # TODO: We shouldn't need this second argument, but since
197
+ # we have `lines` here and in the RoutesFileManipulator,
198
+ # the lines diverge from one another when we edit them individually.
199
+ def indentation_of(line_number, lines)
200
+ lines[line_number].match(/^( +)/)[1]
201
+ rescue
202
+ nil
203
+ end
204
+
205
+ # Shifts the block either to the left or right.
206
+ def shift_block(lines:, block_start:, direction: :left, amount: 2, shift_contents_only: false)
207
+ block_start = lines.index(block_start) if block_start.is_a? String
208
+ block_range = (block_start..(find_block_end(starting_from: block_start, lines: lines)))
209
+ block_range = (block_range.first + 1)..(block_range.last - 1) if shift_contents_only
210
+ new_lines = []
211
+
212
+ lines.each_with_index do |line, line_number|
213
+ if block_range.cover?(line_number)
214
+ # If we're shifting a block to the left, we want to safeguard
215
+ # the String so it doesn't delete any excess characters.
216
+ if direction == :left
217
+ amount.times { line = line.gsub(/^ /, "") }
218
+ elsif direction == :right
219
+ line = "\s" * amount + line
220
+ end
221
+ end
222
+ new_lines << line
202
223
  end
224
+
225
+ new_lines
203
226
  end
204
- new_lines << line
205
- end
206
227
 
207
- new_lines
228
+ private
229
+
230
+ def prepare_content_array(content)
231
+ # Ensure content is an Array
232
+ content = [content].flatten
233
+
234
+ # Ensure there are no stray new lines within each string
235
+ content = content.map { |line| line.split("\n") }.flatten
236
+
237
+ # Ensure each new line has a line break at the end.
238
+ content.map { |line| line.match?(/\n$/) ? line : "#{line}\n" }
239
+ end
240
+ end
208
241
  end
209
242
  end
@@ -3,7 +3,7 @@ require "scaffolding/block_manipulator"
3
3
  # TODO: If we move this and the BlockManipulator into their own gems,
4
4
  # we can probably call these methods with something shorter without `Scaffolding::`.
5
5
  module Scaffolding::FileManipulator
6
- def self.find(lines, needle, within = nil)
6
+ def self.find(lines, needle, within = 0)
7
7
  lines_within(lines, within).each_with_index do |line, line_number|
8
8
  return (within + (within ? 1 : 0) + line_number) if line.match?(needle)
9
9
  end
@@ -15,11 +15,6 @@ module Scaffolding::FileManipulator
15
15
  lines[(within + 1)..(Scaffolding::BlockManipulator.find_block_end(starting_from: within, lines: lines) + 1)]
16
16
  end
17
17
 
18
- # TODO I was running into an error in a downstream application where it couldn't find silence_logs? We should implement it in this package.
19
- def self.silence_logs?
20
- ENV["SILENCE_LOGS"].present?
21
- end
22
-
23
18
  def self.replace_line_in_file(file, content, in_place_of, options = {})
24
19
  begin
25
20
  target_file_content = File.read(file)
@@ -10,11 +10,6 @@ def legacy_resolve_template_path(file)
10
10
  end.compact.first || raise("Couldn't find the Super Scaffolding template for `#{file}` in any of the following locations:\n\n#{BulletTrain::SuperScaffolding.template_paths.join("\n")}")
11
11
  end
12
12
 
13
- # TODO I was running into an error in a downstream application where it couldn't find silence_logs? We should implement it in this package.
14
- def silence_logs?
15
- ENV["SILENCE_LOGS"].present?
16
- end
17
-
18
13
  def legacy_replace_in_file(file, before, after)
19
14
  puts "Replacing in '#{file}'." unless silence_logs?
20
15
  target_file_content = File.read(file)
@@ -1,9 +1,10 @@
1
1
  require "scaffolding/block_manipulator"
2
2
 
3
3
  class Scaffolding::RoutesFileManipulator
4
- attr_accessor :child, :parent, :lines, :transformer_options
4
+ attr_accessor :child, :parent, :lines, :transformer_options, :concerns
5
5
 
6
6
  def initialize(filename, child, parent, transformer_options = {})
7
+ @concerns = []
7
8
  self.child = child
8
9
  self.parent = parent
9
10
  @filename = filename
@@ -375,17 +376,34 @@ class Scaffolding::RoutesFileManipulator
375
376
  within = find_or_convert_resource_block(parent_resource, options: "except: collection_actions", within: within)
376
377
  end
377
378
 
378
- find_or_create_resource(child_namespaces + [child_resource], options: define_concerns, within: within)
379
+ add_concern(:sortable) if transformer_options["sortable"]
380
+ find_or_create_resource(child_namespaces + [child_resource], options: formatted_concerns, within: within)
379
381
 
380
382
  end
381
383
  end
382
384
 
383
- # Pushing custom concerns here will add them to the routes file when Super Scaffolding.
384
- def define_concerns
385
- concerns = []
386
- concerns.push(:sortable) if transformer_options["sortable"]
385
+ def add_concern(concern)
386
+ @concerns.push(concern)
387
+ end
388
+
389
+ def formatted_concerns
390
+ return if @concerns.empty?
391
+ "concerns: #{@concerns}"
392
+ end
387
393
 
388
- return if concerns.empty?
389
- "concerns: #{concerns}"
394
+ # Adds a concern to an existing resource at the given line number. (used by the audit logs gem)
395
+ def add_concern_at_line(concern, line_number)
396
+ line = lines[line_number]
397
+ existing_concerns = line.match(/concerns: \[(.*)\]/).to_a[1].to_s.split(",")
398
+ existing_concerns.map! { |e| e.tr(":", "").tr("\"", "").squish&.to_sym }
399
+ existing_concerns.filter! { |e| e.present? }
400
+ existing_concerns << concern
401
+ if line.include?("concerns:")
402
+ lines[line_number].gsub!(/concerns: \[(.*)\]/, "concerns: [#{existing_concerns.map { |e| ":#{e}" }.join(", ")}]")
403
+ elsif line.ends_with?(" do")
404
+ lines[line_number].gsub!(/ do$/, " concerns: [#{existing_concerns.map { |e| ":#{e}" }.join(", ")}] do")
405
+ else
406
+ lines[line_number].gsub!(/resources :(.*)$/, "resources :\\1, concerns: [#{existing_concerns.map { |e| ":#{e}" }.join(", ")}]")
407
+ end
390
408
  end
391
409
  end
@@ -23,6 +23,16 @@ class Scaffolding::Transformer
23
23
  "Team"
24
24
  end
25
25
 
26
+ def top_level_model?
27
+ parent == "Team" || no_parent?
28
+ end
29
+
30
+ # We write an explicit method here so we know we
31
+ # aren't handling `parent` in this situation as `nil`.
32
+ def no_parent?
33
+ parent == "None"
34
+ end
35
+
26
36
  def update_action_models_abstract_class(targets_n)
27
37
  end
28
38
 
@@ -41,7 +51,9 @@ class Scaffolding::Transformer
41
51
  RUBY_NEW_FIELDS_HOOK = "# 🚅 super scaffolding will insert new fields above this line."
42
52
  RUBY_ADDITIONAL_NEW_FIELDS_HOOK = "# 🚅 super scaffolding will also insert new fields above this line."
43
53
  RUBY_EVEN_MORE_NEW_FIELDS_HOOK = "# 🚅 super scaffolding will additionally insert new fields above this line."
54
+ RUBY_NEW_API_VERSION_HOOK = "# 🚅 super scaffolding will insert new api versions above this line."
44
55
  RUBY_FILES_HOOK = "# 🚅 super scaffolding will insert file-related logic above this line."
56
+ RUBY_FACTORY_SETUP_HOOK = "# 🚅 super scaffolding will insert factory setup in place of this line."
45
57
  ERB_NEW_FIELDS_HOOK = "<%#{RUBY_NEW_FIELDS_HOOK} %>"
46
58
  CONCERNS_HOOK = "# 🚅 add concerns above."
47
59
  ATTR_ACCESSORS_HOOK = "# 🚅 add attribute accessors above."
@@ -251,11 +263,6 @@ class Scaffolding::Transformer
251
263
  transformed_file_content.join
252
264
  end
253
265
 
254
- # TODO I was running into an error in a downstream application where it couldn't find silence_logs? We should implement it in this package.
255
- def silence_logs?
256
- ENV["SILENCE_LOGS"].present?
257
- end
258
-
259
266
  def scaffold_file(file, overrides: false)
260
267
  transformed_file_content = get_transformed_file_content(file)
261
268
  transformed_file_name = transform_string(file)
@@ -290,6 +297,9 @@ class Scaffolding::Transformer
290
297
 
291
298
  Dir.foreach(resolve_template_path(directory)) do |file|
292
299
  file = "#{directory}/#{file}"
300
+
301
+ next if file.match?("/_menu_item.html.erb") && !top_level_model?
302
+
293
303
  unless File.directory?(resolve_template_path(file))
294
304
  scaffold_file(file)
295
305
  end
@@ -305,6 +315,9 @@ class Scaffolding::Transformer
305
315
  if override_path
306
316
  Dir.foreach(override_path) do |file|
307
317
  file = "#{directory}_overrides/#{file}"
318
+
319
+ next if file.match?("/_menu_item.html.erb") && !top_level_model?
320
+
308
321
  unless File.directory?(resolve_template_path(file))
309
322
  scaffold_file(file, overrides: true)
310
323
  end
@@ -571,15 +584,15 @@ class Scaffolding::Transformer
571
584
  def add_has_many_association
572
585
  has_many_line = ["has_many :completely_concrete_tangible_things"]
573
586
 
574
- # TODO I _think_ this is the right way to check for whether we need `class_name` to specify the name of the model.
575
- unless transform_string("completely_concrete_tangible_things").classify == child
587
+ # Specify the class name if the model is namespaced.
588
+ if child.match?("::")
576
589
  has_many_line << "class_name: \"Scaffolding::CompletelyConcrete::TangibleThing\""
577
590
  end
578
591
 
579
592
  has_many_line << "dependent: :destroy"
580
593
 
581
- # TODO I _think_ this is the right way to check for whether we need `foreign_key` to specify the name of the model.
582
- unless transform_string("absolutely_abstract_creative_concept_id") == "#{parent.underscore}_id"
594
+ # Specify the foreign key if the parent is namespaced.
595
+ if parent.match?("::")
583
596
  has_many_line << "foreign_key: :absolutely_abstract_creative_concept_id"
584
597
 
585
598
  # And if we need `foreign_key`, we should also specify `inverse_of`.
@@ -914,7 +927,8 @@ class Scaffolding::Transformer
914
927
  field_content.gsub!(/\s%>/, ", options: { password: true } %>")
915
928
  end
916
929
 
917
- scaffold_add_line_to_file("./app/views/account/scaffolding/completely_concrete/tangible_things/show.html.erb", field_content.strip, ERB_NEW_FIELDS_HOOK, prepend: true)
930
+ show_page_doesnt_exist = child == "User"
931
+ scaffold_add_line_to_file("./app/views/account/scaffolding/completely_concrete/tangible_things/show.html.erb", field_content.strip, ERB_NEW_FIELDS_HOOK, prepend: true, suppress_could_not_find: show_page_doesnt_exist)
918
932
 
919
933
  end
920
934
 
@@ -931,6 +945,20 @@ class Scaffolding::Transformer
931
945
  scaffold_add_line_to_file("./app/views/account/scaffolding/completely_concrete/tangible_things/_index.html.erb", field_content, "<%# 🚅 super scaffolding will insert new field headers above this line. %>", prepend: true)
932
946
  end
933
947
 
948
+ # If these strings are the same, we get duplicate variable names in the _index.html.erb partial,
949
+ # so we account for that here. Run the Super Scaffolding test setup script and check the index partial
950
+ # of models with namespaced parents for reference (i.e. - Objective, Projects::Step).
951
+ transformed_abstract_str = transform_string("absolutely_abstract_creative_concept")
952
+ transformed_concept_str = transform_string("creative_concept")
953
+ transformed_file_name = transform_string("./app/views/account/scaffolding/completely_concrete/tangible_things/_index.html.erb")
954
+ if (transformed_abstract_str == transformed_concept_str) && File.exist?(transformed_file_name)
955
+ replace_in_file(
956
+ transformed_file_name,
957
+ "#{transformed_abstract_str} = @#{transformed_abstract_str} || @#{transformed_concept_str}",
958
+ "#{transformed_abstract_str} = @#{transformed_concept_str}"
959
+ )
960
+ end
961
+
934
962
  table_cell_options = []
935
963
 
936
964
  if first_table_cell
@@ -1393,8 +1421,21 @@ class Scaffolding::Transformer
1393
1421
  add_ability_line_to_roles_yml
1394
1422
  end
1395
1423
 
1424
+ # Add factory setup in API controller test.
1396
1425
  unless cli_options["skip-api"]
1397
- scaffold_replace_line_in_file("./test/controllers/api/v1/scaffolding/completely_concrete/tangible_things_controller_test.rb", build_factory_setup.join("\n"), "# 🚅 super scaffolding will insert factory setup in place of this line.")
1426
+ test_name = transform_string("./test/controllers/api/v1/scaffolding/completely_concrete/tangible_things_controller_test.rb")
1427
+ test_lines = File.open(test_name).readlines
1428
+
1429
+ # Shift contents of controller test after skipping `unless scaffolding_things_disabled?` block.
1430
+ class_block_index = Scaffolding::FileManipulator.find(test_lines, "class #{transform_string("Api::V1::Scaffolding::CompletelyConcrete::TangibleThingsControllerTest")}")
1431
+ new_lines = Scaffolding::BlockManipulator.shift_block(lines: test_lines, block_start: test_lines[class_block_index], shift_contents_only: true)
1432
+ Scaffolding::FileManipulator.write(test_name, new_lines)
1433
+
1434
+ # Ensure variables built with factories are indented properly.
1435
+ factory_hook_index = Scaffolding::FileManipulator.find(new_lines, RUBY_FACTORY_SETUP_HOOK)
1436
+ factory_hook_indentation = Scaffolding::BlockManipulator.indentation_of(factory_hook_index, new_lines)
1437
+ indented_factory_lines = build_factory_setup.map { |line| "#{factory_hook_indentation}#{line}\n" }
1438
+ scaffold_replace_line_in_file(test_name, indented_factory_lines.join, new_lines[factory_hook_index])
1398
1439
  end
1399
1440
 
1400
1441
  # add children to the show page of their parent.
@@ -1490,7 +1531,7 @@ class Scaffolding::Transformer
1490
1531
  collection_actions = [:index, :new, :create]
1491
1532
 
1492
1533
  # 🚅 Don't remove this block, it will break Super Scaffolding.
1493
- begin do
1534
+ begin
1494
1535
  namespace :#{routes_namespace} do
1495
1536
  shallow do
1496
1537
  resources :teams do
@@ -1505,11 +1546,35 @@ class Scaffolding::Transformer
1505
1546
 
1506
1547
  begin
1507
1548
  routes_manipulator.apply([routes_namespace])
1508
- Scaffolding::FileManipulator.write("config/routes.rb", routes_manipulator.lines)
1549
+ Scaffolding::FileManipulator.write(routes_path, routes_manipulator.lines)
1509
1550
  rescue => _
1510
1551
  add_additional_step :red, "We weren't able to automatically add your `#{routes_namespace}` routes for you. In theory this should be very rare, so if you could reach out on Slack, you could probably provide context that will help us fix whatever the problem was. In the meantime, to add the routes manually, we've got a guide at https://blog.bullettrain.co/nested-namespaced-rails-routing-examples/ ."
1511
1552
  end
1512
1553
 
1554
+ # If we're using a custom namespace, we have to make sure the newly
1555
+ # scaffolded routes are drawn in the `config/routes.rb` and API routes files.
1556
+ if cli_options["namespace"]
1557
+ draw_line = "draw \"#{routes_namespace}\""
1558
+
1559
+ [
1560
+ "config/routes.rb",
1561
+ "config/routes/api/#{BulletTrain::Api.current_version}.rb"
1562
+ ].each do |routes_file|
1563
+ original_lines = File.readlines(routes_file)
1564
+
1565
+ # Define which line we want to place the draw line under in the original routes files.
1566
+ insert_line = if routes_file.match?("api")
1567
+ draw_line = " #{draw_line}" # Add necessary indentation.
1568
+ "namespace :v1 do"
1569
+ else
1570
+ "draw \"sidekiq\""
1571
+ end
1572
+
1573
+ new_lines = Scaffolding::BlockManipulator.insert(draw_line, lines: original_lines, within: insert_line)
1574
+ Scaffolding::FileManipulator.write(routes_file, new_lines)
1575
+ end
1576
+ end
1577
+
1513
1578
  unless cli_options["skip-api"]
1514
1579
  begin
1515
1580
  api_routes_manipulator = Scaffolding::RoutesFileManipulator.new("config/routes/api/#{BulletTrain::Api.current_version}.rb", child, parent, cli_options)
@@ -1523,7 +1588,7 @@ class Scaffolding::Transformer
1523
1588
 
1524
1589
  unless cli_options["skip-parent"]
1525
1590
 
1526
- if parent == "Team" || parent == "None"
1591
+ if top_level_model?
1527
1592
  icon_name = nil
1528
1593
  if cli_options["sidebar"].present?
1529
1594
  icon_name = cli_options["sidebar"]
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.2.9
4
+ version: 1.2.11
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-12-28 00:00:00.000000000 Z
11
+ date: 2023-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: standard
@@ -101,27 +101,21 @@ files:
101
101
  - app/models/scaffolding/completely_concrete/tangible_things/assignment.rb
102
102
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/_breadcrumbs.html.erb
103
103
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/_creative_concept.html.erb
104
- - app/views/account/scaffolding/absolutely_abstract/creative_concepts/_creative_concept.json.jbuilder
105
104
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/_form.html.erb
106
105
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/_index.html.erb
107
106
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/_menu_item.html.erb
108
107
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/collaborators/_breadcrumbs.html.erb
109
- - app/views/account/scaffolding/absolutely_abstract/creative_concepts/collaborators/_collaborator.json.jbuilder
110
108
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/collaborators/_form.html.erb
111
109
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/collaborators/_index.html.erb
112
110
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/collaborators/_menu_item.html.erb
113
111
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/collaborators/edit.html.erb
114
112
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/collaborators/index.html.erb
115
- - app/views/account/scaffolding/absolutely_abstract/creative_concepts/collaborators/index.json.jbuilder
116
113
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/collaborators/new.html.erb
117
114
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/collaborators/show.html.erb
118
- - app/views/account/scaffolding/absolutely_abstract/creative_concepts/collaborators/show.json.jbuilder
119
115
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/edit.html.erb
120
116
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/index.html.erb
121
- - app/views/account/scaffolding/absolutely_abstract/creative_concepts/index.json.jbuilder
122
117
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/new.html.erb
123
118
  - app/views/account/scaffolding/absolutely_abstract/creative_concepts/show.html.erb
124
- - app/views/account/scaffolding/absolutely_abstract/creative_concepts/show.json.jbuilder
125
119
  - app/views/account/scaffolding/completely_concrete/tangible_things/_breadcrumbs.html.erb
126
120
  - app/views/account/scaffolding/completely_concrete/tangible_things/_form.html.erb
127
121
  - app/views/account/scaffolding/completely_concrete/tangible_things/_index.html.erb
@@ -198,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
192
  - !ruby/object:Gem::Version
199
193
  version: '0'
200
194
  requirements: []
201
- rubygems_version: 3.3.7
195
+ rubygems_version: 3.4.1
202
196
  signing_key:
203
197
  specification_version: 4
204
198
  summary: Bullet Train Super Scaffolding
@@ -1,8 +0,0 @@
1
- json.extract! creative_concept,
2
- :id,
3
- :name,
4
- :description,
5
- # 🚅 super scaffolding will insert new fields above this line.
6
- :created_at,
7
- :updated_at
8
- json.url account_scaffolding_absolutely_abstract_creative_concept_url(creative_concept, format: :json)
@@ -1,9 +0,0 @@
1
- json.extract! collaborator,
2
- :id,
3
- :creative_concept_id,
4
- :membership_id,
5
- :roles,
6
- # 🚅 super scaffolding will insert new fields above this line.
7
- :created_at,
8
- :updated_at
9
- json.url account_scaffolding_absolutely_abstract_creative_concepts_collaborator_url(collaborator, format: :json)
@@ -1 +0,0 @@
1
- json.array! @collaborators, partial: "scaffolding/absolutely_abstract/creative_concepts/collaborators/collaborator", as: :collaborator
@@ -1 +0,0 @@
1
- json.partial! "scaffolding/absolutely_abstract/creative_concepts/collaborators/collaborator", collaborator: @collaborator
@@ -1 +0,0 @@
1
- json.array! @creative_concepts, partial: "scaffolding/absolutely_abstract/creative_concepts/creative_concept", as: :creative_concept
@@ -1 +0,0 @@
1
- json.partial! "scaffolding/absolutely_abstract/creative_concepts/creative_concept", creative_concept: @creative_concept