Skip to content

Commit d497d21

Browse files
committed
Support interpolated strings in compiled content blocks
Closes #926
1 parent 370ce09 commit d497d21

File tree

5 files changed

+70
-5
lines changed

5 files changed

+70
-5
lines changed

.rubocop.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ inherit_from:
33

44
AllCops:
55
TargetRubyVersion: 3.2
6+
Exclude:
7+
- "quickdraw/compilation_equivalence_cases/**/*.rb"
8+
69

710
# We need to disable this cop because it’s not compatible with TruffleRuby 23.1, which still needs a `require "set"`
811
Lint/RedundantRequireStatement:

comp_test.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# frozen_string_literal: true
2+
3+
require "phlex"
4+
5+
class FlexHTML < Phlex::HTML
6+
def view_template
7+
__buffer__ = @_state.buffer; __buffer__ << "<h1></h1><h1>"
8+
__yield_content__ { "Hello" }; __buffer__ << "</h1><div" \
9+
<< __attributes__(class: "foo"); __buffer__ << "></div><div" \
10+
<< __attributes__(class: "foo"); __buffer__ << ">"; __yield_content__ { "World" }; __buffer__ << "</div>"
11+
end
12+
end
13+
14+
puts FlexHTML.new.call

lib/phlex/compiler.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
require "prism"
44

55
module Phlex::Compiler
6+
Error = Class.new(StandardError)
7+
68
def self.compile(component)
79
path, line = Object.const_source_location(component.name)
810
return unless File.exist?(path)

lib/phlex/compiler/method_compiler.rb

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ def visit_phlex_block(node)
9696
case content
9797
when Prism::StringNode
9898
buffer(Phlex::Escape.html_escape(content.unescaped))
99+
when Prism::InterpolatedStringNode
100+
compile_interpolated_string_node(content)
99101
else
100102
raise
101103
end
@@ -124,6 +126,31 @@ def compile_block_body_node(node)
124126
]
125127
end
126128

129+
def compile_interpolated_string_node(node)
130+
node.parts.map do |part|
131+
case part
132+
when Prism::StringNode
133+
buffer(Phlex::Escape.html_escape(part.unescaped))
134+
when Prism::EmbeddedVariableNode
135+
[
136+
buffer('#{'),
137+
buffer("::Phlex::Escape.html_escape(("),
138+
buffer(part.variable.slice),
139+
buffer(").to_s)}"),
140+
]
141+
when Prism::EmbeddedStatementsNode
142+
[
143+
buffer('#{'),
144+
buffer("::Phlex::Escape.html_escape(("),
145+
buffer(part.statements.slice, escape: false),
146+
buffer(").to_s)}"),
147+
]
148+
else
149+
raise Phlex::Compiler::Error, "Unexpected node type in InterpolatedStringNode: #{part.class}"
150+
end
151+
end
152+
end
153+
127154
def compile_void_element(node, tag)
128155
[
129156
[
@@ -217,19 +244,27 @@ def compile_raw_helper(node)
217244
@current_buffer = nil
218245
end
219246

220-
private def buffer(value)
247+
private def buffer(value, escape: true)
221248
if @current_buffer
222-
@current_buffer << value
249+
if escape
250+
@current_buffer << value.gsub('"', '\\"')
251+
else
252+
@current_buffer << value
253+
end
223254
nil
224255
else
225256
new_buffer = +""
226257
@current_buffer = new_buffer
227-
new_buffer << value
258+
if escape
259+
new_buffer << value.gsub('"', '\\"')
260+
else
261+
new_buffer << value
262+
end
228263

229264
[
230265
:new_line,
231266
"#{buffer_local} << \"",
232-
-> { new_buffer.gsub('"', '\\"') },
267+
new_buffer,
233268
"\" if #{should_render_local}; nil;",
234269
]
235270
end
@@ -250,7 +285,7 @@ def compile_raw_helper(node)
250285

251286
private def content_block?(node)
252287
return false unless node.body.body.length == 1
253-
node.body.body.first in Prism::StringNode
288+
node.body.body.first in Prism::StringNode | Prism::InterpolatedStringNode
254289
end
255290

256291
private def standard_element?(node)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# frozen_string_literal: true
2+
3+
class InterpolatedString < Phlex::HTML
4+
def view_template
5+
name = "Joel"
6+
@ivar = "Will"
7+
h1 { "Hello, #{name}!" }
8+
h2 { "Hello, #@ivar!" } # rubocop:disable Style/VariableInterpolation
9+
h3 { "Hello #{"#{name}"}" }
10+
end
11+
end

0 commit comments

Comments
 (0)