serbea 0.6.0 β 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/README.md +107 -1
- data/Rakefile +5 -3
- data/lib/serbea.rb +7 -1
- data/lib/serbea/bridgetown_support.rb +11 -0
- data/lib/serbea/helpers.rb +20 -2
- data/lib/serbea/template_engine.rb +53 -16
- data/lib/version.rb +1 -1
- data/serbea.gemspec +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c69f1aa7916899c197489290d683afad319c66bccff8bd32d3e9a0e943bfa41
|
4
|
+
data.tar.gz: 267760c9cbbc3cbde6af0a3479b905c4bd8eca6e601dee2d1bb43cb0a819aabd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c50177a140769d470f500446902009faac98bb390ef44f7930ed28b3c1cb92ac0a499e15ee2c66384ef0c7a52e55dca892ff2c17fe3f85bc8022b92c2f1c6a6a
|
7
|
+
data.tar.gz: 330296668991421be44b92b1a4a87470dc93ffd78e4b00530e26003fff1af293a9b4d51ee46fbcac2b541379a6e4c2a0179ec6365fafce14c219905ee8b73617
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,3 +1,109 @@
|
|
1
1
|
π Serbea: Similar to ERB, Except Awesomer
|
2
2
|
|
3
|
-
The Ruby template language you always dreamed of is here. Le roi est mort, vive le roi!
|
3
|
+
The Ruby template language you always dreamed of is here. Le roi est mort, vive le roi!
|
4
|
+
|
5
|
+
Serbea combines the best ideas from "brace-style" template languages such as Liquid, Nunjucks, Twig, Jinja, Mustache, etc.βand applies them to the world of ERB. You can use Serbea in Rails application, Bridgetown static sites, or pretty much any Ruby scenario you could imagine.
|
6
|
+
|
7
|
+
## Features
|
8
|
+
|
9
|
+
* Real Ruby. Like, for real.
|
10
|
+
* Filters!!! Pipeline operators!!!
|
11
|
+
* Autoescaped variables by default within the pipeline (`{{ }}`) tags. Use the `safe`/`raw` or `escape`/`h` filters to control escaping on output.
|
12
|
+
* Render directive `{%@ %}` as shortcut for rendering either string-named partials (`render "tmpl"`) or object instances (`render MyComponent.new`).
|
13
|
+
* Supports every convention of ERB and builds upon it with new features (which is why it's "awesomer!").
|
14
|
+
* Builtin frontmatter support (even in Rails!) so you can access the variables written into the top YAML within your templates.
|
15
|
+
* The filters accessible within Serbea templates are either helpers (where the variable gets passed as the first argument) or instance methods of the variable itself, so you can build extremely expressive pipelines that take advantage of the code you already know and love. (For example, in Rails you could write `{{ "My Link" | link_to: route_path }}`).
|
16
|
+
* The `Serbea::Pipeline.exec` method lets you pass a pipeline template in, along with an optional input value or included helpers module, and you'll get the output as a object of any type (not converted to a string like in traditional templates). For example: `Serbea::Pipeline.exec("[1,2,3] |> map: ->(i) { i * 10 }")` will return `[10, 20, 30]`.
|
17
|
+
|
18
|
+
## What It Looks Like
|
19
|
+
|
20
|
+
```hbs
|
21
|
+
# example.serb
|
22
|
+
|
23
|
+
{% wow = capture do %}
|
24
|
+
This is {{ "amazing" + "!" | upcase }}
|
25
|
+
{% end.each_char.reduce("") do |newstr, c|
|
26
|
+
newstr += " #{c}"
|
27
|
+
end.strip %}
|
28
|
+
|
29
|
+
{{ wow | prepend: "OMG! " }}
|
30
|
+
```
|
31
|
+
|
32
|
+
```hbs
|
33
|
+
<p>
|
34
|
+
{%
|
35
|
+
helper :multiply_array do |input, multiply_by = 2|
|
36
|
+
input.map do |i|
|
37
|
+
i.to_i * multiply_by
|
38
|
+
end
|
39
|
+
end
|
40
|
+
%}
|
41
|
+
|
42
|
+
Multiply! {{ [1,3,6, "9"] | multiply_array: 10 }}
|
43
|
+
</p>
|
44
|
+
```
|
45
|
+
|
46
|
+
```hbs
|
47
|
+
{%= form classname: "checkout" do |f| %}
|
48
|
+
{{ f.input :first_name, required: true | errors: error_messages }}
|
49
|
+
{% end %}
|
50
|
+
```
|
51
|
+
|
52
|
+
```hbs
|
53
|
+
{%= render "box" do %}
|
54
|
+
This is **dope!**
|
55
|
+
{%= render "card", title: "Nifty!" do %}
|
56
|
+
So great.
|
57
|
+
{% end %}
|
58
|
+
{% end %}
|
59
|
+
|
60
|
+
# Let's simplify that using the new render directive!
|
61
|
+
|
62
|
+
{%@ "box" do %}
|
63
|
+
This is **dope!**
|
64
|
+
{%@ "card", title: "Nifty!" do %}
|
65
|
+
So great.
|
66
|
+
{% end %}
|
67
|
+
{% end %}
|
68
|
+
```
|
69
|
+
|
70
|
+
```hbs
|
71
|
+
# Works with ViewComponent!
|
72
|
+
|
73
|
+
{%= render(Theme::DropdownComponent.new(name: "banner", label: "Banners")) do |dropdown| %}
|
74
|
+
{% RegistryTheme::BANNERS.each do |banner| %}
|
75
|
+
{% dropdown.slot(:item, value: banner) do %}
|
76
|
+
<img src="{{ banner | parameterize: separator: "_" | prepend: "/themes/" | append: ".jpg" }}">
|
77
|
+
<strong>{{ banner }}</strong>
|
78
|
+
{% end %}
|
79
|
+
{% end %}
|
80
|
+
{% end %}
|
81
|
+
|
82
|
+
# Even better, use the new render directive!
|
83
|
+
|
84
|
+
{%@ Theme::DropdownComponent name: "banner", label: "Banners" do |dropdown| %}
|
85
|
+
{% RegistryTheme::BANNERS.each do |banner| %}
|
86
|
+
{% dropdown.slot(:item, value: banner) do %}
|
87
|
+
<img src="{{ banner | parameterize: separator: "_" | prepend: "/themes/" | append: ".jpg" }}">
|
88
|
+
<strong>{{ banner }}</strong>
|
89
|
+
{% end %}
|
90
|
+
{% end %}
|
91
|
+
{% end %}
|
92
|
+
```
|
93
|
+
|
94
|
+
```hbs
|
95
|
+
# The | and |> pipeline operators are equivalent, so you can write like this if you want!
|
96
|
+
|
97
|
+
{{
|
98
|
+
[1,2,3] |>
|
99
|
+
map: -> i {
|
100
|
+
i * 10
|
101
|
+
} |>
|
102
|
+
filter: -> i do
|
103
|
+
i > 15
|
104
|
+
end |>
|
105
|
+
assign_to: :array_length
|
106
|
+
}}
|
107
|
+
|
108
|
+
Array length: {{ @array_length.length }}
|
109
|
+
```
|
data/Rakefile
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
require "rake/testtask"
|
3
|
+
require "bundler"
|
4
|
+
|
5
|
+
Bundler.setup
|
3
6
|
|
4
7
|
Rake::TestTask.new(:test) do |t|
|
5
|
-
t.
|
6
|
-
t.
|
7
|
-
t.test_files = FileList["test/**/test_*.rb"]
|
8
|
+
t.test_files = FileList["test/test.rb"]
|
9
|
+
t.warning = false
|
8
10
|
end
|
9
11
|
|
10
12
|
task :default => :test
|
data/lib/serbea.rb
CHANGED
@@ -9,7 +9,13 @@ require "serbea/component_renderer"
|
|
9
9
|
module Tilt
|
10
10
|
class SerbeaTemplate < ErubiTemplate
|
11
11
|
def prepare
|
12
|
-
@options.merge!(
|
12
|
+
@options.merge!(
|
13
|
+
outvar: "@_erbout",
|
14
|
+
bufval: "Serbea::Buffer.new",
|
15
|
+
literal_prefix: "{%",
|
16
|
+
literal_postfix: "%}",
|
17
|
+
engine_class: Serbea::TemplateEngine
|
18
|
+
)
|
13
19
|
super
|
14
20
|
end
|
15
21
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "serbea/rouge_lexer"
|
2
|
+
require "bridgetown-core"
|
2
3
|
|
3
4
|
module Bridgetown
|
4
5
|
class SerbeaView < RubyTemplateView
|
@@ -70,3 +71,13 @@ module Bridgetown
|
|
70
71
|
end
|
71
72
|
end
|
72
73
|
end
|
74
|
+
|
75
|
+
Bridgetown::Hooks.register :site, :pre_render, reloadable: false do |site|
|
76
|
+
# make sure Liquid doesn't find {% %} and decide to process Serbea code!
|
77
|
+
site.contents.each do |convertible|
|
78
|
+
convertible.data.render_with_liquid = false if convertible.extname == ".serb"
|
79
|
+
end
|
80
|
+
site.layouts.values.each do |convertible|
|
81
|
+
convertible.data.render_with_liquid = false if convertible.ext == ".serb"
|
82
|
+
end
|
83
|
+
end
|
data/lib/serbea/helpers.rb
CHANGED
@@ -29,9 +29,27 @@ module Serbea
|
|
29
29
|
Pipeline.new(context, value)
|
30
30
|
end
|
31
31
|
|
32
|
-
def helper(name, &
|
33
|
-
self.class.
|
32
|
+
def helper(name, &helper_block)
|
33
|
+
self.class.define_method(name) do |*args, &block|
|
34
|
+
previous_buffer_state = @_erbout
|
35
|
+
@_erbout = Serbea::Buffer.new
|
36
|
+
|
37
|
+
# For compatibility with ActionView, not used by Bridgetown normally
|
38
|
+
previous_ob_state = @output_buffer
|
39
|
+
@output_buffer = Serbea::Buffer.new
|
40
|
+
|
41
|
+
result = helper_block.call(*args, &block)
|
42
|
+
if @output_buffer != ""
|
43
|
+
# use Rails' ActionView buffer if present
|
44
|
+
result = @output_buffer
|
45
|
+
end
|
46
|
+
@_erbout = previous_buffer_state
|
47
|
+
@output_buffer = previous_ob_state
|
48
|
+
|
49
|
+
result.is_a?(String) ? result.html_safe : result
|
50
|
+
end
|
34
51
|
end
|
52
|
+
alias_method :macro, :helper
|
35
53
|
|
36
54
|
def h(input)
|
37
55
|
ERB::Util.h(input.to_s)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "strscan"
|
2
|
+
|
1
3
|
module Serbea
|
2
4
|
class Buffer < String
|
3
5
|
def concat_to_s(input)
|
@@ -87,22 +89,57 @@ module Serbea
|
|
87
89
|
buff << text
|
88
90
|
if code.length > 0
|
89
91
|
original_line_length = code.lines.size
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
92
|
+
|
93
|
+
s = StringScanner.new(code[2...-2])
|
94
|
+
done = false
|
95
|
+
escaped_segment = ""
|
96
|
+
segments = []
|
97
|
+
while !done
|
98
|
+
portion = s.scan_until(/\|>?/)
|
99
|
+
if portion
|
100
|
+
if portion.end_with?('\|')
|
101
|
+
# the pipe is escaped, so save that for later
|
102
|
+
escaped_segment += portion.sub(/\\\|$/, "|")
|
103
|
+
elsif escaped_segment.length > 0
|
104
|
+
# we already have escaped content, so finish that up
|
105
|
+
segments << escaped_segment + portion.sub(/\|>?$/, "")
|
106
|
+
escaped_segment = ""
|
107
|
+
else
|
108
|
+
# let's find out if this is actionable now
|
109
|
+
if s.check(/\|/)
|
110
|
+
# nope, the next character is another pipe, so let's escape
|
111
|
+
s.pos += 1
|
112
|
+
escaped_segment += portion + "|"
|
113
|
+
else
|
114
|
+
# finally, we have liftoff!
|
115
|
+
segments << portion.sub(/\|>?$/, "")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
else
|
119
|
+
# we've reached the last bit of the code
|
120
|
+
if escaped_segment.length > 0
|
121
|
+
# escape and get the rest
|
122
|
+
segments << escaped_segment + s.rest
|
123
|
+
else
|
124
|
+
# or just the rest will do
|
125
|
+
segments << s.rest
|
126
|
+
end
|
127
|
+
done = true
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
segments[0] = "pipeline(self, (#{segments[0].strip}))"
|
132
|
+
segments[1..-1].each_with_index do |segment, index|
|
133
|
+
filter, args = segment.strip.match(/([^ :]*)(.*)/m).captures
|
134
|
+
segments[index + 1] = ".filter(:" + filter
|
135
|
+
if args == ""
|
136
|
+
segments[index + 1] += ")"
|
137
|
+
else
|
138
|
+
segments[index + 1] += "," + args.sub(/^:/, "") + ")"
|
139
|
+
end
|
100
140
|
end
|
101
|
-
|
102
|
-
pipeline_suffix = processed_filters ? ") %}" : ")) %}"
|
103
|
-
|
104
|
-
subs = subs.sub("{{", "{%= pipeline(self, (").sub("}}", pipeline_suffix).gsub("__PIPE_C__", '|')
|
105
141
|
|
142
|
+
subs = "{%= #{segments.join} %}"
|
106
143
|
buff << subs
|
107
144
|
|
108
145
|
(original_line_length - subs.lines.size).times do
|
@@ -127,8 +164,8 @@ module Serbea
|
|
127
164
|
|
128
165
|
buff << text
|
129
166
|
if code.length > 0
|
130
|
-
code.sub!
|
131
|
-
code.sub!
|
167
|
+
code.sub!(/^\{%@/, "")
|
168
|
+
code.sub!(/%}$/, "")
|
132
169
|
unless ["end", ""].include? code.strip
|
133
170
|
original_line_length = code.lines.size
|
134
171
|
|
data/lib/version.rb
CHANGED
data/serbea.gemspec
CHANGED
@@ -16,6 +16,7 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r!^(test|script|spec|features)/!) }
|
17
17
|
spec.require_paths = ["lib"]
|
18
18
|
|
19
|
+
spec.add_runtime_dependency("rake", "~> 13.0")
|
19
20
|
spec.add_runtime_dependency("erubi", "~> 1.9")
|
20
21
|
spec.add_runtime_dependency("activesupport", "~> 6.0")
|
21
22
|
spec.add_runtime_dependency("tilt", "~> 2.0")
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serbea
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bridgetown Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-10-
|
11
|
+
date: 2020-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '13.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '13.0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: erubi
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|