twig_ruby 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/twig/auto_hash.rb +17 -0
- data/lib/twig/cache/base.rb +31 -0
- data/lib/twig/cache/filesystem.rb +47 -0
- data/lib/twig/cache/nil.rb +19 -0
- data/lib/twig/callable.rb +21 -0
- data/lib/twig/compiler.rb +123 -0
- data/lib/twig/context.rb +64 -0
- data/lib/twig/environment.rb +161 -0
- data/lib/twig/error/base.rb +37 -0
- data/lib/twig/error/syntax.rb +8 -0
- data/lib/twig/expression_parser.rb +517 -0
- data/lib/twig/extension/base.rb +23 -0
- data/lib/twig/extension/core.rb +89 -0
- data/lib/twig/extension/rails.rb +70 -0
- data/lib/twig/extension_set.rb +69 -0
- data/lib/twig/lexer.rb +372 -0
- data/lib/twig/loader/array.rb +39 -0
- data/lib/twig/loader/base.rb +32 -0
- data/lib/twig/loader/filesystem.rb +45 -0
- data/lib/twig/node/base.rb +61 -0
- data/lib/twig/node/block.rb +20 -0
- data/lib/twig/node/block_reference.rb +17 -0
- data/lib/twig/node/empty.rb +11 -0
- data/lib/twig/node/expression/array.rb +50 -0
- data/lib/twig/node/expression/assign_name.rb +28 -0
- data/lib/twig/node/expression/base.rb +20 -0
- data/lib/twig/node/expression/binary/base.rb +63 -0
- data/lib/twig/node/expression/call.rb +28 -0
- data/lib/twig/node/expression/constant.rb +17 -0
- data/lib/twig/node/expression/filter.rb +52 -0
- data/lib/twig/node/expression/get_attribute.rb +30 -0
- data/lib/twig/node/expression/helper_method.rb +31 -0
- data/lib/twig/node/expression/name.rb +37 -0
- data/lib/twig/node/expression/ternary.rb +28 -0
- data/lib/twig/node/expression/unary/base.rb +52 -0
- data/lib/twig/node/expression/variable/assign_context.rb +11 -0
- data/lib/twig/node/expression/variable/context.rb +11 -0
- data/lib/twig/node/for.rb +64 -0
- data/lib/twig/node/for_loop.rb +39 -0
- data/lib/twig/node/if.rb +50 -0
- data/lib/twig/node/include.rb +71 -0
- data/lib/twig/node/module.rb +74 -0
- data/lib/twig/node/nodes.rb +13 -0
- data/lib/twig/node/print.rb +18 -0
- data/lib/twig/node/text.rb +20 -0
- data/lib/twig/node/yield.rb +54 -0
- data/lib/twig/output_buffer.rb +29 -0
- data/lib/twig/parser.rb +131 -0
- data/lib/twig/railtie.rb +60 -0
- data/lib/twig/source.rb +13 -0
- data/lib/twig/template.rb +50 -0
- data/lib/twig/token.rb +48 -0
- data/lib/twig/token_parser/base.rb +20 -0
- data/lib/twig/token_parser/block.rb +54 -0
- data/lib/twig/token_parser/extends.rb +25 -0
- data/lib/twig/token_parser/for.rb +64 -0
- data/lib/twig/token_parser/if.rb +64 -0
- data/lib/twig/token_parser/include.rb +51 -0
- data/lib/twig/token_parser/yield.rb +44 -0
- data/lib/twig/token_stream.rb +73 -0
- data/lib/twig/twig_filter.rb +21 -0
- data/lib/twig_ruby.rb +36 -0
- metadata +103 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
module Expression
|
6
|
+
class Array < Expression::Base
|
7
|
+
def initialize(elements, lineno)
|
8
|
+
super(elements, {}, lineno)
|
9
|
+
|
10
|
+
@index = -1
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param [Expression::Base] value
|
14
|
+
# @param [Expression::Base|nil] key
|
15
|
+
def add_element(value, key = nil)
|
16
|
+
if key.nil?
|
17
|
+
@index += 1
|
18
|
+
key = Constant.new(@index, value.lineno)
|
19
|
+
end
|
20
|
+
|
21
|
+
nodes.add(key, value)
|
22
|
+
end
|
23
|
+
|
24
|
+
def compile(compiler)
|
25
|
+
compiler.
|
26
|
+
raw('{').
|
27
|
+
indent
|
28
|
+
|
29
|
+
key_value_pairs.each do |key, value|
|
30
|
+
compiler.
|
31
|
+
subcompile(key).
|
32
|
+
raw(' => ').
|
33
|
+
subcompile(value).
|
34
|
+
raw(', ')
|
35
|
+
end
|
36
|
+
|
37
|
+
compiler.
|
38
|
+
outdent.
|
39
|
+
raw('}')
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def key_value_pairs
|
45
|
+
nodes.each_value.each_slice(2)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'name'
|
4
|
+
|
5
|
+
module Twig
|
6
|
+
module Node
|
7
|
+
module Expression
|
8
|
+
class AssignName < Expression::Name
|
9
|
+
# @param [String] name
|
10
|
+
# @param [Integer] lineno
|
11
|
+
def initialize(name, lineno)
|
12
|
+
if %w[true false none null nil].include?(name.downcase)
|
13
|
+
raise Error::Syntax.new("You cannot assign a value to #{name}", lineno)
|
14
|
+
end
|
15
|
+
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def compile(compiler)
|
20
|
+
compiler.
|
21
|
+
raw('context[').
|
22
|
+
string(attributes[:name]).
|
23
|
+
raw(']')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
module Expression
|
6
|
+
class Base < Node::Base
|
7
|
+
# @return [Expression::Base]
|
8
|
+
def set_explicit_parentheses
|
9
|
+
attributes[:with_parentheses] = true
|
10
|
+
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def explicit_parentheses?
|
15
|
+
attributes.key?(:with_parentheses) && attributes[:with_parentheses]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
module Expression
|
6
|
+
module Binary
|
7
|
+
class Base < Expression::Base
|
8
|
+
def initialize(left, right, lineno)
|
9
|
+
super({ left:, right: }, {}, lineno)
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param [Compiler] compiler
|
13
|
+
def compile(compiler)
|
14
|
+
compiler.
|
15
|
+
raw('(').
|
16
|
+
subcompile(nodes[:left]).
|
17
|
+
raw(' ')
|
18
|
+
|
19
|
+
operator(compiler)
|
20
|
+
|
21
|
+
compiler.
|
22
|
+
raw(' ').
|
23
|
+
subcompile(nodes[:right]).
|
24
|
+
raw(')')
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param [Compiler] compiler
|
28
|
+
def operator(compiler)
|
29
|
+
raise 'operator is not implemented'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
OPERATORS = {
|
34
|
+
Equal: '==',
|
35
|
+
NotEqual: '!=',
|
36
|
+
Spaceship: '<=>',
|
37
|
+
Less: '<',
|
38
|
+
Greater: '>',
|
39
|
+
LessEqual: '<=',
|
40
|
+
GreaterEqual: '>=',
|
41
|
+
|
42
|
+
Or: '||',
|
43
|
+
Xor: '^',
|
44
|
+
And: '&&',
|
45
|
+
Add: '+',
|
46
|
+
Sub: '-',
|
47
|
+
Concat: '+',
|
48
|
+
Mul: '*',
|
49
|
+
Div: '/',
|
50
|
+
}.freeze
|
51
|
+
|
52
|
+
# Lots of simple operator classes can just be generated dynamically
|
53
|
+
OPERATORS.each do |name, operation|
|
54
|
+
const_set(name.to_s, Class.new(Binary::Base) do
|
55
|
+
def operator(compiler)
|
56
|
+
compiler.raw(self.class.const_get('OPERATOR'))
|
57
|
+
end
|
58
|
+
end).const_set('OPERATOR', operation)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
module Expression
|
6
|
+
class Call < Expression::Base
|
7
|
+
private
|
8
|
+
|
9
|
+
# @param [Compiler] compiler
|
10
|
+
def compile_callable(compiler)
|
11
|
+
callable = attributes[:twig_callable].callable
|
12
|
+
|
13
|
+
compiler.
|
14
|
+
raw("env.extension(%q[#{callable[0].class.name}]).#{callable[1]}")
|
15
|
+
|
16
|
+
compile_arguments(compiler)
|
17
|
+
end
|
18
|
+
|
19
|
+
def compile_arguments(compiler)
|
20
|
+
compiler.
|
21
|
+
raw('(').
|
22
|
+
subcompile(nodes[:node]).
|
23
|
+
raw(')')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
module Expression
|
6
|
+
class Constant < Expression::Base
|
7
|
+
def initialize(value, lineno)
|
8
|
+
super({}, { value: }, lineno)
|
9
|
+
end
|
10
|
+
|
11
|
+
def compile(compiler)
|
12
|
+
compiler.repr(attributes[:value])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
module Expression
|
6
|
+
class Filter < Call
|
7
|
+
# @param [Node::Base] node
|
8
|
+
# @param [TwigFilter|Constant] filter
|
9
|
+
def initialize(node, filter, arguments, lineno)
|
10
|
+
if filter.is_a?(TwigFilter)
|
11
|
+
name = filter.name
|
12
|
+
filter_name = Constant.new(name, lineno)
|
13
|
+
else
|
14
|
+
name = filter.attributes[:value]
|
15
|
+
filter_name = filter
|
16
|
+
end
|
17
|
+
|
18
|
+
super({
|
19
|
+
node:,
|
20
|
+
filter: filter_name,
|
21
|
+
arguments:,
|
22
|
+
}, {
|
23
|
+
name:,
|
24
|
+
type: 'filter',
|
25
|
+
}, lineno)
|
26
|
+
|
27
|
+
if filter.is_a?(Filter)
|
28
|
+
attributes[:twig_callable] = filter
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def compile(compiler)
|
33
|
+
name = nodes[:filter].attributes[:value]
|
34
|
+
|
35
|
+
if name != attributes[:name]
|
36
|
+
raise 'Changing the value of a "filter" node is not supported'
|
37
|
+
end
|
38
|
+
|
39
|
+
if name == 'raw'
|
40
|
+
raise 'Cannot create raw filter via expression'
|
41
|
+
end
|
42
|
+
|
43
|
+
unless attributes.key?(:twig_callable)
|
44
|
+
attributes[:twig_callable] = compiler.environment.filter(name)
|
45
|
+
end
|
46
|
+
|
47
|
+
compile_callable(compiler)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
module Expression
|
6
|
+
class GetAttribute < Expression::Base
|
7
|
+
def initialize(node, attribute, arguments, type, lineno)
|
8
|
+
nodes = { node:, attribute: }
|
9
|
+
nodes[:arguments] = arguments if arguments
|
10
|
+
|
11
|
+
super(nodes, { type: }, lineno)
|
12
|
+
end
|
13
|
+
|
14
|
+
def compile(compiler)
|
15
|
+
var = compiler.var_name
|
16
|
+
|
17
|
+
compiler.
|
18
|
+
raw("(#{var} = ").
|
19
|
+
subcompile(nodes[:node]).
|
20
|
+
raw("\n").
|
21
|
+
write("::Twig::Extension::Core.get_attribute(#{var}, ").
|
22
|
+
subcompile(nodes[:attribute]).
|
23
|
+
raw(', ').
|
24
|
+
repr(attributes[:type]).
|
25
|
+
raw('))')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
module Expression
|
6
|
+
class HelperMethod < Expression::Base
|
7
|
+
def initialize(name, args, lineno)
|
8
|
+
super({ args: }, { name: }, lineno)
|
9
|
+
end
|
10
|
+
|
11
|
+
def compile(compiler)
|
12
|
+
compiler.
|
13
|
+
raw("@call_context.#{attributes[:name]}(")
|
14
|
+
|
15
|
+
nodes[:args].nodes.each do |key, value|
|
16
|
+
unless key.is_a?(Integer)
|
17
|
+
compiler.raw("#{key}: ")
|
18
|
+
end
|
19
|
+
|
20
|
+
compiler.
|
21
|
+
subcompile(value).
|
22
|
+
raw(',')
|
23
|
+
end
|
24
|
+
|
25
|
+
compiler.
|
26
|
+
raw(')')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
module Expression
|
6
|
+
class Name < Expression::Base
|
7
|
+
SPECIAL_VARS = {
|
8
|
+
'_self' => 'get_template_name',
|
9
|
+
'_context' => 'context',
|
10
|
+
'_charset' => 'env.charset',
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
# @param [String] name
|
14
|
+
# @param [Integer] lineno
|
15
|
+
def initialize(name, lineno)
|
16
|
+
super({}, {
|
17
|
+
name:,
|
18
|
+
is_defined_test: false,
|
19
|
+
ignore_strict_check: false,
|
20
|
+
alwways_defined: false,
|
21
|
+
}, lineno)
|
22
|
+
end
|
23
|
+
|
24
|
+
def compile(compiler)
|
25
|
+
name = attributes[:name]
|
26
|
+
|
27
|
+
compiler.
|
28
|
+
raw("(context.key?(:#{name})").
|
29
|
+
raw(" ? context[:#{name}]").
|
30
|
+
raw(' : raise("#{').
|
31
|
+
string(name).
|
32
|
+
raw('} does not exist"))')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
module Expression
|
6
|
+
class Ternary < Expression::Base
|
7
|
+
def initialize(test, left, right, lineno)
|
8
|
+
super({
|
9
|
+
test:,
|
10
|
+
left:,
|
11
|
+
right:,
|
12
|
+
}, {}, lineno)
|
13
|
+
end
|
14
|
+
|
15
|
+
def compile(compiler)
|
16
|
+
compiler.
|
17
|
+
raw('((').
|
18
|
+
subcompile(nodes[:test]).
|
19
|
+
raw(') ? (').
|
20
|
+
subcompile(nodes[:left]).
|
21
|
+
raw(') : (').
|
22
|
+
subcompile(nodes[:right]).
|
23
|
+
raw('))')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
module Expression
|
6
|
+
module Unary
|
7
|
+
class Base < Expression::Base
|
8
|
+
# @param [Node::Base] node
|
9
|
+
# @param [Integer] lineno
|
10
|
+
def initialize(node, lineno)
|
11
|
+
super({ node: }, { with_parenthesis: false }, lineno)
|
12
|
+
end
|
13
|
+
|
14
|
+
def compile(compiler)
|
15
|
+
if explicit_parentheses?
|
16
|
+
compiler.raw('(')
|
17
|
+
else
|
18
|
+
compiler.raw(' ')
|
19
|
+
end
|
20
|
+
|
21
|
+
operator(compiler)
|
22
|
+
compiler.subcompile(nodes[:node])
|
23
|
+
|
24
|
+
if explicit_parentheses?
|
25
|
+
compiler.raw(')')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param [Compiler] compiler
|
30
|
+
def operator(compiler)
|
31
|
+
raise 'operator is not implemented'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
OPERATORS = {
|
36
|
+
Not: '!',
|
37
|
+
Neg: '-',
|
38
|
+
Pos: '+',
|
39
|
+
}.freeze
|
40
|
+
|
41
|
+
# Lots of simple operator classes can just be generated dynamically
|
42
|
+
OPERATORS.each do |name, operation|
|
43
|
+
const_set(name.to_s, Class.new(Unary::Base) do
|
44
|
+
def operator(compiler)
|
45
|
+
compiler.raw(self.class.const_get('OPERATOR'))
|
46
|
+
end
|
47
|
+
end).const_set('OPERATOR', operation)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
class For < Node::Base
|
6
|
+
def initialize(key_target, value_target, seq, if_expr, body, else_expr, lineno)
|
7
|
+
loop = ForLoop.new(lineno)
|
8
|
+
body = Nodes.new(AutoHash.new.add(body, loop))
|
9
|
+
|
10
|
+
nodes = {
|
11
|
+
key_target:,
|
12
|
+
value_target:,
|
13
|
+
seq:,
|
14
|
+
body:,
|
15
|
+
}
|
16
|
+
|
17
|
+
unless else_expr.nil?
|
18
|
+
nodes[:else_expr] = else_expr
|
19
|
+
end
|
20
|
+
|
21
|
+
super(nodes, { with_loop: true }, lineno)
|
22
|
+
end
|
23
|
+
|
24
|
+
def compile(compiler)
|
25
|
+
compiler.
|
26
|
+
write("context.push_stack\n").
|
27
|
+
write('context[:_seq] = ::Twig::Extension::Core.ensure_hash(').
|
28
|
+
subcompile(nodes[:seq]).
|
29
|
+
raw(")\n")
|
30
|
+
|
31
|
+
# @todo Missing some more loops stuff here
|
32
|
+
|
33
|
+
if nodes.key?(:else_expr)
|
34
|
+
compiler.write("context[:_iterated] = false\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
compiler.
|
38
|
+
write("context[:_seq].each do |k, v|\n").
|
39
|
+
indent.
|
40
|
+
write('').
|
41
|
+
subcompile(nodes[:key_target]).
|
42
|
+
raw(" = k\n").
|
43
|
+
write('').
|
44
|
+
subcompile(nodes[:value_target]).
|
45
|
+
raw(" = v\n\n").
|
46
|
+
subcompile(nodes[:body]).
|
47
|
+
outdent.
|
48
|
+
write("end\n")
|
49
|
+
|
50
|
+
if nodes.key?(:else_expr)
|
51
|
+
compiler.
|
52
|
+
write("unless context[:_iterated]\n").
|
53
|
+
indent.
|
54
|
+
subcompile(nodes[:else_expr]).
|
55
|
+
outdent.
|
56
|
+
write("end\n")
|
57
|
+
end
|
58
|
+
|
59
|
+
compiler.
|
60
|
+
write("context.pop_stack\n")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
class ForLoop < Node::Base
|
6
|
+
def initialize(lineno)
|
7
|
+
super({}, { with_loop: false, if_expr: false, else_expr: false }, lineno)
|
8
|
+
end
|
9
|
+
|
10
|
+
def compile(compiler)
|
11
|
+
if attributes.key?(:else_expr)
|
12
|
+
compiler.write("context[:_iterated] = true\n")
|
13
|
+
end
|
14
|
+
|
15
|
+
# @todo if with loop
|
16
|
+
compiler.
|
17
|
+
write("context[:loop] = {\n").
|
18
|
+
write(" index0: 0,\n").
|
19
|
+
write(" index: 1,\n").
|
20
|
+
write(" first: true,\n").
|
21
|
+
write("}\n")
|
22
|
+
|
23
|
+
if attributes.key?(:with_loop)
|
24
|
+
compiler.
|
25
|
+
write("context[:loop][:index0] += 1\n").
|
26
|
+
write("context[:loop][:index] += 1\n").
|
27
|
+
write("context[:loop][:first] = false\n").
|
28
|
+
write("if context[:loop].key?(:revindex0) && context[:loop].key?(:revindex)\n").
|
29
|
+
indent.
|
30
|
+
write("context[:loop][:revindex0] -= 1\n").
|
31
|
+
write("context[:loop][:revindex] -= 1\n").
|
32
|
+
write("context[:loop][:last] = (context[:loop][:revindex0] == 0)\n").
|
33
|
+
outdent.
|
34
|
+
write("end\n")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/twig/node/if.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
class If < Node::Base
|
6
|
+
def initialize(tests, else_node, lineno)
|
7
|
+
nodes = { tests: }
|
8
|
+
nodes[:else] = else_node if else_node
|
9
|
+
|
10
|
+
super(nodes, {}, lineno)
|
11
|
+
end
|
12
|
+
|
13
|
+
def compile(compiler)
|
14
|
+
(0...nodes[:tests].nodes.length).step(2).each do |i|
|
15
|
+
if i.zero?
|
16
|
+
compiler.
|
17
|
+
raw("\n").
|
18
|
+
write('if (')
|
19
|
+
else
|
20
|
+
compiler.
|
21
|
+
outdent.
|
22
|
+
write('elsif (')
|
23
|
+
end
|
24
|
+
|
25
|
+
compiler.
|
26
|
+
subcompile(nodes[:tests].nodes[i]).
|
27
|
+
raw(")\n").
|
28
|
+
indent
|
29
|
+
|
30
|
+
if nodes[:tests].nodes.key?(i + 1)
|
31
|
+
compiler.
|
32
|
+
subcompile(nodes[:tests].nodes[i + 1])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
if nodes.key?(:else)
|
37
|
+
compiler.
|
38
|
+
outdent.
|
39
|
+
write("else\n").
|
40
|
+
indent.
|
41
|
+
subcompile(nodes[:else])
|
42
|
+
end
|
43
|
+
|
44
|
+
compiler.
|
45
|
+
outdent.
|
46
|
+
write("end\n\n")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Twig
|
4
|
+
module Node
|
5
|
+
class Include < Node::Base
|
6
|
+
# @param [Expression::Base] expr
|
7
|
+
# @param [Expression::Base, nil] variables
|
8
|
+
# @param [Boolean] only
|
9
|
+
# @param [Boolean] ignore_missing
|
10
|
+
# @param [Integer] lineno
|
11
|
+
def initialize(expr, variables, only, ignore_missing, lineno)
|
12
|
+
nodes = { expr: }
|
13
|
+
nodes[:variables] = variables if variables
|
14
|
+
|
15
|
+
super(nodes, {
|
16
|
+
only:,
|
17
|
+
ignore_missing:,
|
18
|
+
}, lineno)
|
19
|
+
end
|
20
|
+
|
21
|
+
def compile(compiler)
|
22
|
+
if attributes[:ignore_missing]
|
23
|
+
# @todo
|
24
|
+
raise 'not implemented yet'
|
25
|
+
else
|
26
|
+
compiler.
|
27
|
+
write('')
|
28
|
+
|
29
|
+
add_get_template(compiler)
|
30
|
+
|
31
|
+
compiler.
|
32
|
+
raw('.render(')
|
33
|
+
|
34
|
+
add_template_arguments(compiler)
|
35
|
+
|
36
|
+
compiler.
|
37
|
+
raw(");\n")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# @param [Compiler] compiler
|
44
|
+
def add_get_template(compiler)
|
45
|
+
compiler.
|
46
|
+
raw('load_template(').
|
47
|
+
subcompile(nodes[:expr]).
|
48
|
+
raw(', ').
|
49
|
+
repr(template_name).
|
50
|
+
raw(', ').
|
51
|
+
repr(lineno).
|
52
|
+
raw(')')
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param [Compiler] compiler
|
56
|
+
def add_template_arguments(compiler)
|
57
|
+
if !nodes.key?(:variables)
|
58
|
+
compiler.raw(attributes[:only] == false ? 'context' : '{}')
|
59
|
+
elsif attributes[:only] == false
|
60
|
+
compiler.
|
61
|
+
raw('context.merge(').
|
62
|
+
subcompile(nodes[:variables]).
|
63
|
+
raw(')')
|
64
|
+
else
|
65
|
+
compiler.
|
66
|
+
subcompile(nodes[:variables])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|