mvz-ruby-handlebars 0.0.8 → 0.0.9
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 +10 -0
- data/README.md +59 -17
- data/lib/ruby-handlebars.rb +21 -38
- data/lib/ruby-handlebars/context.rb +30 -4
- data/lib/ruby-handlebars/escapers/dummy_escaper.rb +9 -0
- data/lib/ruby-handlebars/escapers/html_escaper.rb +9 -0
- data/lib/ruby-handlebars/helper.rb +23 -19
- data/lib/ruby-handlebars/helpers/default_helper.rb +28 -0
- data/lib/ruby-handlebars/helpers/each_helper.rb +31 -0
- data/lib/ruby-handlebars/helpers/helper_missing_helper.rb +18 -0
- data/lib/ruby-handlebars/helpers/if_helper.rb +23 -0
- data/lib/ruby-handlebars/helpers/register_default_helpers.rb +15 -0
- data/lib/ruby-handlebars/helpers/unless_helper.rb +21 -0
- data/lib/ruby-handlebars/parser.rb +53 -7
- data/lib/ruby-handlebars/tree.rb +99 -11
- data/lib/ruby-handlebars/version.rb +1 -1
- data/spec/handlebars_spec.rb +143 -193
- data/spec/parser_spec.rb +162 -21
- data/spec/ruby-handlebars/context_spec.rb +145 -0
- data/spec/ruby-handlebars/helpers/each_helper_spec.rb +331 -0
- data/spec/ruby-handlebars/helpers/helper_missing_helper_spec.rb +45 -0
- data/spec/ruby-handlebars/helpers/if_helper_spec.rb +90 -0
- data/spec/ruby-handlebars/helpers/register_default_helpers_spec.rb +34 -0
- data/spec/ruby-handlebars/helpers/shared.rb +55 -0
- data/spec/ruby-handlebars/helpers/unless_helper_spec.rb +65 -0
- data/spec/spec_helper.rb +5 -0
- metadata +36 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c677856bd3e74f5198f64f3b10b9348530b95024889ff1cf6db380c1165c771f
|
4
|
+
data.tar.gz: 1ff2e3bba711f257d9412ef9aa074fad8ca87429ab5b2ad0033187b289c586e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00be980edd23a6f537a5c7e6354f592826651a795f4a4b7055f26db4d31778c90c7e8a9367e9450578bf0b8c74d690409c52137c337017074edd6163c8148ff2
|
7
|
+
data.tar.gz: 2d89f9b244cad437e7ee33b75562197071dac7d0ccb66be0b83d183f86b9774b16c79178f467fa8f72201b9ef563bbc8b7bc7c2288b81462718f0a7aff5b1b07
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
mvz-ruby-handlebars changelog
|
2
|
+
=============================
|
3
|
+
|
4
|
+
0.0.9 (2021-01-04)
|
5
|
+
------------------
|
6
|
+
|
7
|
+
- Pull in upstream master. See
|
8
|
+
https://github.com/SmartBear/ruby-handlebars/blob/master/CHANGELOG.md for
|
9
|
+
included changes.
|
10
|
+
- Prefer variable over helper when processing a replacement if the helper has the wrong arity
|
data/README.md
CHANGED
@@ -40,6 +40,13 @@ hbs.compile("Hello {{> full_name}}").call({person: {first_name: 'Pinkie', last_n
|
|
40
40
|
# Gives: "Hello Pinkie Pie"
|
41
41
|
```
|
42
42
|
|
43
|
+
Partials support parameters:
|
44
|
+
```ruby
|
45
|
+
hbs.register_partial('full_name', "{{fname}} {{lname}}")
|
46
|
+
hbs.compile("Hello {{> full_name fname='jon' lname='doe'}}")
|
47
|
+
# Gives: "Hello jon doe"
|
48
|
+
```
|
49
|
+
|
43
50
|
You can also register inline helpers:
|
44
51
|
|
45
52
|
```ruby
|
@@ -81,22 +88,59 @@ hbs.compile(template).call({description: my_description})
|
|
81
88
|
# Output will depend on the validity of the 'my_description' variable
|
82
89
|
```
|
83
90
|
|
84
|
-
|
91
|
+
Default helpers:
|
92
|
+
----------------
|
93
|
+
|
94
|
+
Three default helpers are provided: ``each``, ``if`` and ``unless``.
|
95
|
+
|
96
|
+
The each helper let you walk through a list. You can either use the basic notation and referencing the current item as ``this``:
|
97
|
+
|
98
|
+
```
|
99
|
+
{{#each items}}
|
100
|
+
{{{ this }}}
|
101
|
+
{{else}}
|
102
|
+
No items
|
103
|
+
{{/each}}
|
104
|
+
```
|
105
|
+
|
106
|
+
or the "as |name|" notation:
|
107
|
+
|
108
|
+
```
|
109
|
+
{{#each items as |item| }}
|
110
|
+
{{{ item }}}
|
111
|
+
{{else}}
|
112
|
+
No items
|
113
|
+
{{/each}}
|
114
|
+
```
|
115
|
+
|
116
|
+
The ``if`` helper can be used to write conditionnal templates:
|
117
|
+
|
118
|
+
```
|
119
|
+
{{#if my_condition}}
|
120
|
+
It's ok
|
121
|
+
{{else}}
|
122
|
+
or maybe not
|
123
|
+
{{/if}}
|
124
|
+
```
|
125
|
+
|
126
|
+
The ``unless`` helper works the opposite way to ``if``:
|
127
|
+
|
128
|
+
```
|
129
|
+
{{#unless my_condition}}
|
130
|
+
It's not ok
|
131
|
+
{{else}}
|
132
|
+
or maybe it is
|
133
|
+
{{/unless}}
|
134
|
+
```
|
135
|
+
|
136
|
+
Currently, if you call an unknown helper, it will raise an exception. You can override that by registering your own version of the ``helperMissing`` helper. Note that only the name of the missing helper will be provided.
|
137
|
+
|
138
|
+
For example:
|
85
139
|
|
86
140
|
```ruby
|
87
|
-
|
88
|
-
"{
|
89
|
-
|
90
|
-
"{{else}}",
|
91
|
-
" No items",
|
92
|
-
"{{/each}}",
|
93
|
-
"",
|
94
|
-
"{{#if my_condition}}",
|
95
|
-
" It's ok",
|
96
|
-
"{{else}}",
|
97
|
-
" or maybe not",
|
98
|
-
"{{/if}}",
|
99
|
-
].join("\n")
|
141
|
+
hbs.register_helper('helperMissing') do |context, name|
|
142
|
+
puts "No helper found with name #{name}"
|
143
|
+
end
|
100
144
|
```
|
101
145
|
|
102
146
|
Limitations and roadmap
|
@@ -104,12 +148,10 @@ Limitations and roadmap
|
|
104
148
|
|
105
149
|
This gem does not reuse the real Handlebars code (the JS one) and not everything is handled yet (but it will be someday ;) ):
|
106
150
|
|
107
|
-
- there is no escaping, all strings are considered as safe (so ``{{{ my_var }}}`` and ``{{ my_var }}``) will output the same thing
|
108
151
|
- the parser is not fully tested yet, it may complain with spaces ...
|
109
|
-
- curly bracket are __not__ usable in the template content yet. one workaround is to create simple helpers to generate them
|
110
152
|
- parsing errors are, well, not helpful at all
|
111
153
|
|
112
154
|
Aknowledgements
|
113
155
|
---------------
|
114
156
|
|
115
|
-
This is a fork of the [ruby-handlebars]("https://github.com/vincent-psarga/ruby-handlebars") gem
|
157
|
+
This is a fork of the [ruby-handlebars]("https://github.com/vincent-psarga/ruby-handlebars") gem. Eventually I hope to have all my changes accepted upstream so I can abandon this fork.
|
data/lib/ruby-handlebars.rb
CHANGED
@@ -1,17 +1,23 @@
|
|
1
1
|
require_relative 'ruby-handlebars/version'
|
2
|
-
require_relative 'ruby-handlebars/helper'
|
3
2
|
require_relative 'ruby-handlebars/context'
|
4
3
|
require_relative 'ruby-handlebars/parser'
|
5
|
-
require_relative 'ruby-handlebars/template'
|
6
4
|
require_relative 'ruby-handlebars/tree'
|
5
|
+
require_relative 'ruby-handlebars/template'
|
6
|
+
require_relative 'ruby-handlebars/helper'
|
7
|
+
require_relative 'ruby-handlebars/helpers/register_default_helpers'
|
8
|
+
require_relative 'ruby-handlebars/escapers/html_escaper'
|
7
9
|
|
8
10
|
module Handlebars
|
9
11
|
class Handlebars
|
12
|
+
attr_reader :escaper
|
13
|
+
|
10
14
|
def initialize
|
15
|
+
@as_helpers = {}
|
11
16
|
@helpers = {}
|
12
17
|
@partials = {}
|
13
18
|
|
14
19
|
register_default_helpers
|
20
|
+
set_escaper
|
15
21
|
end
|
16
22
|
|
17
23
|
def compile(template)
|
@@ -22,10 +28,18 @@ module Handlebars
|
|
22
28
|
@helpers[name.to_s] = Helper.new(self, fn)
|
23
29
|
end
|
24
30
|
|
31
|
+
def register_as_helper(name, &fn)
|
32
|
+
@as_helpers[name.to_s] = Helper.new(self, fn)
|
33
|
+
end
|
34
|
+
|
25
35
|
def get_helper(name)
|
26
36
|
@helpers[name.to_s]
|
27
37
|
end
|
28
38
|
|
39
|
+
def get_as_helper(name)
|
40
|
+
@as_helpers[name.to_s]
|
41
|
+
end
|
42
|
+
|
29
43
|
def register_partial(name, content)
|
30
44
|
@partials[name.to_s] = Template.new(self, template_to_ast(content))
|
31
45
|
end
|
@@ -34,6 +48,10 @@ module Handlebars
|
|
34
48
|
@partials[name.to_s]
|
35
49
|
end
|
36
50
|
|
51
|
+
def set_escaper(escaper = nil)
|
52
|
+
@escaper = escaper || Escapers::HTMLEscaper
|
53
|
+
end
|
54
|
+
|
37
55
|
private
|
38
56
|
|
39
57
|
PARSER = Parser.new
|
@@ -44,42 +62,7 @@ module Handlebars
|
|
44
62
|
end
|
45
63
|
|
46
64
|
def register_default_helpers
|
47
|
-
|
48
|
-
register_each_helper
|
49
|
-
end
|
50
|
-
|
51
|
-
def register_if_helper
|
52
|
-
register_helper('if') do |context, condition, block, else_block|
|
53
|
-
condition = !condition.empty? if condition.respond_to?(:empty?)
|
54
|
-
|
55
|
-
if condition
|
56
|
-
block.fn(context)
|
57
|
-
elsif else_block
|
58
|
-
else_block.fn(context)
|
59
|
-
else
|
60
|
-
""
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def register_each_helper
|
66
|
-
register_helper('each') do |context, items, block, else_block|
|
67
|
-
current_this = context.get('this')
|
68
|
-
|
69
|
-
if (items.nil? || items.empty?)
|
70
|
-
if else_block
|
71
|
-
result = else_block.fn(context)
|
72
|
-
end
|
73
|
-
else
|
74
|
-
result = items.map do |item|
|
75
|
-
context.add_item(:this, item)
|
76
|
-
block.fn(context)
|
77
|
-
end.join('')
|
78
|
-
end
|
79
|
-
|
80
|
-
context.add_item(:this, current_this)
|
81
|
-
result
|
82
|
-
end
|
65
|
+
Helpers.register_default_helpers(self)
|
83
66
|
end
|
84
67
|
end
|
85
68
|
end
|
@@ -8,12 +8,12 @@ module Handlebars
|
|
8
8
|
|
9
9
|
def get(path)
|
10
10
|
items = path.split('.'.freeze)
|
11
|
-
|
12
|
-
|
13
|
-
current = @locals
|
11
|
+
if locals.key? items.first.to_sym
|
12
|
+
current = locals
|
14
13
|
else
|
15
14
|
current = @data
|
16
15
|
end
|
16
|
+
|
17
17
|
until items.empty?
|
18
18
|
current = get_attribute(current, items.shift)
|
19
19
|
end
|
@@ -21,20 +21,46 @@ module Handlebars
|
|
21
21
|
current
|
22
22
|
end
|
23
23
|
|
24
|
+
def escaper
|
25
|
+
@hbs.escaper
|
26
|
+
end
|
27
|
+
|
24
28
|
def get_helper(name)
|
25
29
|
@hbs.get_helper(name)
|
26
30
|
end
|
27
31
|
|
32
|
+
def get_as_helper(name)
|
33
|
+
@hbs.get_as_helper(name)
|
34
|
+
end
|
35
|
+
|
28
36
|
def get_partial(name)
|
29
37
|
@hbs.get_partial(name)
|
30
38
|
end
|
31
39
|
|
32
40
|
def add_item(key, value)
|
33
|
-
|
41
|
+
locals[key.to_sym] = value
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_items(hash)
|
45
|
+
hash.map { |k, v| add_item(k, v) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def with_temporary_context(args = {})
|
49
|
+
saved = args.keys.collect { |key| [key, get(key.to_s)] }.to_h
|
50
|
+
|
51
|
+
add_items(args)
|
52
|
+
block_result = yield
|
53
|
+
locals.merge!(saved)
|
54
|
+
|
55
|
+
block_result
|
34
56
|
end
|
35
57
|
|
36
58
|
private
|
37
59
|
|
60
|
+
def locals
|
61
|
+
@locals ||= {}
|
62
|
+
end
|
63
|
+
|
38
64
|
def get_attribute(item, attribute)
|
39
65
|
sym_attr = attribute.to_sym
|
40
66
|
str_attr = attribute.to_s
|
@@ -7,35 +7,39 @@ module Handlebars
|
|
7
7
|
@fn = fn
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def arity
|
11
|
+
@fn.arity
|
12
|
+
end
|
13
|
+
|
14
|
+
def apply(context, arguments = [], block = [], else_block = [])
|
11
15
|
arguments = [arguments] unless arguments.is_a? Array
|
12
|
-
args = [context] + arguments.map {|arg| arg.eval(context)} + split_block(block
|
16
|
+
args = [context] + arguments.map {|arg| arg.eval(context)} + split_block(block, else_block)
|
13
17
|
|
14
18
|
@fn.call(*args)
|
15
19
|
end
|
16
20
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
receiver = helper_block
|
22
|
-
else_found = false
|
21
|
+
def apply_as(context, arguments = [], as_arguments = [], block = [], else_block = [])
|
22
|
+
arguments = [arguments] unless arguments.is_a? Array
|
23
|
+
as_arguments = [as_arguments] unless as_arguments.is_a? Array
|
24
|
+
args = [context] + arguments.map {|arg| arg.eval(context)} + as_arguments.map(&:name) + split_block(block, else_block)
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
receiver = inverse_block
|
27
|
-
else_found = true
|
28
|
-
next
|
29
|
-
end
|
26
|
+
@fn.call(*args)
|
27
|
+
end
|
30
28
|
|
31
|
-
|
32
|
-
end
|
29
|
+
private
|
33
30
|
|
34
|
-
|
35
|
-
|
31
|
+
def split_block(block, else_block)
|
32
|
+
if else_block
|
33
|
+
[ensure_block(block), ensure_block(else_block)]
|
36
34
|
else
|
37
|
-
|
35
|
+
[ensure_block(block)]
|
38
36
|
end
|
39
37
|
end
|
38
|
+
|
39
|
+
def ensure_block(block)
|
40
|
+
new_block = Tree::Block.new([])
|
41
|
+
block.each {|item| new_block.add_item(item) } unless block.nil?
|
42
|
+
new_block
|
43
|
+
end
|
40
44
|
end
|
41
45
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Handlebars
|
2
|
+
module Helpers
|
3
|
+
class DefaultHelper
|
4
|
+
def self.register(hbs)
|
5
|
+
hbs.register_helper(self.registry_name) do |context, parameters, block, else_block|
|
6
|
+
self.apply(context, parameters, block, else_block)
|
7
|
+
end if self.respond_to?(:apply)
|
8
|
+
|
9
|
+
hbs.register_as_helper(self.registry_name) do |context, parameters, as_names, block, else_block|
|
10
|
+
self.apply_as(context, parameters, as_names, block, else_block)
|
11
|
+
end if self.respond_to?(:apply_as)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Should be implemented by sub-classes
|
15
|
+
# def self.registry_name
|
16
|
+
# 'myHelperName'
|
17
|
+
# end
|
18
|
+
|
19
|
+
# def self.apply(context, parameters, block, else_block)
|
20
|
+
# # Do things and stuff
|
21
|
+
# end
|
22
|
+
|
23
|
+
# def self.apply_as(context, parameters, as_names, block, else_block)
|
24
|
+
# # Do things and stuffa, but with 'as |param| notation'
|
25
|
+
# end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative 'default_helper'
|
2
|
+
|
3
|
+
module Handlebars
|
4
|
+
module Helpers
|
5
|
+
class EachHelper < DefaultHelper
|
6
|
+
def self.registry_name
|
7
|
+
'each'
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.apply(context, items, block, else_block)
|
11
|
+
self.apply_as(context, items, :this, block, else_block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.apply_as(context, items, name, block, else_block)
|
15
|
+
if (items.nil? || items.empty?)
|
16
|
+
if else_block
|
17
|
+
result = else_block.fn(context)
|
18
|
+
end
|
19
|
+
else
|
20
|
+
context.with_temporary_context(name => nil, :@index => 0, :@first => false, :@last => false) do
|
21
|
+
result = items.each_with_index.map do |item, index|
|
22
|
+
context.add_items(name => item, :@index => index, :@first => (index == 0), :@last => (index == items.length - 1))
|
23
|
+
block.fn(context)
|
24
|
+
end.join('')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'default_helper'
|
2
|
+
|
3
|
+
module Handlebars
|
4
|
+
class UnknownHelper < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
module Helpers
|
8
|
+
class HelperMissingHelper < DefaultHelper
|
9
|
+
def self.registry_name
|
10
|
+
'helperMissing'
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.apply(context, name, block, else_block)
|
14
|
+
raise(::Handlebars::UnknownHelper, "Helper \"#{name}\" does not exist" )
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|