bade 0.2.5 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 148aef838267196453c729800e51c4d3b1f194586f5226e00c659d8f3fc80e58
4
- data.tar.gz: dff1e493ea8a08976cd6cdd1fc80cf937cb2582bc41630c2ca6198fc9eab5ada
3
+ metadata.gz: 5a90545fdee8d531bb87e12dd7943c0486daf3eac68f1d0c69ba216c7595f452
4
+ data.tar.gz: cdbf2cbc427cb9dd590768d493f99c91f22ac51a0a3caa172abb0b6c96b81b57
5
5
  SHA512:
6
- metadata.gz: 86853f78cc0d8647ab5d639664dbb12d5e7101165641d91e4afdbc2affb3cf2c5434ea85bc7f9f92cec7ed571d34a4f23dd4bc0db6eaea9522df29e986df071f
7
- data.tar.gz: 335be41aa317132979197275b9c6fad798525af1247d2878239229e4f81b6beaac916000af24a1da0ccd61ea22ee3356127aa7a485fe806cc9385ef8945370be
6
+ metadata.gz: 88708cad2d3145bfe33fb2ca65acbd795b3f8b3074da64f53e8d053d09925a3f750627893c303c2000fe4e9e8328abf4b9fe60a8e1c925a4ccb8966f37887fff
7
+ data.tar.gz: 8b21e240977c4f4c0c0387c244dcfb215141e453e04fde9f47762cb59ec22f43ee8056a17c39f41037d52b2a3d2bde8f66ad2b7623d8f8819f9444eebb075741
data/Bade.gemspec CHANGED
@@ -14,16 +14,17 @@ Gem::Specification.new do |spec|
14
14
  spec.summary = 'Minimalistic template engine for Ruby.'
15
15
  spec.homepage = 'https://github.com/epuber-io/bade'
16
16
  spec.license = 'MIT'
17
- spec.required_ruby_version = '>= 2.0'
17
+ spec.metadata = { 'rubygems_mfa_required' => 'true' }
18
+ spec.required_ruby_version = '>= 2.5'
18
19
 
19
20
  spec.files = Dir['bin/**/*'] + Dir['lib/**/*'] + %w[Bade.gemspec Gemfile README.md]
20
21
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
22
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
23
  spec.require_paths = ['lib']
23
24
 
24
- spec.add_dependency 'psych', '>= 2.2', '< 4.0'
25
+ spec.add_dependency 'psych', '>= 2.2', '< 5.0'
25
26
 
26
- spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'fakefs', '~> 1.3'
27
28
  spec.add_development_dependency 'rspec', '~> 3.2'
28
- spec.add_development_dependency 'rubocop', '~> 0.50.0'
29
+ spec.add_development_dependency 'rubocop', '~> 1.14'
29
30
  end
data/Gemfile CHANGED
@@ -5,9 +5,13 @@ source 'https://rubygems.org'
5
5
  gemspec
6
6
 
7
7
  gem 'benchmark-ips', require: false
8
- gem 'coveralls', require: false
9
8
 
10
- group :banchmarks, optional: true do
9
+ group :dev, optional: true do
10
+ gem 'debase', require: false
11
+ gem 'ruby-debug-ide', require: false
12
+ end
13
+
14
+ group :benchmarks, optional: true do
11
15
  gem 'flamegraph'
12
16
  gem 'ruby-prof'
13
17
  end
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  # Bade
3
3
 
4
- [![Gem Version](https://badge.fury.io/rb/bade.svg)](http://badge.fury.io/rb/bade) [![Build Status](https://travis-ci.org/epuber-io/bade.svg?branch=master)](https://travis-ci.org/epuber-io/bade) [![Coverage Status](https://coveralls.io/repos/epuber-io/bade/badge.svg?branch=master&service=github)](https://coveralls.io/github/epuber-io/bade?branch=master) [![Inline docs](http://inch-ci.org/github/epuber-io/bade.svg?branch=master)](http://inch-ci.org/github/epuber-io/bade)
4
+ [![Gem Version](https://badge.fury.io/rb/bade.svg)](http://badge.fury.io/rb/bade) [![Build Status](https://github.com/epuber-io/bade/actions/workflows/tests.yml/badge.svg)](https://github.com/epuber-io/bade/actions) [![Coverage Status](https://coveralls.io/repos/epuber-io/bade/badge.svg?branch=master&service=github)](https://coveralls.io/github/epuber-io/bade?branch=master) [![Inline docs](https://inch-ci.org/github/epuber-io/bade.svg?branch=master)](https://inch-ci.org/github/epuber-io/bade)
5
5
 
6
6
 
7
7
  Minimalistic template engine written in Ruby for Ruby. Developed mainly to help with creating e-books. Highly influenced by [Jade](http://jade-lang.com) and [Slim](http://slim-lang.com).
@@ -30,7 +30,7 @@ Or install it yourself as:
30
30
 
31
31
  ## Development
32
32
 
33
- After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests.
33
+ After checking out the repo, run `bundle install --with dev` to install dependencies. Then, run `rake spec` to run the tests.
34
34
 
35
35
  To install this gem onto your local machine, run `bundle exec rake install`.
36
36
 
@@ -40,7 +40,7 @@ To install this gem onto your local machine, run `bundle exec rake install`.
40
40
  Bug reports and pull requests are welcome on GitHub at https://github.com/epuber-io/bade. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
41
41
 
42
42
 
43
- ## TODO
43
+ ## TODO
44
44
 
45
45
  - [ ] create documentation about syntax
46
46
  - [ ] create several examples
@@ -24,7 +24,7 @@ module Bade
24
24
 
25
25
  # @param root [Bade::Node]
26
26
  #
27
- def initialize(root: Node.new(:root), file_path: nil)
27
+ def initialize(root: Node.new(:root, nil), file_path: nil)
28
28
  @root = root
29
29
 
30
30
  @file_path = file_path.dup.freeze unless file_path.nil?
@@ -17,17 +17,26 @@ module Bade
17
17
  #
18
18
  attr_accessor :conditional
19
19
 
20
+ # @return [String, nil]
21
+ #
22
+ attr_accessor :default_value
23
+
20
24
  ruby2_keywords def initialize(*args)
21
25
  super(*args)
22
26
 
23
27
  @escaped = false
24
28
  @conditional = false
29
+ @default_value = nil
25
30
  end
26
31
 
27
32
  # @param [ValueNode] other
28
33
  #
29
34
  def ==(other)
30
- super && value == other.value && escaped == other.escaped && conditional == other.conditional
35
+ super &&
36
+ value == other.value &&
37
+ escaped == other.escaped &&
38
+ conditional == other.conditional &&
39
+ default_value == other.default_value
31
40
  end
32
41
  end
33
42
  end
data/lib/bade/ast/node.rb CHANGED
@@ -10,7 +10,11 @@ module Bade
10
10
  #
11
11
  attr_reader :type
12
12
 
13
- # @return [Array<Bade::Node>]
13
+ # @return [Bade::AST::Node, nil]
14
+ #
15
+ attr_accessor :parent
16
+
17
+ # @return [Array<Bade::AST::Node>]
14
18
  #
15
19
  attr_accessor :children
16
20
 
@@ -20,10 +24,16 @@ module Bade
20
24
  #
21
25
  attr_reader :lineno
22
26
 
23
- def initialize(type, lineno: nil)
27
+ # @return [String] filename
28
+ #
29
+ attr_reader :filename
30
+
31
+ def initialize(type, parent = nil, lineno: nil, filename: nil)
24
32
  @type = type
33
+ @parent = parent
25
34
  @children = []
26
35
  @lineno = lineno
36
+ @filename = filename
27
37
  end
28
38
 
29
39
  def to_s
@@ -38,12 +38,12 @@ module Bade
38
38
  #
39
39
  # @return [Bade::AST::Node]
40
40
  #
41
- def create(type, lineno)
41
+ def create(type, parent, lineno: nil, filename: nil)
42
42
  klass = registered_types[type]
43
43
 
44
44
  raise ::KeyError, "Undefined node type #{type.inspect}" if klass.nil?
45
45
 
46
- klass.new(type, lineno: lineno)
46
+ klass.new(type, parent, lineno: lineno, filename: filename)
47
47
  end
48
48
  end
49
49
 
@@ -55,6 +55,7 @@ module Bade
55
55
  register_type DoctypeNode, :doctype
56
56
 
57
57
  register_type ValueNode, :import
58
+ register_type ValueNode, :yield
58
59
 
59
60
  # --- Comments
60
61
 
@@ -37,13 +37,13 @@ module Bade
37
37
 
38
38
  children_s = ''
39
39
  if node.children.count > 0
40
- children_s = "\n" + node.children.map { |n| node_to_s(n, level + 1) }.join("\n") + "\n#{indent}"
40
+ children_s = "\n#{node.children.map { |n| node_to_s(n, level + 1) }.join("\n")}\n#{indent}"
41
41
  end
42
42
 
43
43
  other = ''
44
44
 
45
45
  case node
46
- when TagNode
46
+ when TagNode, MixinCommonNode
47
47
  other = node.name
48
48
  when KeyValueNode
49
49
  other = "#{node.name}:#{node.value}"
@@ -56,15 +56,13 @@ module Bade
56
56
  ''
57
57
  end
58
58
  other = "#{escaped_sign}#{node.value}"
59
- when MixinCommonNode
60
- other = node.name
61
59
  when Node
62
60
  # nothing
63
61
  else
64
62
  raise "Unknown node class #{node.class} of type #{node.type} for serializing"
65
63
  end
66
64
 
67
- other = ' ' + other if other && !other.empty?
65
+ other = " #{other}" if other && !other.empty?
68
66
 
69
67
  "#{indent}(#{type_s}#{other}#{children_s})"
70
68
  end
@@ -41,6 +41,7 @@ module Bade
41
41
  code_indent do
42
42
  buff_code "self.#{NEW_LINE_NAME} = #{NEW_LINE_NAME}"
43
43
  buff_code "self.#{BASE_INDENT_NAME} = #{BASE_INDENT_NAME}"
44
+ buff_code "__buffs_push(#{location(filename: document.file_path, lineno: 0, label: '<top>')})"
44
45
 
45
46
  visit_document(document)
46
47
 
@@ -75,7 +76,7 @@ module Bade
75
76
  end
76
77
 
77
78
  def buff_code(text)
78
- @buff << ' ' * @code_indent + text
79
+ @buff << "#{' ' * @code_indent}#{text}"
79
80
  end
80
81
 
81
82
  # @param document [Bade::Document]
@@ -115,6 +116,8 @@ module Bade
115
116
  # @param current_node [Node]
116
117
  #
117
118
  def visit_node(current_node)
119
+ update_location_node(current_node)
120
+
118
121
  case current_node.type
119
122
  when :root
120
123
  visit_node_children(current_node)
@@ -134,7 +137,7 @@ module Bade
134
137
  buff_print_text ' -->'
135
138
 
136
139
  when :comment
137
- comment_text = '#' + current_node.children.map(&:value).join("\n#")
140
+ comment_text = "##{current_node.children.map(&:value).join("\n#")}"
138
141
  buff_code(comment_text)
139
142
 
140
143
  when :doctype
@@ -166,8 +169,11 @@ module Bade
166
169
  "#{base_path}.rb"
167
170
  end
168
171
 
169
- buff_code "load('#{load_path}')" unless load_path.nil?
170
-
172
+ buff_code "__load('#{load_path}')" unless load_path.nil?
173
+ when :yield
174
+ block_name = DEFAULT_BLOCK_NAME
175
+ method = current_node.conditional ? 'call' : 'call!'
176
+ buff_code "#{block_name}.#{method}"
171
177
  else
172
178
  raise "Unknown type #{current_node.type}"
173
179
  end
@@ -267,19 +273,22 @@ module Bade
267
273
  params = mixin_node.params
268
274
  result = []
269
275
 
270
- if mixin_node.type == :mixin_call
276
+ case mixin_node.type
277
+ when :mixin_call
271
278
  blocks = mixin_node.blocks
272
279
 
273
280
  other_children = (mixin_node.children - mixin_node.blocks - mixin_node.params)
274
281
  if other_children.count { |n| n.type != :newline } > 0
275
- def_block_node = AST::NodeRegistrator.create(:mixin_block, mixin_node.lineno)
282
+ def_block_node = AST::NodeRegistrator.create(:mixin_block, mixin_node, lineno: mixin_node.lineno)
276
283
  def_block_node.name = DEFAULT_BLOCK_NAME
277
284
  def_block_node.children = other_children
278
285
 
279
286
  blocks << def_block_node
280
287
  end
281
288
 
282
- if !blocks.empty?
289
+ if blocks.empty?
290
+ result << '{}'
291
+ else
283
292
  buff_code '__blocks = {}'
284
293
 
285
294
  blocks.each do |block|
@@ -287,17 +296,18 @@ module Bade
287
296
  end
288
297
 
289
298
  result << '__blocks.dup'
290
- else
291
- result << '{}'
292
299
  end
293
- elsif mixin_node.type == :mixin_decl
300
+ when :mixin_decl
294
301
  result << '__blocks'
295
302
  end
296
303
 
304
+ # positional params
305
+ result += params.select { |n| n.type == :mixin_param }
306
+ .map { |param| param.default_value ? "#{param.value} = #{param.default_value}" : param.value }
297
307
 
298
- # normal params
299
- result += params.select { |n| n.type == :mixin_param }.map(&:value)
300
- result += params.select { |n| n.type == :mixin_key_param }.map { |param| "#{param.name}: #{param.value}" }
308
+ # key-value params
309
+ result += params.select { |n| n.type == :mixin_key_param }
310
+ .map { |param| "#{param.name}: #{param.value}" }
301
311
 
302
312
  result.join(', ')
303
313
  end
@@ -309,14 +319,10 @@ module Bade
309
319
  # @return [nil]
310
320
  #
311
321
  def block_definition(block_node)
312
- buff_code "__blocks['#{block_node.name}'] = __create_block('#{block_node.name}') do"
322
+ buff_code "__blocks['#{block_node.name}'] = __create_block('#{block_node.name}', #{location_node(block_node)}) do"
313
323
 
314
324
  code_indent do
315
- buff_code '__buffs_push()'
316
-
317
325
  visit_node_children(block_node)
318
-
319
- buff_code '__buffs_pop()'
320
326
  end
321
327
 
322
328
  buff_code 'end'
@@ -350,7 +356,7 @@ module Bade
350
356
  #
351
357
  def visit_block_decl(current_node)
352
358
  params = formatted_mixin_params(current_node)
353
- buff_code "#{MIXINS_NAME}['#{current_node.name}'] = __create_mixin('#{current_node.name}', &lambda { |#{params}|"
359
+ buff_code "#{MIXINS_NAME}['#{current_node.name}'] = __create_mixin('#{current_node.name}', #{location_node(current_node)}, &lambda { |#{params}|"
354
360
 
355
361
  code_indent do
356
362
  blocks_name_declaration(current_node)
@@ -367,6 +373,55 @@ module Bade
367
373
  def escape_double_quotes!(str)
368
374
  str.gsub!(/"/, '\"')
369
375
  end
376
+
377
+ # @param [Bade::AST::Node]
378
+ # @return [Void]
379
+ def update_location_node(node)
380
+ should_skip = case node.type
381
+ when :code
382
+ value = node.value.strip
383
+
384
+ %w[end else }].include?(value) || value.match(/^(when|elsif) /)
385
+ when :newline
386
+ true
387
+ else
388
+ false
389
+ end
390
+
391
+ return if should_skip
392
+ return if node.lineno.nil?
393
+
394
+ buff_code "__update_lineno(#{node.lineno})"
395
+ end
396
+
397
+ # @param [String] filename
398
+ # @param [Fixnum] lineno
399
+ # @param [String] label
400
+ # @return [String]
401
+ def location(filename:, lineno:, label:)
402
+ args = [
403
+ filename ? "path: '#{filename}'" : nil,
404
+ "lineno: #{lineno}",
405
+ "label: '#{label}'",
406
+ ].compact
407
+
408
+ "Location.new(#{args.join(',')})"
409
+ end
410
+
411
+ # @param [Node] node
412
+ # @return [String]
413
+ def location_node(node)
414
+ label = case node.type
415
+ when :mixin_decl
416
+ "+#{node.name}"
417
+ when :mixin_block
418
+ "#{node.name} in +#{node.parent.name}"
419
+ else
420
+ node.name
421
+ end
422
+
423
+ location(filename: node.filename, lineno: node.lineno, label: label)
424
+ end
370
425
  end
371
426
 
372
427
  # backward compatibility
@@ -7,6 +7,7 @@ module Bade
7
7
  class Parser
8
8
  module LineIndicatorRegexps
9
9
  IMPORT = /\Aimport /.freeze
10
+ YIELD = /\Ayield(!?)/.freeze
10
11
  MIXIN_DECL = /\Amixin #{NAME_RE_STRING}/.freeze
11
12
  MIXIN_CALL = /\A\+#{NAME_RE_STRING}/.freeze
12
13
  BLOCK_DECLARATION = /\Ablock #{NAME_RE_STRING}/.freeze
@@ -135,6 +136,11 @@ module Bade
135
136
  @line = $'
136
137
  parse_import
137
138
 
139
+ when LineIndicatorRegexps::YIELD
140
+ @line = $'
141
+ node = append_node(:yield, add: true)
142
+ node.conditional = $1.nil?
143
+
138
144
  when LineIndicatorRegexps::MIXIN_DECL
139
145
  # Mixin declaration
140
146
  @line = $'
@@ -195,12 +201,8 @@ module Bade
195
201
  @line = $' if $1
196
202
  parse_tag($&)
197
203
 
198
- when LineIndicatorRegexps::TAG_CLASS_START_BLOCK
199
- # Found class name -> implicit div
200
- parse_tag 'div'
201
-
202
- when LineIndicatorRegexps::TAG_ID_START_BLOCK
203
- # Found id name -> implicit div
204
+ when LineIndicatorRegexps::TAG_CLASS_START_BLOCK, LineIndicatorRegexps::TAG_ID_START_BLOCK
205
+ # Found a class or id selector.
204
206
  parse_tag 'div'
205
207
 
206
208
  else
@@ -18,6 +18,7 @@ module Bade
18
18
  PARAMS_PARAM_NAME = /\A\s*#{NAME_RE_STRING}/.freeze
19
19
  PARAMS_BLOCK_NAME = /\A\s*&#{NAME_RE_STRING}/.freeze
20
20
  PARAMS_KEY_PARAM_NAME = CODE_ATTR_RE
21
+ PARAMS_PARAM_DEFAULT_START = /\A\s*=/.freeze
21
22
  end
22
23
 
23
24
  def parse_mixin_call(mixin_name)
@@ -114,7 +115,12 @@ module Bade
114
115
 
115
116
  when MixinRegexps::PARAMS_PARAM_NAME
116
117
  @line = $'
117
- append_node(:mixin_param, value: $1)
118
+ attr_node = append_node(:mixin_param, value: $1)
119
+
120
+ if @line =~ MixinRegexps::PARAMS_PARAM_DEFAULT_START
121
+ @line = $'
122
+ attr_node.default_value = parse_ruby_code(ParseRubyCodeRegexps::END_PARAMS_ARG)
123
+ end
118
124
 
119
125
  when MixinRegexps::PARAMS_BLOCK_NAME
120
126
  @line = $'
data/lib/bade/parser.rb CHANGED
@@ -17,6 +17,8 @@ module Bade
17
17
  attr_reader :error, :file, :line, :lineno, :column
18
18
 
19
19
  def initialize(error, file, line, lineno, column)
20
+ super(error)
21
+
20
22
  @error = error
21
23
  @file = file || '(__TEMPLATE__)'
22
24
  @line = line.to_s
@@ -27,7 +29,7 @@ module Bade
27
29
  def to_s
28
30
  line = @line.lstrip
29
31
  column = @column + line.size - @line.size
30
- <<-MSG.strip_heredoc
32
+ <<~MSG
31
33
  #{error}
32
34
  #{file}, Line #{lineno}, Column #{@column}
33
35
  #{line}
@@ -60,7 +62,7 @@ module Bade
60
62
  @file_path = file_path
61
63
 
62
64
  @tab_re = /\G((?: {#{tabsize}})*) {0,#{tabsize - 1}}\t/
63
- @tab = '\1' + ' ' * tabsize
65
+ @tab = "\1#{' ' * tabsize}"
64
66
 
65
67
  reset
66
68
  end
@@ -106,7 +108,7 @@ module Bade
106
108
  @stacks << @stacks.last.dup while indent >= @stacks.length
107
109
 
108
110
  parent = @stacks[indent].last
109
- node = AST::NodeRegistrator.create(type, @lineno)
111
+ node = AST::NodeRegistrator.create(type, parent, lineno: @lineno, filename: @file_path)
110
112
  parent.children << node
111
113
 
112
114
  node.value = value unless value.nil?
@@ -26,9 +26,9 @@ module Bade
26
26
  end
27
27
 
28
28
  hash = if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.0')
29
- YAML.safe_load(file, filename: file.path, permitted_classes: [Symbol])
29
+ Psych.safe_load(file, filename: file.path, permitted_classes: [Symbol])
30
30
  else
31
- YAML.safe_load(file, [Symbol])
31
+ Psych.safe_load(file, [Symbol])
32
32
  end
33
33
  raise LoadError, 'YAML file is not in valid format' unless hash.is_a?(Hash)
34
34
 
data/lib/bade/renderer.rb CHANGED
@@ -9,7 +9,7 @@ require_relative 'precompiled'
9
9
 
10
10
  module Bade
11
11
  class Renderer
12
- class LoadError < ::RuntimeError
12
+ class LoadError < Bade::Runtime::RuntimeError
13
13
  # @return [String]
14
14
  #
15
15
  attr_reader :loading_path
@@ -22,18 +22,29 @@ module Bade
22
22
  # @param [String] reference_path reference file from which is load performed
23
23
  # @param [String] msg standard message
24
24
  #
25
- def initialize(loading_path, reference_path, msg = nil)
26
- super(msg)
25
+ def initialize(loading_path, reference_path, msg, template_backtrace = [])
26
+ super(msg, template_backtrace)
27
27
  @loading_path = loading_path
28
28
  @reference_path = reference_path
29
29
  end
30
30
  end
31
31
 
32
- def initialize
33
- @optimize = false
32
+ class << self
33
+ def _globals_tracker
34
+ @globals_tracker ||= Bade::Runtime::GlobalsTracker.new
35
+ end
36
+
37
+ # When set to true it will remove all constants that template created. Off by default.
38
+ #
39
+ # @return [Boolean]
40
+ attr_accessor :clear_constants
34
41
  end
35
42
 
36
- TEMPLATE_FILE_NAME = '(__template__)'.freeze
43
+ # @param clear_constants [Boolean] When set to true it will remove all constants that template created. Off by default.
44
+ def initialize(clear_constants: Bade::Renderer.clear_constants)
45
+ @optimize = false
46
+ @clear_constants = clear_constants
47
+ end
37
48
 
38
49
  # @return [String]
39
50
  #
@@ -59,6 +70,10 @@ module Bade
59
70
  #
60
71
  attr_accessor :optimize
61
72
 
73
+ # @return [Boolean] When set to true it will remove all constants that template created. Off by default.
74
+ #
75
+ attr_accessor :clear_constants
76
+
62
77
 
63
78
  # ----------------------------------------------------------------------------- #
64
79
  # Internal attributes
@@ -77,8 +92,8 @@ module Bade
77
92
  #
78
93
  # @return [Renderer] preconfigured instance of this class
79
94
  #
80
- def self.from_source(source, file_path = nil)
81
- inst = new
95
+ def self.from_source(source, file_path = nil, clear_constants: Bade::Renderer.clear_constants)
96
+ inst = new(clear_constants: clear_constants)
82
97
  inst.source_text = source
83
98
  inst.file_path = file_path
84
99
  inst
@@ -88,14 +103,14 @@ module Bade
88
103
  #
89
104
  # @return [Renderer] preconfigured instance of this class
90
105
  #
91
- def self.from_file(file)
106
+ def self.from_file(file, clear_constants: Bade::Renderer.clear_constants)
92
107
  path = if file.is_a?(File)
93
108
  file.path
94
109
  else
95
110
  file
96
111
  end
97
112
 
98
- from_source(nil, path)
113
+ from_source(nil, path, clear_constants: clear_constants)
99
114
  end
100
115
 
101
116
  # Method to create Renderer from Precompiled object, for example when you want to reuse precompiled object from disk
@@ -104,8 +119,8 @@ module Bade
104
119
  #
105
120
  # @return [Renderer] preconfigured instance of this class
106
121
  #
107
- def self.from_precompiled(precompiled)
108
- inst = new
122
+ def self.from_precompiled(precompiled, clear_constants: Bade::Renderer.clear_constants)
123
+ inst = new(clear_constants: clear_constants)
109
124
  inst.precompiled = precompiled
110
125
  inst
111
126
  end
@@ -125,11 +140,20 @@ module Bade
125
140
  self
126
141
  end
127
142
 
143
+ # @return [self]
128
144
  def with_binding(binding)
129
145
  self.lambda_binding = binding
130
146
  self
131
147
  end
132
148
 
149
+ # @param [RenderBinding] binding
150
+ # @return [self]
151
+ def with_render_binding(binding)
152
+ self.lambda_binding = nil
153
+ self.render_binding = binding
154
+ self
155
+ end
156
+
133
157
  def optimized
134
158
  self.optimize = true
135
159
  self
@@ -173,10 +197,12 @@ module Bade
173
197
  # @return [Proc]
174
198
  #
175
199
  def lambda_instance
176
- if lambda_binding
177
- lambda_binding.eval(lambda_string, file_path || TEMPLATE_FILE_NAME)
178
- else
179
- render_binding.instance_eval(lambda_string, file_path || TEMPLATE_FILE_NAME)
200
+ _catching_globals do
201
+ if lambda_binding
202
+ lambda_binding.eval(lambda_string, file_path || Bade::Runtime::TEMPLATE_FILE_NAME)
203
+ else
204
+ render_binding.instance_eval(lambda_string, file_path || Bade::Runtime::TEMPLATE_FILE_NAME)
205
+ end
180
206
  end
181
207
  end
182
208
 
@@ -197,13 +223,22 @@ module Bade
197
223
  Generator::NEW_LINE_NAME.to_sym => new_line,
198
224
  Generator::BASE_INDENT_NAME.to_sym => indent,
199
225
  }
200
- run_vars.reject! { |_key, value| value.nil? } # remove nil values
226
+ run_vars.compact! # remove nil values
201
227
 
202
- lambda_instance.call(**run_vars)
228
+ begin
229
+ return _catching_globals do
230
+ lambda_instance.call(**run_vars)
231
+ end
232
+ rescue Bade::Runtime::RuntimeError => e
233
+ raise e
234
+ rescue Exception => e
235
+ msg = "Exception raised during execution of template: #{e}"
236
+ raise Bade::Runtime::RuntimeError.wrap_existing_error(msg, e, render_binding.__location_stack)
237
+ ensure
238
+ self.class._globals_tracker.clear_constants if @clear_constants
239
+ end
203
240
  end
204
241
 
205
-
206
-
207
242
  private
208
243
 
209
244
  # @param [String] content source code of the template
@@ -275,5 +310,16 @@ module Bade
275
310
  end
276
311
  end
277
312
  end
313
+
314
+ def _catching_globals(&block)
315
+ if @clear_constants
316
+ self.class._globals_tracker.catch(&block)
317
+ else
318
+ block.call
319
+ end
320
+ end
278
321
  end
279
322
  end
323
+
324
+ # Set default value to clear_constants
325
+ Bade::Renderer.clear_constants = false
@@ -1,2 +1,3 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  def ruby2_keywords(*) end if RUBY_VERSION < '2.7'