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.
@@ -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