ruby-handlebars 0.0.6 → 0.1.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 +5 -5
- data/README.md +2 -2
- data/lib/ruby-handlebars.rb +14 -9
- data/lib/ruby-handlebars/context.rb +23 -7
- data/lib/ruby-handlebars/escapers/dummy_escaper.rb +9 -0
- data/lib/ruby-handlebars/escapers/html_escaper.rb +9 -0
- data/lib/ruby-handlebars/parser.rb +24 -11
- data/lib/ruby-handlebars/template.rb +3 -3
- data/lib/ruby-handlebars/tree.rb +22 -5
- metadata +39 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5bb7ada122dcffa528888da4c6a4b1e2822cbecd5626d14e559081a8881670b8
|
4
|
+
data.tar.gz: aeed1a35e4a57bee75e9fa0f67ddfd0c26a07fd33c613608974492f258eb6c06
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6505f37bb31fbdd0d344d5404c1bc5b5a6259e97120039037dc9ae2aa45635cfa2f7b2c40be1c4b5faced929dab3404665a451e495465c94e446c66dbb0362bf
|
7
|
+
data.tar.gz: ca528f8a90911381216fa5af4fe7aba5d36ca83c84dd88f084023860fe3dc6067970f5b5155f9a296ee2baf814024ff32b5fcdc14edc120f75b4257ef6220e0b
|
data/README.md
CHANGED
@@ -105,9 +105,7 @@ Limitations and roadmap
|
|
105
105
|
|
106
106
|
This gem does not reuse the real Handlebars code (the JS one) and not everything is handled yet (but it will be someday ;) ):
|
107
107
|
|
108
|
-
- there is no escaping, all strings are considered as safe (so ``{{{ my_var }}}`` and ``{{ my_var }}``) will output the same thing
|
109
108
|
- the parser is not fully tested yet, it may complain with spaces ...
|
110
|
-
- curly bracket are __not__ usable in the template content yet. one workaround is to create simple helpers to generate them
|
111
109
|
- parsing errors are, well, not helpful at all
|
112
110
|
|
113
111
|
Aknowledgements
|
@@ -115,3 +113,5 @@ Aknowledgements
|
|
115
113
|
|
116
114
|
This gem would simply not exist if the handlebars team was not here. Thanks a lot for this awesome templating system.
|
117
115
|
Thanks a lot to @cowboyd for the [handlebars.rb](https://github.com/cowboyd/handlebars.rb) gem. We used it for a while and it's great (and as told at the beginning of the README, if you do not need any Windows support, use handlebars.rb instead ;) )
|
116
|
+
|
117
|
+
Thanks a lot to the contributors @mvz and @schuetzm for making it a way better Handlebars renderer :)
|
data/lib/ruby-handlebars.rb
CHANGED
@@ -2,15 +2,18 @@ require_relative 'ruby-handlebars/parser'
|
|
2
2
|
require_relative 'ruby-handlebars/tree'
|
3
3
|
require_relative 'ruby-handlebars/template'
|
4
4
|
require_relative 'ruby-handlebars/helper'
|
5
|
+
require_relative 'ruby-handlebars/escapers/html_escaper'
|
5
6
|
|
6
7
|
module Handlebars
|
7
8
|
class Handlebars
|
8
9
|
include Context
|
10
|
+
attr_reader :escaper
|
9
11
|
|
10
|
-
def initialize
|
12
|
+
def initialize()
|
11
13
|
@helpers = {}
|
12
14
|
@partials = {}
|
13
15
|
register_default_helpers
|
16
|
+
set_escaper
|
14
17
|
end
|
15
18
|
|
16
19
|
def compile(template)
|
@@ -37,6 +40,10 @@ module Handlebars
|
|
37
40
|
@data = ctx
|
38
41
|
end
|
39
42
|
|
43
|
+
def set_escaper(escaper = nil)
|
44
|
+
@escaper = escaper || Escapers::HTMLEscaper
|
45
|
+
end
|
46
|
+
|
40
47
|
private
|
41
48
|
|
42
49
|
PARSER = Parser.new
|
@@ -67,20 +74,18 @@ module Handlebars
|
|
67
74
|
|
68
75
|
def register_each_helper
|
69
76
|
register_helper('each') do |context, items, block, else_block|
|
70
|
-
current_this = context.get('this')
|
71
|
-
|
72
77
|
if (items.nil? || items.empty?)
|
73
78
|
if else_block
|
74
79
|
result = else_block.fn(context)
|
75
80
|
end
|
76
81
|
else
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
82
|
+
context.with_temporary_context(:this => nil, :@index => 0, :@first => false, :@last => false) do
|
83
|
+
result = items.each_with_index.map do |item, index|
|
84
|
+
context.add_items(:this => item, :@index => index, :@first => (index == 0), :@last => (index == items.length - 1))
|
85
|
+
block.fn(context)
|
86
|
+
end.join('')
|
87
|
+
end
|
81
88
|
end
|
82
|
-
|
83
|
-
context.add_item(:this, current_this)
|
84
89
|
result
|
85
90
|
end
|
86
91
|
end
|
@@ -2,8 +2,12 @@ module Handlebars
|
|
2
2
|
module Context
|
3
3
|
def get(path)
|
4
4
|
items = path.split('.'.freeze)
|
5
|
+
if locals.key? items.first.to_sym
|
6
|
+
current = locals
|
7
|
+
else
|
8
|
+
current = @data
|
9
|
+
end
|
5
10
|
|
6
|
-
current = @data
|
7
11
|
until items.empty?
|
8
12
|
current = get_attribute(current, items.shift)
|
9
13
|
end
|
@@ -12,16 +16,32 @@ module Handlebars
|
|
12
16
|
end
|
13
17
|
|
14
18
|
def add_item(key, value)
|
15
|
-
|
19
|
+
locals[key.to_sym] = value
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_items(hash)
|
23
|
+
hash.map { |k, v| add_item(k, v) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def with_temporary_context(args = {})
|
27
|
+
saved = args.keys.collect { |key| [key, get(key.to_s)] }.to_h
|
28
|
+
|
29
|
+
add_items(args)
|
30
|
+
yield
|
31
|
+
locals.merge!(saved)
|
16
32
|
end
|
17
33
|
|
18
34
|
private
|
19
35
|
|
36
|
+
def locals
|
37
|
+
@locals ||= {}
|
38
|
+
end
|
39
|
+
|
20
40
|
def get_attribute(item, attribute)
|
21
41
|
sym_attr = attribute.to_sym
|
22
42
|
str_attr = attribute.to_s
|
23
43
|
|
24
|
-
if item.respond_to?(:[])
|
44
|
+
if item.respond_to?(:[]) && item.respond_to?(:has_key?)
|
25
45
|
if item.has_key?(sym_attr)
|
26
46
|
return item[sym_attr]
|
27
47
|
elsif item.has_key?(str_attr)
|
@@ -29,10 +49,6 @@ module Handlebars
|
|
29
49
|
end
|
30
50
|
end
|
31
51
|
|
32
|
-
if item.instance_variables.include?("@#{attribute}")
|
33
|
-
return item.instance_variable_get("@#{attribute}")
|
34
|
-
end
|
35
|
-
|
36
52
|
if item.respond_to?(sym_attr)
|
37
53
|
return item.send(sym_attr)
|
38
54
|
end
|
@@ -13,24 +13,37 @@ module Handlebars
|
|
13
13
|
|
14
14
|
rule(:docurly) { ocurly >> ocurly }
|
15
15
|
rule(:dccurly) { ccurly >> ccurly }
|
16
|
+
rule(:tocurly) { ocurly >> ocurly >> ocurly }
|
17
|
+
rule(:tccurly) { ccurly >> ccurly >> ccurly }
|
16
18
|
|
17
|
-
rule(:identifier) { match['a-zA-Z0-9_\?'].repeat(1) }
|
19
|
+
rule(:identifier) { match['@a-zA-Z0-9_\?'].repeat(1) }
|
18
20
|
rule(:path) { identifier >> (dot >> identifier).repeat }
|
19
21
|
|
20
|
-
rule(:
|
22
|
+
rule(:nocurly) { match('[^{}]') }
|
23
|
+
rule(:eof) { any.absent? }
|
24
|
+
rule(:template_content) {
|
25
|
+
(
|
26
|
+
ocurly >> nocurly | # Opening curly that doesn't start a {{}}
|
27
|
+
ocurly >> eof | # Opening curly that doesn't start a {{}} because it's the end
|
28
|
+
ccurly | # Closing curly that is not inside a {{}}
|
29
|
+
nocurly
|
30
|
+
).repeat(1).as(:template_content) }
|
21
31
|
|
22
|
-
rule(:
|
23
|
-
rule(:safe_replacement) {
|
32
|
+
rule(:unsafe_replacement) { docurly >> space? >> path.as(:replaced_unsafe_item) >> space? >> dccurly }
|
33
|
+
rule(:safe_replacement) { tocurly >> space? >> path.as(:replaced_safe_item) >> space? >> tccurly }
|
24
34
|
|
25
|
-
rule(:sq_string) { match("'") >> match("[^']").repeat
|
26
|
-
rule(:dq_string) { match('"') >> match('[^"]').repeat
|
35
|
+
rule(:sq_string) { match("'") >> match("[^']").repeat.maybe.as(:str_content) >> match("'") }
|
36
|
+
rule(:dq_string) { match('"') >> match('[^"]').repeat.maybe.as(:str_content) >> match('"') }
|
27
37
|
rule(:string) { sq_string | dq_string }
|
28
38
|
|
29
|
-
rule(:parameter) {
|
39
|
+
rule(:parameter) {
|
40
|
+
(path | string).as(:parameter_name) |
|
41
|
+
(str('(') >> space? >> identifier.as(:safe_helper_name) >> (space? >> parameters.as(:parameters)).maybe >> space? >> str(')'))
|
42
|
+
}
|
30
43
|
rule(:parameters) { parameter >> (space >> parameter).repeat }
|
31
44
|
|
32
|
-
rule(:unsafe_helper) { docurly >> space? >> identifier.as(:
|
33
|
-
rule(:safe_helper) {
|
45
|
+
rule(:unsafe_helper) { docurly >> space? >> identifier.as(:unsafe_helper_name) >> (space? >> parameters.as(:parameters)).maybe >> space? >> dccurly }
|
46
|
+
rule(:safe_helper) { tocurly >> space? >> identifier.as(:safe_helper_name) >> (space? >> parameters.as(:parameters)).maybe >> space? >> tccurly }
|
34
47
|
|
35
48
|
rule(:helper) { unsafe_helper | safe_helper }
|
36
49
|
|
@@ -58,8 +71,8 @@ module Handlebars
|
|
58
71
|
dccurly
|
59
72
|
}
|
60
73
|
|
61
|
-
rule(:block) { (template_content |
|
74
|
+
rule(:block) { (template_content | unsafe_replacement | safe_replacement | helper | partial | block_helper ).repeat.as(:block_items) }
|
62
75
|
|
63
76
|
root :block
|
64
77
|
end
|
65
|
-
end
|
78
|
+
end
|
data/lib/ruby-handlebars/tree.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'colorize'
|
2
|
-
|
3
1
|
module Handlebars
|
4
2
|
module Tree
|
5
3
|
class TreeItem < Struct
|
@@ -28,6 +26,12 @@ module Handlebars
|
|
28
26
|
end
|
29
27
|
end
|
30
28
|
|
29
|
+
class EscapedReplacement < Replacement
|
30
|
+
def _eval(context)
|
31
|
+
context.escaper.escape(super(context).to_s)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
31
35
|
class String < TreeItem.new(:content)
|
32
36
|
def _eval(context)
|
33
37
|
return content
|
@@ -50,9 +54,15 @@ module Handlebars
|
|
50
54
|
end
|
51
55
|
end
|
52
56
|
|
57
|
+
class EscapedHelper < Helper
|
58
|
+
def _eval(context)
|
59
|
+
context.escaper.escape(super(context).to_s)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
53
63
|
class Partial < TreeItem.new(:partial_name)
|
54
64
|
def _eval(context)
|
55
|
-
context.get_partial(partial_name.to_s).call
|
65
|
+
context.get_partial(partial_name.to_s).call
|
56
66
|
end
|
57
67
|
end
|
58
68
|
|
@@ -70,12 +80,19 @@ module Handlebars
|
|
70
80
|
|
71
81
|
class Transform < Parslet::Transform
|
72
82
|
rule(template_content: simple(:content)) {Tree::TemplateContent.new(content)}
|
73
|
-
rule(
|
83
|
+
rule(replaced_unsafe_item: simple(:item)) {Tree::EscapedReplacement.new(item)}
|
84
|
+
rule(replaced_safe_item: simple(:item)) {Tree::Replacement.new(item)}
|
74
85
|
rule(str_content: simple(:content)) {Tree::String.new(content)}
|
75
86
|
rule(parameter_name: simple(:name)) {Tree::Parameter.new(name)}
|
76
87
|
|
77
88
|
rule(
|
78
|
-
|
89
|
+
unsafe_helper_name: simple(:name),
|
90
|
+
parameters: subtree(:parameters)
|
91
|
+
) {
|
92
|
+
Tree::EscapedHelper.new(name, parameters)
|
93
|
+
}
|
94
|
+
rule(
|
95
|
+
safe_helper_name: simple(:name),
|
79
96
|
parameters: subtree(:parameters)
|
80
97
|
) {
|
81
98
|
Tree::Helper.new(name, parameters)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-handlebars
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vincent Pretre
|
@@ -9,88 +9,68 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-06-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: parslet
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - ">="
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: 1.6.2
|
21
18
|
- - "~>"
|
22
19
|
- !ruby/object:Gem::Version
|
23
20
|
version: '1.6'
|
24
|
-
type: :runtime
|
25
|
-
prerelease: false
|
26
|
-
version_requirements: !ruby/object:Gem::Requirement
|
27
|
-
requirements:
|
28
21
|
- - ">="
|
29
22
|
- !ruby/object:Gem::Version
|
30
23
|
version: 1.6.2
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '1.6'
|
34
|
-
- !ruby/object:Gem::Dependency
|
35
|
-
name: colorize
|
36
|
-
requirement: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 0.7.5
|
41
|
-
- - "~>"
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: '0.7'
|
44
24
|
type: :runtime
|
45
25
|
prerelease: false
|
46
26
|
version_requirements: !ruby/object:Gem::Requirement
|
47
27
|
requirements:
|
48
|
-
- - ">="
|
49
|
-
- !ruby/object:Gem::Version
|
50
|
-
version: 0.7.5
|
51
28
|
- - "~>"
|
52
29
|
- !ruby/object:Gem::Version
|
53
|
-
version: '
|
30
|
+
version: '1.6'
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.6.2
|
54
34
|
- !ruby/object:Gem::Dependency
|
55
35
|
name: pry
|
56
36
|
requirement: !ruby/object:Gem::Requirement
|
57
37
|
requirements:
|
58
|
-
- - ">="
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: 0.10.1
|
61
38
|
- - "~>"
|
62
39
|
- !ruby/object:Gem::Version
|
63
40
|
version: '0.10'
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.10.1
|
64
44
|
type: :development
|
65
45
|
prerelease: false
|
66
46
|
version_requirements: !ruby/object:Gem::Requirement
|
67
47
|
requirements:
|
68
|
-
- - ">="
|
69
|
-
- !ruby/object:Gem::Version
|
70
|
-
version: 0.10.1
|
71
48
|
- - "~>"
|
72
49
|
- !ruby/object:Gem::Version
|
73
50
|
version: '0.10'
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.10.1
|
74
54
|
- !ruby/object:Gem::Dependency
|
75
55
|
name: pry-stack_explorer
|
76
56
|
requirement: !ruby/object:Gem::Requirement
|
77
57
|
requirements:
|
78
|
-
- - ">="
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
version: 0.4.9.1
|
81
58
|
- - "~>"
|
82
59
|
- !ruby/object:Gem::Version
|
83
60
|
version: '0.4'
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.4.9.1
|
84
64
|
type: :development
|
85
65
|
prerelease: false
|
86
66
|
version_requirements: !ruby/object:Gem::Requirement
|
87
67
|
requirements:
|
88
|
-
- - ">="
|
89
|
-
- !ruby/object:Gem::Version
|
90
|
-
version: 0.4.9.1
|
91
68
|
- - "~>"
|
92
69
|
- !ruby/object:Gem::Version
|
93
70
|
version: '0.4'
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 0.4.9.1
|
94
74
|
- !ruby/object:Gem::Dependency
|
95
75
|
name: rspec
|
96
76
|
requirement: !ruby/object:Gem::Requirement
|
@@ -115,62 +95,62 @@ dependencies:
|
|
115
95
|
name: rspec-mocks
|
116
96
|
requirement: !ruby/object:Gem::Requirement
|
117
97
|
requirements:
|
118
|
-
- - ">="
|
119
|
-
- !ruby/object:Gem::Version
|
120
|
-
version: 3.1.3
|
121
98
|
- - "~>"
|
122
99
|
- !ruby/object:Gem::Version
|
123
100
|
version: '3.1'
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 3.1.3
|
124
104
|
type: :development
|
125
105
|
prerelease: false
|
126
106
|
version_requirements: !ruby/object:Gem::Requirement
|
127
107
|
requirements:
|
128
|
-
- - ">="
|
129
|
-
- !ruby/object:Gem::Version
|
130
|
-
version: 3.1.3
|
131
108
|
- - "~>"
|
132
109
|
- !ruby/object:Gem::Version
|
133
110
|
version: '3.1'
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: 3.1.3
|
134
114
|
- !ruby/object:Gem::Dependency
|
135
115
|
name: codeclimate-test-reporter
|
136
116
|
requirement: !ruby/object:Gem::Requirement
|
137
117
|
requirements:
|
138
|
-
- - ">="
|
139
|
-
- !ruby/object:Gem::Version
|
140
|
-
version: 0.4.6
|
141
118
|
- - "~>"
|
142
119
|
- !ruby/object:Gem::Version
|
143
120
|
version: '0.4'
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 0.4.6
|
144
124
|
type: :development
|
145
125
|
prerelease: false
|
146
126
|
version_requirements: !ruby/object:Gem::Requirement
|
147
127
|
requirements:
|
148
|
-
- - ">="
|
149
|
-
- !ruby/object:Gem::Version
|
150
|
-
version: 0.4.6
|
151
128
|
- - "~>"
|
152
129
|
- !ruby/object:Gem::Version
|
153
130
|
version: '0.4'
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 0.4.6
|
154
134
|
- !ruby/object:Gem::Dependency
|
155
135
|
name: jeweler
|
156
136
|
requirement: !ruby/object:Gem::Requirement
|
157
137
|
requirements:
|
158
|
-
- - ">="
|
159
|
-
- !ruby/object:Gem::Version
|
160
|
-
version: 2.0.1
|
161
138
|
- - "~>"
|
162
139
|
- !ruby/object:Gem::Version
|
163
140
|
version: '2.0'
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: 2.0.1
|
164
144
|
type: :development
|
165
145
|
prerelease: false
|
166
146
|
version_requirements: !ruby/object:Gem::Requirement
|
167
147
|
requirements:
|
168
|
-
- - ">="
|
169
|
-
- !ruby/object:Gem::Version
|
170
|
-
version: 2.0.1
|
171
148
|
- - "~>"
|
172
149
|
- !ruby/object:Gem::Version
|
173
150
|
version: '2.0'
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: 2.0.1
|
174
154
|
description:
|
175
155
|
email: v.pretre@hiptest.net
|
176
156
|
executables: []
|
@@ -183,6 +163,8 @@ files:
|
|
183
163
|
- README.md
|
184
164
|
- lib/ruby-handlebars.rb
|
185
165
|
- lib/ruby-handlebars/context.rb
|
166
|
+
- lib/ruby-handlebars/escapers/dummy_escaper.rb
|
167
|
+
- lib/ruby-handlebars/escapers/html_escaper.rb
|
186
168
|
- lib/ruby-handlebars/helper.rb
|
187
169
|
- lib/ruby-handlebars/parser.rb
|
188
170
|
- lib/ruby-handlebars/template.rb
|
@@ -205,8 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
205
187
|
- !ruby/object:Gem::Version
|
206
188
|
version: '0'
|
207
189
|
requirements: []
|
208
|
-
|
209
|
-
rubygems_version: 2.6.10
|
190
|
+
rubygems_version: 3.0.4
|
210
191
|
signing_key:
|
211
192
|
specification_version: 4
|
212
193
|
summary: Pure Ruby library for Handlebars templates
|