Skip to content

Commit 312ee73

Browse files
committed
Merge branch 'render_in'
* render_in: Use `ruby2_keywords` for the moment (activeadmin#205) Deprecate Element#to_s and #to_str Add Document#render_in Use ActiveSupport::SafeBuffer instead of StringIO. require 'timeout' Use render_in(self) to build context cached_html. Add FieldsForProxy#render_in Deprecate using :to_s for rendering. Test using output_buffer from html tags matches #to_s. Add input and output variables to html rendering specs. Add Context#output_buffer, Element#render_in, ElementCollection#render_in, TextNode#render_in and Tag#render_in.
2 parents 1e50aa6 + 4770068 commit 312ee73

File tree

16 files changed

+225
-47
lines changed

16 files changed

+225
-47
lines changed

arbre.gemspec

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,8 @@ Gem::Specification.new do |s|
1818
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
1919
s.require_paths = ["lib"]
2020

21+
s.required_ruby_version = '>= 2.5'
22+
2123
s.add_dependency("activesupport", ">= 3.0.0")
24+
s.add_dependency("ruby2_keywords", ">= 0.0.2")
2225
end

lib/arbre.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'active_support/core_ext/string/output_safety'
2+
require 'active_support/deprecation'
23
require 'active_support/hash_with_indifferent_access'
34
require 'active_support/inflector'
45

lib/arbre/context.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'arbre/element'
2+
require 'ruby2_keywords'
23

34
module Arbre
45

@@ -74,7 +75,7 @@ def respond_to_missing?(method, include_all)
7475
# Webservers treat Arbre::Context as a string. We override
7576
# method_missing to delegate to the string representation
7677
# of the html.
77-
def method_missing(method, *args, &block)
78+
ruby2_keywords def method_missing(method, *args, &block)
7879
if cached_html.respond_to? method
7980
cached_html.send method, *args, &block
8081
else
@@ -94,6 +95,10 @@ def with_current_arbre_element(tag)
9495
end
9596
alias_method :within, :with_current_arbre_element
9697

98+
def output_buffer
99+
@output_buffer ||= ActiveSupport::SafeBuffer.new
100+
end
101+
97102
private
98103

99104

@@ -103,7 +108,7 @@ def cached_html
103108
if defined?(@cached_html)
104109
@cached_html
105110
else
106-
html = to_s
111+
html = render_in(self)
107112
@cached_html = html if html.length > 0
108113
html
109114
end

lib/arbre/element.rb

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require 'arbre/element/builder_methods'
22
require 'arbre/element/proxy'
33
require 'arbre/element_collection'
4+
require 'ruby2_keywords'
45

56
module Arbre
67

@@ -132,17 +133,36 @@ def each(&block)
132133
end
133134

134135
def inspect
135-
to_s
136+
content
136137
end
137138

138139
def to_str
139-
to_s
140+
ActiveSupport::Deprecation.warn("don't rely on implicit conversion of Element to String")
141+
content
140142
end
141143

142144
def to_s
145+
ActiveSupport::Deprecation.warn("#render_in should be defined for rendering #{method_owner(:to_s)} instead of #to_s")
143146
content
144147
end
145148

149+
# Rendering strategy that visits all elements and appends output to a buffer.
150+
def render_in(context = arbre_context)
151+
children.collect do |element|
152+
element.render_in_or_to_s(context)
153+
end.join('')
154+
end
155+
156+
# Use render_in to render element unless closer ancestor overrides :to_s only.
157+
def render_in_or_to_s(context)
158+
if method_distance(:render_in) <= method_distance(:to_s)
159+
render_in(context)
160+
else
161+
ActiveSupport::Deprecation.warn("#render_in should be defined for rendering #{method_owner(:to_s)} instead of #to_s")
162+
to_s.tap { |s| context.output_buffer << s }
163+
end
164+
end
165+
146166
def +(element)
147167
case element
148168
when Element, ElementCollection
@@ -172,7 +192,7 @@ def clear_children!
172192
# 3. Call the method on the helper object
173193
# 4. Call super
174194
#
175-
def method_missing(name, *args, &block)
195+
ruby2_keywords def method_missing(name, *args, &block)
176196
if current_arbre_element.respond_to?(name)
177197
current_arbre_element.send name, *args, &block
178198
elsif assigns && assigns.has_key?(name)
@@ -188,10 +208,18 @@ def method_missing(name, *args, &block)
188208
# which will be rendered (#to_s) inside ActionView::Base#capture.
189209
# We do not want such elements added to self, so we push a dummy
190210
# current_arbre_element.
191-
def helper_capture(name, *args, &block)
211+
ruby2_keywords def helper_capture(name, *args, &block)
192212
s = ""
193213
within(Element.new) { s = helpers.send(name, *args, &block) }
194214
s.is_a?(Element) ? s.to_s : s
195215
end
216+
217+
def method_distance(name)
218+
self.class.ancestors.index method_owner(name)
219+
end
220+
221+
def method_owner(name)
222+
self.class.instance_method(name).owner
223+
end
196224
end
197225
end

lib/arbre/element_collection.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ def to_s
2020
element.to_s
2121
end.join('').html_safe
2222
end
23+
24+
def render_in(context)
25+
self.collect do |element|
26+
element.render_in(context)
27+
end.join('').html_safe
28+
end
2329
end
2430

2531
end

lib/arbre/html/document.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ def to_s
2525
doctype + super
2626
end
2727

28+
def render_in(context = arbre_context)
29+
context.output_buffer << doctype
30+
super
31+
context.output_buffer
32+
end
33+
2834
protected
2935

3036
def build_head

lib/arbre/html/tag.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ def to_s
100100
indent(opening_tag, content, closing_tag).html_safe
101101
end
102102

103+
def render_in(context = arbre_context)
104+
indent_in_context(context)
105+
end
106+
103107
private
104108

105109
def opening_tag
@@ -136,6 +140,32 @@ def indent(open_tag, child_content, close_tag)
136140
html
137141
end
138142

143+
def indent_in_context(context)
144+
spaces = ' ' * indent_level * INDENT_SIZE
145+
146+
pos = context.output_buffer.length
147+
148+
if no_child? || child_is_text?
149+
if self_closing_tag?
150+
context.output_buffer << spaces << opening_tag.sub( />$/, '/>' ).html_safe
151+
else
152+
# one line
153+
context.output_buffer << spaces << opening_tag.html_safe
154+
children.render_in(context)
155+
context.output_buffer << closing_tag.html_safe
156+
end
157+
else
158+
# multiple lines
159+
context.output_buffer << spaces << opening_tag.html_safe << "\n"
160+
children.render_in(context)
161+
context.output_buffer << spaces << closing_tag.html_safe
162+
end
163+
164+
context.output_buffer << "\n"
165+
166+
context.output_buffer[pos..].html_safe
167+
end
168+
139169
def self_closing_tag?
140170
SELF_CLOSING_ELEMENTS.include?(tag_name.to_sym)
141171
end

lib/arbre/html/text_node.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ def tag_name
3333
def to_s
3434
ERB::Util.html_escape(@content.to_s)
3535
end
36+
37+
def render_in(context)
38+
to_s.tap { |s| context.output_buffer << s }
39+
end
3640
end
3741

3842
end

lib/arbre/rails/forms.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ def to_s
8686
children.to_s
8787
end
8888

89+
def render_in(context)
90+
children.collect do |element|
91+
element.render_in_or_to_s(context)
92+
end.join('')
93+
end
94+
8995
end
9096

9197
end

lib/arbre/rails/template_handler.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def call(template, source = nil)
2525
<<-END
2626
Arbre::Context.new(assigns, self) {
2727
#{source}
28-
}.to_s
28+
}.render_in(self).html_safe
2929
END
3030
end
3131
end

0 commit comments

Comments
 (0)