Class: Twig::Template
- Inherits:
-
Object
- Object
- Twig::Template
- Defined in:
- lib/twig/template.rb
Overview
Base class for compiled templates
Constant Summary collapse
- ARRAY_CALL =
:array_call
- METHOD_CALL =
:method_call
- ANY_CALL =
:any_call
Instance Attribute Summary collapse
-
#blocks ⇒ Object
Returns the value of attribute blocks.
Instance Method Summary collapse
- #block?(name, context, blocks = {}) ⇒ Boolean
- #call(context = {}, blocks = {}) ⇒ Object
- #get_parent(context) ⇒ Template, false
-
#initialize(environment) ⇒ Template
constructor
A new instance of Template.
- #macro?(name, context) ⇒ Boolean
- #macro_template_reference(name, context, lineno, source) ⇒ Method
- #render(context) ⇒ Object
- #render_block(name, context, blocks = {}, use_blocks: true, template_context: self) ⇒ Object
- #render_macro(name, context, args, lineno, source) ⇒ Object
- #render_parent_block(name, context, blocks = {}) ⇒ Object
- #render_with_blocks(context = {}, blocks = {}) ⇒ Object
- #source_context ⇒ Object
- #traitable? ⇒ Boolean
- #unwrap ⇒ Object
Constructor Details
#initialize(environment) ⇒ Template
Returns a new instance of Template.
13 14 15 16 17 18 19 20 21 |
# File 'lib/twig/template.rb', line 13 def initialize(environment) @environment = environment @parent = nil @parents = {} @blocks = {} @traits = {} @macros = {} @trait_aliases = {} end |
Instance Attribute Details
#blocks ⇒ Object
Returns the value of attribute blocks.
10 11 12 |
# File 'lib/twig/template.rb', line 10 def blocks @blocks end |
Instance Method Details
#block?(name, context, blocks = {}) ⇒ Boolean
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/twig/template.rb', line 123 def block?(name, context, blocks = {}) name = name.to_sym if blocks.key?(name) && blocks[name][0].is_a?(Template) return true end if @blocks&.key?(name) return true end if (parent = get_parent(context)) return parent.block?(name, context) end false end |
#call(context = {}, blocks = {}) ⇒ Object
23 24 25 |
# File 'lib/twig/template.rb', line 23 def call(context = {}, blocks = {}) raise 'call is not implemented' end |
#get_parent(context) ⇒ Template, false
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/twig/template.rb', line 155 def get_parent(context) if @parent return @parent end unless (parent = do_get_parent(context)) return false end if parent.is_a?(Template) return @parents[parent.source_context.name] = parent end unless @parents.key?(parent) @parents[parent] = load(parent, -1) end @parents[parent] end |
#macro?(name, context) ⇒ Boolean
175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/twig/template.rb', line 175 def macro?(name, context) if respond_to?(name.to_sym) return true end unless (parent = get_parent(context)) return false end parent.macro?(name, context) end |
#macro_template_reference(name, context, lineno, source) ⇒ Method
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/twig/template.rb', line 220 def macro_template_reference(name, context, lineno, source) if respond_to?(name.to_sym) return method(name.to_sym) end parent = self while (parent = parent.get_parent(context)) if parent.respond_to?(name.to_sym) return parent.method(name.to_sym) end end raise Error::Runtime.new( "Macro \"#{name.delete_prefix('macro_')}\" is not defined in template \"#{template_name}\".", lineno, source ) end |
#render(context) ⇒ Object
28 29 30 31 32 33 34 |
# File 'lib/twig/template.rb', line 28 def render(context) unless context.is_a?(Runtime::Context) raise Error::Runtime, 'Render must implement Twig::Runtime::Context.' end render_with_blocks(context.merge(env.globals), blocks.merge(blocks)) end |
#render_block(name, context, blocks = {}, use_blocks: true, template_context: self) ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/twig/template.rb', line 54 def render_block(name, context, blocks = {}, use_blocks: true, template_context: self) unless context.is_a?(Runtime::Context) context = Runtime::Context.new(context) end name = name.to_sym template = if use_blocks && blocks.key?(name) blocks[name] elsif self.blocks.key?(name) self.blocks[name] end # avoid RCEs when sandbox is enabled if !template.nil? && !template[0].is_a?(::Twig::Template) raise Error::Logic, 'A block must be a method on a ::Twig::Template instance.' end if !template.nil? begin context.buffer_and_return do template[0].public_send(template[1], context, blocks) end.to_s.html_safe rescue Error::Base => e unless e.source_context e.source_context = template[0].source_context end if e.lineno == -1 e.guess end raise e rescue StandardError => e # Rails wraps exceptions that happened using render if e.respond_to?(:cause) && e.cause.is_a?(Error::Base) e = e.cause unless e.source_context e.source_context = template[0].source_context end end exception = Error::Runtime.new( "An exception has been thrown during the rendering of a template (#{e})", -1, template[0].source_context, e ) exception.guess raise exception end elsif (parent = get_parent(context)) parent.render_block(name, context, self.blocks.merge(blocks), use_blocks: false, template_context:) elsif blocks.key?(name) raise Error::Runtime.new( "Block \"#{name}\" should not call parent() in \"#{blocks[name][0].template_name}\" " \ "as the block does not exist in the parent template \"#{template_name}\".", -1, blocks[name][0].source_context ) else raise Error::Runtime.new( "Block \"#{name}\" on template \"#{template_name}\" does not exist.", -1, template_context.source_context ) end end |
#render_macro(name, context, args, lineno, source) ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/twig/template.rb', line 187 def render_macro(name, context, args, lineno, source) macro_method = macro_template_reference(name, context, lineno, source) macro_arguments = macro_method.parameters.select { |arg| arg[0] == :key }.map { |_, arg| arg } mapped_arguments = AutoHash.new kwarg = false args.each do |key, value| if !kwarg && key.is_a?(Integer) if key >= 0 && key < macro_arguments.length mapped_key = macro_arguments[key] else mapped_arguments.add(value) next end elsif kwarg && key.is_a?(Integer) raise Error::Runtime.new('Cannot place a positional argument after a keyword argument.', lineno, source) else kwarg = true mapped_key = key.to_sym end if mapped_arguments.key?(mapped_key) raise Error::Runtime.new("Argument \"#{mapped_key.inspect}\" passed twice.", lineno, source) end mapped_arguments[mapped_key] = value end macro_method.call(context.call_context, **mapped_arguments) end |
#render_parent_block(name, context, blocks = {}) ⇒ Object
140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/twig/template.rb', line 140 def render_parent_block(name, context, blocks = {}) if @traits.key?(name.to_sym) @traits[name.to_sym][0].render_block(@trait_aliases[name.to_sym] || name, context, blocks, use_blocks: false) elsif (parent = get_parent(context)) parent.render_block(name, context, blocks, use_blocks: false) else raise Error::Runtime.new( "The template has no parent and no traits defining the #{name} block.", -1, source_context ) end end |
#render_with_blocks(context = {}, blocks = {}) ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/twig/template.rb', line 36 def render_with_blocks(context = {}, blocks = {}) call(context, blocks) rescue Error::Base => e e.source_context = source_context unless e.source_context e.guess if e.lineno == -1 raise e rescue StandardError => e exception = Error::Runtime.new( "An exception has been thrown during the rendering of a template (\"#{e}\").", -1, source_context, e ) exception.guess raise exception end |
#source_context ⇒ Object
239 240 241 |
# File 'lib/twig/template.rb', line 239 def source_context raise NotImplementedError end |
#traitable? ⇒ Boolean
243 244 245 |
# File 'lib/twig/template.rb', line 243 def traitable? true end |
#unwrap ⇒ Object
247 248 249 |
# File 'lib/twig/template.rb', line 247 def unwrap self end |