curlybars 1.1.4 → 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/lib/curlybars.rb +19 -6
- data/lib/curlybars/version.rb +1 -1
- data/lib/curlybars/visitor.rb +100 -0
- data/spec/integration/visitor_spec.rb +146 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7aaafd32b96d9cdf8e9af98ebe3636fc14d4df85761eea4ac804d4b623e1d186
|
4
|
+
data.tar.gz: f177926ffc2cf7c9026a15f6ba7f43089cc9bab4da6e3318ab29a38003f4afdd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 25125dc3e0887ee7878a09f29e96c56f6d863d4aea21cb4c37e226d032cd9b5006c6a512837a9893b95188308d72de426673c8d8815c6d942bdad1ca60032403
|
7
|
+
data.tar.gz: 2cc5791470872a77703979523e3de41a0db3491b8dd453628dc2c68ffe00dbef6374db91feb2da56ddae6edf75d5e6c21c5da3947048a3e320eb67da4d6a10c6
|
data/lib/curlybars.rb
CHANGED
@@ -28,12 +28,7 @@ module Curlybars
|
|
28
28
|
cache_key = ["Curlybars.compile", identifier, Digest::SHA256.hexdigest(source)]
|
29
29
|
|
30
30
|
cache.fetch(cache_key) do
|
31
|
-
|
32
|
-
transformed_source = transformers.inject(source) do |memo, transformer|
|
33
|
-
transformer.transform(memo, identifier)
|
34
|
-
end
|
35
|
-
|
36
|
-
ast(transformed_source, identifier, run_processors: true).compile
|
31
|
+
ast(transformed_source(source), identifier, run_processors: true).compile
|
37
32
|
end
|
38
33
|
end
|
39
34
|
|
@@ -72,6 +67,16 @@ module Curlybars
|
|
72
67
|
errors.empty?
|
73
68
|
end
|
74
69
|
|
70
|
+
# Visit nodes in the AST.
|
71
|
+
#
|
72
|
+
# visitor - An instance of a subclass of `Curlybars::Visitor`.
|
73
|
+
# source - The source HBS String used to generate an AST.
|
74
|
+
# identifier - The the file name of the template being checked (defaults to `nil`).
|
75
|
+
def visit(visitor, source, identifier = nil)
|
76
|
+
tree = ast(transformed_source(source), identifier, run_processors: true)
|
77
|
+
visitor.accept(tree)
|
78
|
+
end
|
79
|
+
|
75
80
|
def cache
|
76
81
|
@cache ||= ActiveSupport::Cache::MemoryStore.new
|
77
82
|
end
|
@@ -80,6 +85,13 @@ module Curlybars
|
|
80
85
|
|
81
86
|
private
|
82
87
|
|
88
|
+
def transformed_source(source)
|
89
|
+
transformers = Curlybars.configuration.compiler_transformers
|
90
|
+
transformers.inject(source) do |memo, transformer|
|
91
|
+
transformer.transform(memo, identifier)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
83
95
|
def ast(source, identifier, run_processors:)
|
84
96
|
tokens = Curlybars::Lexer.lex(source, identifier)
|
85
97
|
|
@@ -118,3 +130,4 @@ require 'curlybars/template_handler'
|
|
118
130
|
require 'curlybars/railtie' if defined?(Rails)
|
119
131
|
require 'curlybars/presenter'
|
120
132
|
require 'curlybars/method_whitelist'
|
133
|
+
require 'curlybars/visitor'
|
data/lib/curlybars/version.rb
CHANGED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'active_support/core_ext/string/inflections'
|
2
|
+
|
3
|
+
module Curlybars
|
4
|
+
class Visitor
|
5
|
+
attr_accessor :context
|
6
|
+
|
7
|
+
def initialize(context)
|
8
|
+
@context = context
|
9
|
+
end
|
10
|
+
|
11
|
+
def accept(node)
|
12
|
+
visit(node)
|
13
|
+
context
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def visit(node)
|
19
|
+
class_name = node.class.name.to_s
|
20
|
+
return unless class_name.start_with?('Curlybars::Node')
|
21
|
+
|
22
|
+
method_name = class_name.demodulize.underscore
|
23
|
+
send("visit_#{method_name}", node)
|
24
|
+
end
|
25
|
+
|
26
|
+
def visit_block_helper_else(node)
|
27
|
+
node.arguments.each { |arg| visit(arg) }
|
28
|
+
node.options.each { |opt| visit(opt) }
|
29
|
+
visit(node.helper)
|
30
|
+
visit(node.helper_template)
|
31
|
+
visit(node.else_template)
|
32
|
+
end
|
33
|
+
|
34
|
+
def visit_boolean(_node)
|
35
|
+
end
|
36
|
+
|
37
|
+
def visit_each_else(node)
|
38
|
+
visit(node.path)
|
39
|
+
visit(node.each_template)
|
40
|
+
visit(node.else_template)
|
41
|
+
end
|
42
|
+
|
43
|
+
def visit_if_else(node)
|
44
|
+
visit(node.expression)
|
45
|
+
visit(node.if_template)
|
46
|
+
visit(node.else_template)
|
47
|
+
end
|
48
|
+
|
49
|
+
def visit_item(node)
|
50
|
+
visit(node.item)
|
51
|
+
end
|
52
|
+
|
53
|
+
def visit_literal(_node)
|
54
|
+
end
|
55
|
+
|
56
|
+
def visit_option(node)
|
57
|
+
visit(node.expression)
|
58
|
+
end
|
59
|
+
|
60
|
+
def visit_output(node)
|
61
|
+
visit(node.value)
|
62
|
+
end
|
63
|
+
|
64
|
+
def visit_partial(node)
|
65
|
+
visit(node.path)
|
66
|
+
end
|
67
|
+
|
68
|
+
def visit_path(_node)
|
69
|
+
end
|
70
|
+
|
71
|
+
def visit_root(node)
|
72
|
+
visit(node.template)
|
73
|
+
end
|
74
|
+
|
75
|
+
def visit_string(_node)
|
76
|
+
end
|
77
|
+
|
78
|
+
def visit_template(node)
|
79
|
+
node.items.each { |item| visit(item) }
|
80
|
+
end
|
81
|
+
|
82
|
+
def visit_text(_node)
|
83
|
+
end
|
84
|
+
|
85
|
+
def visit_unless_else(node)
|
86
|
+
visit(node.expression)
|
87
|
+
visit(node.unless_template)
|
88
|
+
visit(node.else_template)
|
89
|
+
end
|
90
|
+
|
91
|
+
def visit_variable(_node)
|
92
|
+
end
|
93
|
+
|
94
|
+
def visit_with_else(node)
|
95
|
+
visit(node.path)
|
96
|
+
visit(node.with_template)
|
97
|
+
visit(node.else_template)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
describe "visitor" do
|
2
|
+
let(:source) do
|
3
|
+
<<-HBS
|
4
|
+
{{#print_args_and_options 'first' 'second' key='value'}}
|
5
|
+
{{/print_args_and_options}}
|
6
|
+
|
7
|
+
{{#render_inverse}}
|
8
|
+
fn
|
9
|
+
{{else}}
|
10
|
+
inverse
|
11
|
+
{{@variable}}
|
12
|
+
{{/render_inverse}}
|
13
|
+
|
14
|
+
{{#each foo}}
|
15
|
+
top
|
16
|
+
{{#each bar}}
|
17
|
+
middle
|
18
|
+
{{#each baz}}
|
19
|
+
inner
|
20
|
+
{{else}}
|
21
|
+
inner inverse
|
22
|
+
{{/each}}
|
23
|
+
{{/each}}
|
24
|
+
{{/each}}
|
25
|
+
|
26
|
+
{{#if valid}}
|
27
|
+
if_template
|
28
|
+
{{#if bar}}
|
29
|
+
foo
|
30
|
+
{{else}}
|
31
|
+
qux
|
32
|
+
{{/if}}
|
33
|
+
{{/if}}
|
34
|
+
|
35
|
+
{{#if baz}}
|
36
|
+
qux
|
37
|
+
{{/if}}
|
38
|
+
|
39
|
+
{{> partial}}
|
40
|
+
|
41
|
+
{{user.avatar.url}}
|
42
|
+
{{#with this}}
|
43
|
+
{{user.avatar.url}}
|
44
|
+
{{/with}}
|
45
|
+
|
46
|
+
{{#unless things}}
|
47
|
+
hi
|
48
|
+
{{/unless}}
|
49
|
+
HBS
|
50
|
+
end
|
51
|
+
|
52
|
+
describe ".visit" do
|
53
|
+
it "visits BlockHelperElse nodes" do
|
54
|
+
visitor = counting_visitor_for(Curlybars::Node::BlockHelperElse)
|
55
|
+
output = Curlybars.visit(visitor, source)
|
56
|
+
expect(output).to eq(4)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "visits EachElse nodes" do
|
60
|
+
visitor = counting_visitor_for(Curlybars::Node::EachElse)
|
61
|
+
output = Curlybars.visit(visitor, source)
|
62
|
+
expect(output).to eq(3)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "visits IfElse nodes" do
|
66
|
+
visitor = counting_visitor_for(Curlybars::Node::IfElse)
|
67
|
+
output = Curlybars.visit(visitor, source)
|
68
|
+
expect(output).to eq(3)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "visits Item nodes" do
|
72
|
+
visitor = counting_visitor_for(Curlybars::Node::Item)
|
73
|
+
output = Curlybars.visit(visitor, source)
|
74
|
+
expect(output).to eq(42)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "visits Literal nodes" do
|
78
|
+
visitor = counting_visitor_for(Curlybars::Node::Literal)
|
79
|
+
output = Curlybars.visit(visitor, source)
|
80
|
+
expect(output).to eq(3)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "visits Option nodes" do
|
84
|
+
visitor = counting_visitor_for(Curlybars::Node::Option)
|
85
|
+
output = Curlybars.visit(visitor, source)
|
86
|
+
expect(output).to eq(1)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "visits Partial nodes" do
|
90
|
+
visitor = counting_visitor_for(Curlybars::Node::Partial)
|
91
|
+
output = Curlybars.visit(visitor, source)
|
92
|
+
expect(output).to eq(1)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "visits Path nodes" do
|
96
|
+
visitor = counting_visitor_for(Curlybars::Node::Path)
|
97
|
+
output = Curlybars.visit(visitor, source)
|
98
|
+
expect(output).to eq(13)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "visits Root nodes" do
|
102
|
+
visitor = counting_visitor_for(Curlybars::Node::Root)
|
103
|
+
output = Curlybars.visit(visitor, source)
|
104
|
+
expect(output).to eq(1)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "visits Template nodes" do
|
108
|
+
visitor = counting_visitor_for(Curlybars::Node::Template)
|
109
|
+
output = Curlybars.visit(visitor, source)
|
110
|
+
expect(output).to eq(14)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "visits Text nodes" do
|
114
|
+
visitor = counting_visitor_for(Curlybars::Node::Text)
|
115
|
+
output = Curlybars.visit(visitor, source)
|
116
|
+
expect(output).to eq(28)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "visits UnlessElse nodes" do
|
120
|
+
visitor = counting_visitor_for(Curlybars::Node::UnlessElse)
|
121
|
+
output = Curlybars.visit(visitor, source)
|
122
|
+
expect(output).to eq(1)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "visits Variable nodes" do
|
126
|
+
visitor = counting_visitor_for(Curlybars::Node::Variable)
|
127
|
+
output = Curlybars.visit(visitor, source)
|
128
|
+
expect(output).to eq(1)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "visits WithElse nodes" do
|
132
|
+
visitor = counting_visitor_for(Curlybars::Node::WithElse)
|
133
|
+
output = Curlybars.visit(visitor, source)
|
134
|
+
expect(output).to eq(1)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def counting_visitor_for(klass)
|
139
|
+
Class.new(Curlybars::Visitor) do
|
140
|
+
define_method "visit_#{klass.name.demodulize.underscore}" do |node|
|
141
|
+
self.context += 1
|
142
|
+
super(node)
|
143
|
+
end
|
144
|
+
end.new(0)
|
145
|
+
end
|
146
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: curlybars
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Libo Cannici
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date:
|
16
|
+
date: 2019-03-15 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: actionpack
|
@@ -234,6 +234,7 @@ files:
|
|
234
234
|
- lib/curlybars/safe_buffer.rb
|
235
235
|
- lib/curlybars/template_handler.rb
|
236
236
|
- lib/curlybars/version.rb
|
237
|
+
- lib/curlybars/visitor.rb
|
237
238
|
- spec/acceptance/application_layout_spec.rb
|
238
239
|
- spec/acceptance/collection_blocks_spec.rb
|
239
240
|
- spec/acceptance/global_helper_spec.rb
|
@@ -270,6 +271,7 @@ files:
|
|
270
271
|
- spec/integration/node/with_spec.rb
|
271
272
|
- spec/integration/processor/tilde_spec.rb
|
272
273
|
- spec/integration/processors_spec.rb
|
274
|
+
- spec/integration/visitor_spec.rb
|
273
275
|
homepage: https://github.com/zendesk/curlybars
|
274
276
|
licenses:
|
275
277
|
- Apache-2.0
|
@@ -291,7 +293,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
291
293
|
version: '0'
|
292
294
|
requirements: []
|
293
295
|
rubyforge_project:
|
294
|
-
rubygems_version: 2.7.
|
296
|
+
rubygems_version: 2.7.6
|
295
297
|
signing_key:
|
296
298
|
specification_version: 4
|
297
299
|
summary: Create your views using Handlebars templates!
|
@@ -312,6 +314,7 @@ test_files:
|
|
312
314
|
- spec/integration/processor/tilde_spec.rb
|
313
315
|
- spec/integration/exception_spec.rb
|
314
316
|
- spec/integration/processors_spec.rb
|
317
|
+
- spec/integration/visitor_spec.rb
|
315
318
|
- spec/integration/node/escape_spec.rb
|
316
319
|
- spec/integration/node/unless_else_spec.rb
|
317
320
|
- spec/integration/node/output_spec.rb
|