tzispa_rig 0.4.5 → 0.5.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/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
|