Class: Scaffolding::BlockManipulator
- Inherits:
-
Object
- Object
- Scaffolding::BlockManipulator
- Defined in:
- lib/scaffolding/block_manipulator.rb
Class Method Summary collapse
- .find_block_end(starting_from:, lines:) ⇒ Object
- .find_block_parent(starting_line_number, lines) ⇒ Object
- .find_block_start(starting_from:, lines:) ⇒ Object
-
.indentation_of(line_number, lines) ⇒ Object
TODO: We shouldn’t need this second argument, but since we have ‘lines` here and in the RoutesFileManipulator, the lines diverge from one another when we edit them individually.
- .insert(content, lines:, within: nil, after: nil, before: nil, after_block: nil, append: false) ⇒ Object
- .insert_block(block_content, after_block:, lines:) ⇒ Object
-
.insert_line(content, insert_at_index, lines, indent = true) ⇒ Object
TODO: We should eventually replace this with ‘insert_lines“, I just want to make sure everything doesn’t break first.
- .insert_lines(content, insert_at_index, lines, indent) ⇒ Object
-
.shift_block(lines:, block_start:, direction: :left, amount: 2, shift_contents_only: false) ⇒ Object
Shifts the block either to the left or right.
-
.unwrap_block(lines:, block_start:) ⇒ Object
This method unwraps the block from the perspective of the child.
-
.wrap_block(starting:, with:, lines:) ⇒ Object
Wrap a block of ruby code with another block on the outside.
Class Method Details
.find_block_end(starting_from:, lines:) ⇒ Object
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/scaffolding/block_manipulator.rb', line 174 def find_block_end(starting_from:, lines:) # This loop was previously in the RoutesFileManipulator. lines.each_with_index do |line, line_number| next unless line_number > starting_from if /^#{indentation_of(starting_from, lines)}end\s*/.match?(line) return line_number end end depth = 0 current_line = starting_from lines[starting_from..lines.count].each_with_index do |line, index| current_line = starting_from + index depth += 1 if line.match?(/\s*<%.+ do .*%>/) depth += 1 if line.match?(/\s*<% if .*%>/) depth += 1 if line.match?(/\s*<% unless .*%>/) depth -= 1 if line.match?(/\s*<%.* end .*%>/) break current_line if depth == 0 end current_line end |
.find_block_parent(starting_line_number, lines) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/scaffolding/block_manipulator.rb', line 149 def find_block_parent(starting_line_number, lines) return nil unless indentation_of(starting_line_number, lines) cursor = starting_line_number while cursor >= 0 unless lines[cursor].match?(/^#{indentation_of(starting_line_number, lines)}/) || !lines[cursor].present? return cursor end cursor -= 1 end nil end |
.find_block_start(starting_from:, lines:) ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/scaffolding/block_manipulator.rb', line 161 def find_block_start(starting_from:, lines:) matcher = Regexp.escape(starting_from) starting_line = 0 lines.each_with_index do |line, index| if line.match?(matcher) starting_line = index break end end starting_line end |
.indentation_of(line_number, lines) ⇒ Object
TODO: We shouldn’t need this second argument, but since we have ‘lines` here and in the RoutesFileManipulator, the lines diverge from one another when we edit them individually.
199 200 201 202 203 |
# File 'lib/scaffolding/block_manipulator.rb', line 199 def indentation_of(line_number, lines) lines[line_number].match(/^( +)/)[1] rescue nil end |
.insert(content, lines:, within: nil, after: nil, before: nil, after_block: nil, append: false) ⇒ Object
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/scaffolding/block_manipulator.rb', line 70 def insert(content, lines:, within: nil, after: nil, before: nil, after_block: nil, append: false) content = prepare_content_array(content) # We initialize the search with the entire file's lines and look for the block below. start_line = 0 end_line = lines.count - 1 # Search for before like we do after, we'll just inject before it. after ||= before # If within is given, find the start and end lines of the block if within.present? start_line = find_block_start(starting_from: within, lines: lines) end_line = find_block_end(starting_from: start_line, lines: lines) # start_line += 1 # ensure we actually insert the content _within_ the given block # end_line += 1 if end_line == start_line end if after_block.present? block_start = find_block_start(starting_from: after_block, lines: lines) block_end = find_block_end(starting_from: block_start, lines: lines) start_line = block_end end_line = lines.count - 1 end index = start_line match = false while index < end_line && !match line = lines[index] if after.nil? || line.match?(after) unless append match = true indent = !(before.present? || after.present? || after_block.present?) # We adjust the injection point if we really wanted to insert before. lines = insert_lines(content, index - (before ? 1 : 0), lines, indent) end end index += 1 end return lines if match # Match should always be false here. if append && !match lines = insert_lines(content, index - 1, lines) end lines end |
.insert_block(block_content, after_block:, lines:) ⇒ Object
138 139 140 141 142 143 144 145 146 147 |
# File 'lib/scaffolding/block_manipulator.rb', line 138 def insert_block(block_content, after_block:, lines:) # Since `after_block` must be present for this method to work, # the assumption is we never inseart a block inside an empty block, but # always after the end of one. For that reason, ident defaults to false. indent = false block_start = find_block_start(starting_from: after_block, lines: lines) block_end = find_block_end(starting_from: block_start, lines: lines) lines = insert_line(block_content[0], block_end, lines, indent) insert_line(block_content[1], block_end + 1, lines, indent) end |
.insert_line(content, insert_at_index, lines, indent = true) ⇒ Object
TODO: We should eventually replace this with ‘insert_lines“, I just want to make sure everything doesn’t break first.
134 135 136 |
# File 'lib/scaffolding/block_manipulator.rb', line 134 def insert_line(content, insert_at_index, lines, indent = true) insert_lines(prepare_content_array(content), insert_at_index, lines, indent) end |
.insert_lines(content, insert_at_index, lines, indent) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/scaffolding/block_manipulator.rb', line 120 def insert_lines(content, insert_at_index, lines, indent) final = [] lines.each_with_index do |line, index| indentation = line.match(/^\s*/).to_s indentation += "\s" * 2 if indent final << line content.each { |new_line| final << indentation + new_line } if index == insert_at_index end final end |
.shift_block(lines:, block_start:, direction: :left, amount: 2, shift_contents_only: false) ⇒ Object
Shifts the block either to the left or right.
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/scaffolding/block_manipulator.rb', line 206 def shift_block(lines:, block_start:, direction: :left, amount: 2, shift_contents_only: false) block_start = lines.index(block_start) if block_start.is_a? String block_range = (block_start..(find_block_end(starting_from: block_start, lines: lines))) block_range = (block_range.first + 1)..(block_range.last - 1) if shift_contents_only new_lines = [] lines.each_with_index do |line, line_number| if block_range.cover?(line_number) # If we're shifting a block to the left, we want to safeguard # the String so it doesn't delete any excess characters. if direction == :left amount.times { line = line.gsub(/^ /, "") } elsif direction == :right line = "\s" * amount + line end end new_lines << line end new_lines end |
.unwrap_block(lines:, block_start:) ⇒ Object
This method unwraps the block from the perspective of the child.
2.times do
3.times do
puts "foo"
end
end
Here we would pass the index of ‘“3.times don”` to `block_start` which would result in removing the outer block.
56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/scaffolding/block_manipulator.rb', line 56 def unwrap_block(lines:, block_start:) block_start = if block_start.is_a? String block_start_line = lines.find { |line| line.match?(block_start) } lines.index(block_start_line) end # Find the proper indices for both child and parent blocks. block_parent_start = find_block_parent(block_start, lines) block_parent_end = find_block_end(starting_from: block_parent_start, lines: lines) new_lines = shift_block(lines: lines, block_start: block_start) new_lines.reject.with_index { |lines, idx| idx == block_parent_start || idx == block_parent_end } end |
.wrap_block(starting:, with:, lines:) ⇒ Object
Wrap a block of ruby code with another block on the outside.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/scaffolding/block_manipulator.rb', line 12 def wrap_block(starting:, with:, lines:) with[0] += "\n" unless with[0].match?(/\n$/) with[1] += "\n" unless with[1].match?(/\n$/) starting_line = find_block_start(starting_from: starting, lines: lines) end_line = find_block_end(starting_from: starting_line, lines: lines) final = [] block_indent = "" spacer = " " lines.each_with_index do |line, index| line += "\n" unless line.match?(/\n$/) if index < starting_line final << line elsif index == starting_line block_indent = line.match(/^\s*/).to_s final << block_indent + with[0] final << (line.blank? ? "\n" : "#{spacer}#{line}") elsif index > starting_line && index < end_line final << (line.blank? ? "\n" : "#{spacer}#{line}") elsif index == end_line final << (line.blank? ? "\n" : "#{spacer}#{line}") final << block_indent + with[1] else final << line end end lines = final unless lines.last.match?(/\n$/) lines[-1] += "\n" end lines end |