rblade 1.1.0 → 1.2.0
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 +36 -9
- data/REFERENCE.md +2 -2
- 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 +7 -7
- 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 +25 -3
- 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: d1a00aab0f9732f42b21921bda5f23b25ce2581f2b0f898c26c5665f0a51046d
|
4
|
+
data.tar.gz: 46db536cfc37cb9307c446d8e23ae7bde18ad7d9947d09f83d1db766d42a505d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79920ad59e36a19996a5bceb55370560b6af5ba6075f4db9494c6844f7b729fc63339f7cb106c76a7fb2be4d410554ac5c69793b09e6a4729a1a30213b1c78cb
|
7
|
+
data.tar.gz: 0ba0f79cc1b8cae6997c02821ca724f3211f50c8978f4923bfe0692a626e63a5fc09fb4bcb3de3b206dbda47e6c825a95a6c2faa91784e83cd420e5d31ba0a35
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## 1.2.0 [2024-10-22]
|
2
|
+
- Add support for custom directives (#2)
|
3
|
+
- Add support for helper functions that use block content (#14)
|
4
|
+
- Change to use frozen string literals
|
5
|
+
- Fix issue with no space after starting ERB style tag
|
6
|
+
- Ignore any @ directives that don't have a handler
|
7
|
+
- Make @endruby directive case insensitive and allow underscore
|
8
|
+
|
9
|
+
## 1.1.1 [2024-08-23]
|
10
|
+
- Remove requirement for including braces in `@props` directive
|
11
|
+
|
1
12
|
## 1.1.0 [2024-08-23]
|
2
13
|
- Add `@eachWithIndex` directive
|
3
14
|
- Fix attribute manager output of attributes with no value (#10)
|
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
|
|
@@ -491,7 +518,7 @@ You can define a component's data properties using a `@props` directive at the t
|
|
491
518
|
|
492
519
|
```rblade
|
493
520
|
{{-- alert.rblade --}}
|
494
|
-
@props(
|
521
|
+
@props(type: "warning", message: required)
|
495
522
|
<div class="{{ type }}">{{ message }}</div>
|
496
523
|
```
|
497
524
|
|
@@ -505,7 +532,7 @@ The `@props` directive accepts a Hash where the key is the name of the attribute
|
|
505
532
|
All properties in the `@props` directive are automatically removed from `attributes`. Properties with names that aren't valid Ruby variable names or are Ruby reserved keywords are not created as local variables. However, you can reference them via the `attributes` local variable:
|
506
533
|
|
507
534
|
```rblade
|
508
|
-
@props(
|
535
|
+
@props("for": required, "data-value": nil)
|
509
536
|
<div>{{ attributes[:for] }} {{ attributes[:'data-value'] }}</div>
|
510
537
|
```
|
511
538
|
|
@@ -697,7 +724,7 @@ Sometimes a component may need to render multiple different slots in different l
|
|
697
724
|
|
698
725
|
```rblade
|
699
726
|
{{-- /app/views/components/alert.rblade --}}
|
700
|
-
@props(
|
727
|
+
@props(title: required)
|
701
728
|
<span class="alert-title">{{ title }}</span>
|
702
729
|
<div class="alert alert-danger">
|
703
730
|
{{ slot }}
|
@@ -752,10 +779,10 @@ Like RBlade components, you can assign additional [attributes](#component-attrib
|
|
752
779
|
To interact with slot attributes, you can access the `attributes` property of the slot's variable. For more information on how to interact with attributes, please consult the documentation on [component attributes](#component-attributes):
|
753
780
|
|
754
781
|
```rblade
|
755
|
-
@props(
|
782
|
+
@props(
|
756
783
|
"heading": required,
|
757
784
|
"footer": required,
|
758
|
-
|
785
|
+
)
|
759
786
|
|
760
787
|
<div {{ attributes.class('border') }}>
|
761
788
|
<h1 {{ heading.attributes.class('text-lg') }}>
|
@@ -777,7 +804,7 @@ Sometimes, you may wish to return early from a component without printing anythi
|
|
777
804
|
|
778
805
|
```rblade
|
779
806
|
{{-- components/error.rblade --}}
|
780
|
-
@props(
|
807
|
+
@props(errors: [])
|
781
808
|
@shouldRender(errors.present?)
|
782
809
|
...
|
783
810
|
```
|
data/REFERENCE.md
CHANGED
@@ -30,8 +30,8 @@ By default, RBlade will look for components in the `app/views/components` folder
|
|
30
30
|
| `<x-name @style({'bg-red-600': is_error})/>` | Conditionally pass styles to a component |
|
31
31
|
| `<x-name attribute/>` | Pass an attribute to a component with value `true` |
|
32
32
|
| `<x-name {{ attributes }}/>` | Pass attributes to a child component |
|
33
|
-
| `@props(
|
34
|
-
| `@props(
|
33
|
+
| `@props(header: "Header")` | Remove `header` from the attributes Hash and introduce it as a local variable, using the specified value as a default |
|
34
|
+
| `@props(header: required)` | Remove `header` from the attributes Hash and introduce it as a local variable, raising an error if it is not set |
|
35
35
|
| `{{ slot }}` | Output the block content passed into the current component |
|
36
36
|
| `<x-name><x-slot::header><h1>Header</h1><//>Content<//>` | Pass a named block to a component |
|
37
37
|
| `{{ header }}` | Output the contents of a named block |
|
@@ -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
|
@@ -18,17 +20,15 @@ module RBlade
|
|
18
20
|
|
19
21
|
props = extractProps args[0]
|
20
22
|
props.map do |key, value|
|
21
|
-
compiled_code = ""
|
22
|
-
|
23
23
|
# `_required` is deprecated. Use `required`. To be removed in 2.0.0
|
24
|
-
compiled_code
|
24
|
+
compiled_code = if value == "_required" || value == "required"
|
25
25
|
"if !attributes.has?(:'#{RBlade.escape_quotes(key)}');raise \"Props statement: #{key} is not defined\";end;"
|
26
26
|
else
|
27
27
|
"attributes.default(:'#{RBlade.escape_quotes(key)}', #{value});"
|
28
28
|
end
|
29
29
|
|
30
30
|
if isValidVariableName key
|
31
|
-
compiled_code
|
31
|
+
compiled_code += if variableIsSlot key, tokens
|
32
32
|
"#{key}=RBlade::SlotManager.wrap(attributes.delete :'#{RBlade.escape_quotes(key)}');"
|
33
33
|
else
|
34
34
|
"#{key}=attributes.delete :'#{RBlade.escape_quotes(key)}';"
|
@@ -42,12 +42,12 @@ module RBlade
|
|
42
42
|
private
|
43
43
|
|
44
44
|
def extractProps prop_string
|
45
|
-
if
|
46
|
-
|
45
|
+
if prop_string.start_with?("{") && prop_string.end_with?("}")
|
46
|
+
prop_string = prop_string.delete_prefix("{").delete_suffix("}")
|
47
47
|
end
|
48
48
|
|
49
49
|
props = {}
|
50
|
-
prop_strings = Tokenizer.extractCommaSeparatedValues prop_string
|
50
|
+
prop_strings = Tokenizer.extractCommaSeparatedValues prop_string
|
51
51
|
|
52
52
|
prop_strings.each do |prop|
|
53
53
|
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] != ""
|
@@ -64,6 +81,11 @@ module RBlade
|
|
64
81
|
statement_data = {name: segments[i + 1]}
|
65
82
|
segments.delete_at i + 1
|
66
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
|
88
|
+
|
67
89
|
if segments.count > i + 1 && segments[i + 1][0] == "("
|
68
90
|
arguments = tokenizeArguments! segments, i + 1
|
69
91
|
|
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.0"
|
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.0
|
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-22 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.
|
143
|
+
rubygems_version: 3.5.11
|
144
144
|
signing_key:
|
145
145
|
specification_version: 4
|
146
146
|
summary: A component-first templating engine for Rails
|