lib/erb/formatter.rb in erb-formatter-0.1.1 vs lib/erb/formatter.rb in erb-formatter-0.2.0
- old
+ new
@@ -1,18 +1,18 @@
# frozen_string_literal: false
-# $DEBUG = true
+# @debug = true
require "erb"
require "cgi"
require "ripper"
require 'securerandom'
require 'strscan'
require 'pp'
require 'stringio'
class ERB::Formatter
- VERSION = "0.1.1"
+ VERSION = "0.2.0"
autoload :IgnoreList, 'erb/formatter/ignore_list'
class Error < StandardError; end
# https://stackoverflow.com/a/317081
@@ -60,18 +60,19 @@
def self.format(source, filename: nil)
new(source, filename: filename).html
end
- def initialize(source, line_width: 80, filename: nil)
+ def initialize(source, line_width: 80, filename: nil, debug: $DEBUG)
@original_source = source
@filename = filename || '(erb)'
@line_width = line_width
@source = source.dup
@html = +""
+ @debug = debug
- html.extend DebugShovel if $DEBUG
+ html.extend DebugShovel if @debug
@tag_stack = []
@pre_pos = 0
build_uid = -> { ['erb', SecureRandom.uuid, 'tag'].join.delete('-') }
@@ -166,17 +167,17 @@
end
end
def tag_stack_push(tag_name, code)
tag_stack << [tag_name, code]
- p PUSH: tag_stack if $DEBUG
+ p PUSH: tag_stack if @debug
end
def tag_stack_pop(tag_name, code)
if tag_name == tag_stack.last&.first
tag_stack.pop
- p POP_: tag_stack if $DEBUG
+ p POP_: tag_stack if @debug
else
raise "Unmatched close tag, tried with #{[tag_name, code]}, but #{tag_stack.last} was on the stack"
end
end
@@ -199,27 +200,37 @@
indent = " " * tag_stack.size
"\n#{indent}#{string.strip}"
end
def format_text(text)
+ p format_text: text if @debug
starting_space = text.match?(/\A\s/)
final_newlines_count = text.match(/(\s*)\z/m).captures.last.count("\n")
html << "\n" if final_newlines_count > 1
return if text.match?(/\A\s*\z/m) # empty
text = text.gsub(/\s+/m, ' ').strip
- offset = (starting_space ? indented("") : "").size
+ offset = indented("").size
+ # Restore full line width if there are less than 40 columns available
+ offset = 0 if (line_width - offset) <= 40
+ available_width = line_width - offset
+
lines = []
until text.empty?
- lines << text.slice!(0..text.rindex(' ', -(line_width - offset)))
+ if text.size >= available_width
+ last_space_index = text[0..available_width].rindex(' ')
+ lines << text.slice!(0..last_space_index)
+ else
+ lines << text.slice!(0..-1)
+ end
offset = 0
end
-
+ p lines: lines if @debug
html << lines.shift.strip unless starting_space
lines.each do |line|
html << indented(line)
end
end
@@ -251,36 +262,38 @@
def format_ruby(code, autoclose: false)
if autoclose
code += "\nend" unless ERB_OPEN_BLOCK["#{code}\nend"]
code += "\n}" unless ERB_OPEN_BLOCK["#{code}\n}"]
end
- p RUBY_IN_: code if $DEBUG
+ p RUBY_IN_: code if @debug
offset = tag_stack.size * 2
if defined? Rubocop
code = format_code_with_rubocop(code, line_width - offset) if (offset + code.size) > line_width
elsif defined?(Rufo)
code = Rufo.format(code) rescue code
end
lines = code.strip.lines
lines = lines[0...-1] if autoclose
- code = lines.map { indented(_1) }.join.strip
- p RUBY_OUT: code if $DEBUG
+ code = lines.map { |l| indented(l) }.join.strip
+ p RUBY_OUT: code if @debug
code
end
def format_erb_tags(string)
+ p format_erb_tags: string if @debug
if %w[style script].include?(tag_stack.last&.first)
html << string.rstrip
return
end
erb_scanner = StringScanner.new(string.to_s)
erb_pre_pos = 0
until erb_scanner.eos?
if erb_scanner.scan_until(erb_tags_regexp)
+ p PRE_MATCH: [erb_pre_pos, '..', erb_scanner.pre_match]
erb_pre_match = erb_scanner.pre_match
erb_pre_match = erb_pre_match[erb_pre_pos..]
erb_pre_pos = erb_scanner.pos
erb_code = erb_tags[erb_scanner.captures.first]
@@ -306,10 +319,11 @@
else
ruby_code = format_ruby(ruby_code, autoclose: false)
html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag)
end
else
+ p ERB_REST: erb_scanner.rest if @debug
rest = erb_scanner.rest.to_s
format_text(rest)
erb_scanner.terminate
end
end
@@ -317,14 +331,16 @@
def format
scanner = StringScanner.new(source)
until scanner.eos?
-
if matched = scanner.scan_until(tags_regexp)
+ p format_pre_match: [pre_pos, '..', scanner.pre_match[pre_pos..]] if @debug
pre_match = scanner.pre_match[pre_pos..]
- self.pre_pos = scanner.pos
+ p POS: pre_pos...scanner.pos, advanced: source[pre_pos...scanner.pos] if @debug
+ p MATCHED: matched if @debug
+ self.pre_pos = scanner.charpos
# Don't accept `name= "value"` attributes
raise "Bad attribute, please fix spaces after the equal sign." if BAD_ATTR.match? pre_match
format_erb_tags(pre_match) if pre_match
@@ -350,9 +366,10 @@
tag_stack_push(tag_name, full_tag) unless tag_self_closing
else
raise "Unrecognized content: #{matched.inspect}"
end
else
+ p format_rest: scanner.rest if @debug
format_erb_tags(scanner.rest.to_s)
scanner.terminate
end
end