Skip to content

Commit

Permalink
Rename context to state (#846)
Browse files Browse the repository at this point in the history
A bunch of misc refactors and renaming.

Note: this will break `phlex-rails` and should be merged at the same
time as an update over there.
  • Loading branch information
joeldrapper authored Feb 6, 2025
1 parent abd53a6 commit f155108
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 104 deletions.
1 change: 0 additions & 1 deletion lib/phlex.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
module Phlex
autoload :ArgumentError, "phlex/errors/argument_error"
autoload :CSV, "phlex/csv"
autoload :Context, "phlex/context"
autoload :DoubleRenderError, "phlex/errors/double_render_error"
autoload :Error, "phlex/error"
autoload :FIFO, "phlex/fifo"
Expand Down
2 changes: 1 addition & 1 deletion lib/phlex/fifo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def expand(bytes)

def [](key)
k, v = @store[key.hash]
v if k == key
v if k.eql?(key)
end

def []=(key, value)
Expand Down
6 changes: 3 additions & 3 deletions lib/phlex/html.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ class Phlex::HTML < Phlex::SGML

# Output an HTML doctype.
def doctype
context = @_context
return unless context.should_render?
state = @_state
return unless state.should_render?

context.buffer << "<!doctype html>"
state.buffer << "<!doctype html>"
nil
end

Expand Down
134 changes: 68 additions & 66 deletions lib/phlex/sgml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class Phlex::SGML
autoload :Elements, "phlex/sgml/elements"
autoload :SafeObject, "phlex/sgml/safe_object"
autoload :SafeValue, "phlex/sgml/safe_value"
autoload :State, "phlex/sgml/state"

include Phlex::Helpers

Expand Down Expand Up @@ -42,25 +43,36 @@ def to_proc
proc { |c| c.render(self) }
end

def call(buffer = +"", context: {}, view_context: nil, parent: nil, fragments: nil, &block)
@_buffer = buffer
@_context = phlex_context = parent&.__context__ || Phlex::Context.new(user_context: context, view_context:)
@_parent = parent
def call(buffer = +"", context: {}, view_context: nil, fragments: nil, &)
state = Phlex::SGML::State.new(
user_context: context,
view_context:,
output_buffer: buffer,
fragments: fragments&.to_set,
)

raise Phlex::DoubleRenderError.new("You can't render a #{self.class.name} more than once.") if @_rendered
@_rendered = true
internal_call(parent: nil, state:, &)

if fragments
phlex_context.target_fragments(fragments)
state.output_buffer << state.buffer
end

def internal_call(parent: nil, state: nil, &block)
return "" unless render?

if @_context
raise Phlex::DoubleRenderError.new(
"You can't render a #{self.class.name} more than once."
)
end

block ||= @_content_block
@_context = state
@_state = state

return "" unless render?
block ||= @_content_block

Thread.current[:__phlex_component__] = [self, Fiber.current.object_id].freeze

phlex_context.around_render do
state.around_render(self) do
before_template(&block)

around_template do
Expand All @@ -79,18 +91,12 @@ def call(buffer = +"", context: {}, view_context: nil, parent: nil, fragments: n

after_template(&block)
end

unless parent
buffer << phlex_context.buffer
end
ensure
Thread.current[:__phlex_component__] = [parent, Fiber.current.object_id].freeze
end

protected def __context__ = @_context

def context
@_context.user_context
@_state._state
end

# Output plain text.
Expand All @@ -104,10 +110,10 @@ def plain(content)

# Output a single space character. If a block is given, a space will be output before and after the block.
def whitespace(&)
context = @_context
return unless context.should_render?
state = @_state
return unless state.should_render?

buffer = context.buffer
buffer = state.buffer

buffer << " "

Expand All @@ -123,10 +129,10 @@ def whitespace(&)
#
# [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Comments)
def comment(&)
context = @_context
return unless context.should_render?
state = @_state
return unless state.should_render?

buffer = context.buffer
buffer = state.buffer

buffer << "<!-- "
__yield_content__(&)
Expand All @@ -139,10 +145,10 @@ def comment(&)
def raw(content)
case content
when Phlex::SGML::SafeObject
context = @_context
return unless context.should_render?
state = @_state
return unless state.should_render?

context.buffer << content.to_s
state.buffer << content.to_s
when nil, "" # do nothing
else
raise Phlex::ArgumentError.new("You passed an unsafe object to `raw`.")
Expand All @@ -156,18 +162,18 @@ def capture(*args, &block)
return "" unless block

if args.length > 0
@_context.capturing_into(+"") { __yield_content_with_args__(*args, &block) }
@_state.capturing_into(+"") { __yield_content_with_args__(*args, &block) }
else
@_context.capturing_into(+"") { __yield_content__(&block) }
@_state.capturing_into(+"") { __yield_content__(&block) }
end
end

# Define a named fragment that can be selectively rendered.
def fragment(name)
context = @_context
context.begin_fragment(name)
state = @_state
state.begin_fragment(name)
yield
context.end_fragment(name)
state.end_fragment(name)
nil
end

Expand All @@ -184,20 +190,18 @@ def safe(value)
alias_method :🦺, :safe

def flush
return if @_context.capturing

buffer = @_context.buffer
@_buffer << buffer.dup
buffer.clear
@_state.flush
end

def render(renderable = nil, &)
case renderable
when Phlex::SGML
renderable.call(@_buffer, parent: self, &)
Thread.current[:__phlex_component__] = [renderable, Fiber.current.object_id].freeze
renderable.internal_call(state: @_context, parent: self, &)
Thread.current[:__phlex_component__] = [self, Fiber.current.object_id].freeze
when Class
if renderable < Phlex::SGML
renderable.new.call(@_buffer, parent: self, &)
render(renderable.new, &)
end
when Enumerable
renderable.each { |r| render(r, &) }
Expand Down Expand Up @@ -228,8 +232,6 @@ def render(renderable = nil, &)
# end
# ```
def cache(*cache_key, **, &content)
context = @_context

location = caller_locations(1, 1)[0]

full_key = [
Expand All @@ -256,21 +258,21 @@ def cache(*cache_key, **, &content)
# Note: To allow you more control, this method does not take a splat of cache keys.
# If you need to pass multiple cache keys, you should pass an array.
def low_level_cache(cache_key, **options, &content)
context = @_context
state = @_state

cached_buffer, fragment_map = cache_store.fetch(cache_key, **options) { context.caching(&content) }
cached_buffer, fragment_map = cache_store.fetch(cache_key, **options) { state.caching(&content) }

if context.should_render?
if state.should_render?
fragment_map.each do |fragment_name, (offset, length, nested_fragments)|
context.record_fragment(fragment_name, offset, length, nested_fragments)
state.record_fragment(fragment_name, offset, length, nested_fragments)
end
context.buffer << cached_buffer
state.buffer << cached_buffer
else
fragment_map.each do |fragment_name, (offset, length, nested_fragments)|
if context.fragments.include?(fragment_name)
context.fragments.delete(fragment_name)
context.fragments.subtract(nested_fragments)
context.buffer << cached_buffer.byteslice(offset, length)
if state.fragments.include?(fragment_name)
state.fragments.delete(fragment_name)
state.fragments.subtract(nested_fragments)
state.buffer << cached_buffer.byteslice(offset, length)
end
end
end
Expand All @@ -289,9 +291,9 @@ def vanish(*args)
return unless block_given?

if args.length > 0
@_context.capturing_into(Phlex::Vanish) { yield(*args) }
@_state.capturing_into(Phlex::Vanish) { yield(*args) }
else
@_context.capturing_into(Phlex::Vanish) { yield(self) }
@_state.capturing_into(Phlex::Vanish) { yield(self) }
end

nil
Expand Down Expand Up @@ -324,7 +326,7 @@ def after_template
def __yield_content__
return unless block_given?

buffer = @_context.buffer
buffer = @_state.buffer

original_length = buffer.bytesize
content = yield(self)
Expand All @@ -336,7 +338,7 @@ def __yield_content__
def __yield_content_with_no_args__
return unless block_given?

buffer = @_context.buffer
buffer = @_state.buffer

original_length = buffer.bytesize
content = yield
Expand All @@ -348,7 +350,7 @@ def __yield_content_with_no_args__
def __yield_content_with_args__(*a)
return unless block_given?

buffer = @_context.buffer
buffer = @_state.buffer

original_length = buffer.bytesize
content = yield(*a)
Expand All @@ -358,21 +360,21 @@ def __yield_content_with_args__(*a)
end

def __implicit_output__(content)
context = @_context
return true unless context.should_render?
state = @_state
return true unless state.should_render?

case content
when Phlex::SGML::SafeObject
context.buffer << content.to_s
state.buffer << content.to_s
when String
context.buffer << Phlex::Escape.html_escape(content)
state.buffer << Phlex::Escape.html_escape(content)
when Symbol
context.buffer << Phlex::Escape.html_escape(content.name)
state.buffer << Phlex::Escape.html_escape(content.name)
when nil
nil
else
if (formatted_object = format_object(content))
context.buffer << Phlex::Escape.html_escape(formatted_object)
state.buffer << Phlex::Escape.html_escape(formatted_object)
else
return false
end
Expand All @@ -383,19 +385,19 @@ def __implicit_output__(content)

# same as __implicit_output__ but escapes even `safe` objects
def __text__(content)
context = @_context
return true unless context.should_render?
state = @_state
return true unless state.should_render?

case content
when String
context.buffer << Phlex::Escape.html_escape(content)
state.buffer << Phlex::Escape.html_escape(content)
when Symbol
context.buffer << Phlex::Escape.html_escape(content.name)
state.buffer << Phlex::Escape.html_escape(content.name)
when nil
nil
else
if (formatted_object = format_object(content))
context.buffer << Phlex::Escape.html_escape(formatted_object)
state.buffer << Phlex::Escape.html_escape(formatted_object)
else
return false
end
Expand Down
Loading

0 comments on commit f155108

Please sign in to comment.