rblade 1.2.1 → 2.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/.github/workflows/ruby.yml +2 -5
- data/CHANGELOG.md +17 -0
- data/README.md +1 -1
- data/docker-compose.yml +1 -1
- data/lib/rblade/compiler/compiles_components.rb +32 -39
- data/lib/rblade/compiler/compiles_prints.rb +18 -16
- data/lib/rblade/compiler/compiles_ruby.rb +1 -7
- data/lib/rblade/compiler/compiles_statements.rb +2 -8
- data/lib/rblade/compiler/statements/compiles_component_helpers.rb +5 -5
- data/lib/rblade/compiler/statements/compiles_conditionals.rb +23 -23
- data/lib/rblade/compiler/statements/compiles_form.rb +7 -7
- data/lib/rblade/compiler/statements/compiles_html_attributes.rb +4 -4
- data/lib/rblade/compiler/statements/compiles_inline_ruby.rb +1 -1
- data/lib/rblade/compiler/statements/compiles_loops.rb +15 -15
- data/lib/rblade/compiler/statements/compiles_once.rb +6 -24
- data/lib/rblade/compiler/statements/compiles_stacks.rb +10 -54
- data/lib/rblade/compiler/tokenizes_components.rb +21 -11
- data/lib/rblade/compiler/tokenizes_statements.rb +10 -4
- data/lib/rblade/compiler.rb +23 -14
- data/lib/rblade/component_store.rb +35 -35
- data/lib/rblade/helpers/attributes_manager.rb +11 -9
- data/lib/rblade/helpers/slot_manager.rb +7 -4
- data/lib/rblade/helpers/stack_manager.rb +18 -18
- data/lib/rblade/rails_template.rb +4 -9
- data/rblade.gemspec +3 -3
- metadata +6 -7
- data/lib/rblade/helpers/html_string.rb +0 -6
@@ -9,7 +9,7 @@ module RBlade
|
|
9
9
|
|
10
10
|
def compileBreak args
|
11
11
|
if args&.count&.> 1
|
12
|
-
raise
|
12
|
+
raise RBladeTemplateError.new "Break statement: wrong number of arguments (given #{args.count}, expecting 0 or 1)"
|
13
13
|
end
|
14
14
|
|
15
15
|
if args.nil?
|
@@ -21,13 +21,13 @@ module RBlade
|
|
21
21
|
|
22
22
|
def compileEach args
|
23
23
|
if args.nil? || args.count > 2
|
24
|
-
raise
|
24
|
+
raise RBladeTemplateError.new "Each statement: wrong number of arguments (given #{args&.count || 0}, expecting 1 or 2)"
|
25
25
|
end
|
26
26
|
last_arg, collection = args.pop.split(" in ")
|
27
27
|
args.push(last_arg)
|
28
28
|
|
29
29
|
if collection.nil?
|
30
|
-
raise
|
30
|
+
raise RBladeTemplateError.new "Each statement: collection not found (expecting 'in')"
|
31
31
|
end
|
32
32
|
|
33
33
|
"#{collection}.each do |#{args.join(",")}|;"
|
@@ -35,13 +35,13 @@ module RBlade
|
|
35
35
|
|
36
36
|
def compileEachWithIndex args
|
37
37
|
if args.nil? || args.count > 3
|
38
|
-
raise
|
38
|
+
raise RBladeTemplateError.new "Each with index statement: wrong number of arguments (given #{args&.count || 0}, expecting 1 to 3)"
|
39
39
|
end
|
40
40
|
last_arg, collection = args.pop.split(" in ")
|
41
41
|
args.push(last_arg)
|
42
42
|
|
43
43
|
if collection.nil?
|
44
|
-
raise
|
44
|
+
raise RBladeTemplateError.new "Each with index statement: collection not found (expecting 'in')"
|
45
45
|
end
|
46
46
|
|
47
47
|
# Special case for 3 arguments: the first 2 arguments are the key/value pair in a Hash, and
|
@@ -55,13 +55,13 @@ module RBlade
|
|
55
55
|
|
56
56
|
def compileEachElse args
|
57
57
|
if args.nil? || args.count > 2
|
58
|
-
raise
|
58
|
+
raise RBladeTemplateError.new "Each else statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
59
59
|
end
|
60
60
|
last_arg, collection = args.pop.split(" in ")
|
61
61
|
args.push(last_arg)
|
62
62
|
|
63
63
|
if collection.nil?
|
64
|
-
raise
|
64
|
+
raise RBladeTemplateError.new "Each else statement: collection not found (expecting 'in')"
|
65
65
|
end
|
66
66
|
|
67
67
|
@loop_else_counter += 1
|
@@ -71,13 +71,13 @@ module RBlade
|
|
71
71
|
|
72
72
|
def compileEachWithIndexElse args
|
73
73
|
if args.nil? || args.count > 3
|
74
|
-
raise
|
74
|
+
raise RBladeTemplateError.new "Each with index statement: wrong number of arguments (given #{args&.count || 0}, expecting 1 to 3)"
|
75
75
|
end
|
76
76
|
last_arg, collection = args.pop.split(" in ")
|
77
77
|
args.push(last_arg)
|
78
78
|
|
79
79
|
if collection.nil?
|
80
|
-
raise
|
80
|
+
raise RBladeTemplateError.new "Each with index statement: collection not found (expecting 'in')"
|
81
81
|
end
|
82
82
|
|
83
83
|
@loop_else_counter += 1
|
@@ -93,7 +93,7 @@ module RBlade
|
|
93
93
|
|
94
94
|
def compileFor args
|
95
95
|
if args&.count != 1
|
96
|
-
raise
|
96
|
+
raise RBladeTemplateError.new "For statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
97
97
|
end
|
98
98
|
|
99
99
|
"for #{args[0]};"
|
@@ -101,7 +101,7 @@ module RBlade
|
|
101
101
|
|
102
102
|
def compileForElse args
|
103
103
|
if args&.count != 1
|
104
|
-
raise
|
104
|
+
raise RBladeTemplateError.new "For else statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
105
105
|
end
|
106
106
|
@loop_else_counter += 1
|
107
107
|
|
@@ -110,7 +110,7 @@ module RBlade
|
|
110
110
|
|
111
111
|
def compileEmpty args
|
112
112
|
unless args.nil?
|
113
|
-
raise
|
113
|
+
raise RBladeTemplateError.new "Empty statement: wrong number of arguments (given #{args.count}, expecting 0)"
|
114
114
|
end
|
115
115
|
|
116
116
|
@loop_else_counter -= 1
|
@@ -120,7 +120,7 @@ module RBlade
|
|
120
120
|
|
121
121
|
def compileNext args
|
122
122
|
if args&.count&.> 1
|
123
|
-
raise
|
123
|
+
raise RBladeTemplateError.new "Next statement: wrong number of arguments (given #{args.count}, expecting 0 or 1)"
|
124
124
|
end
|
125
125
|
|
126
126
|
if args.nil?
|
@@ -132,7 +132,7 @@ module RBlade
|
|
132
132
|
|
133
133
|
def compileUntil args
|
134
134
|
if args&.count != 1
|
135
|
-
raise
|
135
|
+
raise RBladeTemplateError.new "Until statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
136
136
|
end
|
137
137
|
|
138
138
|
"until #{args[0]};"
|
@@ -140,7 +140,7 @@ module RBlade
|
|
140
140
|
|
141
141
|
def compileWhile args
|
142
142
|
if args&.count != 1
|
143
|
-
raise
|
143
|
+
raise RBladeTemplateError.new "While statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
144
144
|
end
|
145
145
|
|
146
146
|
"while #{args[0]};"
|
@@ -9,50 +9,32 @@ module RBlade
|
|
9
9
|
|
10
10
|
def compileOnce args
|
11
11
|
if args&.count&.> 1
|
12
|
-
raise
|
12
|
+
raise RBladeTemplateError.new "Once statement: wrong number of arguments (given #{args.count}, expecting 0 or 1)"
|
13
13
|
end
|
14
14
|
|
15
15
|
once_id = args.nil? ? ":_#{@once_counter += 1}" : args[0]
|
16
16
|
|
17
|
-
"unless
|
17
|
+
"unless @_rblade_once_tokens.include? #{once_id};@_rblade_once_tokens<<#{once_id};"
|
18
18
|
end
|
19
19
|
|
20
20
|
def compilePushOnce args
|
21
21
|
if args&.count != 1 && args&.count != 2
|
22
|
-
raise
|
22
|
+
raise RBladeTemplateError.new "Push once statement: wrong number of arguments (given #{args&.count || 0}, expecting 1 or 2)"
|
23
23
|
end
|
24
24
|
@once_counter += 1
|
25
25
|
once_id = args[1].nil? ? ":_#{@once_counter}" : args[1]
|
26
26
|
|
27
|
-
"
|
28
|
-
<< "_p1_#{@once_counter}=#{args[0]};_p1_#{@once_counter}_b=_out;_out=+'';"
|
29
|
-
end
|
30
|
-
|
31
|
-
def compileEndPushOnce args
|
32
|
-
unless args.nil?
|
33
|
-
raise StandardError.new "End push once statement: wrong number of arguments (given #{args.count}, expecting 0)"
|
34
|
-
end
|
35
|
-
|
36
|
-
"RBlade::StackManager.push(_p1_#{@once_counter}, _out);_out=_p1_#{@once_counter}_b;end;"
|
27
|
+
"(@_rblade_once_tokens.include? #{once_id}) || @_rblade_once_tokens<<#{once_id} && @_rblade_stack_manager.push(#{args[0]}, @output_buffer) do;"
|
37
28
|
end
|
38
29
|
|
39
30
|
def compilePrependOnce args
|
40
31
|
if args&.count != 1 && args&.count != 2
|
41
|
-
raise
|
32
|
+
raise RBladeTemplateError.new "Prepend once statement: wrong number of arguments (given #{args&.count || 0}, expecting 1 or 2)"
|
42
33
|
end
|
43
34
|
@once_counter += 1
|
44
35
|
once_id = args[1].nil? ? ":_#{@once_counter}" : args[1]
|
45
36
|
|
46
|
-
"
|
47
|
-
<< "_p1_#{@once_counter}=#{args[0]};_p1_#{@once_counter}_b=_out;_out=+'';"
|
48
|
-
end
|
49
|
-
|
50
|
-
def compileEndPrependOnce args
|
51
|
-
unless args.nil?
|
52
|
-
raise StandardError.new "End prepend once statement: wrong number of arguments (given #{args.count}, expecting 0)"
|
53
|
-
end
|
54
|
-
|
55
|
-
"RBlade::StackManager.prepend(_p1_#{@once_counter}, _out);_out=_p1_#{@once_counter}_b;end;"
|
37
|
+
"(@_rblade_once_tokens.include? #{once_id}) || @_rblade_once_tokens<<#{once_id} && @_rblade_stack_manager.prepend(#{args[0]}, @output_buffer) do;"
|
56
38
|
end
|
57
39
|
end
|
58
40
|
end
|
@@ -3,88 +3,44 @@
|
|
3
3
|
module RBlade
|
4
4
|
class CompilesStatements
|
5
5
|
class CompilesStacks
|
6
|
-
def initialize
|
7
|
-
@push_counter = 0
|
8
|
-
end
|
9
|
-
|
10
6
|
def compileStack args
|
11
7
|
if args&.count != 1
|
12
|
-
raise
|
8
|
+
raise RBladeTemplateError.new "Stack statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
13
9
|
end
|
14
10
|
|
15
|
-
"
|
11
|
+
"@_rblade_stack_manager.initialize_stack(#{args[0]}, @output_buffer);_stacks.push(#{args[0]});"
|
16
12
|
end
|
17
13
|
|
18
14
|
def compilePrepend args
|
19
15
|
if args&.count != 1
|
20
|
-
raise
|
16
|
+
raise RBladeTemplateError.new "Prepend statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
21
17
|
end
|
22
18
|
|
23
|
-
@
|
24
|
-
|
25
|
-
"_p_#{@push_counter}=#{args[0]};_p_#{@push_counter}_b=_out;_out=+'';"
|
26
|
-
end
|
27
|
-
|
28
|
-
def compileEndPrepend args
|
29
|
-
unless args.nil?
|
30
|
-
raise StandardError.new "End prepend statement: wrong number of arguments (given #{args&.count}, expecting 0)"
|
31
|
-
end
|
32
|
-
|
33
|
-
@push_counter -= 1
|
34
|
-
|
35
|
-
"RBlade::StackManager.prepend(_p_#{@push_counter + 1}, _out);_out=_p_#{@push_counter + 1}_b;"
|
19
|
+
"@_rblade_stack_manager.prepend(#{args[0]}, @output_buffer) do;"
|
36
20
|
end
|
37
21
|
|
38
22
|
def compilePrependIf args
|
39
23
|
if args&.count != 2
|
40
|
-
raise
|
41
|
-
end
|
42
|
-
|
43
|
-
"if #{args[0]};" + compilePrepend([args[1]])
|
44
|
-
end
|
45
|
-
|
46
|
-
def compileEndPrependIf args
|
47
|
-
unless args.nil?
|
48
|
-
raise StandardError.new "End prepend if statement: wrong number of arguments (given #{args.count}, expecting 0)"
|
24
|
+
raise RBladeTemplateError.new "Prepend if statement: wrong number of arguments (given #{args&.count}, expecting 2)"
|
49
25
|
end
|
50
26
|
|
51
|
-
"
|
27
|
+
"(#{args[0]}) && @_rblade_stack_manager.prepend(#{args[1]}, @output_buffer) do;"
|
52
28
|
end
|
53
29
|
|
54
30
|
def compilePush args
|
55
31
|
if args&.count != 1
|
56
|
-
raise
|
32
|
+
raise RBladeTemplateError.new "Push statement: wrong number of arguments (given #{args&.count}, expecting 1)"
|
57
33
|
end
|
58
34
|
|
59
|
-
@
|
60
|
-
|
61
|
-
"_p_#{@push_counter}=#{args[0]};_p_#{@push_counter}_b=_out;_out=+'';"
|
35
|
+
"@_rblade_stack_manager.push(#{args[0]}, @output_buffer) do;"
|
62
36
|
end
|
63
37
|
|
64
38
|
def compilePushIf args
|
65
39
|
if args&.count != 2
|
66
|
-
raise
|
67
|
-
end
|
68
|
-
|
69
|
-
"if #{args[0]};" + compilePush([args[1]])
|
70
|
-
end
|
71
|
-
|
72
|
-
def compileEndPush args
|
73
|
-
unless args.nil?
|
74
|
-
raise StandardError.new "End push statement: wrong number of arguments (given #{args.count}, expecting 0)"
|
75
|
-
end
|
76
|
-
|
77
|
-
@push_counter -= 1
|
78
|
-
|
79
|
-
"RBlade::StackManager.push(_p_#{@push_counter + 1}, _out);_out=_p_#{@push_counter + 1}_b;"
|
80
|
-
end
|
81
|
-
|
82
|
-
def compileEndPushIf args
|
83
|
-
unless args.nil?
|
84
|
-
raise StandardError.new "End push if statement: wrong number of arguments (given #{args.count}, expecting 0)"
|
40
|
+
raise RBladeTemplateError.new "Push if statement: wrong number of arguments (given #{args&.count || 0}, expecting 2)"
|
85
41
|
end
|
86
42
|
|
87
|
-
"
|
43
|
+
"(#{args[0]}) && @_rblade_stack_manager.push(#{args[1]}, @output_buffer) do;"
|
88
44
|
end
|
89
45
|
end
|
90
46
|
end
|
@@ -12,7 +12,7 @@ module RBlade
|
|
12
12
|
|
13
13
|
i = 0
|
14
14
|
while i < segments.count
|
15
|
-
if segments[i] == "</" && segments[i + 1]&.match(/x[-:]/)
|
15
|
+
if segments[i] == "</" && segments[i + 1]&.match?(/x[-:]/)
|
16
16
|
segments[i] = Token.new(type: :component_end, value: {name: segments[i + 1][2..]})
|
17
17
|
|
18
18
|
segments.delete_at i + 1
|
@@ -20,7 +20,7 @@ module RBlade
|
|
20
20
|
elsif segments[i] == "<//>"
|
21
21
|
segments[i] = Token.new(type: :component_unsafe_end)
|
22
22
|
i += 1
|
23
|
-
elsif segments[i] == "<" && segments[i + 1]&.match(/x[-:]/)
|
23
|
+
elsif segments[i] == "<" && segments[i + 1]&.match?(/x[-:]/)
|
24
24
|
name = segments[i + 1][2..]
|
25
25
|
raw_attributes = (segments[i + 2] != ">") ? tokenizeAttributes(segments[i + 2]) : nil
|
26
26
|
|
@@ -66,7 +66,7 @@ module RBlade
|
|
66
66
|
attributes.push({type: "attributes", value: raw_attributes[i + 1]})
|
67
67
|
i += 3
|
68
68
|
else
|
69
|
-
attribute = {
|
69
|
+
attribute = {}
|
70
70
|
|
71
71
|
if raw_attributes[i + 1] == "="
|
72
72
|
attribute[:value] = raw_attributes[i + 2]
|
@@ -78,18 +78,28 @@ module RBlade
|
|
78
78
|
# The "::" at the start of attributes is used to escape attribute names beginning with ":"
|
79
79
|
if name[0..1] == "::"
|
80
80
|
attribute[:type] = "string"
|
81
|
-
attribute[:name]
|
81
|
+
attribute[:name] = name[1..]
|
82
|
+
attributes.push(attribute)
|
83
|
+
next
|
84
|
+
end
|
85
|
+
|
86
|
+
# If the entire value is a single interpolated string, make this a ruby value
|
87
|
+
if attribute[:value]&.match?(/\A\{\{([^}]|(?!\}\})\})*\}\}\Z/)
|
88
|
+
attribute[:type] = "ruby"
|
89
|
+
attribute[:name] = name
|
90
|
+
attribute[:value] = attribute[:value][2..-3]
|
82
91
|
attributes.push(attribute)
|
83
92
|
next
|
84
93
|
end
|
85
94
|
|
86
95
|
if name[0] == ":"
|
87
96
|
attribute[:type] = attribute[:value].nil? ? "pass_through" : "ruby"
|
88
|
-
attribute[:name]
|
97
|
+
attribute[:name] = name[1..]
|
89
98
|
attributes.push(attribute)
|
90
99
|
next
|
91
100
|
end
|
92
101
|
|
102
|
+
attribute[:name] = name
|
93
103
|
attribute[:type] = if attribute[:value].nil?
|
94
104
|
"empty"
|
95
105
|
else
|
@@ -129,11 +139,11 @@ module RBlade
|
|
129
139
|
(?:
|
130
140
|
=
|
131
141
|
(?:
|
132
|
-
"[^"]*"
|
142
|
+
"(?:[^"{]*?|(?<!@)\{\{.*?\}\}|\{)*"
|
133
143
|
|
|
134
|
-
'[
|
144
|
+
'(?:[^'{]*?|(?<!@)\{\{.*?\}\}|\{)*'
|
135
145
|
|
|
136
|
-
[^'"=<>\s\/]
|
146
|
+
(?:[^'"=<>\s\/{]+|(?<!@)\{\{.*?\}\}|\{)*
|
137
147
|
)
|
138
148
|
)?
|
139
149
|
)
|
@@ -178,11 +188,11 @@ module RBlade
|
|
178
188
|
(?:
|
179
189
|
(=)
|
180
190
|
(?:
|
181
|
-
"([^"]*)"
|
191
|
+
"((?:[^"{]*?|(?<!@)\{\{.*?\}\}|\{)*)"
|
182
192
|
|
|
183
|
-
'([
|
193
|
+
'((?:[^'{]*?|(?<!@)\{\{.*?\}\}|\{)*)'
|
184
194
|
|
|
185
|
-
([^'"=<>\s\/]
|
195
|
+
((?:[^'"=<>\s\/{]+|(?<!@)\{\{.*?\}\}|\{)*)
|
186
196
|
)
|
187
197
|
)?
|
188
198
|
)
|
@@ -10,7 +10,7 @@ module RBlade
|
|
10
10
|
next(token) if token.type != :unprocessed
|
11
11
|
|
12
12
|
segments = token.value.split(/
|
13
|
-
\s?(?<!\w)
|
13
|
+
(\s)?(?<!\w)
|
14
14
|
(?:
|
15
15
|
(?:
|
16
16
|
(@@)
|
@@ -25,7 +25,7 @@ module RBlade
|
|
25
25
|
)?
|
26
26
|
)
|
27
27
|
)
|
28
|
-
\s?
|
28
|
+
(\s)?
|
29
29
|
/mx)
|
30
30
|
|
31
31
|
parseSegments! segments
|
@@ -49,12 +49,18 @@ module RBlade
|
|
49
49
|
if CompilesStatements.has_handler(segments[i + 1])
|
50
50
|
tokenizeStatement! segments, i
|
51
51
|
handleSpecialCases! segments, i
|
52
|
+
|
53
|
+
segments.delete_at(i + 1) if segments[i + 1]&.match?(/\A\s\Z/)
|
54
|
+
if segments[i - 1].is_a?(Token) && segments[i - 1].type == :unprocessed && segments[i - 1].value.match?(/\A\s\Z/)
|
55
|
+
segments.delete_at i - 1
|
56
|
+
i -= 1
|
57
|
+
end
|
52
58
|
else
|
53
59
|
# For unhandled statements, restore the original string
|
54
60
|
segments[i] = Token.new(type: :unprocessed, value: segments[i] + segments[i + 1])
|
55
61
|
segments.delete_at i + 1
|
56
62
|
|
57
|
-
if segments.count > i + 2 && segments[i + 1].match(
|
63
|
+
if segments.count > i + 2 && segments[i + 1].match?(/\A[ \t]*\Z/) && segments[i + 2][0] == "("
|
58
64
|
segments[i].value += segments[i + 1] + segments[i + 2]
|
59
65
|
segments.delete_at i + 1
|
60
66
|
segments.delete_at i + 1
|
@@ -82,7 +88,7 @@ module RBlade
|
|
82
88
|
statement_name = segments.delete_at i + 1
|
83
89
|
|
84
90
|
# Remove optional whitespace
|
85
|
-
if segments.count > i + 2 && segments[i + 1].match(
|
91
|
+
if segments.count > i + 2 && segments[i + 1].match?(/\A[ \t]*\Z/) && segments[i + 2][0] == "("
|
86
92
|
segments.delete_at i + 1
|
87
93
|
end
|
88
94
|
|
data/lib/rblade/compiler.rb
CHANGED
@@ -8,7 +8,6 @@ require "rblade/compiler/compiles_verbatim"
|
|
8
8
|
require "rblade/compiler/compiles_statements"
|
9
9
|
require "rblade/compiler/tokenizes_components"
|
10
10
|
require "rblade/compiler/tokenizes_statements"
|
11
|
-
require "rblade/helpers/html_string"
|
12
11
|
require "active_support/core_ext/string/output_safety"
|
13
12
|
|
14
13
|
Token = Struct.new(:type, :value)
|
@@ -23,13 +22,7 @@ module RBlade
|
|
23
22
|
string.gsub(/['\\\x0]/, '\\\\\0')
|
24
23
|
end
|
25
24
|
|
26
|
-
|
27
|
-
if string.is_a?(HtmlString) || string.is_a?(ActiveSupport::SafeBuffer)
|
28
|
-
string
|
29
|
-
else
|
30
|
-
h(string)
|
31
|
-
end
|
32
|
-
end
|
25
|
+
class RBladeTemplateError < StandardError; end
|
33
26
|
|
34
27
|
# Register a new custom directive by providing a class and method that will compile the directive into ruby code.
|
35
28
|
#
|
@@ -41,7 +34,7 @@ module RBlade
|
|
41
34
|
end
|
42
35
|
|
43
36
|
class Compiler
|
44
|
-
def self.compileString(string_template)
|
37
|
+
def self.compileString(string_template, component_store)
|
45
38
|
tokens = [Token.new(:unprocessed, string_template)]
|
46
39
|
|
47
40
|
CompilesVerbatim.new.compile! tokens
|
@@ -51,7 +44,10 @@ module RBlade
|
|
51
44
|
CompilesPrints.new.compile! tokens
|
52
45
|
TokenizesStatements.new.tokenize! tokens
|
53
46
|
CompilesStatements.new.compile! tokens
|
54
|
-
|
47
|
+
|
48
|
+
component_compiler = CompilesComponents.new(component_store)
|
49
|
+
component_compiler.compile! tokens
|
50
|
+
component_compiler.ensure_all_tags_closed
|
55
51
|
|
56
52
|
compileTokens tokens
|
57
53
|
end
|
@@ -69,12 +65,25 @@ module RBlade
|
|
69
65
|
def self.compileTokens tokens
|
70
66
|
output = +""
|
71
67
|
|
72
|
-
|
73
|
-
|
74
|
-
|
68
|
+
i = 0
|
69
|
+
while i < tokens.count
|
70
|
+
token = tokens[i]
|
71
|
+
if token.type == :unprocessed || token.type == :raw_text
|
72
|
+
output << "@output_buffer.raw_buffer<<-'"
|
73
|
+
|
74
|
+
# Merge together consecutive prints
|
75
|
+
while tokens[i + 1]&.type == :unprocessed || tokens[i + 1]&.type == :raw_text
|
76
|
+
output << RBlade.escape_quotes(token.value)
|
77
|
+
i += 1
|
78
|
+
token = tokens[i]
|
79
|
+
end
|
80
|
+
|
81
|
+
output << RBlade.escape_quotes(token.value)
|
82
|
+
output << "';"
|
75
83
|
else
|
76
|
-
token.value
|
84
|
+
output << token.value
|
77
85
|
end
|
86
|
+
i += 1
|
78
87
|
end
|
79
88
|
|
80
89
|
output
|
@@ -1,22 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RBlade
|
4
|
-
FILE_EXTENSIONS = [".rblade", ".html.rblade"]
|
5
|
-
|
6
4
|
class ComponentStore
|
5
|
+
FILE_EXTENSIONS = [".rblade", ".html.rblade"]
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@component_definitions = +""
|
9
|
+
@component_name_stack = []
|
10
|
+
@component_method_names = {}
|
11
|
+
end
|
12
|
+
|
7
13
|
# Retrieve the method name for a component, and compile it if it hasn't already been compiled
|
8
|
-
def
|
14
|
+
def component(full_name)
|
9
15
|
# If this is a relative path, prepend with the previous component name's base
|
10
16
|
if full_name.start_with? "."
|
11
|
-
full_name =
|
17
|
+
full_name = @component_name_stack.last.gsub(/\.[^\.]+\Z/, "") + full_name
|
12
18
|
end
|
13
19
|
|
14
20
|
# Ensure each component is only compiled once
|
15
|
-
unless
|
16
|
-
return
|
21
|
+
unless @component_method_names[full_name].nil?
|
22
|
+
return @component_method_names[full_name]
|
17
23
|
end
|
18
24
|
|
19
|
-
|
25
|
+
@component_name_stack << full_name
|
20
26
|
|
21
27
|
namespace = nil
|
22
28
|
name = full_name
|
@@ -26,36 +32,32 @@ module RBlade
|
|
26
32
|
end
|
27
33
|
|
28
34
|
method_name = compile_component full_name, File.read(find_component_file(namespace, name))
|
29
|
-
|
35
|
+
@component_name_stack.pop
|
30
36
|
|
31
37
|
method_name
|
32
38
|
end
|
33
39
|
|
34
|
-
def self.add_path
|
40
|
+
def self.add_path(path, namespace = nil)
|
35
41
|
path = path.to_s
|
36
|
-
|
37
|
-
path
|
42
|
+
unless path.end_with? "/"
|
43
|
+
path << "/"
|
38
44
|
end
|
39
45
|
|
40
46
|
@@template_paths[namespace] ||= []
|
41
47
|
@@template_paths[namespace] << path
|
42
48
|
end
|
43
49
|
|
44
|
-
def
|
45
|
-
|
50
|
+
def view_name(view_name)
|
51
|
+
@component_name_stack.push view_name
|
46
52
|
end
|
47
53
|
|
48
|
-
def
|
49
|
-
|
54
|
+
def get
|
55
|
+
@component_definitions
|
50
56
|
end
|
51
57
|
|
52
|
-
|
53
|
-
@@component_definitions = +""
|
54
|
-
@@component_method_names = {}
|
55
|
-
@@component_name_stack = []
|
56
|
-
end
|
58
|
+
private
|
57
59
|
|
58
|
-
def
|
60
|
+
def find_component_file(namespace, name)
|
59
61
|
file_path = name.tr ".", "/"
|
60
62
|
|
61
63
|
@@template_paths[namespace]&.each do |base_path|
|
@@ -65,32 +67,30 @@ module RBlade
|
|
65
67
|
end
|
66
68
|
if File.exist? base_path + file_path + "/index" + extension
|
67
69
|
# Account for index files for relative components
|
68
|
-
|
70
|
+
@component_name_stack << @component_name_stack.pop + ".index"
|
69
71
|
return "#{base_path}#{file_path}/index#{extension}"
|
70
72
|
end
|
71
73
|
end
|
72
74
|
end
|
73
75
|
|
74
|
-
raise
|
76
|
+
raise RBladeTemplateError.new "Unknown component #{namespace}::#{name}"
|
75
77
|
end
|
76
|
-
private_class_method :find_component_file
|
77
78
|
|
78
|
-
def
|
79
|
-
|
79
|
+
def compile_component(name, template)
|
80
|
+
escaped_name = name.gsub(/[^0-9a-zA-Z_]/) do |match|
|
81
|
+
# Convert invalid characters to hex
|
82
|
+
(match == ".") ? "__" : "_#{match.unpack1("H*")}_"
|
83
|
+
end
|
80
84
|
|
81
|
-
compiled_component = RBlade::Compiler.compileString(
|
85
|
+
compiled_component = RBlade::Compiler.compileString(template, self)
|
82
86
|
|
83
|
-
|
87
|
+
slot_assignment = compiled_component.match?(/\Wslot\W/) ? "slot=" : ""
|
84
88
|
|
85
|
-
|
86
|
-
end
|
87
|
-
private_class_method :compile_component
|
89
|
+
@component_definitions << "def self._rblade_component_#{escaped_name}(attributes,&);#{slot_assignment}if block_given?;RBlade::SlotManager.new(@output_buffer.capture(->(name, slot_attributes, &slot_block)do;attributes[name]=RBlade::SlotManager.new(@output_buffer.capture(&slot_block), slot_attributes);end,&));end;_stacks=[];@output_buffer.raw_buffer<<@output_buffer.capture do;#{compiled_component}@output_buffer.raw_buffer.prepend(@_rblade_stack_manager.get(_stacks));end;end;"
|
88
90
|
|
89
|
-
|
91
|
+
@component_method_names[name] = "_rblade_component_#{escaped_name}"
|
92
|
+
end
|
90
93
|
|
91
|
-
@@component_definitions = +""
|
92
|
-
@@component_name_stack = []
|
93
|
-
@@component_method_names = {}
|
94
94
|
@@template_paths = {}
|
95
95
|
end
|
96
96
|
end
|
@@ -1,9 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "rblade/helpers/html_string"
|
4
|
-
|
5
3
|
module RBlade
|
6
|
-
class AttributesManager
|
4
|
+
class AttributesManager
|
7
5
|
@attributes = {}
|
8
6
|
def initialize attributes
|
9
7
|
@attributes = attributes
|
@@ -35,16 +33,20 @@ module RBlade
|
|
35
33
|
@attributes.respond_to?(method_name)
|
36
34
|
end
|
37
35
|
|
38
|
-
def
|
36
|
+
def html_safe?
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_str attributes = nil
|
39
41
|
attributes ||= @attributes
|
40
42
|
|
41
43
|
attributes.map do |key, value|
|
42
44
|
(value == true) ? key : "#{key}=\"#{h(value)}\""
|
43
|
-
end.join
|
45
|
+
end.join(" ")
|
44
46
|
end
|
45
47
|
|
46
|
-
def
|
47
|
-
|
48
|
+
def to_s
|
49
|
+
self
|
48
50
|
end
|
49
51
|
|
50
52
|
def only(keys)
|
@@ -111,7 +113,7 @@ module RBlade
|
|
111
113
|
return classes_1
|
112
114
|
end
|
113
115
|
|
114
|
-
classes_combined = classes_1
|
116
|
+
classes_combined = +classes_1
|
115
117
|
unless classes_combined.end_with? " "
|
116
118
|
classes_combined << " "
|
117
119
|
end
|
@@ -128,7 +130,7 @@ module RBlade
|
|
128
130
|
return styles_1
|
129
131
|
end
|
130
132
|
|
131
|
-
styles_combined = styles_1
|
133
|
+
styles_combined = +styles_1
|
132
134
|
unless styles_combined.end_with? ";"
|
133
135
|
styles_combined << ";"
|
134
136
|
end
|