tzispa_rig 0.4.5 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +10 -6
- data/Rakefile +7 -0
- data/lib/tzispa/rig/binder.rb +15 -7
- data/lib/tzispa/rig/engine.rb +43 -31
- data/lib/tzispa/rig/parameters.rb +4 -8
- data/lib/tzispa/rig/parsernext.rb +68 -378
- data/lib/tzispa/rig/syntax.rb +4 -7
- data/lib/tzispa/rig/template.rb +78 -54
- data/lib/tzispa/rig/token.rb +57 -0
- data/lib/tzispa/rig/type_token/api_url.rb +83 -0
- data/lib/tzispa/rig/type_token/block.rb +144 -0
- data/lib/tzispa/rig/type_token/expression.rb +65 -0
- data/lib/tzispa/rig/type_token/statement.rb +73 -0
- data/lib/tzispa/rig/version.rb +1 -1
- data/lib/tzispa/rig.rb +3 -2
- data/test/engine_test.rb +41 -0
- data/test/parameters_test.rb +35 -0
- data/test/parsernext_test.rb +256 -0
- data/test/res/apps/test_domain/view/product/layout/list.rig.htm +1 -0
- data/test/template_test.rb +78 -0
- data/test/test_helper.rb +174 -0
- metadata +31 -5
@@ -1,438 +1,128 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
require 'tzispa/utils/string'
|
5
|
-
require_relative 'syntax'
|
6
|
-
|
3
|
+
require 'tzispa/rig/syntax'
|
7
4
|
|
8
5
|
module Tzispa
|
9
6
|
module Rig
|
10
7
|
|
11
|
-
class ParsedEntity
|
12
|
-
extend Forwardable
|
13
|
-
|
14
|
-
STRING_EMPTY = ''.freeze
|
15
|
-
RE_ANCHOR = /(@@\h+@@)/
|
16
|
-
|
17
|
-
attr_reader :type, :parser
|
18
|
-
def_delegators :@parser, :template
|
19
|
-
|
20
|
-
def initialize(parser, type)
|
21
|
-
@parser = parser
|
22
|
-
@type = type
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.instance(parser, type, match)
|
26
|
-
case type
|
27
|
-
when :meta
|
28
|
-
ParsedMeta.new parser, type, match[1]
|
29
|
-
when :var
|
30
|
-
ParsedVar.new parser, type, match[1], match[2]
|
31
|
-
when :url
|
32
|
-
ParsedUrl.new parser, match[1].to_sym, match[3], match[5], match[2]&.slice(1..-1)&.to_sym
|
33
|
-
when :api
|
34
|
-
ParsedApi.new parser, match[1].to_sym, match[3], match[4], match[5], match[6], match[2]&.slice(1..-1)&.to_sym
|
35
|
-
when :loop
|
36
|
-
ParsedLoop.new parser, type, match[3], match[4]
|
37
|
-
when :ife
|
38
|
-
ParsedIfe.new parser, type, match[7], match[8], match[10]
|
39
|
-
when :blk
|
40
|
-
ParsedBlock.new parser, type, match[3], match[4]
|
41
|
-
when :iblk
|
42
|
-
ParsedIBlock.new parser, type, match[7], match[8], match[9], match[10], match[11]
|
43
|
-
when :static
|
44
|
-
ParsedStatic.new parser, type, match[14], match[15]
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def anchor
|
49
|
-
#[[object_id].pack("h*")].pack("m0")
|
50
|
-
@anchor ||= "@@#{"%x" % object_id}@@".freeze
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
class ParsedMeta < ParsedEntity
|
56
|
-
|
57
|
-
attr_reader :id
|
58
|
-
|
59
|
-
def initialize(parser, type, id)
|
60
|
-
super(parser, type)
|
61
|
-
@id = id.to_sym
|
62
|
-
end
|
63
|
-
|
64
|
-
def render(binder)
|
65
|
-
if binder.data.respond_to? @id
|
66
|
-
binder.data.send(@id).to_s
|
67
|
-
else
|
68
|
-
unknown
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
private
|
73
|
-
|
74
|
-
def unknown
|
75
|
-
@unknown ||= "#{@id}:unknown!!".freeze
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
class ParsedVar < ParsedEntity
|
82
|
-
|
83
|
-
attr_reader :id
|
84
|
-
|
85
|
-
def initialize(parser, type, format, id)
|
86
|
-
super(parser, type)
|
87
|
-
@format = format
|
88
|
-
@id = id.to_sym
|
89
|
-
end
|
90
|
-
|
91
|
-
def render(binder)
|
92
|
-
binder.data.respond_to?(@id) ? binder.data.send(@id).to_s : unknown
|
93
|
-
end
|
94
|
-
|
95
|
-
private
|
96
|
-
|
97
|
-
def unknown
|
98
|
-
@unknown ||= "#{@id}:unknown!!".freeze
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
|
104
|
-
class ParsedUrl < ParsedEntity
|
105
|
-
|
106
|
-
attr_reader :layout, :params, :app_name
|
107
|
-
|
108
|
-
def initialize(parser, type, layout, params, app_name = nil)
|
109
|
-
super(parser, type)
|
110
|
-
@layout = layout
|
111
|
-
@params = params
|
112
|
-
@app_name = app_name
|
113
|
-
end
|
114
|
-
|
115
|
-
def render(binder)
|
116
|
-
b_params = @params.dup.gsub(RE_ANCHOR) { |match|
|
117
|
-
parser.the_parsed.select { |p| p.anchor == match}.first.render(binder)
|
118
|
-
} if @params
|
119
|
-
b_layout = bind_value(@layout.dup, binder).to_sym
|
120
|
-
case type
|
121
|
-
when :purl
|
122
|
-
app_name ?
|
123
|
-
binder.context.app_layout_path(app_name, b_layout, Parameters.new(b_params).tp_h) :
|
124
|
-
binder.context.layout_path(b_layout, Parameters.new(b_params).to_h)
|
125
|
-
when :url
|
126
|
-
app_name ?
|
127
|
-
binder.context.app_layout_canonical_url(app_name, b_layout, Parameters.new(b_params).to_h) :
|
128
|
-
binder.context.layout_canonical_url(b_layout, Parameters.new(b_params).to_h)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def bind_value(value, binder)
|
133
|
-
value.gsub(RE_ANCHOR) { |match|
|
134
|
-
parser.the_parsed.select { |p| p.anchor == match}.first.render(binder)
|
135
|
-
}
|
136
|
-
end
|
137
|
-
|
138
|
-
|
139
|
-
end
|
140
|
-
|
141
|
-
|
142
|
-
class ParsedApi < ParsedEntity
|
143
|
-
|
144
|
-
attr_reader :handler, :verb, :predicate, :app_name
|
145
|
-
|
146
|
-
def initialize(parser, type, handler, verb, predicate, sufix, app_name = nil)
|
147
|
-
super(parser, type)
|
148
|
-
@handler = handler
|
149
|
-
@verb = verb
|
150
|
-
@predicate = predicate
|
151
|
-
@sufix = sufix
|
152
|
-
@app_name = app_name
|
153
|
-
end
|
154
|
-
|
155
|
-
def render(binder)
|
156
|
-
b_handler = bind_value @handler.dup, binder
|
157
|
-
b_verb = bind_value @verb.dup, binder
|
158
|
-
b_predicate = bind_value( @predicate.dup, binder ) if @predicate
|
159
|
-
b_sufix = bind_value( @sufix.dup, binder ) if @sufix
|
160
|
-
binder.context.send(type.to_sym, b_handler, b_verb, b_predicate, b_sufix, app_name)
|
161
|
-
end
|
162
|
-
|
163
|
-
private
|
164
|
-
|
165
|
-
def bind_value(value, binder)
|
166
|
-
value.gsub(RE_ANCHOR) { |match|
|
167
|
-
parser.the_parsed.select { |p| p.anchor == match}.first.render(binder)
|
168
|
-
}
|
169
|
-
end
|
170
|
-
|
171
|
-
end
|
172
|
-
|
173
|
-
|
174
|
-
class ParsedLoop < ParsedEntity
|
175
|
-
extend Forwardable
|
176
|
-
|
177
|
-
attr_reader :id
|
178
|
-
def_delegators :@loop_parser, :attribute_tags, :loop_parser
|
179
|
-
|
180
|
-
def initialize(parser, type, id, body)
|
181
|
-
super(parser, type)
|
182
|
-
@id = id.to_sym
|
183
|
-
@body = body
|
184
|
-
end
|
185
|
-
|
186
|
-
def parse!
|
187
|
-
@loop_parser = ParserNext.new( template, @body ).parse!
|
188
|
-
self
|
189
|
-
end
|
190
|
-
|
191
|
-
def render(binder)
|
192
|
-
String.new.tap { |text|
|
193
|
-
looper = binder.data.send(@id) if binder.data.respond_to?(@id)
|
194
|
-
looper.data.each { |loop_item|
|
195
|
-
text << @loop_parser.render(loop_item) if loop_item
|
196
|
-
} if looper
|
197
|
-
}
|
198
|
-
end
|
199
|
-
|
200
|
-
end
|
201
|
-
|
202
|
-
|
203
|
-
class ParsedIfe < ParsedEntity
|
204
|
-
|
205
|
-
attr_reader :test
|
206
|
-
|
207
|
-
def initialize(parser, type, test, then_body, else_body)
|
208
|
-
super(parser, type)
|
209
|
-
@test = test.to_sym
|
210
|
-
@then_body = then_body
|
211
|
-
@else_body = else_body
|
212
|
-
end
|
213
|
-
|
214
|
-
def parse!
|
215
|
-
@then_parser = ParserNext.new( template, @then_body ).parse!
|
216
|
-
@else_parser = ParserNext.new( template, @else_body ).parse! if @else_body
|
217
|
-
self
|
218
|
-
end
|
219
|
-
|
220
|
-
def attribute_tags
|
221
|
-
@attribute_tags ||= [@test].concat(@then_parser.attribute_tags).concat((@else_parser && @else_parser.attribute_tags) || Array.new).compact.uniq.freeze
|
222
|
-
end
|
223
|
-
|
224
|
-
def loop_parser(id)
|
225
|
-
@then_parser.loop_parser(id).concat((@else_parser && @else_parser.loop_parser(id)) || Array.new).compact.freeze
|
226
|
-
end
|
227
|
-
|
228
|
-
def render(binder)
|
229
|
-
test_eval = binder.data && binder.data.respond_to?(@test) && binder.data.send(@test)
|
230
|
-
ifeparser = test_eval ? @then_parser : @else_parser
|
231
|
-
ifeparser ? ifeparser.render(binder) : STRING_EMPTY
|
232
|
-
end
|
233
|
-
|
234
|
-
end
|
235
|
-
|
236
|
-
class ParsedBlock < ParsedEntity
|
237
|
-
|
238
|
-
attr_reader :params
|
239
|
-
|
240
|
-
def initialize(parser, type, id, params)
|
241
|
-
super(parser, type)
|
242
|
-
@id = id
|
243
|
-
@params = params
|
244
|
-
end
|
245
|
-
|
246
|
-
def parse!
|
247
|
-
@parsed_block = template.engine.block name: @id, parent: template
|
248
|
-
template.childrens << @parsed_block
|
249
|
-
self
|
250
|
-
end
|
251
|
-
|
252
|
-
def render(binder)
|
253
|
-
blk = @parsed_block.dup
|
254
|
-
if @params
|
255
|
-
b_params = @params.dup.gsub(RE_ANCHOR) { |match|
|
256
|
-
parser.the_parsed.select { |p| p.anchor == match}.first.render(binder)
|
257
|
-
}
|
258
|
-
blk.params = b_params
|
259
|
-
end
|
260
|
-
blk.render binder.context
|
261
|
-
end
|
262
|
-
|
263
|
-
end
|
264
|
-
|
265
|
-
class ParsedIBlock < ParsedEntity
|
266
|
-
|
267
|
-
attr_reader :id
|
268
|
-
|
269
|
-
def initialize(parser, type, test, id_then, params_then, id_else, params_else)
|
270
|
-
super(parser, type)
|
271
|
-
@id = test
|
272
|
-
@id_then = id_then
|
273
|
-
@params_then = params_then
|
274
|
-
@id_else = id_else
|
275
|
-
@params_else = params_else
|
276
|
-
end
|
277
|
-
|
278
|
-
def parse!
|
279
|
-
@block_then = template.engine.block name: @id_then, parent: template
|
280
|
-
@block_else = template.engine.block name: @id_else, parent: template
|
281
|
-
template.childrens << @block_then
|
282
|
-
template.childrens << @block_else
|
283
|
-
self
|
284
|
-
end
|
285
|
-
|
286
|
-
def render(binder)
|
287
|
-
if binder.data.respond_to?(@id) && binder.data.send(@id)
|
288
|
-
blk = @block_then.dup
|
289
|
-
if @params_then
|
290
|
-
b_params = @params_then.dup.gsub(RE_ANCHOR) { |match|
|
291
|
-
parser.the_parsed.select { |p| p.anchor == match}.first.render(binder)
|
292
|
-
}
|
293
|
-
blk.params = b_params
|
294
|
-
end
|
295
|
-
else
|
296
|
-
blk = @block_else.dup
|
297
|
-
if @params_else
|
298
|
-
b_params = @params_else.dup.gsub(RE_ANCHOR) { |match|
|
299
|
-
parser.the_parsed.select { |p| p.anchor == match}.first.render(binder)
|
300
|
-
}
|
301
|
-
blk.params = b_params
|
302
|
-
end
|
303
|
-
end
|
304
|
-
blk.render binder.context
|
305
|
-
end
|
306
|
-
|
307
|
-
end
|
308
|
-
|
309
|
-
|
310
|
-
class ParsedStatic < ParsedEntity
|
311
|
-
|
312
|
-
def initialize(parser, type, id, params)
|
313
|
-
super(parser, type)
|
314
|
-
@id = id
|
315
|
-
@params = params
|
316
|
-
end
|
317
|
-
|
318
|
-
def parse!
|
319
|
-
@parsed_static = template.engine.static name: @id, parent: template
|
320
|
-
template.childrens << @parsed_static
|
321
|
-
self
|
322
|
-
end
|
323
|
-
|
324
|
-
def render(binder)
|
325
|
-
blk = @parsed_static.dup
|
326
|
-
if @params
|
327
|
-
b_params = @params.dup.gsub(RE_ANCHOR) { |match|
|
328
|
-
parser.the_parsed.select { |p| p.anchor == match}.first.render(binder)
|
329
|
-
}
|
330
|
-
blk.params = b_params
|
331
|
-
end
|
332
|
-
blk.render binder.context
|
333
|
-
end
|
334
|
-
|
335
|
-
end
|
336
|
-
|
337
|
-
|
338
8
|
class ParserNext
|
339
9
|
|
340
10
|
EMPTY_STRING = ''
|
341
11
|
|
342
12
|
include Tzispa::Rig::Syntax
|
343
13
|
|
344
|
-
attr_reader :flags, :template, :
|
14
|
+
attr_reader :flags, :template, :tokens, :domain, :format, :childrens,
|
15
|
+
:bindable, :content_type, :inner_text, :content_escape_method
|
345
16
|
|
346
|
-
def initialize(template, text
|
17
|
+
def initialize(template = nil, text: nil, domain: nil, content_type: nil, bindable: nil, parent: nil)
|
18
|
+
@parsed = false
|
347
19
|
@template = template
|
348
|
-
@inner_text = text
|
349
|
-
@
|
20
|
+
@inner_text = (text || template&.content)&.dup
|
21
|
+
@domain = domain || parent.domain
|
22
|
+
@bindable = bindable.nil? ? parent.bindable : bindable
|
23
|
+
@content_type = content_type || parent.content_type
|
24
|
+
@content_escape_method = :"escape_#{content_type}"
|
350
25
|
end
|
351
26
|
|
352
27
|
def empty?
|
353
|
-
@
|
28
|
+
@tokens.empty?
|
354
29
|
end
|
355
30
|
|
356
31
|
def parse!
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
32
|
+
unless parsed?
|
33
|
+
@attribute_tags = nil
|
34
|
+
@childrens = Array.new
|
35
|
+
@tokens = Array.new
|
36
|
+
parse_flags
|
37
|
+
if bindable
|
38
|
+
parse_statements
|
39
|
+
parse_expressions
|
40
|
+
parse_url_builder
|
41
|
+
parse_templates
|
42
|
+
end
|
43
|
+
@parsed = true
|
362
44
|
end
|
363
|
-
parse_url_builder
|
364
|
-
parse_templates
|
365
45
|
self
|
366
46
|
end
|
367
47
|
|
368
|
-
def
|
48
|
+
def parsed?
|
49
|
+
@parsed
|
50
|
+
end
|
51
|
+
|
52
|
+
def render(binder)
|
369
53
|
@inner_text.dup.tap { |text|
|
370
|
-
@
|
54
|
+
@tokens.each { |value|
|
371
55
|
text.gsub! value.anchor, value.render(binder)
|
372
56
|
}
|
373
57
|
}.freeze
|
374
58
|
end
|
375
59
|
|
376
60
|
def attribute_tags
|
377
|
-
@attribute_tags ||=
|
61
|
+
@attribute_tags ||= tokens.map { |p|
|
378
62
|
p.id.to_sym if p.respond_to? :id
|
379
|
-
}.concat(
|
380
|
-
|
381
|
-
|
63
|
+
}.concat(
|
64
|
+
tokens.map{ |p|
|
65
|
+
p.attribute_tags if p.type == :ife
|
66
|
+
}
|
67
|
+
).compact.flatten.uniq.freeze
|
382
68
|
end
|
383
69
|
|
384
70
|
def loop_parser(id)
|
385
|
-
|
386
|
-
|
71
|
+
tokens.select{ |p|
|
72
|
+
p.type==:loop && p.id==id
|
73
|
+
}.concat(
|
74
|
+
tokens.select{ |p|
|
75
|
+
p.type==:ife }.map {
|
76
|
+
|p| p.loop_parser(id)
|
77
|
+
}.flatten.compact
|
387
78
|
)
|
388
79
|
end
|
389
80
|
|
390
81
|
private
|
391
82
|
|
392
83
|
def parse_flags
|
393
|
-
@inner_text.
|
84
|
+
while match = @inner_text.match(RIG_EMPTY[:flags]) do
|
394
85
|
@flags = Regexp.last_match(1)
|
395
|
-
|
396
|
-
|
86
|
+
@inner_text.gsub! match[0], ''
|
87
|
+
end
|
397
88
|
end
|
398
89
|
|
399
90
|
def parse_url_builder
|
400
91
|
RIG_URL_BUILDER.each_key { |kre|
|
401
|
-
@inner_text.
|
402
|
-
|
403
|
-
@
|
404
|
-
|
405
|
-
|
92
|
+
while match = @inner_text.match(RIG_URL_BUILDER[kre]) do
|
93
|
+
tk = Token.instance(self, kre, match )
|
94
|
+
@tokens << tk
|
95
|
+
@inner_text.gsub! match[0], tk.anchor
|
96
|
+
end
|
406
97
|
}
|
407
98
|
end
|
408
99
|
|
409
100
|
def parse_expressions
|
410
|
-
RIG_EXPRESSIONS.
|
411
|
-
@inner_text.
|
412
|
-
|
413
|
-
@
|
414
|
-
|
415
|
-
|
101
|
+
RIG_EXPRESSIONS.each { |kre, re|
|
102
|
+
while match = @inner_text.match(re) do
|
103
|
+
tk = Token.instance(self, kre, match )
|
104
|
+
@tokens << tk
|
105
|
+
@inner_text.gsub! match[0], tk.anchor
|
106
|
+
end
|
416
107
|
}
|
417
108
|
end
|
418
109
|
|
419
110
|
def parse_statements
|
420
|
-
@inner_text.
|
421
|
-
type = (
|
422
|
-
|
423
|
-
@
|
424
|
-
|
425
|
-
|
111
|
+
while match = @inner_text.match(RIG_STATEMENTS) do
|
112
|
+
type = (match[2] || String.new) << (match[6] || String.new)
|
113
|
+
tk = Token.instance(self, type.to_sym, match )
|
114
|
+
@tokens << tk.parse!
|
115
|
+
@inner_text.gsub! match[0], tk.anchor
|
116
|
+
end
|
426
117
|
end
|
427
118
|
|
428
119
|
def parse_templates
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
@
|
434
|
-
|
435
|
-
}
|
120
|
+
while match = @inner_text.match(RIG_TEMPLATES) do
|
121
|
+
type = (match[2] || String.new) << (match[6] || String.new) << (match[13] || String.new)
|
122
|
+
tk = Token.instance(self, type.to_sym, match )
|
123
|
+
@tokens << tk.parse!
|
124
|
+
@inner_text.gsub! match[0], tk.anchor
|
125
|
+
end
|
436
126
|
end
|
437
127
|
|
438
128
|
end
|
data/lib/tzispa/rig/syntax.rb
CHANGED
@@ -12,17 +12,14 @@ module Tzispa
|
|
12
12
|
}.freeze
|
13
13
|
|
14
14
|
RIG_URL_BUILDER = {
|
15
|
-
:url => /<(url|purl)(
|
16
|
-
:api
|
15
|
+
:url => /<(url|purl)(#\w+)?:([^\[\@\/]+(?:\@[^\[\/]+)?)(\[(\w+=[^,\]]+(,\w+=[^,\]]+)*?)\])?\/>/,
|
16
|
+
:api => /<(api|sapi)(#\w+)?:([^:\@]+(?:\@[^:]+)?):([^:\/]+)(?::([^:\/]+))?(?::([^\/]+))?\/>/
|
17
17
|
}.freeze
|
18
18
|
|
19
19
|
RIG_STATEMENTS = /(<(loop):(\w+)>(.*?)<\/loop:\3>)|(<(ife):(\w+)>(.*?)(<else:\7\/>(.*?))?<\/ife:\7>)/m
|
20
20
|
|
21
|
-
RIG_TEMPLATES =
|
22
|
-
|
23
|
-
:iblk => /<(iblk):(\w+):(\w+(?:\.\w+)?)(?:\[(\w+=[^,\]]+(?:,\w+=[^,\]]+)*)\])?:(\w+(?:\.\w+)?)(?:\[(\w+=[^,\]]+(?:,\w+=[^,\]]+)*)\])?\/>/,
|
24
|
-
:static => /<(static):(\w+(?:\.\w+)?)(?:\[(\w+=[^,\]]+(?:,\w+=[^,\]]+)*)\])?\/>/
|
25
|
-
}.freeze
|
21
|
+
RIG_TEMPLATES = /(<(blk):(\w+(?:@\w+)?)(?:\[(\w+=[^,\]]+(?:,\w+=[^,\]]+)*)\])?\/>)|(<(iblk):(\w+):(\w+(?:@\w+)?)(?:\[(\w+=[^,\]]+(?:,\w+=[^,\]]+)*)\])?:(\w+(?:@\w+)?)(?:\[(\w+=[^,\]]+(?:,\w+=[^,\]]+)*)\])?\/>)|(<(static):(\w+(?:@\w+)?)(?:\[(\w+=[^,\]]+(?:,\w+=[^,\]]+)*)\])?\/>)/
|
22
|
+
|
26
23
|
|
27
24
|
end
|
28
25
|
end
|