Skip to content

Commit

Permalink
Supports ERB-tags with if-else-end in same tag (#61)
Browse files Browse the repository at this point in the history
- Fixes #60
- Release v0.10.3
  • Loading branch information
davidwessman authored Aug 27, 2023
1 parent f24718a commit f8559fe
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 45 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a

## [Unreleased]

## [0.10.3] - 2023-08-27

## Fixes

- Allows parsing ERB-tags with if, else and end in the same tag

```erb
<%= if true
what
end %>
```

This opens the possibility for formatting all if-statements with SyntaxTree properly
and removes the fix where any if-statement was force to one line.

## [0.10.2] - 2023-08-22

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
w_syntax_tree-erb (0.10.2)
w_syntax_tree-erb (0.10.3)
prettier_print (~> 1.2, >= 1.2.0)
syntax_tree (~> 6.1, >= 6.1.1)

Expand Down
23 changes: 3 additions & 20 deletions lib/syntax_tree/erb/format.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def visit_erb(node)
q.text(" ")
visit(node.keyword)
end
node.content.nil? ? q.text(" ") : visit(node.content)
node.content.blank? ? q.text(" ") : visit(node.content)

visit(node.closing_tag)
end
Expand Down Expand Up @@ -163,7 +163,8 @@ def visit_erb_content(node)

def format_statement(statement)
formatter =
SyntaxTree::Formatter.new("", [], erb_print_width(statement))
SyntaxTree::Formatter.new("", [], SyntaxTree::ERB::MAX_WIDTH)

formatter.format(statement)
formatter.flush
rows = formatter.output.join.split("\n")
Expand Down Expand Up @@ -305,24 +306,6 @@ def node_new_line_count(node)
node.respond_to?(:new_line) ? node.new_line&.count || 0 : 0
end

def erb_print_width(node)
# Set the width to maximum if we have an IfNode or IfOp,
# we cannot format them purely with SyntaxTree because the ERB-syntax will be unparseable.
check_for_if_statement(node) ? 999_999 : SyntaxTree::ERB::MAX_WIDTH
end

def check_for_if_statement(node)
return false if node.nil?

if node.is_a?(SyntaxTree::IfNode) || node.is_a?(SyntaxTree::IfOp)
return true
end

node.child_nodes.any? do |child_node|
check_for_if_statement(child_node)
end
end

def handle_child_nodes(child_nodes)
group = []

Expand Down
52 changes: 34 additions & 18 deletions lib/syntax_tree/erb/nodes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -295,16 +295,7 @@ def initialize(
)
end

@content =
if content.is_a?(ErbContent)
content
else
# Set content to nil if it is empty
content ||= []
content = content.map(&:value).join if content.is_a?(Array)
ErbContent.new(value: content) unless content.strip.empty?
end

@content = prepare_content(content)
@closing_tag = closing_tag
end

Expand Down Expand Up @@ -338,6 +329,24 @@ def deconstruct_keys(keys)
closing_tag: closing_tag
)
end

private

def prepare_content(content)
if content.is_a?(ErbContent)
content
else
# Set content to nil if it is empty
content ||= []

ErbContent.new(value: content)
end
rescue SyntaxTree::Parser::ParseError
# Try to add the keyword to see if it parses
result = ErbContent.new(value: [keyword, *content])
@keyword = nil
result
end
end

class ErbBlock < Block
Expand Down Expand Up @@ -413,7 +422,7 @@ def accept(visitor)

class ErbElse < ErbIf
def accept(visitor)
visitor.visit_erb_if(self)
visitor.visit_erb_else(self)
end
end

Expand Down Expand Up @@ -448,16 +457,23 @@ def accept(visitor)
end

class ErbContent < Node
attr_reader(:value, :unparsed_value)
attr_reader(:value)

def initialize(value:)
@unparsed_value = value
begin
@value = SyntaxTree.parse(value.strip)
rescue SyntaxTree::Parser::ParseError
# Removes leading and trailing whitespace
@value = value&.lstrip&.rstrip
if value.is_a?(Array)
value =
value.map { |token| token.is_a?(Token) ? token.value : token }.join
end
@value = SyntaxTree.parse(value.strip)
end

def blank?
value.nil? ||
value
.statements
.child_nodes
.reject { |node| node.is_a?(SyntaxTree::VoidStmt) }
.empty?
end

def accept(visitor)
Expand Down
2 changes: 1 addition & 1 deletion lib/syntax_tree/erb/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ def parse_erb_tag
location: opening_tag.location.to(closing_tag.location)
)

case keyword&.type
case erb_node.keyword&.type
when :erb_if, :erb_unless, :erb_elsif
parse_erb_if(erb_node)
when :erb_case, :erb_when
Expand Down
2 changes: 1 addition & 1 deletion lib/syntax_tree/erb/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

module SyntaxTree
module ERB
VERSION = "0.10.2"
VERSION = "0.10.3"
end
end
39 changes: 36 additions & 3 deletions test/erb_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,44 @@ def test_erb_code_with_non_ascii
assert_instance_of(SyntaxTree::ERB::ErbNode, parsed.elements.first)
end

def test_if_and_end_in_same_output_tag_short
source = "<%= if true\n what\nend %>"
expected = "<%= what if true %>\n"

assert_formatting(source, expected)
end

def test_if_and_end_in_same_tag
source = "<% if true then this elsif false then that else maybe end %>"
expected =
"<% if true\n this\nelsif false\n that\nelse\n maybe\nend %>\n"

assert_formatting(source, expected)
end

def test_long_if_statement
source =
"<%=number_to_percentage(@reports&.first&.stability*100,precision: 1) if @reports&.first&.other&.stronger&.longer %>"
expected =
"<%= number_to_percentage(@reports&.first&.stability * 100, precision: 1) if @reports&.first&.other&.stronger&.longer %>\n"
"<%= if @reports&.first&.other&.stronger&.longer\n number_to_percentage(@reports&.first&.stability * 100, precision: 1)\nend %>\n"

assert_formatting(source, expected)
end

def test_erb_else_if_statement
source =
"<%if this%>\n <h1>A</h1>\n<%elsif that%>\n <h1>B</h1>\n<%else%>\n <h1>C</h1>\n<%end%>"
expected =
"<% if this %>\n <h1>A</h1>\n<% elsif that %>\n <h1>B</h1>\n<% else %>\n <h1>C</h1>\n<% end %>\n"

assert_formatting(source, expected)
end

def test_long_ternary
source =
"<%= number_to_percentage(@reports&.first&.stability * 100, precision: @reports&.first&.stability ? 'Stable' : 'Unstable') %>"
expected =
"<%= number_to_percentage(\n @reports&.first&.stability * 100,\n precision: @reports&.first&.stability ? \"Stable\" : \"Unstable\"\n) %>\n"

assert_formatting(source, expected)
end
Expand Down Expand Up @@ -73,9 +106,9 @@ def test_erb_only_erb_comment

def test_erb_ternary_as_argument_without_parentheses
source =
"<%= f.submit f.object.id.present? ? t('buttons.titles.save'):t('buttons.titles.create') %>"
"<%= f.submit( f.object.id.present? ? t('buttons.titles.save'):t('buttons.titles.create')) %>"
expected =
"<%= f.submit f.object.id.present? ? t(\"buttons.titles.save\") : t(\"buttons.titles.create\") %>\n"
"<%= f.submit(\n f.object.id.present? ? t(\"buttons.titles.save\") : t(\"buttons.titles.create\")\n) %>\n"

assert_formatting(source, expected)
end
Expand Down
6 changes: 5 additions & 1 deletion test/fixture/if_statements_formatted.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@
<% end %>
</h1>

<%= @model ? @model.name : t("views.more_than_80_characters_long_row.categories.shared.version.default") %>
<%= if @model
@model.name
else
t("views.more_than_80_characters_long_row.categories.shared.version.default")
end %>

0 comments on commit f8559fe

Please sign in to comment.