rblade 0.5.0 → 1.0.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 +23 -2
- data/README.md +180 -543
- data/REFERENCE.md +138 -0
- data/examples/README.md +3 -0
- data/examples/application/home.rblade +23 -0
- data/examples/components/content/alert.rblade +6 -0
- data/examples/components/content/hero.rblade +14 -0
- data/examples/components/h1.rblade +6 -0
- data/examples/components/p.rblade +14 -0
- data/examples/layouts/app.rblade +16 -0
- data/lib/rblade/compiler/compiles_components.rb +3 -3
- data/lib/rblade/compiler/{compiles_echos.rb → compiles_prints.rb} +11 -10
- data/lib/rblade/compiler/compiles_ruby.rb +1 -1
- data/lib/rblade/compiler/compiles_statements.rb +24 -17
- data/lib/rblade/compiler/statements/{compiles_props.rb → compiles_component_helpers.rb} +13 -5
- data/lib/rblade/compiler/statements/compiles_conditionals.rb +45 -13
- data/lib/rblade/compiler/statements/compiles_form.rb +48 -0
- data/lib/rblade/compiler/statements/compiles_loops.rb +8 -4
- data/lib/rblade/compiler/statements/compiles_once.rb +6 -6
- data/lib/rblade/compiler/statements/compiles_stacks.rb +43 -19
- data/lib/rblade/compiler/tokenizes_statements.rb +13 -2
- data/lib/rblade/compiler.rb +3 -3
- data/lib/rblade/component_store.rb +1 -1
- data/lib/rblade/helpers/attributes_manager.rb +28 -8
- data/lib/rblade/helpers/slot_manager.rb +8 -2
- data/rblade.gemspec +1 -1
- metadata +17 -9
- data/TODO.md +0 -2
data/REFERENCE.md
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
<a name="quick-reference"></a>
|
2
|
+
# Quick Reference
|
3
|
+
|
4
|
+
A table below provides a quick overview of RBlade syntax and directives. The [readme](README.md) has a more in depth look at RBlade's capabilities.
|
5
|
+
|
6
|
+
| Syntax | Description |
|
7
|
+
|:--------------------------------------------------------|:------------------------------------------------------------------------------------------|
|
8
|
+
| `{{ RUBY_EXPRESSION }}`<br/>`<%= RUBY_EXPRESSION %>` | Print the string value of the ruby expression, escaping HTML special characters |
|
9
|
+
| `{!! RUBY_EXPRESSION !!}`<br/>`<%== RUBY_EXPRESSION %>` | Print the string value of the ruby expression, _without_ escaping HTML special characters |
|
10
|
+
| `@ruby( RUBY_EXPRESSION )` | Execute an inline ruby expression |
|
11
|
+
| `@ruby ... @endRuby` | Execute a block of ruby code |
|
12
|
+
| `{{-- ... --}}`<br/>`<%# ... %>` | Comments, removed from the compiled template with no performance cost |
|
13
|
+
| `@verbatim ... @endVerbatim` | Print the given content without parsing RBlade directives |
|
14
|
+
|
15
|
+
<a name="quick-reference-components"></a>
|
16
|
+
## Components
|
17
|
+
|
18
|
+
By default, RBlade will look for components in the `app/views/components` folder. Additionally, components in the `layout` namespace are found in the `app/views/layouts` folder, and components in the `view` namespace are found in the `app/views` folder.
|
19
|
+
|
20
|
+
| Syntax | Description |
|
21
|
+
|:---------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------|
|
22
|
+
| `<x-component.name/>` | Render the component found at `app/views/components/name{.rblade,.html.rblade}` or `app/views/components/name/index{.rblade,.html.rblade}` |
|
23
|
+
| `<x-layout::name/>` | Render the "name" component found in the "layout" namespace folder |
|
24
|
+
| `<x-component.name>...</x-component.name>` | Render the component with the given slot content |
|
25
|
+
| `<x-component.name>...<//>` | Short closing tag syntax (note: this bypasses some sanity checking during compilation) |
|
26
|
+
| `<x-name attribute="STRING"/>` | Pass a string value to a component |
|
27
|
+
| `<x-name :attribute="RUBY_EXPRESSION"/>` | Pass a ruby expression, executed in the local scope, to a component |
|
28
|
+
| `<x-name :attribute/>` | Pass the `attribute` local variable into a component |
|
29
|
+
| `<x-name @class({'bg-red-600': is_error})/>` | Conditionally pass classes to a component |
|
30
|
+
| `<x-name @style({'bg-red-600': is_error})/>` | Conditionally pass styles to a component |
|
31
|
+
| `<x-name attribute/>` | Pass an attribute to a component with value `true` |
|
32
|
+
| `<x-name {{ attributes }}/>` | Pass attributes to a child component |
|
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
|
+
| `{{ slot }}` | Output the block content passed into the current component |
|
36
|
+
| `<x-name><x-slot::header><h1>Header</h1><//>Content<//>` | Pass a named block to a component |
|
37
|
+
| `{{ header }}` | Output the contents of a named block |
|
38
|
+
| `<div {{ header.attributes }}>` | Output the attributes passed into a named block |
|
39
|
+
|
40
|
+
<a name="quick-reference-attributes"></a>
|
41
|
+
## Attributes
|
42
|
+
|
43
|
+
The attributes variable is an instance of a class that manages attributes. As well as the methods used in the examples below, you can use any method belonging to the Hash class.
|
44
|
+
|
45
|
+
| Syntax | Description |
|
46
|
+
|:-------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------|
|
47
|
+
| `<div {{ attributes }}>` | Print the contents of attributes as HTML attributes |
|
48
|
+
| `<div {{ attributes.merge({class: "text-black", type: "button"}) }}>` | Merge in additional attributes, combining the `:class` and `:style`, and setting defaults for other values |
|
49
|
+
| `<div {{ attributes.except(['type']) }}>` | Output the attributes array excluding the given keys |
|
50
|
+
| `<div {{ attributes.only(['type']) }}>` | Output only the given keys of the attributes array |
|
51
|
+
| `<div {{ attributes.filter { \|key, value\| key.start_with? "on:" } }}>` | Output the attributes for which the block returns true |
|
52
|
+
| `<div @class({'bg-red-600': is_error})>` | Conditionally print classes in an HTML class attribute |
|
53
|
+
| `<div @style({'bg-red-600': is_error})>` | Conditionally print styles in an HTML style attribute |
|
54
|
+
|
55
|
+
<a name="quick-reference-conditions"></a>
|
56
|
+
## Conditions
|
57
|
+
|
58
|
+
| Syntax | Description |
|
59
|
+
|:----------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------|
|
60
|
+
| `@if( RUBY_EXPRESSION ) ... @endIf` | Compiles to a Ruby if statement |
|
61
|
+
| `@if( RUBY_EXPRESSION ) ... @else ... @endIf` | Compiles to a Ruby if/else statement |
|
62
|
+
| `@if( RUBY_EXPRESSION ) ... @elsif( RUBY_EXPRESSION ) ... @endIf` | Compiles to a Ruby if/elsif statement |
|
63
|
+
| `@unless( RUBY_EXPRESSION ) ... @endunless` | Compiles to a Ruby unless statement |
|
64
|
+
| `@case( RUBY_EXPRESSION ) @when(1) ... @when(2) ... @else ... @endIf` | Compiles to a Ruby case statement |
|
65
|
+
| `@blank?( RUBY_EXPRESSION ) ... @endBlank?` | Compiles to a Ruby if statement that calls `blank?` method on the given expression |
|
66
|
+
| `@defined?( RUBY_EXPRESSION ) ... @endDefined?` | Compiles to a Ruby if statement that calls `defined?` function on the given expression |
|
67
|
+
| `@empty?( RUBY_EXPRESSION ) ... @endEmpty?` | Compiles to a Ruby if statement that calls `empty?` method on the given expression |
|
68
|
+
| `@nil?( RUBY_EXPRESSION ) ... @endNil?` | Compiles to a Ruby if statement that calls `nil?` method on the given expression |
|
69
|
+
| `@present?( RUBY_EXPRESSION ) ... @endPresent?` | Compiles to a Ruby if statement that calls `present?` method on the given expression |
|
70
|
+
| `@env(['development', 'test']) ... @endEnv` | Compiles to a Ruby if statement that checks if the current Rails environment matches any of the given environments |
|
71
|
+
| `@production ... @endProduction` | Shortcut for `@env('production')` |
|
72
|
+
| `@once ... @endOnce` | Render the given block the first time it appears in the template |
|
73
|
+
| `@once('unique key') ... @endOnce` | Render the given block the first time "unique key" is used in the template |
|
74
|
+
|
75
|
+
<a name="quick-reference-loops"></a>
|
76
|
+
## Loops
|
77
|
+
|
78
|
+
| Syntax | Description |
|
79
|
+
|:------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------|
|
80
|
+
| `@while( looping ) ... @endWhile` | Compiles to a Ruby while statement |
|
81
|
+
| `@until( finished ) ... @endUntil` | Compiles to a Ruby until statement |
|
82
|
+
| `@for( i in 1..10 ) ... @endFor` | Compiles to a Ruby for loop |
|
83
|
+
| `@each( i in 1..10 ) ... @endEach` | Calls `each` on the given collection, with `\|i\|` as the block argument |
|
84
|
+
| `@each( key, value in {a: 1} ) ... @endEach` | Calls `each` on the given Hash, with `\|key, value\|` as the block arguments |
|
85
|
+
| `@forElse( i in 1..10 ) ... @empty ... @endForElse` | Compiles to a for loop as above, but the block after `@empty` is printed if the given collection is empty |
|
86
|
+
| `@eachElse( i in 1..10 ) ... @empty ... @endEachElse` | Compiles to a each loop as above, but the block after `@empty` is printed if the given collection is empty |
|
87
|
+
| `@break` | Break out of the current loop |
|
88
|
+
| `@next` | Go to the next iteration in the current loop |
|
89
|
+
| `@break( RUBY_EXPRESSION )` | Break out of the current loop if the expression evaluate to true |
|
90
|
+
| `@next( RUBY_EXPRESSION )` | Go to the next iteration in the current loop if the expression evaluate to true |
|
91
|
+
|
92
|
+
<a name="quick-reference-forms"></a>
|
93
|
+
## Forms
|
94
|
+
|
95
|
+
| Syntax | Description |
|
96
|
+
|:---------------------------------|:-----------------------------------------------------------------------------------------------------------------|
|
97
|
+
| `@old(:email, user[:email])` | Fetches `:email` from the params Hash, defaulting to the user's email if it doesn't exist |
|
98
|
+
| `@method('PATCH')` | Prints a hidden input setting the HTTP request type to the given value using the Rails MethodOverride middleware |
|
99
|
+
| `@DELETE` | Shortcut for `@method('DELETE')` |
|
100
|
+
| `@PATCH` | Shortcut for `@method('PATCH')` |
|
101
|
+
| `@PUT` | Shortcut for `@method('PUT')` |
|
102
|
+
| `@checked( RUBY_EXPRESSION )` | Prints "checked" if the ruby expression evaluates to true |
|
103
|
+
| `@disabled( RUBY_EXPRESSION )` | Prints "disabled" if the ruby expression evaluates to true |
|
104
|
+
| `@readonly( RUBY_EXPRESSION )` | Prints "readonly" if the ruby expression evaluates to true |
|
105
|
+
| `@required( RUBY_EXPRESSION )` | Prints "required" if the ruby expression evaluates to true |
|
106
|
+
| `@selected( RUBY_EXPRESSION )` | Prints "selected" if the ruby expression evaluates to true |
|
107
|
+
|
108
|
+
<a name="quick-reference-stacks"></a>
|
109
|
+
## Stacks
|
110
|
+
|
111
|
+
Stacks are a way of rendering content outside of the usual document order. For example, you could define a "sidebar" stack, then you'd be able to add content to that sidebar from anywhere else in the site.
|
112
|
+
|
113
|
+
Note that the stack is printed once the current view or component finishes.
|
114
|
+
|
115
|
+
| Syntax | Description |
|
116
|
+
|:------------------------------------------------------------|:--------------------------------------------------------------------------------------------|
|
117
|
+
| `@stack('scripts')` | Start a stack with the name 'scripts'. Stacks can be pushed to elsewhere in the code. |
|
118
|
+
| `@push('scripts') ... @endPush` | Add block content to the 'scripts' stack |
|
119
|
+
| `@prepend('scripts') ... @endPrepend` | Add block content to the start of the 'scripts' stack |
|
120
|
+
| `@pushIf(RUBY_EXPRESSION, 'scripts') ... @endPushIf` | Add block content to the 'scripts' stack if the expression evaluate to true |
|
121
|
+
| `@prependIf(RUBY_EXPRESSION, 'scripts') ... @endprependIf` | Add block content to the start of the 'scripts' stack if the expression evaluate to true |
|
122
|
+
| `@pushOnce('scripts') ... @endPushOnce` | Add block content to the 'scripts' stack only once |
|
123
|
+
| `@prependOnce('scripts') ... @endPrependOnce` | Add block content to the start of the 'scripts' stack only once |
|
124
|
+
| `@pushOnce('scripts', 'unique key') ... @endPushOnce` | Add block content to the 'scripts' stack the first time "unique key" is pushed |
|
125
|
+
| `@prependOnce('scripts', 'unique key') ... @endPrependOnce` | Add block content to the start of the 'scripts' stack the first time "unique key" is pushed |
|
126
|
+
|
127
|
+
## Tips
|
128
|
+
|
129
|
+
* Except for `@push`, `@prepend` and their variants, all end directives can simply be replaced with `@end` if preferred:
|
130
|
+
- `@nil?(...) ... @endnil?`
|
131
|
+
- `@nil?(...) ... @endnil`
|
132
|
+
- `@nil?(...) ... @end`
|
133
|
+
* Except for `@ruby` and `@verbatim`, directives are case insensitive and can contain underscores. The following are identical:
|
134
|
+
- `@pushonce`
|
135
|
+
- `@pushOnce`
|
136
|
+
- `@PushOnce`
|
137
|
+
- `@push_once`
|
138
|
+
- `@PUSHONCE`
|
data/examples/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
@ruby
|
2
|
+
# Typically these values would be set in the controller
|
3
|
+
banner_image = 'banner.png'
|
4
|
+
alert = nil
|
5
|
+
@endruby
|
6
|
+
<x-layout::app title="Home page">
|
7
|
+
<x-content.alert :alert/>
|
8
|
+
<x-content.alert alert="This is an alert"/>
|
9
|
+
<x-h1 blue>Welcome to the home page!</x-h1>
|
10
|
+
|
11
|
+
<x-p class="mt-2">
|
12
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias amet architecto, at commodi consectetur ipsa itaque magni minus neque nostrum pariatur possimus recusandae sunt! Est explicabo praesentium quidem vero voluptatum!
|
13
|
+
</x-p>
|
14
|
+
|
15
|
+
@if (banner_image)
|
16
|
+
<x-content.hero class="mt-4">
|
17
|
+
<x-slot::heading class="text-blue-600">
|
18
|
+
Beatae placeat porro quibusdam repudiandae sunt?
|
19
|
+
</x-slot::heading>
|
20
|
+
Adipisci blanditiis, dolor dolorem, ea iste laudantium minima natus nesciunt nostrum odio perferendis praesentium quae, similique.
|
21
|
+
</x-content.hero>
|
22
|
+
@endif
|
23
|
+
</x-layout::app>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
@props({heading: nil})
|
2
|
+
@pushOnce('scripts')
|
3
|
+
<script src="/js/hero.js"></script>
|
4
|
+
@endPushOnce
|
5
|
+
<div class="bg-blue-50 p-16">
|
6
|
+
<div class="max-w-96">
|
7
|
+
@if (heading)
|
8
|
+
<h2 {{ heading.attributes.merge({class: "text-lg font-bold"}) }}>
|
9
|
+
{{ heading }}
|
10
|
+
</h2>
|
11
|
+
@end
|
12
|
+
<p class="mt-4">{{ slot }}</p>
|
13
|
+
</div>
|
14
|
+
</div>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<p {{ attributes.merge({
|
2
|
+
class: "
|
3
|
+
text-base font-normal
|
4
|
+
{{--
|
5
|
+
The tailwindcss-unimportant plugin works well with component design:
|
6
|
+
the "-:" prefix allows the consumer of the component to easily override
|
7
|
+
the component classes and extend the component.
|
8
|
+
See: https://www.npmjs.com/package/tailwindcss-unimportant
|
9
|
+
--}}
|
10
|
+
-:mt-1
|
11
|
+
"
|
12
|
+
}) }}>
|
13
|
+
{{ slot }}
|
14
|
+
</p>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
@props({title: _required})
|
2
|
+
<!DOCTYPE html>
|
3
|
+
<html lang="en">
|
4
|
+
<head>
|
5
|
+
<meta charset="UTF-8">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7
|
+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
8
|
+
<title>{{ title }}</title>
|
9
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
10
|
+
@stack('scripts')
|
11
|
+
</head>
|
12
|
+
<body>
|
13
|
+
<div {{ attributes.merge({class: "max-w-prose mt-8 mx-auto flex flex-col gap-4"}) }}>
|
14
|
+
{{ slot }}
|
15
|
+
</body>
|
16
|
+
</html>
|
@@ -51,11 +51,11 @@ module RBlade
|
|
51
51
|
|
52
52
|
namespace = nil
|
53
53
|
name = component[:name]
|
54
|
-
if name.match
|
54
|
+
if name.match? "::"
|
55
55
|
namespace, name = component[:name].split("::")
|
56
56
|
end
|
57
57
|
|
58
|
-
|
58
|
+
if namespace == "slot"
|
59
59
|
compile_slot_end name, component
|
60
60
|
else
|
61
61
|
compile_component_end component
|
@@ -73,7 +73,7 @@ module RBlade
|
|
73
73
|
|
74
74
|
def compile_component_end component
|
75
75
|
code = "_slot=RBlade::SlotManager.new(_out);_out=_c#{component[:index]}_swap;"
|
76
|
-
code << "_out<<#{ComponentStore.component(component[:name])}(_slot,_c#{component[:index]}_attr);"
|
76
|
+
code << "_out<<#{ComponentStore.component(component[:name])}(_slot,_c#{component[:index]}_attr,params,session,flash,cookies);"
|
77
77
|
code << "_slot=nil;_c#{component[:index]}_swap=nil;_c#{component[:index]}_attr=nil;"
|
78
78
|
|
79
79
|
code
|
@@ -1,22 +1,23 @@
|
|
1
1
|
module RBlade
|
2
|
-
class
|
2
|
+
class CompilesPrints
|
3
3
|
def compile!(tokens)
|
4
|
-
|
5
|
-
|
4
|
+
compile_unsafe_prints!(tokens)
|
5
|
+
compile_regular_prints!(tokens)
|
6
6
|
end
|
7
7
|
|
8
8
|
private
|
9
9
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
10
|
+
def compile_regular_prints!(tokens)
|
11
|
+
compile_prints! tokens, "{{", "}}", "RBlade.e"
|
12
|
+
compile_prints! tokens, "<%=", "%>", "RBlade.e"
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
|
15
|
+
def compile_unsafe_prints!(tokens)
|
16
|
+
compile_prints! tokens, "{!!", "!!}"
|
17
|
+
compile_prints! tokens, "<%==", "%>"
|
17
18
|
end
|
18
19
|
|
19
|
-
def
|
20
|
+
def compile_prints!(tokens, start_token, end_token, wrapper_function = nil)
|
20
21
|
tokens.map! do |token|
|
21
22
|
next(token) if token.type != :unprocessed
|
22
23
|
|
@@ -41,7 +42,7 @@ module RBlade
|
|
41
42
|
else
|
42
43
|
"(" + segments[i] + ").to_s;"
|
43
44
|
end
|
44
|
-
segments[i] = Token.new(:
|
45
|
+
segments[i] = Token.new(:print, segment_value)
|
45
46
|
|
46
47
|
i += 1
|
47
48
|
elsif !segments[i].nil? && segments[i] != ""
|
@@ -1,9 +1,10 @@
|
|
1
|
+
require "rblade/compiler/statements/compiles_component_helpers"
|
1
2
|
require "rblade/compiler/statements/compiles_conditionals"
|
3
|
+
require "rblade/compiler/statements/compiles_form"
|
2
4
|
require "rblade/compiler/statements/compiles_html_attributes"
|
3
5
|
require "rblade/compiler/statements/compiles_inline_ruby"
|
4
6
|
require "rblade/compiler/statements/compiles_loops"
|
5
7
|
require "rblade/compiler/statements/compiles_once"
|
6
|
-
require "rblade/compiler/statements/compiles_props"
|
7
8
|
require "rblade/compiler/statements/compiles_stacks"
|
8
9
|
|
9
10
|
module RBlade
|
@@ -48,7 +49,12 @@ module RBlade
|
|
48
49
|
handler_class, handler_method = @@statement_handlers[name.tr("_", "").downcase]
|
49
50
|
|
50
51
|
if !handler_class&.method_defined?(handler_method)
|
51
|
-
|
52
|
+
if name.start_with? "end"
|
53
|
+
## Fallback to the default end handler
|
54
|
+
handler_class, handler_method = @@statement_handlers["end"]
|
55
|
+
else
|
56
|
+
raise StandardError.new "Unhandled statement: @#{name}"
|
57
|
+
end
|
52
58
|
end
|
53
59
|
|
54
60
|
if handler_class == CompilesStatements
|
@@ -63,51 +69,52 @@ module RBlade
|
|
63
69
|
@@handler_instances = {}
|
64
70
|
|
65
71
|
@@statement_handlers = {
|
72
|
+
"blank?" => [CompilesConditionals, :compileBlank],
|
66
73
|
"break" => [CompilesLoops, :compileBreak],
|
67
|
-
"breakif" => [CompilesLoops, :compileBreakIf],
|
68
74
|
"case" => [CompilesConditionals, :compileCase],
|
69
75
|
"checked" => [CompilesConditionals, :compileChecked],
|
70
76
|
"class" => [CompilesHtmlAttributes, :compileClass],
|
77
|
+
"defined?" => [CompilesConditionals, :compileDefined],
|
78
|
+
"delete" => [CompilesForm, :compileDelete],
|
71
79
|
"disabled" => [CompilesConditionals, :compileDisabled],
|
72
80
|
"else" => [CompilesConditionals, :compileElse],
|
73
81
|
"elsif" => [CompilesConditionals, :compileElsif],
|
74
82
|
"each" => [CompilesLoops, :compileEach],
|
75
83
|
"eachelse" => [CompilesLoops, :compileEachElse],
|
76
84
|
"empty" => [CompilesLoops, :compileEmpty],
|
85
|
+
"empty?" => [CompilesConditionals, :compileEmpty],
|
77
86
|
"end" => [CompilesStatements, :compileEnd],
|
78
|
-
"endcase" => [CompilesStatements, :compileEnd],
|
79
|
-
"endeach" => [CompilesStatements, :compileEnd],
|
80
|
-
"endeachelse" => [CompilesStatements, :compileEnd],
|
81
|
-
"endenv" => [CompilesStatements, :compileEnd],
|
82
|
-
"endfor" => [CompilesStatements, :compileEnd],
|
83
|
-
"endforelse" => [CompilesStatements, :compileEnd],
|
84
|
-
"endif" => [CompilesStatements, :compileEnd],
|
85
|
-
"endonce" => [CompilesStatements, :compileEnd],
|
86
87
|
"endprepend" => [CompilesStacks, :compileEndPrepend],
|
88
|
+
"endprependif" => [CompilesStacks, :compileEndPrependIf],
|
87
89
|
"endprependonce" => [CompilesOnce, :compileEndPrependOnce],
|
88
|
-
"endproduction" => [CompilesStatements, :compileEnd],
|
89
90
|
"endpush" => [CompilesStacks, :compileEndPush],
|
91
|
+
"endpushif" => [CompilesStacks, :compileEndPushIf],
|
90
92
|
"endpushonce" => [CompilesOnce, :compileEndPushOnce],
|
91
|
-
"endunless" => [CompilesStatements, :compileEnd],
|
92
|
-
"enduntil" => [CompilesStatements, :compileEnd],
|
93
|
-
"endwhile" => [CompilesStatements, :compileEnd],
|
94
93
|
"env" => [CompilesConditionals, :compileEnv],
|
95
94
|
"for" => [CompilesLoops, :compileFor],
|
96
95
|
"forelse" => [CompilesLoops, :compileForElse],
|
97
96
|
"if" => [CompilesConditionals, :compileIf],
|
97
|
+
"method" => [CompilesForm, :compileMethod],
|
98
98
|
"next" => [CompilesLoops, :compileNext],
|
99
|
-
"
|
99
|
+
"nil?" => [CompilesConditionals, :compileNil],
|
100
|
+
"old" => [CompilesForm, :compileOld],
|
100
101
|
"once" => [CompilesOnce, :compileOnce],
|
102
|
+
"patch" => [CompilesForm, :compilePatch],
|
101
103
|
"prepend" => [CompilesStacks, :compilePrepend],
|
104
|
+
"prependif" => [CompilesStacks, :compilePrependIf],
|
102
105
|
"prependonce" => [CompilesOnce, :compilePrependOnce],
|
106
|
+
"present?" => [CompilesConditionals, :compilePresent],
|
103
107
|
"production" => [CompilesConditionals, :compileProduction],
|
104
|
-
"props" => [
|
108
|
+
"props" => [CompilesComponentHelpers, :compileProps],
|
105
109
|
"push" => [CompilesStacks, :compilePush],
|
110
|
+
"pushif" => [CompilesStacks, :compilePushIf],
|
106
111
|
"pushonce" => [CompilesOnce, :compilePushOnce],
|
112
|
+
"put" => [CompilesForm, :compilePut],
|
107
113
|
"readonly" => [CompilesConditionals, :compileReadonly],
|
108
114
|
"required" => [CompilesConditionals, :compileRequired],
|
109
115
|
"ruby" => [CompilesInlineRuby, :compile],
|
110
116
|
"selected" => [CompilesConditionals, :compileSelected],
|
117
|
+
"shouldrender" => [CompilesComponentHelpers, :compileShouldRender],
|
111
118
|
"stack" => [CompilesStacks, :compileStack],
|
112
119
|
"style" => [CompilesHtmlAttributes, :compileStyle],
|
113
120
|
"unless" => [CompilesConditionals, :compileUnless],
|
@@ -2,10 +2,18 @@ require "rblade/helpers/tokenizer"
|
|
2
2
|
|
3
3
|
module RBlade
|
4
4
|
class CompilesStatements
|
5
|
-
class
|
5
|
+
class CompilesComponentHelpers
|
6
|
+
def compileShouldRender args
|
7
|
+
if args&.count != 1
|
8
|
+
raise StandardError.new "Should render statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
9
|
+
end
|
10
|
+
|
11
|
+
"unless(#{args[0]});return'';end;"
|
12
|
+
end
|
13
|
+
|
6
14
|
def compileProps args
|
7
|
-
if args
|
8
|
-
raise StandardError.new "Props statement: wrong number of arguments (given #{args&.count}, expecting 1)"
|
15
|
+
if args&.count != 1
|
16
|
+
raise StandardError.new "Props statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
9
17
|
end
|
10
18
|
|
11
19
|
props = extractProps args[0]
|
@@ -13,8 +21,8 @@ module RBlade
|
|
13
21
|
compiled_code = ""
|
14
22
|
if value == "_required"
|
15
23
|
compiled_code << "if !attributes.has?(:'#{RBlade.escape_quotes(key)}');raise \"Props statement: #{key} is not defined\";end;"
|
16
|
-
|
17
|
-
|
24
|
+
compiled_code << "#{key}=attributes[:'#{RBlade.escape_quotes(key)}'];attributes.delete :'#{RBlade.escape_quotes(key)}';"
|
25
|
+
elsif isValidVariableName key
|
18
26
|
compiled_code << "#{key}=attributes[:'#{RBlade.escape_quotes(key)}'].nil? ? #{value} : attributes[:'#{RBlade.escape_quotes(key)}'];"
|
19
27
|
compiled_code << "attributes.delete :'#{RBlade.escape_quotes(key)}';"
|
20
28
|
else
|
@@ -9,6 +9,46 @@ module RBlade
|
|
9
9
|
"if #{args[0]};"
|
10
10
|
end
|
11
11
|
|
12
|
+
def compileBlank args
|
13
|
+
if args&.count != 1
|
14
|
+
raise StandardError.new "Blank? statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
15
|
+
end
|
16
|
+
|
17
|
+
"if (#{args[0]}).blank?;"
|
18
|
+
end
|
19
|
+
|
20
|
+
def compileDefined args
|
21
|
+
if args&.count != 1
|
22
|
+
raise StandardError.new "Defined? statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
23
|
+
end
|
24
|
+
|
25
|
+
"if defined? #{args[0]};"
|
26
|
+
end
|
27
|
+
|
28
|
+
def compileEmpty args
|
29
|
+
if args&.count != 1
|
30
|
+
raise StandardError.new "Empty? statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
31
|
+
end
|
32
|
+
|
33
|
+
"if (#{args[0]}).empty?;"
|
34
|
+
end
|
35
|
+
|
36
|
+
def compileNil args
|
37
|
+
if args&.count != 1
|
38
|
+
raise StandardError.new "Nil? statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
39
|
+
end
|
40
|
+
|
41
|
+
"if (#{args[0]}).nil?;"
|
42
|
+
end
|
43
|
+
|
44
|
+
def compilePresent args
|
45
|
+
if args&.count != 1
|
46
|
+
raise StandardError.new "Present? statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
47
|
+
end
|
48
|
+
|
49
|
+
"if (#{args[0]}).present?;"
|
50
|
+
end
|
51
|
+
|
12
52
|
def compileElsif args
|
13
53
|
if args&.count != 1
|
14
54
|
raise StandardError.new "Elsif statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
@@ -18,8 +58,8 @@ module RBlade
|
|
18
58
|
end
|
19
59
|
|
20
60
|
def compileElse args
|
21
|
-
|
22
|
-
raise StandardError.new "Else statement: wrong number of arguments (given #{args
|
61
|
+
unless args.nil?
|
62
|
+
raise StandardError.new "Else statement: wrong number of arguments (given #{args.count}, expecting 0)"
|
23
63
|
end
|
24
64
|
|
25
65
|
"else;"
|
@@ -42,8 +82,8 @@ module RBlade
|
|
42
82
|
end
|
43
83
|
|
44
84
|
def compileWhen args
|
45
|
-
if args.nil?
|
46
|
-
raise StandardError.new "When statement: wrong number of arguments (given
|
85
|
+
if args.nil?
|
86
|
+
raise StandardError.new "When statement: wrong number of arguments (given 0, expecting at least 1)"
|
47
87
|
end
|
48
88
|
|
49
89
|
"when #{args.join ","};"
|
@@ -101,19 +141,11 @@ module RBlade
|
|
101
141
|
|
102
142
|
def compileProduction args
|
103
143
|
unless args.nil?
|
104
|
-
raise StandardError.new "Production statement: wrong number of arguments (given #{args.count}, expecting
|
144
|
+
raise StandardError.new "Production statement: wrong number of arguments (given #{args.count}, expecting 0)"
|
105
145
|
end
|
106
146
|
|
107
147
|
"if Rails.env.production?;"
|
108
148
|
end
|
109
|
-
|
110
|
-
def compileOnce args
|
111
|
-
if args&.count&.> 1
|
112
|
-
raise StandardError.new "Production statement: wrong number of arguments (given #{args.count}, expecting 0 or 1)"
|
113
|
-
end
|
114
|
-
|
115
|
-
args[0].nil? ? "" : args[0]
|
116
|
-
end
|
117
149
|
end
|
118
150
|
end
|
119
151
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module RBlade
|
2
|
+
class CompilesStatements
|
3
|
+
class CompilesForm
|
4
|
+
def compileMethod args
|
5
|
+
if args&.count != 1
|
6
|
+
raise StandardError.new "Method statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
7
|
+
end
|
8
|
+
method = RBlade.h(args[0].tr("\"'", ""))
|
9
|
+
|
10
|
+
%(_out<<'<input type="hidden" name="_method" value="#{method}">';)
|
11
|
+
end
|
12
|
+
|
13
|
+
def compileDelete args
|
14
|
+
unless args.nil?
|
15
|
+
raise StandardError.new "Delete statement: wrong number of arguments (given #{args.count}, expecting 0)"
|
16
|
+
end
|
17
|
+
|
18
|
+
compileMethod(["DELETE"])
|
19
|
+
end
|
20
|
+
|
21
|
+
def compilePatch args
|
22
|
+
unless args.nil?
|
23
|
+
raise StandardError.new "Patch statement: wrong number of arguments (given #{args.count}, expecting 0)"
|
24
|
+
end
|
25
|
+
|
26
|
+
compileMethod(["PATCH"])
|
27
|
+
end
|
28
|
+
|
29
|
+
def compilePut args
|
30
|
+
unless args.nil?
|
31
|
+
raise StandardError.new "Put statement: wrong number of arguments (given #{args.count}, expecting 0)"
|
32
|
+
end
|
33
|
+
|
34
|
+
compileMethod(["PUT"])
|
35
|
+
end
|
36
|
+
|
37
|
+
def compileOld args
|
38
|
+
if args.nil? || args.count > 2
|
39
|
+
raise StandardError.new "Old statement: wrong number of arguments (given #{args&.count || 0}, expecting 1 or 2)"
|
40
|
+
end
|
41
|
+
|
42
|
+
default_value = args[1] || "''"
|
43
|
+
|
44
|
+
"_out<<params.fetch(#{args[0]},#{default_value});"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -7,7 +7,7 @@ module RBlade
|
|
7
7
|
|
8
8
|
def compileBreak args
|
9
9
|
if args&.count&.> 1
|
10
|
-
raise StandardError.new "Break statement: wrong number of arguments (given #{args
|
10
|
+
raise StandardError.new "Break statement: wrong number of arguments (given #{args.count}, expecting 0 or 1)"
|
11
11
|
end
|
12
12
|
|
13
13
|
if args.nil?
|
@@ -31,7 +31,7 @@ module RBlade
|
|
31
31
|
|
32
32
|
def compileEachElse args
|
33
33
|
if args.nil? || args.count > 2
|
34
|
-
raise StandardError.new "Each statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
34
|
+
raise StandardError.new "Each else statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
|
35
35
|
end
|
36
36
|
# Allow variables to be a key, value pair
|
37
37
|
args = args.join ","
|
@@ -59,7 +59,11 @@ module RBlade
|
|
59
59
|
"_looped_#{@loop_else_counter}=false;for #{args[0]};_looped_#{@loop_else_counter}=true;"
|
60
60
|
end
|
61
61
|
|
62
|
-
def compileEmpty
|
62
|
+
def compileEmpty args
|
63
|
+
unless args.nil?
|
64
|
+
raise StandardError.new "Empty statement: wrong number of arguments (given #{args.count}, expecting 0)"
|
65
|
+
end
|
66
|
+
|
63
67
|
@loop_else_counter -= 1
|
64
68
|
|
65
69
|
"end;if !_looped_#{@loop_else_counter + 1};"
|
@@ -67,7 +71,7 @@ module RBlade
|
|
67
71
|
|
68
72
|
def compileNext args
|
69
73
|
if args&.count&.> 1
|
70
|
-
raise StandardError.new "
|
74
|
+
raise StandardError.new "Next statement: wrong number of arguments (given #{args.count}, expecting 0 or 1)"
|
71
75
|
end
|
72
76
|
|
73
77
|
if args.nil?
|