rblade 1.1.1 → 1.2.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 +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +30 -3
- data/lib/rblade/compiler/compiles_comments.rb +2 -0
- data/lib/rblade/compiler/compiles_components.rb +5 -3
- data/lib/rblade/compiler/compiles_prints.rb +29 -9
- data/lib/rblade/compiler/compiles_ruby.rb +14 -6
- data/lib/rblade/compiler/compiles_statements.rb +21 -1
- data/lib/rblade/compiler/compiles_verbatim.rb +2 -0
- data/lib/rblade/compiler/statements/compiles_component_helpers.rb +6 -15
- data/lib/rblade/compiler/statements/compiles_conditionals.rb +2 -0
- data/lib/rblade/compiler/statements/compiles_form.rb +2 -0
- data/lib/rblade/compiler/statements/compiles_html_attributes.rb +2 -0
- data/lib/rblade/compiler/statements/compiles_inline_ruby.rb +2 -0
- data/lib/rblade/compiler/statements/compiles_loops.rb +2 -0
- data/lib/rblade/compiler/statements/compiles_once.rb +4 -2
- data/lib/rblade/compiler/statements/compiles_stacks.rb +5 -3
- data/lib/rblade/compiler/tokenizes_components.rb +2 -0
- data/lib/rblade/compiler/tokenizes_statements.rb +39 -7
- data/lib/rblade/compiler.rb +17 -6
- data/lib/rblade/component_store.rb +5 -8
- data/lib/rblade/helpers/attributes_manager.rb +2 -0
- data/lib/rblade/helpers/class_manager.rb +3 -1
- data/lib/rblade/helpers/html_string.rb +2 -0
- data/lib/rblade/helpers/slot_manager.rb +2 -0
- data/lib/rblade/helpers/stack_manager.rb +4 -2
- data/lib/rblade/helpers/style_manager.rb +3 -1
- data/lib/rblade/helpers/tokenizer.rb +3 -1
- data/lib/rblade/rails_template.rb +3 -1
- data/lib/rblade/railtie.rb +2 -0
- data/lib/rblade.rb +2 -0
- data/rblade.gemspec +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e633d7cbf716d70b0f9353e8d29990da0379f30171da143077c303e9557cdab8
|
4
|
+
data.tar.gz: ad29e9a1b4cbb0f493a7fa6dbe6fcb82ec64c822fe1c7351de65ab8d268cd1aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 261023b42b8ad6d163c3ac24fcc5d844a5d85c2915af94f26c40254f7ff3cd03b847e2107c97219f32967c402df09594583856c327ee071d9ac56f992a4fd1e2
|
7
|
+
data.tar.gz: 94e955703c7f041f6fc7e2dd5c40e143cb7779437ded8c4acbb5f7e81c0bc9cf424385093607c11a236560c83c389e201f1d1aa8a3f3e95de8aff3323921adf5
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## 1.2.1 [2024-10-31]
|
2
|
+
- Fix issue with @props directive when defining multiple properties without braces
|
3
|
+
|
4
|
+
## 1.2.0 [2024-10-22]
|
5
|
+
- Add support for custom directives (#2)
|
6
|
+
- Add support for helper functions that use block content (#14)
|
7
|
+
- Change to use frozen string literals
|
8
|
+
- Fix issue with no space after starting ERB style tag
|
9
|
+
- Ignore any @ directives that don't have a handler
|
10
|
+
- Make @endruby directive case insensitive and allow underscore
|
11
|
+
|
1
12
|
## 1.1.1 [2024-08-23]
|
2
13
|
- Remove requirement for including braces in `@props` directive
|
3
14
|
|
data/README.md
CHANGED
@@ -26,6 +26,7 @@ For a quick overview of RBlade's capabilities, refer to the [reference file](REF
|
|
26
26
|
* [Table of Contents](#table-of-contents)
|
27
27
|
* [Displaying Data](#displaying-data)
|
28
28
|
+ [HTML Entity Encoding](#html-entity-encoding)
|
29
|
+
+ [ERB Compatbility and Rails Helper Methods](#erb-compatibility-and-rails-helper-methods)
|
29
30
|
+ [RBlade and JavaScript Frameworks](#rblade-and-javascript-frameworks)
|
30
31
|
- [The `@verbatim` Directive](#the-at-verbatim-directive)
|
31
32
|
* [RBlade Directives](#rblade-directives)
|
@@ -37,6 +38,7 @@ For a quick overview of RBlade's capabilities, refer to the [reference file](REF
|
|
37
38
|
+ [Additional Attributes](#additional-attributes)
|
38
39
|
+ [The `@once` Directive](#the-once-directive)
|
39
40
|
+ [Raw Ruby](#raw-ruby)
|
41
|
+
+ [Custom Directives](#custom-directives)
|
40
42
|
+ [Comments](#comments)
|
41
43
|
* [Components](#components)
|
42
44
|
+ [Rendering Components](#rendering-components)
|
@@ -66,14 +68,14 @@ You can display data that is passed to your RBlade views by wrapping the variabl
|
|
66
68
|
|
67
69
|
```ruby
|
68
70
|
def index
|
69
|
-
name = "Samantha"
|
71
|
+
@name = "Samantha"
|
70
72
|
end
|
71
73
|
```
|
72
74
|
|
73
75
|
You can display the contents of the `name` variable like so:
|
74
76
|
|
75
77
|
```rblade
|
76
|
-
Hello, {{ name }}.
|
78
|
+
Hello, {{ @name }}.
|
77
79
|
```
|
78
80
|
|
79
81
|
> [!NOTE]
|
@@ -91,12 +93,20 @@ The current UNIX timestamp is {{ Time.now.to_i }}.
|
|
91
93
|
By default, RBlade `{{ }}` directives are automatically sent through Rails' `h` function to prevent XSS attacks. If you do not want your data to be escaped, you can use the following syntax:
|
92
94
|
|
93
95
|
```rblade
|
94
|
-
Hello, {!! name !!}.
|
96
|
+
Hello, {!! @name !!}.
|
95
97
|
```
|
96
98
|
|
97
99
|
> [!WARNING]
|
98
100
|
> Be very careful when printing content that is supplied by users of your application. You should typically use the escaped, double curly brace syntax to prevent XSS attacks when displaying user supplied data.
|
99
101
|
|
102
|
+
|
103
|
+
<a name="erb-compatibility-and-rails-helper-methods"></a>
|
104
|
+
### ERB Compatbility and Rails Helper Methods
|
105
|
+
|
106
|
+
For the most part, RBlade templates are backwards compatible with the built in ERB templates. Anything that works in an ERB template should also work in an RBlade template.
|
107
|
+
|
108
|
+
This includes helper methods, path helpers and methods from third party gems such as `simple_forms` or `vite-ruby`. It additionally includes the ERB syntax for outputting data, `<%= ... %>`, and running ruby code, `<%= ... %>`.
|
109
|
+
|
100
110
|
<a name="rblade-and-javascript-frameworks"></a>
|
101
111
|
### RBlade and JavaScript Frameworks
|
102
112
|
|
@@ -419,6 +429,23 @@ In some situations, it's useful to embed Ruby code into your views. You can use
|
|
419
429
|
@endRuby
|
420
430
|
```
|
421
431
|
|
432
|
+
<a name="custom-directives"></a>
|
433
|
+
### Custom Directives
|
434
|
+
|
435
|
+
RBlade also allows you to define your own directives using the `RBlade.register_directive_handler`
|
436
|
+
method. When the compiler encounters the custom directive, it will call the provided block and
|
437
|
+
output the returned value.
|
438
|
+
|
439
|
+
```rblade
|
440
|
+
RBlade::register_directive_handler('sum') do |args|
|
441
|
+
args.inject(0) { |sum, num| sum + num.to_i }
|
442
|
+
end
|
443
|
+
|
444
|
+
@sum(1) -> 1
|
445
|
+
@sum(1, 2) -> 3
|
446
|
+
@sum(1, 2, 3) -> 6
|
447
|
+
```
|
448
|
+
|
422
449
|
<a name="comments"></a>
|
423
450
|
### Comments
|
424
451
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "rblade/component_store"
|
2
4
|
|
3
5
|
module RBlade
|
@@ -34,7 +36,7 @@ module RBlade
|
|
34
36
|
|
35
37
|
attributes = compile_attributes token.value[:attributes]
|
36
38
|
|
37
|
-
code = "_c#{component[:index]}_swap=_out;_out
|
39
|
+
code = +"_c#{component[:index]}_swap=_out;_out=+'';"
|
38
40
|
code << "_c#{component[:index]}_attr={#{attributes.join(",")}};"
|
39
41
|
|
40
42
|
code
|
@@ -65,14 +67,14 @@ module RBlade
|
|
65
67
|
def compile_slot_end name, component
|
66
68
|
parent = @component_stack.last
|
67
69
|
|
68
|
-
code = "_c#{parent[:index]}_attr[:'#{RBlade.escape_quotes(name)}']=RBlade::SlotManager.new(_out,_c#{component[:index]}_attr);"
|
70
|
+
code = +"_c#{parent[:index]}_attr[:'#{RBlade.escape_quotes(name)}']=RBlade::SlotManager.new(_out,_c#{component[:index]}_attr);"
|
69
71
|
code << "_out=_c#{component[:index]}_swap;_c#{component[:index]}_swap=nil;_c#{component[:index]}_attr=nil;"
|
70
72
|
|
71
73
|
code
|
72
74
|
end
|
73
75
|
|
74
76
|
def compile_component_end component
|
75
|
-
code = "_slot=RBlade::SlotManager.new(_out);_out=_c#{component[:index]}_swap;"
|
77
|
+
code = +"_slot=RBlade::SlotManager.new(_out);_out=_c#{component[:index]}_swap;"
|
76
78
|
code << "_out<<#{ComponentStore.component(component[:name])}(_slot,_c#{component[:index]}_attr,params,session,flash,cookies);"
|
77
79
|
code << "_slot=nil;_c#{component[:index]}_swap=nil;_c#{component[:index]}_attr=nil;"
|
78
80
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RBlade
|
2
4
|
class CompilesPrints
|
3
5
|
def compile!(tokens)
|
@@ -8,8 +10,8 @@ module RBlade
|
|
8
10
|
private
|
9
11
|
|
10
12
|
def compile_regular_prints!(tokens)
|
11
|
-
compile_prints! tokens, "{{", "}}", "RBlade.e"
|
12
|
-
compile_prints! tokens, "<%=", "%>", "RBlade.e"
|
13
|
+
compile_prints! tokens, "{{", "}}", +"RBlade.e"
|
14
|
+
compile_prints! tokens, "<%=", "%>", +"RBlade.e"
|
13
15
|
end
|
14
16
|
|
15
17
|
def compile_unsafe_prints!(tokens)
|
@@ -35,14 +37,8 @@ module RBlade
|
|
35
37
|
elsif segments[i] == start_token
|
36
38
|
segments.delete_at i
|
37
39
|
segments.delete_at i + 1
|
38
|
-
segment_value = "_out<<"
|
39
40
|
|
40
|
-
|
41
|
-
wrapper_function + "(" + segments[i] + ");"
|
42
|
-
else
|
43
|
-
"(" + segments[i] + ").to_s;"
|
44
|
-
end
|
45
|
-
segments[i] = Token.new(:print, segment_value)
|
41
|
+
segments[i] = create_token(segments[i], wrapper_function)
|
46
42
|
|
47
43
|
i += 1
|
48
44
|
elsif !segments[i].nil? && segments[i] != ""
|
@@ -57,5 +53,29 @@ module RBlade
|
|
57
53
|
segments
|
58
54
|
end.flatten!
|
59
55
|
end
|
56
|
+
|
57
|
+
def create_token expression, wrapper_function
|
58
|
+
if expression.match?(/
|
59
|
+
do\s*
|
60
|
+
(
|
61
|
+
\|\s*
|
62
|
+
[a-zA-Z0-9_]+\s*
|
63
|
+
(,\s*[a-zA-Z0-9_]+)?\s*
|
64
|
+
\|\s*
|
65
|
+
)?
|
66
|
+
$/x)
|
67
|
+
return Token.new(:print, "_out+=#{expression};_out=+'';")
|
68
|
+
elsif expression.match?(/^\s*end(?![a-zA-Z0-9_])/i)
|
69
|
+
return Token.new(:print, "_out;#{expression};")
|
70
|
+
end
|
71
|
+
|
72
|
+
segment_value = if !wrapper_function.nil?
|
73
|
+
"_out<<#{wrapper_function}(#{expression});"
|
74
|
+
else
|
75
|
+
"_out<<(#{expression}).to_s;"
|
76
|
+
end
|
77
|
+
|
78
|
+
Token.new(:print, segment_value)
|
79
|
+
end
|
60
80
|
end
|
61
81
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RBlade
|
2
4
|
class CompilesRuby
|
3
5
|
def compile!(tokens)
|
@@ -6,15 +8,15 @@ module RBlade
|
|
6
8
|
|
7
9
|
segments = token.value.split(/
|
8
10
|
# @ escapes blade style tags
|
9
|
-
(@)(@ruby.+?@
|
11
|
+
(@)(@ruby.+?@end_?ruby)
|
10
12
|
|
|
11
13
|
# <%% and %%> are escape ERB style tags
|
12
14
|
(<%%)(.+?)(%%>)
|
13
15
|
|
|
14
|
-
\s?(?<!\w)(@ruby)\s+(.+?)[\s;]*(@
|
16
|
+
\s?(?<!\w)(@ruby)\s+(.+?)[\s;]*(@end_?ruby)(?!\w)\s?
|
15
17
|
|
|
16
|
-
(<%)\s
|
17
|
-
/
|
18
|
+
(<%)(?!=)\s*(.+?)[\s;]*(%>)
|
19
|
+
/xmi)
|
18
20
|
|
19
21
|
i = 0
|
20
22
|
while i < segments.count
|
@@ -29,7 +31,7 @@ module RBlade
|
|
29
31
|
segments[i] = Token.new(type: :raw_text, value: "<%#{segments[i]}%>")
|
30
32
|
|
31
33
|
i += 1
|
32
|
-
elsif segments[i] == "@ruby" || segments[i] == "<%"
|
34
|
+
elsif segments[i].downcase == "@ruby" || segments[i] == "<%"
|
33
35
|
segments.delete_at i
|
34
36
|
segments.delete_at i + 1
|
35
37
|
|
@@ -38,7 +40,13 @@ module RBlade
|
|
38
40
|
segments[i] << ";"
|
39
41
|
end
|
40
42
|
|
41
|
-
|
43
|
+
# Ensure _out is returned at the end of any blocks
|
44
|
+
# See also ./compiles_prints.rb
|
45
|
+
segments[i] = if segments[i].match?(/^end(?![a-zA-Z0-9_])/i)
|
46
|
+
Token.new(type: :ruby, value: "_out;#{segments[i]}")
|
47
|
+
else
|
48
|
+
Token.new(type: :ruby, value: segments[i])
|
49
|
+
end
|
42
50
|
|
43
51
|
i += 1
|
44
52
|
elsif !segments[i].nil? && segments[i] != ""
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "rblade/compiler/statements/compiles_component_helpers"
|
2
4
|
require "rblade/compiler/statements/compiles_conditionals"
|
3
5
|
require "rblade/compiler/statements/compiles_form"
|
@@ -13,6 +15,7 @@ module RBlade
|
|
13
15
|
token_index = 0
|
14
16
|
while token_index < tokens.count
|
15
17
|
token = tokens[token_index]
|
18
|
+
|
16
19
|
if token.type != :statement
|
17
20
|
token_index += 1
|
18
21
|
next
|
@@ -34,7 +37,11 @@ module RBlade
|
|
34
37
|
end
|
35
38
|
end
|
36
39
|
|
37
|
-
token.value = handler.
|
40
|
+
token.value = if handler.is_a? Proc
|
41
|
+
"_out<<'#{RBlade.escape_quotes(handler.call(*handler_arguments).to_s)}';"
|
42
|
+
else
|
43
|
+
handler.call(*handler_arguments)
|
44
|
+
end
|
38
45
|
token_index += 1
|
39
46
|
end
|
40
47
|
end
|
@@ -43,11 +50,24 @@ module RBlade
|
|
43
50
|
"end;"
|
44
51
|
end
|
45
52
|
|
53
|
+
def self.has_handler(name)
|
54
|
+
name = name.downcase
|
55
|
+
@@statement_handlers[name.tr("_", "")].present? || name.start_with?("end")
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.register_handler(name, &block)
|
59
|
+
@@statement_handlers[name.tr("_", "").downcase] = ["proc", block]
|
60
|
+
end
|
61
|
+
|
46
62
|
private
|
47
63
|
|
48
64
|
def getHandler(name)
|
49
65
|
handler_class, handler_method = @@statement_handlers[name.tr("_", "").downcase]
|
50
66
|
|
67
|
+
if handler_class == "proc"
|
68
|
+
return handler_method
|
69
|
+
end
|
70
|
+
|
51
71
|
if !handler_class&.method_defined?(handler_method)
|
52
72
|
if name.start_with? "end"
|
53
73
|
## Fallback to the default end handler
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "rblade/helpers/tokenizer"
|
2
4
|
|
3
5
|
module RBlade
|
@@ -12,23 +14,17 @@ module RBlade
|
|
12
14
|
end
|
13
15
|
|
14
16
|
def compileProps args, tokens
|
15
|
-
|
16
|
-
raise StandardError.new "Props statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
17
|
-
end
|
18
|
-
|
19
|
-
props = extractProps args[0]
|
17
|
+
props = extractProps args
|
20
18
|
props.map do |key, value|
|
21
|
-
compiled_code = ""
|
22
|
-
|
23
19
|
# `_required` is deprecated. Use `required`. To be removed in 2.0.0
|
24
|
-
compiled_code
|
20
|
+
compiled_code = if value == "_required" || value == "required"
|
25
21
|
"if !attributes.has?(:'#{RBlade.escape_quotes(key)}');raise \"Props statement: #{key} is not defined\";end;"
|
26
22
|
else
|
27
23
|
"attributes.default(:'#{RBlade.escape_quotes(key)}', #{value});"
|
28
24
|
end
|
29
25
|
|
30
26
|
if isValidVariableName key
|
31
|
-
compiled_code
|
27
|
+
compiled_code += if variableIsSlot key, tokens
|
32
28
|
"#{key}=RBlade::SlotManager.wrap(attributes.delete :'#{RBlade.escape_quotes(key)}');"
|
33
29
|
else
|
34
30
|
"#{key}=attributes.delete :'#{RBlade.escape_quotes(key)}';"
|
@@ -41,13 +37,8 @@ module RBlade
|
|
41
37
|
|
42
38
|
private
|
43
39
|
|
44
|
-
def extractProps
|
45
|
-
if prop_string.start_with?("{") && prop_string.end_with?("}")
|
46
|
-
prop_string = prop_string.delete_prefix("{").delete_suffix("}")
|
47
|
-
end
|
48
|
-
|
40
|
+
def extractProps prop_strings
|
49
41
|
props = {}
|
50
|
-
prop_strings = Tokenizer.extractCommaSeparatedValues prop_string
|
51
42
|
|
52
43
|
prop_strings.each do |prop|
|
53
44
|
prop.strip!
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RBlade
|
2
4
|
class CompilesStatements
|
3
5
|
class CompilesOnce
|
@@ -23,7 +25,7 @@ module RBlade
|
|
23
25
|
once_id = args[1].nil? ? ":_#{@once_counter}" : args[1]
|
24
26
|
|
25
27
|
"unless $_once_tokens.include? #{once_id};$_once_tokens<<#{once_id};" \
|
26
|
-
<< "_p1_#{@once_counter}=#{args[0]};_p1_#{@once_counter}_b=_out;_out
|
28
|
+
<< "_p1_#{@once_counter}=#{args[0]};_p1_#{@once_counter}_b=_out;_out=+'';"
|
27
29
|
end
|
28
30
|
|
29
31
|
def compileEndPushOnce args
|
@@ -42,7 +44,7 @@ module RBlade
|
|
42
44
|
once_id = args[1].nil? ? ":_#{@once_counter}" : args[1]
|
43
45
|
|
44
46
|
"unless $_once_tokens.include? #{once_id};$_once_tokens<<#{once_id};" \
|
45
|
-
<< "_p1_#{@once_counter}=#{args[0]};_p1_#{@once_counter}_b=_out;_out
|
47
|
+
<< "_p1_#{@once_counter}=#{args[0]};_p1_#{@once_counter}_b=_out;_out=+'';"
|
46
48
|
end
|
47
49
|
|
48
50
|
def compileEndPrependOnce args
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RBlade
|
2
4
|
class CompilesStatements
|
3
5
|
class CompilesStacks
|
@@ -10,7 +12,7 @@ module RBlade
|
|
10
12
|
raise StandardError.new "Stack statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
11
13
|
end
|
12
14
|
|
13
|
-
"RBlade::StackManager.initialize(#{args[0]}, _out);_stacks.push(#{args[0]});_out
|
15
|
+
"RBlade::StackManager.initialize(#{args[0]}, _out);_stacks.push(#{args[0]});_out=+'';"
|
14
16
|
end
|
15
17
|
|
16
18
|
def compilePrepend args
|
@@ -20,7 +22,7 @@ module RBlade
|
|
20
22
|
|
21
23
|
@push_counter += 1
|
22
24
|
|
23
|
-
"_p_#{@push_counter}=#{args[0]};_p_#{@push_counter}_b=_out;_out
|
25
|
+
"_p_#{@push_counter}=#{args[0]};_p_#{@push_counter}_b=_out;_out=+'';"
|
24
26
|
end
|
25
27
|
|
26
28
|
def compileEndPrepend args
|
@@ -56,7 +58,7 @@ module RBlade
|
|
56
58
|
|
57
59
|
@push_counter += 1
|
58
60
|
|
59
|
-
"_p_#{@push_counter}=#{args[0]};_p_#{@push_counter}_b=_out;_out
|
61
|
+
"_p_#{@push_counter}=#{args[0]};_p_#{@push_counter}_b=_out;_out=+'';"
|
60
62
|
end
|
61
63
|
|
62
64
|
def compilePushIf args
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "rblade/helpers/tokenizer"
|
2
4
|
require "ripper"
|
3
5
|
|
@@ -18,7 +20,7 @@ module RBlade
|
|
18
20
|
(?:
|
19
21
|
(@)
|
20
22
|
(\w+(?!\w)[!\?]?)
|
21
|
-
(?:[ \t]*
|
23
|
+
(?:([ \t]*)
|
22
24
|
(\(.*?\))
|
23
25
|
)?
|
24
26
|
)
|
@@ -44,8 +46,23 @@ module RBlade
|
|
44
46
|
|
45
47
|
i += 1
|
46
48
|
elsif segment == "@"
|
47
|
-
|
48
|
-
|
49
|
+
if CompilesStatements.has_handler(segments[i + 1])
|
50
|
+
tokenizeStatement! segments, i
|
51
|
+
handleSpecialCases! segments, i
|
52
|
+
else
|
53
|
+
# For unhandled statements, restore the original string
|
54
|
+
segments[i] = Token.new(type: :unprocessed, value: segments[i] + segments[i + 1])
|
55
|
+
segments.delete_at i + 1
|
56
|
+
|
57
|
+
if segments.count > i + 2 && segments[i + 1].match(/^[ \t]*$/) && segments[i + 2][0] == "("
|
58
|
+
segments[i].value += segments[i + 1] + segments[i + 2]
|
59
|
+
segments.delete_at i + 1
|
60
|
+
segments.delete_at i + 1
|
61
|
+
elsif segments.count > i + 1 && segments[i + 1][0] == "("
|
62
|
+
segments[i].value += segments[i + 1]
|
63
|
+
segments.delete_at i + 1
|
64
|
+
end
|
65
|
+
end
|
49
66
|
|
50
67
|
i += 1
|
51
68
|
elsif !segments[i].nil? && segments[i] != ""
|
@@ -62,10 +79,15 @@ module RBlade
|
|
62
79
|
|
63
80
|
def tokenizeStatement!(segments, i)
|
64
81
|
statement_data = {name: segments[i + 1]}
|
65
|
-
segments.delete_at i + 1
|
82
|
+
statement_name = segments.delete_at i + 1
|
83
|
+
|
84
|
+
# Remove optional whitespace
|
85
|
+
if segments.count > i + 2 && segments[i + 1].match(/^[ \t]*$/) && segments[i + 2][0] == "("
|
86
|
+
segments.delete_at i + 1
|
87
|
+
end
|
66
88
|
|
67
89
|
if segments.count > i + 1 && segments[i + 1][0] == "("
|
68
|
-
arguments = tokenizeArguments! segments, i + 1
|
90
|
+
arguments = tokenizeArguments! statement_name, segments, i + 1
|
69
91
|
|
70
92
|
if !arguments.nil?
|
71
93
|
statement_data[:arguments] = arguments
|
@@ -85,7 +107,7 @@ module RBlade
|
|
85
107
|
end
|
86
108
|
end
|
87
109
|
|
88
|
-
def tokenizeArguments!(segments, segment_index)
|
110
|
+
def tokenizeArguments!(statement_name, segments, segment_index)
|
89
111
|
success = expandSegmentToEndParenthesis! segments, segment_index
|
90
112
|
|
91
113
|
# If no matching parentheses were found, so we combine the argument string with the next segment
|
@@ -98,7 +120,17 @@ module RBlade
|
|
98
120
|
return nil
|
99
121
|
end
|
100
122
|
|
101
|
-
|
123
|
+
# Remove the parentheses from the argument string
|
124
|
+
argument_string = segments[segment_index][1..-2]
|
125
|
+
|
126
|
+
# Special case for the props statement: remove the wrapping braces if they exist
|
127
|
+
if statement_name == "props"
|
128
|
+
if argument_string.start_with?("{") && argument_string.end_with?("}")
|
129
|
+
argument_string = argument_string[1..-2]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
arguments = Tokenizer.extractCommaSeparatedValues argument_string
|
102
134
|
segments.delete_at segment_index
|
103
135
|
|
104
136
|
arguments
|
data/lib/rblade/compiler.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "rblade/compiler/compiles_comments"
|
2
4
|
require "rblade/compiler/compiles_components"
|
3
5
|
require "rblade/compiler/compiles_prints"
|
@@ -21,7 +23,7 @@ module RBlade
|
|
21
23
|
string.gsub(/['\\\x0]/, '\\\\\0')
|
22
24
|
end
|
23
25
|
|
24
|
-
def self.e
|
26
|
+
def self.e(string)
|
25
27
|
if string.is_a?(HtmlString) || string.is_a?(ActiveSupport::SafeBuffer)
|
26
28
|
string
|
27
29
|
else
|
@@ -29,6 +31,15 @@ module RBlade
|
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
34
|
+
# Register a new custom directive by providing a class and method that will compile the directive into ruby code.
|
35
|
+
#
|
36
|
+
# @param [String] name The directive tag without the "@", e.g. "if" for the "@if" directive
|
37
|
+
# @param [Proc] block The block that will return the compiled ruby code for the directive. Any arguments will be passed to this Proc as an array.
|
38
|
+
# @return [void]
|
39
|
+
def self.register_directive_handler(name, &)
|
40
|
+
CompilesStatements.register_handler(name, &)
|
41
|
+
end
|
42
|
+
|
32
43
|
class Compiler
|
33
44
|
def self.compileString(string_template)
|
34
45
|
tokens = [Token.new(:unprocessed, string_template)]
|
@@ -56,13 +67,13 @@ module RBlade
|
|
56
67
|
end
|
57
68
|
|
58
69
|
def self.compileTokens tokens
|
59
|
-
output = ""
|
70
|
+
output = +""
|
60
71
|
|
61
|
-
tokens.each do |token
|
62
|
-
if token.type == :unprocessed || token.type == :raw_text
|
63
|
-
|
72
|
+
tokens.each do |token|
|
73
|
+
output << if token.type == :unprocessed || token.type == :raw_text
|
74
|
+
"_out<<'#{RBlade.escape_quotes(token.value)}';"
|
64
75
|
else
|
65
|
-
|
76
|
+
token.value
|
66
77
|
end
|
67
78
|
end
|
68
79
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RBlade
|
2
4
|
FILE_EXTENSIONS = [".rblade", ".html.rblade"]
|
3
5
|
|
@@ -48,7 +50,7 @@ module RBlade
|
|
48
50
|
end
|
49
51
|
|
50
52
|
def self.clear
|
51
|
-
@@component_definitions = ""
|
53
|
+
@@component_definitions = +""
|
52
54
|
@@component_method_names = {}
|
53
55
|
@@component_name_stack = []
|
54
56
|
end
|
@@ -78,12 +80,7 @@ module RBlade
|
|
78
80
|
|
79
81
|
compiled_component = RBlade::Compiler.compileString(code)
|
80
82
|
|
81
|
-
@@component_definitions
|
82
|
-
<< "def #{@@component_method_names[name]}(slot,attributes,params,session,flash,cookies);_out='';" \
|
83
|
-
<< "_stacks=[];" \
|
84
|
-
<< "attributes=RBlade::AttributesManager.new(attributes);" \
|
85
|
-
<< compiled_component \
|
86
|
-
<< "RBlade::StackManager.get(_stacks) + _out;end;"
|
83
|
+
@@component_definitions << "def #{@@component_method_names[name]}(slot,attributes,params,session,flash,cookies);_out=+'';_stacks=[];attributes=RBlade::AttributesManager.new(attributes);#{compiled_component}RBlade::StackManager.get(_stacks) + _out;end;"
|
87
84
|
|
88
85
|
@@component_method_names[name]
|
89
86
|
end
|
@@ -91,7 +88,7 @@ module RBlade
|
|
91
88
|
|
92
89
|
private
|
93
90
|
|
94
|
-
@@component_definitions = ""
|
91
|
+
@@component_definitions = +""
|
95
92
|
@@component_name_stack = []
|
96
93
|
@@component_method_names = {}
|
97
94
|
@@template_paths = {}
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RBlade
|
2
4
|
class ClassManager
|
3
5
|
def initialize classes
|
@@ -6,7 +8,7 @@ module RBlade
|
|
6
8
|
elsif classes.is_a? Array
|
7
9
|
@classes = classes.join " "
|
8
10
|
elsif classes.is_a? Hash
|
9
|
-
@classes = ""
|
11
|
+
@classes = +""
|
10
12
|
classes.map do |value, predicate|
|
11
13
|
if predicate
|
12
14
|
@classes << "#{value} "
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RBlade
|
2
4
|
class StackManager
|
3
5
|
def self.initialize stack_name, before_stack
|
@@ -34,8 +36,8 @@ module RBlade
|
|
34
36
|
|
35
37
|
class Stack
|
36
38
|
def initialize
|
37
|
-
@prepends = ""
|
38
|
-
@stack = ""
|
39
|
+
@prepends = +""
|
40
|
+
@stack = +""
|
39
41
|
end
|
40
42
|
|
41
43
|
def set_before_stack before_stack
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RBlade
|
2
4
|
class StyleManager
|
3
5
|
def initialize styles
|
@@ -16,7 +18,7 @@ module RBlade
|
|
16
18
|
style
|
17
19
|
end.join
|
18
20
|
elsif styles.is_a? Hash
|
19
|
-
@styles = ""
|
21
|
+
@styles = +""
|
20
22
|
styles.each do |value, predicate|
|
21
23
|
if predicate
|
22
24
|
value = value.to_s.strip
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RBlade
|
2
4
|
class Tokenizer
|
3
5
|
def self.extractCommaSeparatedValues segment
|
@@ -36,7 +38,7 @@ module RBlade
|
|
36
38
|
next
|
37
39
|
end
|
38
40
|
|
39
|
-
argument = ""
|
41
|
+
argument = +""
|
40
42
|
|
41
43
|
# Concatenate all lines up to this token's line, including the tail end of the current line
|
42
44
|
if token[0][0] != current_line
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "rails"
|
2
4
|
require "rblade/compiler"
|
3
5
|
require "rblade/component_store"
|
@@ -25,7 +27,7 @@ module RBlade
|
|
25
27
|
"view::#{view_name}"
|
26
28
|
)
|
27
29
|
end
|
28
|
-
setup = "_out
|
30
|
+
setup = "_out=+'';_stacks=[];$_once_tokens=[];"
|
29
31
|
code = RBlade::Compiler.compileString(source || template.source)
|
30
32
|
setdown = "RBlade::StackManager.get(_stacks) + _out"
|
31
33
|
setup + ComponentStore.get + code + setdown
|
data/lib/rblade/railtie.rb
CHANGED
data/lib/rblade.rb
CHANGED
data/rblade.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "rblade"
|
3
|
-
s.version = "1.
|
3
|
+
s.version = "1.2.1"
|
4
4
|
s.summary = "A component-first templating engine for Rails"
|
5
5
|
s.description = "RBlade is a simple, yet powerful templating engine for Ruby on Rails, inspired by Laravel Blade."
|
6
6
|
s.authors = ["Simon J"]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rblade
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simon J
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -140,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
140
|
- !ruby/object:Gem::Version
|
141
141
|
version: '0'
|
142
142
|
requirements: []
|
143
|
-
rubygems_version: 3.3.
|
143
|
+
rubygems_version: 3.0.3.1
|
144
144
|
signing_key:
|
145
145
|
specification_version: 4
|
146
146
|
summary: A component-first templating engine for Rails
|