bullet_train-super_scaffolding 1.2.9 → 1.2.10

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: 850aff688799324e6aea7b1569259f09160a10401a2f298fec0c81a9ec418658
4
- data.tar.gz: f8fbdf234386a2931731c6e82efdd8fd2ee99f4d627bad2b1fdd07fd3fd32c30
3
+ metadata.gz: 6a6b8531f537d4602893ec912e8b2a5d4c0098418d247273d0bd3b06f6bc6b52
4
+ data.tar.gz: 2df15d02e422183c0ff5120e886081cde75396ec444fce92c5ec3e0c28c20f81
5
5
  SHA512:
6
- metadata.gz: 671b90bc86112e8babd7d93fc9360257b092498438b4a8f46923ac43d9039f7f0b9f289d340803574162dd2b0e4f31cce98c22bc20ba544ed30f8caace3d14ea
7
- data.tar.gz: 8cc555f6a9f895f67eb6ee2abbae34c109fcce6b75794c5788a5fd45d9bc686c9babd4d5d8ba664d73efc03102ebcbc0eae9f6a048eecca0a0fcc40069b47ff6
6
+ metadata.gz: fe62bc608b0af044613a6a6d6ef2653f8143a76ef3f0e261df8d77ccdc98460f78349267624791c261b8c9be0b223c75e53179e189b7c4343b821bc0c5719cf6
7
+ data.tar.gz: 1191a1288797016d937ba7d8af3a466dda7050545d65a3bc3b58ebf28eca98792554f65280ea94f8e30d559cd478bd215beb0c7f307ec3ab66241e874fc9b532
@@ -1,5 +1,5 @@
1
1
  module BulletTrain
2
2
  module SuperScaffolding
3
- VERSION = "1.2.9"
3
+ VERSION = "1.2.10"
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(/^\s/, "") }
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
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.10
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: 2022-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: standard
@@ -198,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
198
  - !ruby/object:Gem::Version
199
199
  version: '0'
200
200
  requirements: []
201
- rubygems_version: 3.3.7
201
+ rubygems_version: 3.4.1
202
202
  signing_key:
203
203
  specification_version: 4
204
204
  summary: Bullet Train Super Scaffolding