Skip to content

Commit 3dd3877

Browse files
authored
Direct buffering (#271)
1 parent d1c80b8 commit 3dd3877

32 files changed

+440
-212
lines changed

app/components/nested_table.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# frozen_string_literal: true
2+
3+
class Components::NestedTable < Phlex::HTML
4+
def with_head(&)
5+
@head = Components::NestedTable::RowContainer.new(tag: "thead", &)
6+
end
7+
8+
def with_body(&)
9+
@bodies << Components::NestedTable::RowContainer.new(tag: "tbody", &)
10+
end
11+
12+
def with_foot(&)
13+
@foot = Components::NestedTable::RowContainer.new(tag: "tfoot", &)
14+
end
15+
16+
def initialize
17+
@head = nil
18+
@bodies = []
19+
@foot = nil
20+
end
21+
22+
def before_template(&)
23+
capture(&)
24+
super
25+
end
26+
27+
def view_template(&)
28+
div do
29+
table(border: 2) do
30+
render @head if @head
31+
render @bodies
32+
render @foot if @foot
33+
end
34+
end
35+
end
36+
end

app/components/nested_table/cell.rb

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 Components::NestedTable::Cell < Phlex::HTML
4+
include Phlex::Rails::Helpers::ContentTag
5+
6+
def view_template(&)
7+
td do
8+
yield
9+
end
10+
end
11+
end

app/components/nested_table/row.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
class Components::NestedTable::Row < Phlex::HTML
4+
def initialize
5+
@cells = []
6+
end
7+
8+
def with_cell(&)
9+
@cells << Components::NestedTable::Cell.new(&)
10+
end
11+
12+
def before_template(&)
13+
capture(&)
14+
super
15+
end
16+
17+
def view_template(&)
18+
tr do
19+
render @cells
20+
end
21+
end
22+
end
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# frozen_string_literal: true
2+
3+
class Components::NestedTable::RowContainer < Phlex::HTML
4+
attr_accessor :tag
5+
6+
def initialize(tag: "tbody")
7+
@tag = tag
8+
@rows = []
9+
end
10+
11+
def with_row(&)
12+
@rows << Components::NestedTable::Row.new(&)
13+
end
14+
15+
def with_content(&block)
16+
@rows << block
17+
end
18+
19+
def before_template(&)
20+
capture(&)
21+
super
22+
end
23+
24+
def view_template
25+
case @tag
26+
when "thead"
27+
thead { render @rows }
28+
when "tbody"
29+
tbody { render @rows }
30+
when "tfoot"
31+
tfoot { render @rows }
32+
end
33+
end
34+
end

app/view_components/nav_component.html.erb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<h1>Before</h1>
22
<%= render Components::Nav.new do |n| %>
3-
<%= n.item("/") do %>
3+
<% n.item("/") do %>
44
Home
55
<% end %>
6-
<%= n.divider %>
7-
<%= n.item("/about") do %>
6+
<% n.divider %>
7+
<% n.item("/about") do %>
88
About
99
<% end %>
1010
<% end %>

app/views/nav.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<h1>Before</h1>
22
<%= render Components::Nav.new do |n| %>
3-
<%= n.item("/") do %>
3+
<% n.item("/") do %>
44
Home
55
<% end %>
66
<%= n.divider %>

app/views/nested_table.html.erb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<%= render Components::NestedTable.new do |t| %>
2+
<% t.with_body do |h| %>
3+
<% h.with_row do |r| %>
4+
<% r.with_cell do %>
5+
HELLO WORLD
6+
<% end %>
7+
<% end %>
8+
<% end %>
9+
<% end %>

app/views/table.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<span><%= row[:name] %></span>
55
<% end %>
66

7-
<%= t.column("Email") do |row| %>
7+
<% t.column("Email") do |row| %>
88
<span><%= row[:email] %></span>
99
<% end %>
1010
<% end %>

lib/phlex/rails.rb

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ module Rails
77
class HelpersCalledBeforeRenderError < StandardError; end
88

99
autoload :Buffered, "phlex/rails/buffered"
10-
autoload :Unbuffered, "phlex/rails/unbuffered"
10+
autoload :Decorator, "phlex/rails/decorator"
1111

12-
autoload :BufferedCheckboxBuilder, "phlex/rails/buffered_checkbox_builder"
13-
autoload :BufferedFormBuilder, "phlex/rails/buffered_form_builder"
14-
autoload :BufferedLabelBuilder, "phlex/rails/buffered_label_builder"
15-
autoload :BufferedRadioButtonBuilder, "phlex/rails/buffered_radio_button_builder"
16-
17-
autoload :SGML, "phlex/rails/sgml"
18-
autoload :HTML, "phlex/rails/html"
19-
autoload :SVG, "phlex/rails/svg"
12+
autoload :FormBuilder, "phlex/rails/form_builder"
13+
autoload :LabelBuilder, "phlex/rails/label_builder"
14+
autoload :CheckboxBuilder, "phlex/rails/checkbox_builder"
15+
autoload :RadioButtonBuilder, "phlex/rails/radio_button_builder"
2016

2117
autoload :CSV, "phlex/rails/csv"
2218

19+
autoload :SVG, "phlex/rails/svg"
20+
autoload :HTML, "phlex/rails/html"
21+
autoload :SGML, "phlex/rails/sgml"
22+
2323
autoload :Helpers, "phlex/rails/helpers"
2424
autoload :HelperMacros, "phlex/rails/helper_macros"
2525

@@ -34,5 +34,7 @@ class HelpersCalledBeforeRenderError < StandardError; end
3434
HTML.include(Phlex::Rails::HTML)
3535
SVG.include(Phlex::Rails::SVG)
3636

37+
SGML::State.prepend(Phlex::Rails::SGML::State)
38+
3739
ActiveSupport::SafeBuffer.include(Phlex::SGML::SafeObject)
3840
end

lib/phlex/rails/buffered.rb

Lines changed: 7 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,7 @@
11
# frozen_string_literal: true
22

3-
require "forwardable"
4-
53
module Phlex::Rails
64
class Buffered < BasicObject
7-
extend ::Forwardable
8-
9-
def self.define_builder_yielding_method(method_name, builder)
10-
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
11-
# frozen_string_literal: true
12-
13-
def #{method_name}(*args, **kwargs, &block)
14-
output = if block
15-
@object.#{method_name}(*args, **kwargs) { |builder|
16-
@component.capture do
17-
yield(
18-
::#{builder.name}.new(builder,
19-
component: @component
20-
)
21-
)
22-
end
23-
}
24-
else
25-
@object.#{method_name}(*args, **kwargs)
26-
end
27-
28-
case output
29-
when ::ActiveSupport::SafeBuffer
30-
@component.raw(output)
31-
end
32-
33-
nil
34-
end
35-
RUBY
36-
end
37-
385
def initialize(object, component:)
396
@object = object
407
@component = component
@@ -45,18 +12,15 @@ def respond_to_missing?(...)
4512
end
4613

4714
def method_missing(*, **, &block)
48-
output = if block
49-
@object.public_send(*, **) { |*a| @component.capture(*a, &block) }
15+
if block
16+
@component.raw(
17+
@object.public_send(*, **) { |*a| @component.capture(*a, &block) }
18+
)
5019
else
51-
@object.public_send(*, **)
20+
@component.raw(
21+
@object.public_send(*, **)
22+
)
5223
end
53-
54-
case output
55-
when ::ActiveSupport::SafeBuffer
56-
@component.raw(output)
57-
end
58-
59-
nil
6024
end
6125
end
6226
end

lib/phlex/rails/buffered_checkbox_builder.rb

Lines changed: 0 additions & 10 deletions
This file was deleted.

lib/phlex/rails/buffered_form_builder.rb

Lines changed: 0 additions & 35 deletions
This file was deleted.

lib/phlex/rails/buffered_label_builder.rb

Lines changed: 0 additions & 9 deletions
This file was deleted.

lib/phlex/rails/buffered_radio_button_builder.rb

Lines changed: 0 additions & 10 deletions
This file was deleted.

lib/phlex/rails/checkbox_builder.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# frozen_string_literal: true
2+
3+
class Phlex::Rails::CheckboxBuilder < Phlex::Rails::Decorator
4+
def text(...) = @object.text(...)
5+
def value(...) = @object.value(...)
6+
def object(...) = @object.object(...)
7+
8+
output def label(...) = nil
9+
output def checkbox(...) = nil
10+
end

lib/phlex/rails/decorator.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# frozen_string_literal: true
2+
3+
class Phlex::Rails::Decorator < BasicObject
4+
def self.output(method_name)
5+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
6+
def #{method_name}(...)
7+
@component.raw(
8+
@object.#{method_name}(...)
9+
)
10+
end
11+
RUBY
12+
end
13+
14+
def initialize(object, component:)
15+
@object = object
16+
@component = component
17+
end
18+
19+
def respond_to_missing?(method_name, include_private = false)
20+
@object.respond_to?(method_name, include_private)
21+
end
22+
23+
def method_missing(...)
24+
@object.public_send(...)
25+
end
26+
end

0 commit comments

Comments
 (0)