module Papercraft::Tags
Markup (HTML/XML) extensions
Constants
- INITIAL_BUFFER_CAPACITY
- S_EQUAL_QUOTE
- S_GT
- S_LT
- S_LT_SLASH
- S_QUOTE
- S_SLASH_GT
- S_SPACE
- S_SPACE_LT_SLASH
- S_TAG_METHOD
- S_TAG_METHOD_LINE
The tag method template below is optimized for performance. Do not touch!
Public Class Methods
Initializes a tag renderer.
# File lib/papercraft/tags.rb, line 50 def initialize(&template) @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY) super end
Public Instance Methods
Defers the given block to be evaluated later. Deferred evaluation allows Papercraft
templates to inject state into sibling components, regardless of the component’s order in the container component. For example, a nested component may set an instance variable used by another component. This is an elegant solution to the problem of setting the XML
page’s title, or adding elements to the ‘<head>` section. Here’s how a title can be controlled from a nested component:
layout = Papercraft.html { html { head { defer { title @title } } body { emit_yield } } } html.render { @title = 'My super page' h1 'content' }
@param &block [Proc] Deferred block to be emitted @return [void]
# File lib/papercraft/tags.rb, line 102 def defer(&block) if !@parts @parts = [@buffer, block] else @parts << @buffer unless @buffer.empty? @parts << block end @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY) end
Catches undefined tag method call and handles it by defining the method.
@param sym [Symbol] XML
tag or component identifier @param args [Array] method arguments @param opts [Hash] named method arguments @param &block [Proc] block passed to method @return [void]
# File lib/papercraft/tags.rb, line 162 def method_missing(sym, *args, **opts, &block) tag = sym.to_s if tag =~ /^[A-Z]/ && (Object.const_defined?(tag)) define_const_tag_method(tag) # return send(tag, *args, **opts) else define_tag_method(tag) end send(sym, *args, **opts, &block) end
Emits an XML
tag with the given content, properties and optional block. This method is an alternative to emitting XML
tags using dynamically created methods. This is particularly useful when using extensions that have method names that clash with XML
tags, such as ‘button` or `a`, or when you need to override the behaviour of a particular XML
tag.
The following two method calls have the same effect:
button ‘text’, id: ‘button1’ tag :button, ‘text’, id: ‘button1’
@param sym [Symbol, String] XML
tag @param text [String, nil] tag content @param **props [Hash] tag attributes @param &block [Proc] optional inner XML
@return [void]
# File lib/papercraft/tags.rb, line 129 def tag(sym, text = nil, **props, &block) if text.is_a?(Hash) && props.empty? props = text text = nil end tag = tag_repr(sym) @buffer << S_LT << tag emit_props(props) unless props.empty? if block @buffer << S_GT instance_eval(&block) @buffer << S_LT_SLASH << tag << S_GT elsif Proc === text @buffer << S_GT emit(text) @buffer << S_LT_SLASH << tag << S_GT elsif text @buffer << S_GT << escape_text(text.to_s) << S_LT_SLASH << tag << S_GT else @buffer << S_SLASH_GT end end
Emits text into the rendering buffer, escaping any special characters to the respective XML
entities.
@param data [String] text @return [void]
# File lib/papercraft/tags.rb, line 179 def text(data) @buffer << escape_text(data) end
Returns the rendered template.
@return [String]
# File lib/papercraft/tags.rb, line 58 def to_s if @parts last = @buffer @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY) parts = @parts @parts = nil parts.each do |p| if Proc === p render_deferred_proc(&p) else @buffer << p end end @buffer << last unless last.empty? end @buffer end
Private Instance Methods
Converts an attribute to its string representation. This method must be overriden in Renderers which include this module.
@param att [Symbol, String] attribute
# File lib/papercraft/tags.rb, line 258 def att_repr(att) raise NotImplementedError end
Defines a method that emits the given tag based on a constant. The constant must be defined on the main (Object) binding.
@param tag [Symbol, String] tag/method name @return [void]
# File lib/papercraft/tags.rb, line 190 def define_const_tag_method(tag) const = Object.const_get(tag) self.class.define_method(tag) { |*a, **b, &blk| emit const, *a, **b, &blk } end
Defines a normal tag method.
@param tag [Symbol, String] tag/method name @return [void]
# File lib/papercraft/tags.rb, line 201 def define_tag_method(tag) repr = tag_repr(tag) code = S_TAG_METHOD % { tag: tag, TAG: tag.upcase, tag_pre: "<#{repr}".inspect, tag_close: "</#{repr}>".inspect } self.class.class_eval(code, __FILE__, S_TAG_METHOD_LINE) end
Emits an arbitrary object by converting it to string, then adding it to the internal buffer. This method is called internally by ‘Renderer#emit`.
@param obj [Object] emitted object @return [void]
# File lib/papercraft/tags.rb, line 217 def emit_object(obj) @buffer << obj.to_s end
Emits tag attributes into the rendering buffer.
@param props [Hash] tag attributes @return [void]
# File lib/papercraft/tags.rb, line 266 def emit_props(props) props.each { |k, v| case k when :src, :href @buffer << S_SPACE << k.to_s << S_EQUAL_QUOTE << EscapeUtils.escape_uri(v) << S_QUOTE else case v when true @buffer << S_SPACE << att_repr(k) when false, nil # emit nothing else @buffer << S_SPACE << att_repr(k) << S_EQUAL_QUOTE << escape_text(v) << S_QUOTE end end } end
Escapes text. This method must be overriden in Renderers which include this module.
@param text [String] text to be escaped
# File lib/papercraft/tags.rb, line 242 def escape_text(text) raise NotImplementedError end
Renders a deferred proc by evaluating it, then adding the rendered result to the buffer.
@param &block [Proc] deferred proc @return [void]
# File lib/papercraft/tags.rb, line 226 def render_deferred_proc(&block) old_buffer = @buffer @buffer = String.new(capacity: INITIAL_BUFFER_CAPACITY) @parts = nil instance_eval(&block) old_buffer << to_s @buffer = old_buffer end
Converts a tag to its string representation. This method must be overriden in Renderers which include this module.
@param tag [Symbol, String] tag
# File lib/papercraft/tags.rb, line 250 def tag_repr(tag) raise NotImplementedError end