Class: Hexp::Builder
Overview
Build Hexps using the builder pattern
Defined Under Namespace
Classes: NodeBuilder
Constant Summary
Constants included from Hexp
Instance Method Summary collapse
-
#<<(*args) ⇒ Hexp::Builder
Add Hexp objects to the current tag.
-
#_process(&block) ⇒ nil
private
Call the block, with a specific value of ‘self’.
-
#initialize(tag = nil, *args) {|If| ... } ⇒ Builder
constructor
private
Construct a new builder, and start building.
-
#inspect ⇒ String
Return a debugging representation.
-
#tag!(tag, *args, &block) ⇒ nil
(also: #method_missing)
Add a tag (HTML element).
-
#text!(text) ⇒ Hexp::Builder
Add a text node to the tree.
-
#to_hexp ⇒ Hexp::Node
Implement the standard Hexp coercion protocol.
Methods included from Hexp
Constructor Details
#initialize(tag = nil, *args) {|If| ... } ⇒ Builder
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Construct a new builder, and start building
The recommended way to call this is through ‘Hexp.build`. If the block takes an argument, then builder methods need to be called on that variable.
28 29 30 31 32 33 34 35 |
# File 'lib/hexp/builder.rb', line 28 def initialize(tag = nil, *args, &block) @stack = [] if tag tag!(tag, *args, &block) else _process(&block) if block end end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing ⇒ nil
Add a tag (HTML element)
Typically this is called implicitly through method missing, but in case of name clashes or dynamically generated tags you can call this directly.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/hexp/builder.rb', line 83 def tag!(tag, *args, &block) text, attributes = nil, {} args.each do |arg| case arg when ::Hash attributes.merge!(arg) when ::String text ||= '' text << arg end end @stack << [tag, attributes, text ? [text] : []] if block _process(&block) end if @stack.length > 1 node = @stack.pop @stack.last[2] << node NodeBuilder.new(node, self) else NodeBuilder.new(@stack.last, self) end end |
Instance Method Details
#<<(*args) ⇒ Hexp::Builder
Add Hexp objects to the current tag
Any Hexp::Node or other object implementing to_hexp can be added with this operator. Multiple objects can be specified in one call.
Nokogiri and Builder allow inserting of strings containing HTML through this operator. Since this would violate the core philosophy of Hexp, and open the door for XSS vulnerabilities, we do not support that usage.
If you really want to insert HTML that is already in serialized form, consider parsing it to Hexps first
132 133 134 135 136 137 138 139 140 141 |
# File 'lib/hexp/builder.rb', line 132 def <<(*args) args.each do |arg| if arg.respond_to?(:to_hexp) @stack.last[2] << arg self else ::Kernel.raise ::Hexp::FormatError, "Inserting literal HTML into a builder with << is deliberately not supported by Hexp" end end end |
#_process(&block) ⇒ nil
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Call the block, with a specific value of ‘self’
If the block takes an argument, then we pass ourselves (the builder) to the block, and call it as a closure. This way ‘self’ refers to the calling object, and it can reference its own methods and ivars.
If the block does not take an argument, then we evaluate it in the context of ourselves (the builder), so unqualified method calls are seen as builder calls.
175 176 177 178 179 180 181 |
# File 'lib/hexp/builder.rb', line 175 def _process(&block) if block.arity == 1 block.call(self) else self.instance_eval(&block) end end |
#inspect ⇒ String
Return a debugging representation
Hexp is intended for HTML, so it shouldn’t be a problem that this is an actual method. It really helps for debugging or when playing around in irb. If you really want an ‘<inspect>` tag, use `tag!(:inspect)`.
238 239 240 |
# File 'lib/hexp/builder.rb', line 238 def inspect "#<Hexp::Builder #{@stack.empty? ? '[]' : to_hexp.inspect}>" end |
#tag!(tag, *args, &block) ⇒ nil Also known as: method_missing
Add a tag (HTML element)
Typically this is called implicitly through method missing, but in case of name clashes or dynamically generated tags you can call this directly.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/hexp/builder.rb', line 59 def tag!(tag, *args, &block) text, attributes = nil, {} args.each do |arg| case arg when ::Hash attributes.merge!(arg) when ::String text ||= '' text << arg end end @stack << [tag, attributes, text ? [text] : []] if block _process(&block) end if @stack.length > 1 node = @stack.pop @stack.last[2] << node NodeBuilder.new(node, self) else NodeBuilder.new(@stack.last, self) end end |
#text!(text) ⇒ Hexp::Builder
Add a text node to the tree
100 101 102 103 104 |
# File 'lib/hexp/builder.rb', line 100 def text!(text) _raise_if_empty! "Hexp::Builder needs a root element to add text elements to" @stack.last[2] << text.to_s self end |
#to_hexp ⇒ Hexp::Node
Implement the standard Hexp coercion protocol
By implementing this a Builder is interchangeable for a regular node, so you can use it inside other nodes transparently. But you can call this method if you really, really just want the plain Node
155 156 157 158 |
# File 'lib/hexp/builder.rb', line 155 def to_hexp _raise_if_empty! ::Hexp::Node[*@stack.last] end |