twig_ruby 0.0.1 → 0.0.2
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 +4 -4
- data/lib/tasks/twig_parity.rake +278 -0
- data/lib/twig/auto_hash.rb +7 -1
- data/lib/twig/callable.rb +28 -1
- data/lib/twig/compiler.rb +35 -3
- data/lib/twig/environment.rb +198 -41
- data/lib/twig/error/base.rb +81 -16
- data/lib/twig/error/loader.rb +8 -0
- data/lib/twig/error/logic.rb +8 -0
- data/lib/twig/error/runtime.rb +8 -0
- data/lib/twig/expression_parser/base.rb +30 -0
- data/lib/twig/expression_parser/expression_parsers.rb +57 -0
- data/lib/twig/expression_parser/infix/arrow.rb +31 -0
- data/lib/twig/expression_parser/infix/binary.rb +34 -0
- data/lib/twig/expression_parser/infix/conditional_ternary.rb +39 -0
- data/lib/twig/expression_parser/infix/dot.rb +72 -0
- data/lib/twig/expression_parser/infix/filter.rb +43 -0
- data/lib/twig/expression_parser/infix/function.rb +67 -0
- data/lib/twig/expression_parser/infix/is.rb +53 -0
- data/lib/twig/expression_parser/infix/is_not.rb +19 -0
- data/lib/twig/expression_parser/infix/parses_arguments.rb +84 -0
- data/lib/twig/expression_parser/infix/square_bracket.rb +66 -0
- data/lib/twig/expression_parser/infix_expression_parser.rb +34 -0
- data/lib/twig/expression_parser/prefix/grouping.rb +60 -0
- data/lib/twig/expression_parser/prefix/literal.rb +244 -0
- data/lib/twig/expression_parser/prefix/unary.rb +29 -0
- data/lib/twig/expression_parser/prefix_expression_parser.rb +18 -0
- data/lib/twig/extension/base.rb +26 -4
- data/lib/twig/extension/core.rb +1076 -48
- data/lib/twig/extension/debug.rb +25 -0
- data/lib/twig/extension/escaper.rb +73 -0
- data/lib/twig/extension/rails.rb +10 -57
- data/lib/twig/extension/string_loader.rb +19 -0
- data/lib/twig/extension_set.rb +117 -20
- data/lib/twig/file_extension_escaping_strategy.rb +35 -0
- data/lib/twig/lexer.rb +225 -81
- data/lib/twig/loader/array.rb +25 -8
- data/lib/twig/loader/chain.rb +93 -0
- data/lib/twig/loader/filesystem.rb +106 -7
- data/lib/twig/node/auto_escape.rb +18 -0
- data/lib/twig/node/base.rb +58 -2
- data/lib/twig/node/block.rb +2 -0
- data/lib/twig/node/block_reference.rb +5 -1
- data/lib/twig/node/body.rb +7 -0
- data/lib/twig/node/cache.rb +50 -0
- data/lib/twig/node/capture.rb +22 -0
- data/lib/twig/node/deprecated.rb +53 -0
- data/lib/twig/node/do.rb +19 -0
- data/lib/twig/node/embed.rb +43 -0
- data/lib/twig/node/expression/array.rb +29 -20
- data/lib/twig/node/expression/arrow_function.rb +55 -0
- data/lib/twig/node/expression/assign_name.rb +1 -1
- data/lib/twig/node/expression/binary/and.rb +17 -0
- data/lib/twig/node/expression/binary/base.rb +6 -4
- data/lib/twig/node/expression/binary/boolean.rb +24 -0
- data/lib/twig/node/expression/binary/concat.rb +20 -0
- data/lib/twig/node/expression/binary/elvis.rb +35 -0
- data/lib/twig/node/expression/binary/ends_with.rb +24 -0
- data/lib/twig/node/expression/binary/floor_div.rb +21 -0
- data/lib/twig/node/expression/binary/has_every.rb +20 -0
- data/lib/twig/node/expression/binary/has_some.rb +20 -0
- data/lib/twig/node/expression/binary/in.rb +20 -0
- data/lib/twig/node/expression/binary/matches.rb +24 -0
- data/lib/twig/node/expression/binary/not_in.rb +20 -0
- data/lib/twig/node/expression/binary/null_coalesce.rb +49 -0
- data/lib/twig/node/expression/binary/or.rb +15 -0
- data/lib/twig/node/expression/binary/starts_with.rb +24 -0
- data/lib/twig/node/expression/binary/xor.rb +17 -0
- data/lib/twig/node/expression/block_reference.rb +62 -0
- data/lib/twig/node/expression/call.rb +126 -6
- data/lib/twig/node/expression/constant.rb +3 -1
- data/lib/twig/node/expression/filter/default.rb +37 -0
- data/lib/twig/node/expression/filter/raw.rb +31 -0
- data/lib/twig/node/expression/filter.rb +2 -2
- data/lib/twig/node/expression/function.rb +37 -0
- data/lib/twig/node/expression/get_attribute.rb +51 -7
- data/lib/twig/node/expression/hash.rb +75 -0
- data/lib/twig/node/expression/helper_method.rb +6 -18
- data/lib/twig/node/expression/macro_reference.rb +43 -0
- data/lib/twig/node/expression/name.rb +42 -8
- data/lib/twig/node/expression/operator_escape.rb +13 -0
- data/lib/twig/node/expression/parent.rb +28 -0
- data/lib/twig/node/expression/support_defined_test.rb +23 -0
- data/lib/twig/node/expression/ternary.rb +7 -1
- data/lib/twig/node/expression/test/base.rb +26 -0
- data/lib/twig/node/expression/test/constant.rb +35 -0
- data/lib/twig/node/expression/test/defined.rb +33 -0
- data/lib/twig/node/expression/test/divisible_by.rb +23 -0
- data/lib/twig/node/expression/test/even.rb +21 -0
- data/lib/twig/node/expression/test/iterable.rb +21 -0
- data/lib/twig/node/expression/test/mapping.rb +21 -0
- data/lib/twig/node/expression/test/null.rb +21 -0
- data/lib/twig/node/expression/test/odd.rb +21 -0
- data/lib/twig/node/expression/test/same_as.rb +23 -0
- data/lib/twig/node/expression/test/sequence.rb +21 -0
- data/lib/twig/node/expression/unary/base.rb +3 -1
- data/lib/twig/node/expression/unary/not.rb +18 -0
- data/lib/twig/node/expression/unary/spread.rb +18 -0
- data/lib/twig/node/expression/unary/string_cast.rb +18 -0
- data/lib/twig/node/expression/variable/assign_template.rb +35 -0
- data/lib/twig/node/expression/variable/local.rb +35 -0
- data/lib/twig/node/expression/variable/template.rb +54 -0
- data/lib/twig/node/for.rb +38 -8
- data/lib/twig/node/for_loop.rb +0 -22
- data/lib/twig/node/if.rb +4 -1
- data/lib/twig/node/import.rb +32 -0
- data/lib/twig/node/include.rb +38 -8
- data/lib/twig/node/macro.rb +79 -0
- data/lib/twig/node/module.rb +278 -23
- data/lib/twig/node/output.rb +7 -0
- data/lib/twig/node/print.rb +4 -1
- data/lib/twig/node/set.rb +72 -0
- data/lib/twig/node/text.rb +4 -1
- data/lib/twig/node/with.rb +50 -0
- data/lib/twig/node/yield.rb +6 -1
- data/lib/twig/node_traverser.rb +50 -0
- data/lib/twig/node_visitor/base.rb +30 -0
- data/lib/twig/node_visitor/escaper.rb +165 -0
- data/lib/twig/node_visitor/safe_analysis.rb +127 -0
- data/lib/twig/node_visitor/spreader.rb +39 -0
- data/lib/twig/output_buffer.rb +14 -12
- data/lib/twig/parser.rb +281 -8
- data/lib/twig/rails/config.rb +33 -0
- data/lib/twig/rails/engine.rb +44 -0
- data/lib/twig/rails/renderer.rb +41 -0
- data/lib/twig/runtime/argument_spreader.rb +46 -0
- data/lib/twig/runtime/context.rb +154 -0
- data/lib/twig/runtime/enumerable_hash.rb +51 -0
- data/lib/twig/runtime/escaper.rb +155 -0
- data/lib/twig/runtime/loop_context.rb +81 -0
- data/lib/twig/runtime/loop_iterator.rb +60 -0
- data/lib/twig/runtime/spread.rb +21 -0
- data/lib/twig/runtime_loader/base.rb +12 -0
- data/lib/twig/runtime_loader/factory.rb +23 -0
- data/lib/twig/template.rb +267 -14
- data/lib/twig/template_wrapper.rb +42 -0
- data/lib/twig/token.rb +28 -2
- data/lib/twig/token_parser/apply.rb +48 -0
- data/lib/twig/token_parser/auto_escape.rb +45 -0
- data/lib/twig/token_parser/base.rb +26 -0
- data/lib/twig/token_parser/block.rb +4 -4
- data/lib/twig/token_parser/cache.rb +31 -0
- data/lib/twig/token_parser/deprecated.rb +40 -0
- data/lib/twig/token_parser/do.rb +19 -0
- data/lib/twig/token_parser/embed.rb +62 -0
- data/lib/twig/token_parser/extends.rb +4 -3
- data/lib/twig/token_parser/for.rb +14 -9
- data/lib/twig/token_parser/from.rb +57 -0
- data/lib/twig/token_parser/guard.rb +65 -0
- data/lib/twig/token_parser/if.rb +9 -9
- data/lib/twig/token_parser/import.rb +29 -0
- data/lib/twig/token_parser/include.rb +2 -2
- data/lib/twig/token_parser/macro.rb +109 -0
- data/lib/twig/token_parser/set.rb +76 -0
- data/lib/twig/token_parser/use.rb +54 -0
- data/lib/twig/token_parser/with.rb +36 -0
- data/lib/twig/token_parser/yield.rb +7 -7
- data/lib/twig/token_stream.rb +23 -3
- data/lib/twig/twig_filter.rb +20 -0
- data/lib/twig/twig_function.rb +37 -0
- data/lib/twig/twig_test.rb +31 -0
- data/lib/twig/util/callable_arguments_extractor.rb +227 -0
- data/lib/twig_ruby.rb +21 -2
- metadata +145 -6
- data/lib/twig/context.rb +0 -64
- data/lib/twig/expression_parser.rb +0 -517
- data/lib/twig/railtie.rb +0 -60
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
module Binary
|
|
7
|
+
class Concat < Binary::Base
|
|
8
|
+
def compile(compiler)
|
|
9
|
+
compiler.
|
|
10
|
+
raw('(').
|
|
11
|
+
subcompile(nodes[:left]).
|
|
12
|
+
raw(').to_s + (').
|
|
13
|
+
subcompile(nodes[:right]).
|
|
14
|
+
raw(').to_s')
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
module Binary
|
|
7
|
+
class Elvis < Binary::Base
|
|
8
|
+
include OperatorEscape
|
|
9
|
+
|
|
10
|
+
def initialize(left, right, lineno)
|
|
11
|
+
super
|
|
12
|
+
|
|
13
|
+
nodes[:test] = left.dup
|
|
14
|
+
left.attributes[:always_defined] = true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def compile(compiler)
|
|
18
|
+
compiler.
|
|
19
|
+
raw('(::Twig::Extension::Core.bool(').
|
|
20
|
+
subcompile(nodes[:test]).
|
|
21
|
+
raw(') ? (').
|
|
22
|
+
subcompile(nodes[:left]).
|
|
23
|
+
raw(') : (').
|
|
24
|
+
subcompile(nodes[:right]).
|
|
25
|
+
raw('))')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def operand_names_to_escape
|
|
29
|
+
%i[left right]
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
module Binary
|
|
7
|
+
class EndsWith < Binary::Base
|
|
8
|
+
def compile(compiler)
|
|
9
|
+
left = compiler.var_name
|
|
10
|
+
right = compiler.var_name
|
|
11
|
+
|
|
12
|
+
compiler.
|
|
13
|
+
raw("(#{left} = ").
|
|
14
|
+
subcompile(nodes[:left]).
|
|
15
|
+
raw(').respond_to?(:end_with?) && ').
|
|
16
|
+
raw("(#{right} = ").
|
|
17
|
+
subcompile(nodes[:right]).
|
|
18
|
+
raw(").respond_to?(:end_with?) && (#{left}.end_with?(#{right}))")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
module Binary
|
|
7
|
+
class FloorDiv < Binary::Base
|
|
8
|
+
def compile(compiler)
|
|
9
|
+
compiler.raw('(')
|
|
10
|
+
super
|
|
11
|
+
compiler.raw(').floor.to_i')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def operator(compiler)
|
|
15
|
+
compiler.raw('/')
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
module Binary
|
|
7
|
+
class HasEvery < Binary::Base
|
|
8
|
+
def compile(compiler)
|
|
9
|
+
compiler.
|
|
10
|
+
raw('::Twig::Extension::Core.array_every?(').
|
|
11
|
+
subcompile(nodes[:left]).
|
|
12
|
+
raw(', ').
|
|
13
|
+
subcompile(nodes[:right]).
|
|
14
|
+
raw(')')
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
module Binary
|
|
7
|
+
class HasSome < Binary::Base
|
|
8
|
+
def compile(compiler)
|
|
9
|
+
compiler.
|
|
10
|
+
raw('::Twig::Extension::Core.array_some?(').
|
|
11
|
+
subcompile(nodes[:left]).
|
|
12
|
+
raw(', ').
|
|
13
|
+
subcompile(nodes[:right]).
|
|
14
|
+
raw(')')
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
module Binary
|
|
7
|
+
class In < Binary::Base
|
|
8
|
+
def compile(compiler)
|
|
9
|
+
compiler.
|
|
10
|
+
raw('::Twig::Extension::Core.in_filter(').
|
|
11
|
+
subcompile(nodes[:left]).
|
|
12
|
+
raw(', ').
|
|
13
|
+
subcompile(nodes[:right]).
|
|
14
|
+
raw(')')
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
module Binary
|
|
7
|
+
class Matches < Binary::Base
|
|
8
|
+
def compile(compiler)
|
|
9
|
+
compiler.
|
|
10
|
+
raw('::Twig::Extension::Core.matches(').
|
|
11
|
+
subcompile(nodes[:right]).
|
|
12
|
+
raw(', ').
|
|
13
|
+
subcompile(nodes[:left]).
|
|
14
|
+
raw(')')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def operator(compiler)
|
|
18
|
+
compiler.raw('')
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
module Binary
|
|
7
|
+
class NotIn < Binary::Base
|
|
8
|
+
def compile(compiler)
|
|
9
|
+
compiler.
|
|
10
|
+
raw('!::Twig::Extension::Core.in_filter(').
|
|
11
|
+
subcompile(nodes[:left]).
|
|
12
|
+
raw(', ').
|
|
13
|
+
subcompile(nodes[:right]).
|
|
14
|
+
raw(')')
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
module Binary
|
|
7
|
+
class NullCoalesce < Binary::Base
|
|
8
|
+
include OperatorEscape
|
|
9
|
+
|
|
10
|
+
def initialize(left, right, lineno)
|
|
11
|
+
super
|
|
12
|
+
|
|
13
|
+
test = Test::Defined.new(left.dup, TwigTest.new('defined'), Node::Empty.new, left.lineno)
|
|
14
|
+
|
|
15
|
+
unless left.is_a?(Expression::BlockReference)
|
|
16
|
+
test = Binary::And.new(
|
|
17
|
+
test,
|
|
18
|
+
Unary::Not.new(
|
|
19
|
+
Test::Null.new(left, TwigTest.new('null'), Node::Empty.new, left.lineno),
|
|
20
|
+
left.lineno
|
|
21
|
+
),
|
|
22
|
+
left.lineno
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
left.attributes[:always_defined] = true
|
|
27
|
+
nodes[:test] = test
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @param [Compiler] compiler
|
|
31
|
+
def compile(compiler)
|
|
32
|
+
compiler.
|
|
33
|
+
raw('((').
|
|
34
|
+
subcompile(nodes[:test]).
|
|
35
|
+
raw(') ? (').
|
|
36
|
+
subcompile(nodes[:left]).
|
|
37
|
+
raw(') : (').
|
|
38
|
+
subcompile(nodes[:right]).
|
|
39
|
+
raw('))')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def operand_names_to_escape
|
|
43
|
+
%i[left right]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
module Binary
|
|
7
|
+
class StartsWith < Binary::Base
|
|
8
|
+
def compile(compiler)
|
|
9
|
+
left = compiler.var_name
|
|
10
|
+
right = compiler.var_name
|
|
11
|
+
|
|
12
|
+
compiler.
|
|
13
|
+
raw("(#{left} = ").
|
|
14
|
+
subcompile(nodes[:left]).
|
|
15
|
+
raw(').respond_to?(:start_with?) && ').
|
|
16
|
+
raw("(#{right} = ").
|
|
17
|
+
subcompile(nodes[:right]).
|
|
18
|
+
raw(").respond_to?(:start_with?) && (#{left}.start_with?(#{right}))")
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
# Represents a block reference node
|
|
7
|
+
class BlockReference < Expression::Base
|
|
8
|
+
include SupportDefinedTest
|
|
9
|
+
|
|
10
|
+
# @param [String] name
|
|
11
|
+
# @param [String, nil] template
|
|
12
|
+
# @param [Integer] lineno
|
|
13
|
+
def initialize(name, template, lineno)
|
|
14
|
+
nodes = { name: }
|
|
15
|
+
nodes[:template] = template unless template.nil?
|
|
16
|
+
|
|
17
|
+
super(nodes, { output: false }, lineno)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def compile(compiler)
|
|
21
|
+
if define_test_enabled?
|
|
22
|
+
compile_template_call(compiler, 'block?')
|
|
23
|
+
else
|
|
24
|
+
compile_template_call(compiler, 'render_block')
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def compile_template_call(compiler, method)
|
|
31
|
+
if nodes.key?(:template)
|
|
32
|
+
compiler.
|
|
33
|
+
write('load(').
|
|
34
|
+
subcompile(nodes[:template]).
|
|
35
|
+
raw(', ').
|
|
36
|
+
repr(lineno).
|
|
37
|
+
raw(').unwrap')
|
|
38
|
+
else
|
|
39
|
+
compiler.write('self')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
compiler.raw(".#{method}")
|
|
43
|
+
|
|
44
|
+
compile_block_arguments(compiler)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def compile_block_arguments(compiler)
|
|
48
|
+
compiler.
|
|
49
|
+
raw('(').
|
|
50
|
+
subcompile(nodes[:name]).
|
|
51
|
+
raw(', context')
|
|
52
|
+
|
|
53
|
+
unless nodes.key?(:template)
|
|
54
|
+
compiler.raw(', blocks')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
compiler.raw(')')
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -4,23 +4,143 @@ module Twig
|
|
|
4
4
|
module Node
|
|
5
5
|
module Expression
|
|
6
6
|
class Call < Expression::Base
|
|
7
|
+
def compile(compiler)
|
|
8
|
+
compile_callable(compiler)
|
|
9
|
+
end
|
|
10
|
+
|
|
7
11
|
private
|
|
8
12
|
|
|
9
13
|
# @param [Compiler] compiler
|
|
10
14
|
def compile_callable(compiler)
|
|
11
|
-
|
|
15
|
+
argument_nodes = [nodes.key?(:node) ? nodes[:node] : nil, *nodes[:arguments].nodes.values]
|
|
16
|
+
has_spread = argument_nodes.any? { |node| node.is_a?(Unary::Spread) }
|
|
17
|
+
|
|
18
|
+
if has_spread
|
|
19
|
+
compiler.
|
|
20
|
+
raw('::Twig::Runtime::ArgumentSpreader.new(').
|
|
21
|
+
raw(callable_method).
|
|
22
|
+
raw(').call')
|
|
23
|
+
else
|
|
24
|
+
compiler.
|
|
25
|
+
raw(callable_method).
|
|
26
|
+
raw('.call')
|
|
27
|
+
end
|
|
12
28
|
|
|
13
29
|
compiler.
|
|
14
|
-
raw("
|
|
30
|
+
raw("(\n").
|
|
31
|
+
indent.
|
|
32
|
+
write('')
|
|
15
33
|
|
|
16
34
|
compile_arguments(compiler)
|
|
35
|
+
|
|
36
|
+
compiler.
|
|
37
|
+
raw("\n").
|
|
38
|
+
outdent.
|
|
39
|
+
write(')')
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [String]
|
|
43
|
+
def callable_method
|
|
44
|
+
# @type [Twig::Callable] callable
|
|
45
|
+
twig_callable = attributes[:twig_callable]
|
|
46
|
+
callable = twig_callable.callable
|
|
47
|
+
|
|
48
|
+
case callable
|
|
49
|
+
when ::Array
|
|
50
|
+
if callable[0] == :runtime
|
|
51
|
+
_, klass, method = callable
|
|
52
|
+
|
|
53
|
+
"env.runtime(%q[#{klass}]).method(:#{method})"
|
|
54
|
+
else
|
|
55
|
+
extension, method = callable[0, 2]
|
|
56
|
+
extension = extension.class.name if extension.is_a?(Extension::Base)
|
|
57
|
+
|
|
58
|
+
"env.extension(%q[#{extension.delete_prefix('::')}]).method(:#{method})"
|
|
59
|
+
end
|
|
60
|
+
when ::Method
|
|
61
|
+
# Instance method
|
|
62
|
+
if callable.receiver.is_a?(Extension::Base)
|
|
63
|
+
"env.extension(%q[#{callable.owner.name}]).method(:#{callable.name})"
|
|
64
|
+
# Class method
|
|
65
|
+
else
|
|
66
|
+
"#{callable.receiver.name}.method(:#{callable.name})"
|
|
67
|
+
end
|
|
68
|
+
when ::Proc
|
|
69
|
+
"env.#{attributes[:type]}(%q[#{twig_callable.dynamic_name}]).callable"
|
|
70
|
+
else
|
|
71
|
+
raise "Callable not supported: #{callable.inspect}"
|
|
72
|
+
end
|
|
17
73
|
end
|
|
18
74
|
|
|
19
75
|
def compile_arguments(compiler)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
76
|
+
first = true
|
|
77
|
+
# @type [Twig::Callable] callable
|
|
78
|
+
callable = attributes.fetch(:twig_callable, nil)
|
|
79
|
+
|
|
80
|
+
callable&.arguments&.each do |argument|
|
|
81
|
+
compiler.raw(', ') unless first
|
|
82
|
+
|
|
83
|
+
compiler.string(argument)
|
|
84
|
+
|
|
85
|
+
first = false
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
if callable&.needs_charset?
|
|
89
|
+
compiler.raw(', ') unless first
|
|
90
|
+
compiler.raw('env.charset')
|
|
91
|
+
first = false
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
if callable&.needs_environment?
|
|
95
|
+
compiler.raw(', ') unless first
|
|
96
|
+
compiler.raw('env')
|
|
97
|
+
first = false
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
if callable&.needs_context?
|
|
101
|
+
compiler.raw(', ') unless first
|
|
102
|
+
compiler.raw('context')
|
|
103
|
+
first = false
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
if nodes.key?(:node)
|
|
107
|
+
compiler.raw(', ') unless first
|
|
108
|
+
|
|
109
|
+
compiler.
|
|
110
|
+
subcompile(nodes[:node])
|
|
111
|
+
|
|
112
|
+
first = false
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Only callables that come through without are helper methods, which still
|
|
116
|
+
# can't be determined at compile time for Rails
|
|
117
|
+
if callable
|
|
118
|
+
positional, kwargs = Util::CallableArgumentsExtractor.
|
|
119
|
+
new(self, callable, compiler.environment).
|
|
120
|
+
extract_arguments(nodes[:arguments])
|
|
121
|
+
else
|
|
122
|
+
positional, kwargs = nodes[:arguments].nodes.partition do |key, node|
|
|
123
|
+
key.is_a?(Integer) || node.is_a?(Unary::Spread)
|
|
124
|
+
end.map(&:to_h)
|
|
125
|
+
|
|
126
|
+
positional = positional.values
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
positional.each do |node|
|
|
130
|
+
compiler.raw(', ') unless first
|
|
131
|
+
compiler.subcompile(node)
|
|
132
|
+
|
|
133
|
+
first = false
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
kwargs.each do |key, node|
|
|
137
|
+
compiler.raw(', ') unless first
|
|
138
|
+
compiler.
|
|
139
|
+
raw("'#{key}': ").
|
|
140
|
+
subcompile(node)
|
|
141
|
+
|
|
142
|
+
first = false
|
|
143
|
+
end
|
|
24
144
|
end
|
|
25
145
|
end
|
|
26
146
|
end
|
|
@@ -4,12 +4,14 @@ module Twig
|
|
|
4
4
|
module Node
|
|
5
5
|
module Expression
|
|
6
6
|
class Constant < Expression::Base
|
|
7
|
+
include Expression::SupportDefinedTest
|
|
8
|
+
|
|
7
9
|
def initialize(value, lineno)
|
|
8
10
|
super({}, { value: }, lineno)
|
|
9
11
|
end
|
|
10
12
|
|
|
11
13
|
def compile(compiler)
|
|
12
|
-
compiler.repr(attributes[:value])
|
|
14
|
+
compiler.repr(define_test_enabled? || attributes[:value])
|
|
13
15
|
end
|
|
14
16
|
end
|
|
15
17
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
class Filter
|
|
7
|
+
# Returns the value or the default value when it is undefined or empty.
|
|
8
|
+
#
|
|
9
|
+
# {{ var.foo|default('foo item on var is not defined') }}
|
|
10
|
+
class Default < Expression::Filter
|
|
11
|
+
# @param [Expression::Base] node
|
|
12
|
+
# @param [TwigFilter] filter
|
|
13
|
+
# @param [Node::Base] arguments
|
|
14
|
+
# @param [Integer] lineno
|
|
15
|
+
def initialize(node, filter, arguments, lineno)
|
|
16
|
+
name = filter.name
|
|
17
|
+
default = Expression::Filter.new(node, filter, arguments, node.lineno)
|
|
18
|
+
|
|
19
|
+
if name == 'default' && (node.is_a?(Variable::Context) || node.is_a?(GetAttribute))
|
|
20
|
+
test = Test::Defined.new(node.dup, TwigTest.new('defined'), Empty.new, node.lineno)
|
|
21
|
+
false_case = arguments.empty? ? Expression::Constant.new('', node.lineno) : arguments.nodes[0]
|
|
22
|
+
node = Ternary.new(test, default, false_case, node.lineno)
|
|
23
|
+
else
|
|
24
|
+
node = default
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def compile(compiler)
|
|
31
|
+
compiler.subcompile(nodes[:node])
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Twig
|
|
4
|
+
module Node
|
|
5
|
+
module Expression
|
|
6
|
+
class Filter
|
|
7
|
+
class Raw < Expression::Filter
|
|
8
|
+
# @param [Expression::Base] node
|
|
9
|
+
# @param [TwigFilter|nil] filter
|
|
10
|
+
# @param [Node::Base|nil] arguments
|
|
11
|
+
# @param [Integer] lineno
|
|
12
|
+
def initialize(node, filter = nil, arguments = nil, lineno = nil)
|
|
13
|
+
super(
|
|
14
|
+
node,
|
|
15
|
+
filter || TwigFilter.new('raw', nil, { is_safe: [:all] }),
|
|
16
|
+
arguments || Node::Empty.new,
|
|
17
|
+
lineno || node.lineno
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def compile(compiler)
|
|
22
|
+
compiler.
|
|
23
|
+
raw('((tmp = ').
|
|
24
|
+
subcompile(nodes[:node]).
|
|
25
|
+
raw(').respond_to?(:html_safe) ? tmp.html_safe : tmp)')
|
|
26
|
+
end
|
|
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 Function < Call
|
|
7
|
+
include SupportDefinedTest
|
|
8
|
+
|
|
9
|
+
# @param [TwigFunction] function
|
|
10
|
+
# @param [Node::Base] arguments
|
|
11
|
+
# @param [Integer] lineno
|
|
12
|
+
def initialize(function, arguments, lineno)
|
|
13
|
+
super({ arguments: }, {
|
|
14
|
+
name: function.name,
|
|
15
|
+
type: :function,
|
|
16
|
+
twig_callable: function,
|
|
17
|
+
is_defined_test: false,
|
|
18
|
+
}, lineno)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def enable_defined_test
|
|
22
|
+
if attributes[:name] == 'constant'
|
|
23
|
+
super
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def compile(compiler)
|
|
28
|
+
if attributes[:name] == 'constant' && define_test_enabled?
|
|
29
|
+
nodes[:arguments].nodes[:defined_test] = Expression::Constant.new(true, lineno)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|