Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for case/when #23

Merged
merged 5 commits into from
Mar 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 8 additions & 47 deletions lib/erb/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ class Error < StandardError; end

ERB_TAG = %r{(<%(?:==|=|-|))\s*(.*?)\s*(-?%>)}m
ERB_PLACEHOLDER = %r{erb[a-z0-9]+tag}
ERB_END = %r{(<%-?)\s*(end)\s*(-?%>)}
ERB_ELSE = %r{(<%-?)\s*(else|elsif\b.*)\s*(-?%>)}

TAG_NAME = /[a-z0-9_:-]+/
TAG_NAME_ONLY = /\A#{TAG_NAME}\z/
Expand All @@ -49,10 +47,12 @@ class Error < StandardError; end

SELF_CLOSING_TAG = /\A(area|base|br|col|command|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)\z/i

ERB_OPEN_BLOCK = ->(code) do
RUBY_OPEN_BLOCK = ->(code) do
# is nil when the parsing is broken, meaning it's an open expression
Ripper.sexp(code).nil?
end.freeze
RUBY_CLOSE_BLOCK = /\Aend\z/
RUBY_REOPEN_BLOCK = /\A(else|elsif\b(.*)|when\b(.*))\z/

RUBOCOP_STDIN_MARKER = "===================="

Expand Down Expand Up @@ -146,45 +146,6 @@ def format_attributes(tag_name, attrs, tag_closing)
attr_html
end

def format_erb_attributes(string)
erb_scanner = StringScanner.new(string.to_s)
erb_pre_pos = 0
until erb_scanner.eos?
if erb_scanner.scan_until(erb_tags_regexp)
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]

format_attributes(erb_pre_match)

erb_open, ruby_code, erb_close = ERB_TAG.match(erb_code).captures
full_erb_tag = "#{erb_open} #{ruby_code} #{erb_close}"

case ruby_code
when /\Aend\z/
tag_stack_pop('%erb%', ruby_code)
html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag)
when /\A(else|elsif\b(.*))\z/
tag_stack_pop('%erb%', ruby_code)
html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag)
tag_stack_push('%erb%', ruby_code)
when ERB_OPEN_BLOCK
html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag)
tag_stack_push('%erb%', ruby_code)
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
rest = erb_scanner.rest.to_s
format_erb_attributes(rest)
erb_scanner.terminate
end
end
end

def tag_stack_push(tag_name, code)
tag_stack << [tag_name, code]
p PUSH: tag_stack if @debug
Expand Down Expand Up @@ -258,8 +219,8 @@ def format_text(text)

def format_ruby(code, autoclose: false)
if autoclose
code += "\nend" unless ERB_OPEN_BLOCK["#{code}\nend"]
code += "\n}" unless ERB_OPEN_BLOCK["#{code}\n}"]
code += "\nend" unless RUBY_OPEN_BLOCK["#{code}\nend"]
code += "\n}" unless RUBY_OPEN_BLOCK["#{code}\n}"]
end
p RUBY_IN_: code if @debug

Expand Down Expand Up @@ -303,16 +264,16 @@ def format_erb_tags(string)
erb_open << ' ' unless ruby_code.start_with?('#')

case ruby_code
when /\Aend\z/
when RUBY_CLOSE_BLOCK
full_erb_tag = "#{erb_open}#{ruby_code} #{erb_close}"
tag_stack_pop('%erb%', ruby_code)
html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag)
when /\A(else|elsif\b(.*))\z/
when RUBY_REOPEN_BLOCK
full_erb_tag = "#{erb_open}#{ruby_code} #{erb_close}"
tag_stack_pop('%erb%', ruby_code)
html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag)
tag_stack_push('%erb%', ruby_code)
when ERB_OPEN_BLOCK
when RUBY_OPEN_BLOCK
full_erb_tag = "#{erb_open}#{ruby_code} #{erb_close}"
html << (erb_pre_match.match?(/\s+\z/) ? indented(full_erb_tag) : full_erb_tag)
tag_stack_push('%erb%', ruby_code)
Expand Down
10 changes: 10 additions & 0 deletions test/fixtures/case_when.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<% case 'fake' %>
<% when 'fake' %>
<span>there</span>
<% when 'something' %>
<span>there</span>
<% when 'else' %>
<span>hi</span>
<% else %>
<span>there</span>
<% end %>
10 changes: 10 additions & 0 deletions test/fixtures/case_when.html.expected.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<% case 'fake' %>
<% when 'fake' %>
<span>there</span>
<% when 'something' %>
<span>there</span>
<% when 'else' %>
<span>hi</span>
<% else %>
<span>there</span>
<% end %>
22 changes: 22 additions & 0 deletions test/fixtures/complex_case_when.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div>
<% if payment_method.present? %>
<% case payment_method.class.to_s %>
<% when 'Foo::PaymentMethod::FooCreditCard' %>
<% if payment_method.active %>
<span class="card-icon <%= payment_source.cc_type %>"></span>
*<%= payment_source.last_digits %>
<%= payment_source.month %>/<%= payment_source.year %>
<% else %>
<%= t('.payment.card_removed_or_expired') %>
<% end %>
<% when 'Foo::PaymentMethod::Bar' %>
<span><%= t('.payment.invoice') %></span>
<% when 'Foo::PaymentMethod' %>
<span><%= t('.payment.stripe_invoice') %></span>
<% else %>
<% Rails.logger.error.report(StandardError.new("No human readable name found for payment method #{payment_method.class}")) %>
<% end %>
<% else %>
<%= t('.payment.no_payment_method_found') %>
<% end %>
</div>
26 changes: 26 additions & 0 deletions test/fixtures/complex_case_when.html.expected.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<div>
<% if payment_method.present? %>
<% case payment_method.class.to_s %>
<% when 'Foo::PaymentMethod::FooCreditCard' %>
<% if payment_method.active %>
<span class="card-icon <%= payment_source.cc_type %>"></span>
*<%= payment_source.last_digits %>
<%= payment_source.month %>/<%= payment_source.year %>
<% else %>
<%= t(".payment.card_removed_or_expired") %>
<% end %>
<% when 'Foo::PaymentMethod::Bar' %>
<span><%= t(".payment.invoice") %></span>
<% when 'Foo::PaymentMethod' %>
<span><%= t(".payment.stripe_invoice") %></span>
<% else %>
<% Rails.logger.error.report(
StandardError.new(
"No human readable name found for payment method #{payment_method.class}"
)
) %>
<% end %>
<% else %>
<%= t(".payment.no_payment_method_found") %>
<% end %>
</div>