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.
@@ -1,438 +1,128 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
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, :the_parsed
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=nil)
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 ? text : template.content
349
- @the_parsed = Array.new
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
- @the_parsed.empty?
28
+ @tokens.empty?
354
29
  end
355
30
 
356
31
  def parse!
357
- @tags = nil
358
- parse_flags
359
- if @template.bindable?
360
- parse_statements
361
- parse_expressions
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 render(binder, context=nil)
48
+ def parsed?
49
+ @parsed
50
+ end
51
+
52
+ def render(binder)
369
53
  @inner_text.dup.tap { |text|
370
- @the_parsed.each { |value|
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 ||= @the_parsed.map { |p|
61
+ @attribute_tags ||= tokens.map { |p|
378
62
  p.id.to_sym if p.respond_to? :id
379
- }.concat(@the_parsed.map{ |p|
380
- p.attribute_tags if p.type==:ife
381
- }).compact.flatten.uniq.freeze
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
- @the_parsed.select{ |p| p.type==:loop && p.id==id}.concat(
386
- @the_parsed.select{ |p| p.type==:ife }.map { |p| p.loop_parser(id) }.flatten.compact
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.gsub!(RIG_EMPTY[:flags]) { |match|
84
+ while match = @inner_text.match(RIG_EMPTY[:flags]) do
394
85
  @flags = Regexp.last_match(1)
395
- EMPTY_STRING
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.gsub!(RIG_URL_BUILDER[kre]) { |match|
402
- pe = ParsedEntity.instance(self, kre, Regexp.last_match )
403
- @the_parsed << pe
404
- pe.anchor
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.each_key { |kre|
411
- @inner_text.gsub!(RIG_EXPRESSIONS[kre]) { |match|
412
- pe = ParsedEntity.instance(self, kre, Regexp.last_match )
413
- @the_parsed << pe
414
- pe.anchor
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.gsub!(RIG_STATEMENTS) { |match|
421
- type = (Regexp.last_match[2] || String.new) << (Regexp.last_match[6] || String.new)
422
- pe = ParsedEntity.instance(self, type.to_sym, Regexp.last_match )
423
- @the_parsed << pe.parse!
424
- pe.anchor
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
- reTemplates = Regexp.new RIG_TEMPLATES.values.map{ |re| "(#{re})"}.join('|')
430
- @inner_text.gsub!(reTemplates) { |match|
431
- type = (Regexp.last_match[2] || String.new) << (Regexp.last_match[6] || String.new) << (Regexp.last_match[13] || String.new)
432
- pe = ParsedEntity.instance(self, type.to_sym, Regexp.last_match )
433
- @the_parsed << pe.parse!
434
- pe.anchor
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
@@ -12,17 +12,14 @@ module Tzispa
12
12
  }.freeze
13
13
 
14
14
  RIG_URL_BUILDER = {
15
- :url => /<(url|purl)(@\w+)?:([^\[\.\/]+(?:\.[^\[\/]+)?)(\[(\w+=[^,\]]+(,\w+=[^,\]]+)*?)\])?\/>/,
16
- :api => /<(api|sapi)(@\w+)?:([^:\.]+(?:\.[^:]+)?):([^:\/]+)(?::([^:\/]+))?(?::([^\/]+))?\/>/
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
- :blk => /<(blk):(\w+(?:\.\w+)?)(?:\[(\w+=[^,\]]+(?:,\w+=[^,\]]+)*)\])?\/>/,
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