bullet_train-super_scaffolding 1.2.8 → 1.2.10
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 +213 -180
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a6b8531f537d4602893ec912e8b2a5d4c0098418d247273d0bd3b06f6bc6b52
|
4
|
+
data.tar.gz: 2df15d02e422183c0ff5120e886081cde75396ec444fce92c5ec3e0c28c20f81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe62bc608b0af044613a6a6d6ef2653f8143a76ef3f0e261df8d77ccdc98460f78349267624791c261b8c9be0b223c75e53179e189b7c4343b821bc0c5719cf6
|
7
|
+
data.tar.gz: 1191a1288797016d937ba7d8af3a466dda7050545d65a3bc3b58ebf28eca98792554f65280ea94f8e30d559cd478bd215beb0c7f307ec3ab66241e874fc9b532
|
@@ -1,209 +1,242 @@
|
|
1
1
|
require "scaffolding/file_manipulator"
|
2
2
|
|
3
|
-
module Scaffolding
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
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
|
-
|
65
|
-
|
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
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
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
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
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
|
-
|
144
|
-
|
145
|
-
|
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
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
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
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
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
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
if
|
199
|
-
|
200
|
-
|
201
|
-
|
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
|
-
|
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.
|
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-
|
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.
|
201
|
+
rubygems_version: 3.4.1
|
202
202
|
signing_key:
|
203
203
|
specification_version: 4
|
204
204
|
summary: Bullet Train Super Scaffolding
|