class Phlex::HTML
def self.method_added(method_name)
def self.method_added(method_name) if method_name[0] == "_" && Phlex::HTML.instance_methods.include?(method_name) && instance_method(method_name).owner != Phlex::HTML raise NameError, "👋 Redefining the method `#{name}##{method_name}` is not a good idea." end super end
def __attributes__(**attributes)
def __attributes__(**attributes) _attributes__(**attributes).tap do |buffer| :ATTRIBUTE_CACHE[attributes.hash] = buffer.freeze
def __build_attributes__(attributes, buffer:)
def __build_attributes__(attributes, buffer:) tes.each do |k, v| nless v case k String then k Symbol then k.name.tr("_", "-") k.to_s name = name.downcase f lower_name == "href" && v.start_with?(/\s*javascript:/i) ct unsafe attribute names. Attribute names are considered unsafe if they match an event attribute or include unsafe characters. L::EVENT_ATTRIBUTES[lower_name] || name.match?(/[<>&"']/) ArgumentError, "Unsafe attribute name detected: #{k}." rue r << " " << name tring r << " " << name << '="' << ERB::Util.html_escape(v) << '"' ymbol r << " " << name << '="' << ERB::Util.html_escape(v.name) << '"' ash ld_attributes__( ansform_keys { |subkey| e subkey en Symbol then"#{k}-#{subkey.name.tr('_', '-')}" se "#{k}-#{subkey}" uffer: buffer r << " " << name << '="' << ERB::Util.html_escape(v.to_s) << '"'
def __final_attributes__(**attributes)
def __final_attributes__(**attributes) = +"" _attributes__(attributes, buffer: buffer)
def __final_call__(buffer = +"", view_context: nil, parent: nil, &block)
def __final_call__(buffer = +"", view_context: nil, parent: nil, &block) @_target = buffer @_view_context = view_context @_parent = parent block ||= @_content_block return buffer unless render? around_template do if block if DeferredRender === self __vanish__(self, &block) template else template do |*args| if args.length > 0 yield_content_with_args(*args, &block) else yield_content(&block) end end end else template end end buffer end
def __unbuffered_class__
def __unbuffered_class__ UNBUFFERED_MUTEX.synchronize do if defined? @unbuffered_class @unbuffered_class else @unbuffered_class = Class.new(Unbuffered) end end end
def __vanish__(*args)
Like `capture` but the output is vanished into a BlackHole buffer.
def __vanish__(*args) unless block_given? l_buffer = @_target t = BlackHole args) t = original_buffer
def after_template
def after_template
def around_template
def around_template template emplate
def before_template
def before_template
def call(...)
def call(...) new(...).call end
def call(...)
def call(...) __final_call__(...).tap do self.class.rendered_at_least_once! end end
def capture(&block)
def capture(&block) return unless block_given? original_buffer = @_target new_buffer = +"" @_target = new_buffer yield_content(&block) new_buffer ensure @_target = original_buffer end
def comment(&block)
def comment(&block) @_target << "<!-- " yield_content(&block) @_target << " -->" nil end
def doctype
def doctype @_target << DOCTYPE nil end
def format
def format :html end
def format_object(object)
def format_object(object) ject oat .to_s
def new(*args, **kwargs, &block)
def new(*args, **kwargs, &block) if block object = super(*args, **kwargs, &nil) object.instance_variable_set(:@_content_block, block) object else super end end
def render(renderable, &block)
def render(renderable, &block) case renderable when Phlex::HTML renderable.call(@_target, view_context: @_view_context, parent: self, &block) when Class if renderable < Phlex::HTML renderable.new.call(@_target, view_context: @_view_context, parent: self, &block) end else raise ArgumentError, "You can't render a #{renderable}." end nil end
def render?
def render?
def rendered_at_least_once!
def rendered_at_least_once! alias_method :__attributes__, :__final_attributes__ alias_method :call, :__final_call__ end
def text(content)
def text(content) @_target << ERB::Util.html_escape( case content when String then content when Symbol then content.name when Integer then content.to_s else format_object(content) || content.to_s end ) nil end
def unbuffered
def unbuffered self.class.__unbuffered_class__.new(self) end
def unsafe_raw(content = nil)
def unsafe_raw(content = nil) return nil unless content @_target << content end
def whitespace
def whitespace @_target << " " if block_given? yield @_target << " " end nil end
def yield_content
def yield_content unless block_given? l_length = @_target.length = yield(self) ed = (original_length == @_target.length) anged ontent tring get << ERB::Util.html_escape(content) ymbol get << ERB::Util.html_escape(content.name) nteger get << ERB::Util.html_escape(content.to_s) ormatted_object = format_object(content)) rget << ERB::Util.html_escape(formatted_object)
def yield_content_with_args(*args)
def yield_content_with_args(*args) unless block_given? l_length = @_target.length = yield(*args) ed = (original_length == @_target.length) anged ontent tring get << ERB::Util.html_escape(content) ymbol get << ERB::Util.html_escape(content.name) nteger, Float get << ERB::Util.html_escape(content.to_s) ormatted_object = format_object(content)) rget << ERB::Util.html_escape(formatted_object)