bade 0.2.3 → 0.3.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.
@@ -6,8 +6,8 @@ module Bade
6
6
 
7
7
  class Parser
8
8
  module ParseRubyCodeRegexps
9
- END_NEW_LINE = /\A\s*\n/
10
- END_PARAMS_ARG = /\A\s*[,)]/
9
+ END_NEW_LINE = /\A\s*\n/.freeze
10
+ END_PARAMS_ARG = /\A\s*[,)]/.freeze
11
11
  end
12
12
 
13
13
  # Parse ruby code, ended with outer delimiters
@@ -16,17 +16,27 @@ module Bade
16
16
  #
17
17
  # @return [Void] parsed ruby code
18
18
  #
19
- def parse_ruby_code(outer_delimiters)
19
+ def parse_ruby_code(outer_delimiters, allow_multiline: false)
20
20
  code = String.new
21
21
  end_re = if outer_delimiters.is_a?(Regexp)
22
22
  outer_delimiters
23
23
  else
24
24
  /\A\s*[#{Regexp.escape outer_delimiters.to_s}]/
25
25
  end
26
+
26
27
  delimiters = []
27
28
  string_start_quote_char = nil
28
29
 
29
- until @line.empty? || (delimiters.empty? && @line =~ end_re)
30
+ loop do
31
+ break if !allow_multiline && @line.empty?
32
+ break if allow_multiline && @line.empty? && (@lines && @lines.empty?)
33
+ break if delimiters.empty? && @line =~ end_re
34
+
35
+ if @line.empty? && allow_multiline && !(@lines && @lines.empty?)
36
+ next_line
37
+ code << "\n"
38
+ end
39
+
30
40
  char = @line[0]
31
41
 
32
42
  # backslash escaped delimiter
@@ -70,7 +80,7 @@ module Bade
70
80
  '{' => '}',
71
81
  }.freeze
72
82
 
73
- RUBY_QUOTES = %w(' ").freeze
83
+ RUBY_QUOTES = %w[' "].freeze
74
84
 
75
85
  RUBY_NOT_NESTABLE_DELIMITERS = RUBY_QUOTES
76
86
 
@@ -78,7 +88,7 @@ module Bade
78
88
  RUBY_END_DELIMITERS = (%w(\) ] }) + RUBY_NOT_NESTABLE_DELIMITERS).freeze
79
89
  RUBY_ALL_DELIMITERS = (RUBY_START_DELIMITERS + RUBY_END_DELIMITERS).uniq.freeze
80
90
 
81
- RUBY_START_DELIMITERS_RE = /\A[#{Regexp.escape RUBY_START_DELIMITERS.join}]/
82
- RUBY_END_DELIMITERS_RE = /\A[#{Regexp.escape RUBY_END_DELIMITERS.join}]/
91
+ RUBY_START_DELIMITERS_RE = /\A[#{Regexp.escape RUBY_START_DELIMITERS.join}]/.freeze
92
+ RUBY_END_DELIMITERS_RE = /\A[#{Regexp.escape RUBY_END_DELIMITERS.join}]/.freeze
83
93
  end
84
94
  end
@@ -6,12 +6,12 @@ module Bade
6
6
 
7
7
  class Parser
8
8
  module TagRegexps
9
- BLOCK_EXPANSION = /\A:\s+/
9
+ BLOCK_EXPANSION = /\A:\s+/.freeze
10
10
  OUTPUT_CODE = LineIndicatorRegexps::OUTPUT_BLOCK
11
- TEXT_START = /\A /
11
+ TEXT_START = /\A /.freeze
12
12
 
13
- PARAMS_ARGS_DELIMITER = /\A\s*,/
14
- PARAMS_END = /\A\s*\)/
13
+ PARAMS_ARGS_DELIMITER = /\A\s*,/.freeze
14
+ PARAMS_END = /\A\s*\)/.freeze
15
15
  end
16
16
 
17
17
  # @param [String] tag tag name
@@ -6,8 +6,8 @@ module Bade
6
6
 
7
7
  class Parser
8
8
  module TextRegexps
9
- INTERPOLATION_START = /(\\)?(&|#)\{/
10
- INTERPOLATION_END = /\A\}/
9
+ INTERPOLATION_START = /(\\)?(&|#)\{/.freeze
10
+ INTERPOLATION_END = /\A\}/.freeze
11
11
  end
12
12
 
13
13
  def parse_text
@@ -64,7 +64,7 @@ module Bade
64
64
 
65
65
  next_line
66
66
 
67
- @line.remove_indent!(text_indent ? text_indent : indent, @tabsize)
67
+ @line.remove_indent!(text_indent || indent, @tabsize)
68
68
 
69
69
  parse_text
70
70
 
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
@@ -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?
@@ -126,7 +128,9 @@ module Bade
126
128
 
127
129
  def parse_import
128
130
  # TODO: change this to something better
129
- path = eval(@line) # rubocop:disable Lint/Eval
131
+ # rubocop:disable Security/Eval
132
+ path = eval(@line)
133
+ # rubocop:enable Security/Eval
130
134
  append_node(:import, value: path)
131
135
 
132
136
  @dependency_paths << path unless @dependency_paths.include?(path)
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
-
3
+ require 'psych'
5
4
 
6
5
  module Bade
7
6
  class Precompiled
@@ -26,7 +25,11 @@ module Bade
26
25
  file
27
26
  end
28
27
 
29
- hash = YAML.load(file)
28
+ hash = if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.0')
29
+ Psych.safe_load(file, filename: file.path, permitted_classes: [Symbol])
30
+ else
31
+ Psych.safe_load(file, [Symbol])
32
+ end
30
33
  raise LoadError, 'YAML file is not in valid format' unless hash.is_a?(Hash)
31
34
 
32
35
  file_path = hash[:source_file_path]
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
@@ -164,17 +188,21 @@ module Bade
164
188
 
165
189
  # @return [RenderBinding]
166
190
  #
191
+ # rubocop:disable Lint/DuplicateMethods
167
192
  def render_binding
168
193
  @render_binding ||= Runtime::RenderBinding.new(locals || {})
169
194
  end
195
+ # rubocop:enable Lint/DuplicateMethods
170
196
 
171
197
  # @return [Proc]
172
198
  #
173
199
  def lambda_instance
174
- if lambda_binding
175
- lambda_binding.eval(lambda_string, file_path || TEMPLATE_FILE_NAME)
176
- else
177
- 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
178
206
  end
179
207
  end
180
208
 
@@ -195,13 +223,22 @@ module Bade
195
223
  Generator::NEW_LINE_NAME.to_sym => new_line,
196
224
  Generator::BASE_INDENT_NAME.to_sym => indent,
197
225
  }
198
- run_vars.reject! { |_key, value| value.nil? } # remove nil values
226
+ run_vars.compact! # remove nil values
199
227
 
200
- 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
201
240
  end
202
241
 
203
-
204
-
205
242
  private
206
243
 
207
244
  # @param [String] content source code of the template
@@ -249,6 +286,7 @@ module Bade
249
286
 
250
287
  if File.exist?(sub_path)
251
288
  return if sub_path.end_with?('.rb') # handled in Generator
289
+
252
290
  sub_path
253
291
  else
254
292
  bade_path = "#{sub_path}.bade"
@@ -272,5 +310,16 @@ module Bade
272
310
  end
273
311
  end
274
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
275
321
  end
276
322
  end
323
+
324
+ # Set default value to clear_constants
325
+ Bade::Renderer.clear_constants = false
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ def ruby2_keywords(*) end if RUBY_VERSION < '2.7'
@@ -13,12 +13,10 @@ class String
13
13
  %('#{self}')
14
14
  end
15
15
 
16
-
17
16
  def blank?
18
17
  strip.empty?
19
18
  end
20
19
 
21
-
22
20
  def remove_last(count = 1)
23
21
  slice(0, length - count)
24
22
  end
@@ -27,7 +25,6 @@ class String
27
25
  slice!(length - count, count)
28
26
  end
29
27
 
30
-
31
28
  def remove_first(count = 1)
32
29
  slice(count, length - count)
33
30
  end
@@ -67,7 +64,6 @@ class String
67
64
  remove_first(__chars_count_for_indent(indent, tabsize))
68
65
  end
69
66
 
70
-
71
67
  # Remove indent
72
68
  #
73
69
  # @param [Int] indent
@@ -77,7 +73,6 @@ class String
77
73
  remove_first!(__chars_count_for_indent(indent, tabsize))
78
74
  end
79
75
 
80
-
81
76
  # Calculate indent for line
82
77
  #
83
78
  # @param [Int] tabsize
@@ -88,9 +83,10 @@ class String
88
83
  count = 0
89
84
 
90
85
  each_char do |char|
91
- if char == SPACE_CHAR
86
+ case char
87
+ when SPACE_CHAR
92
88
  count += 1
93
- elsif char == TAB_CHAR
89
+ when TAB_CHAR
94
90
  count += tabsize
95
91
  else
96
92
  break
@@ -105,7 +101,7 @@ class String
105
101
  #
106
102
  def strip_heredoc
107
103
  min_val = scan(/^[ \t]*(?=\S)/).min
108
- indent = (min_val && min_val.size) || 0
104
+ indent = min_val&.size || 0
109
105
  gsub(/^[ \t]{#{indent}}/, '')
110
106
  end
111
107
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../ruby2_keywords'
4
+
3
5
  module Bade
4
6
  module Runtime
5
- class RuntimeError < ::StandardError; end
6
-
7
7
  class Block
8
8
  class MissingBlockDefinitionError < RuntimeError
9
9
  # @return [String]
@@ -14,8 +14,8 @@ module Bade
14
14
  #
15
15
  attr_accessor :context
16
16
 
17
- def initialize(name, context, msg = nil)
18
- super()
17
+ def initialize(name, context, msg, template_backtrace)
18
+ super(msg, template_backtrace)
19
19
 
20
20
  self.name = name
21
21
  self.context = context
@@ -36,34 +36,51 @@ module Bade
36
36
  #
37
37
  attr_reader :name
38
38
 
39
+ # @return [RenderBinding::Location, nil]
40
+ #
41
+ attr_reader :location
42
+
39
43
  # @return [RenderBinding]
40
44
  #
41
45
  attr_reader :render_binding
42
46
 
43
47
  # @param [String] name name of the block
48
+ # @param [RenderBinding::Location, nil] location
44
49
  # @param [RenderBinding] render_binding reference to current binding instance
45
50
  # @param [Proc] block reference to lambda
46
51
  #
47
- def initialize(name, render_binding, &block)
52
+ def initialize(name, location, render_binding, &block)
48
53
  @name = name
54
+ @location = location
49
55
  @render_binding = render_binding
50
56
  @block = block
51
57
  end
52
58
 
53
59
  # --- Calling methods
54
60
 
55
- def call(*args)
61
+ # Calls the block and adds rendered content into current buffer stack.
62
+ #
63
+ # @return [Void]
64
+ ruby2_keywords def call(*args)
56
65
  call!(*args) unless @block.nil?
57
66
  end
58
67
 
59
- def call!(*args)
60
- raise MissingBlockDefinitionError.new(name, :call) if @block.nil?
68
+ # Calls the block and adds rendered content into current buffer stack.
69
+ #
70
+ # @return [Void]
71
+ ruby2_keywords def call!(*args)
72
+ raise MissingBlockDefinitionError.new(name, :call, nil, render_binding.__location_stack) if @block.nil?
61
73
 
62
- render_binding.__buff.concat(@block.call(*args))
74
+ __call(*args)
63
75
  end
64
76
 
65
77
  # --- Rendering methods
66
78
 
79
+ # Calls the block and returns rendered content in string.
80
+ #
81
+ # Returns empty string when there is no block.
82
+ #
83
+ # @return [String]
67
84
  def render(*args)
68
85
  if @block.nil?
69
86
  ''
@@ -72,10 +89,33 @@ module Bade
72
89
  end
73
90
  end
74
91
 
92
+ # Calls the block and returns rendered content in string.
93
+ #
94
+ # Throws error when there is no block.
95
+ #
96
+ # @return [String]
75
97
  def render!(*args)
76
- raise MissingBlockDefinitionError.new(name, :render) if @block.nil?
98
+ raise MissingBlockDefinitionError.new(name, :render, nil, render_binding.__location_stack) if @block.nil?
99
+
100
+ loc = location.dup
101
+ render_binding.__buffs_push(loc)
102
+
103
+ @block.call(*args)
104
+
105
+ render_binding.__buffs_pop&.join || ''
106
+ end
107
+
108
+ # Calls the block and adds rendered content into current buffer stack.
109
+ #
110
+ # @return [Void]
111
+ ruby2_keywords def __call(*args)
112
+ loc = location.dup
113
+ render_binding.__buffs_push(loc)
114
+
115
+ @block.call(*args)
77
116
 
78
- @block.call(*args).join
117
+ res = render_binding.__buffs_pop
118
+ render_binding.__buff&.concat(res) if !res.nil? && !res.empty?
79
119
  end
80
120
  end
81
121
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bade
4
+ module Runtime
5
+ # Tracks created global variables and constants in block.
6
+ class GlobalsTracker
7
+ # @return [Array<Symbol>]
8
+ attr_accessor :caught_variables
9
+
10
+ # @return [Array<[Object, :Symbol]>]
11
+ attr_accessor :caught_constants
12
+
13
+ def initialize
14
+ @caught_variables = []
15
+ @caught_constants = []
16
+ end
17
+
18
+ # @yieldreturn [T]
19
+ # @return [T]
20
+ def catch
21
+ before_variables = global_variables
22
+ before_global_constants = Object.constants
23
+ before_binding_constants = Bade::Runtime::RenderBinding.constants(false)
24
+
25
+ res = nil
26
+ begin
27
+ res = yield
28
+ ensure
29
+ @caught_variables += global_variables - before_variables
30
+
31
+ @caught_constants += (Object.constants - before_global_constants)
32
+ .map { |name| [Object, name] }
33
+ @caught_constants += (Bade::Runtime::RenderBinding.constants(false) - before_binding_constants)
34
+ .map { |name| [Bade::Runtime::RenderBinding, name] }
35
+ end
36
+
37
+ res
38
+ end
39
+
40
+ def clear_all
41
+ clear_global_variables
42
+ clear_constants
43
+ end
44
+
45
+ def clear_constants
46
+ @caught_constants.each do |(obj, name)|
47
+ obj.send(:remove_const, name) if obj.const_defined?(name)
48
+ end
49
+ @caught_constants = []
50
+ end
51
+
52
+ def clear_global_variables
53
+ @caught_variables.each do |name|
54
+ eval("#{name} = nil", binding, __FILE__, __LINE__)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,43 +1,58 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../ruby2_keywords'
4
+
3
5
  module Bade
4
6
  module Runtime
5
7
  require_relative 'block'
6
8
 
7
9
  class Mixin < Block
8
- def call!(blocks, *args)
9
- block.call(blocks, *args)
10
- rescue ArgumentError => e
11
- case e.message
12
- when /\Awrong number of arguments \(given ([0-9]+), expected ([0-9]+)\)\Z/,
13
- /\Awrong number of arguments \(([0-9]+) for ([0-9]+)\)\Z/
14
- # handle incorrect parameters count
15
-
16
- # minus one, because first argument is always hash of blocks
17
- given = $1.to_i - 1
18
- expected = $2.to_i - 1
19
- raise ArgumentError, "wrong number of arguments (given #{given}, expected #{expected}) for mixin `#{name}`"
20
-
21
- when /\Aunknown keyword: (.*)\Z/
22
- # handle unknown key-value parameter
23
- key_name = $1
24
- raise ArgumentError, "unknown key-value argument `#{key_name}` for mixin `#{name}`"
25
-
26
- else
27
- raise
28
- end
10
+ ruby2_keywords def call!(blocks, *args)
11
+ begin
12
+ __call(blocks, *args)
13
+ rescue ::ArgumentError => e
14
+ case e.message
15
+ when /\Awrong number of arguments \(given ([0-9]+), expected ([0-9]+)\)\Z/,
16
+ /\Awrong number of arguments \(([0-9]+) for ([0-9]+)\)\Z/
17
+ # handle incorrect parameters count
18
+
19
+ # minus one, because first argument is always hash of blocks
20
+ given = $1.to_i - 1
21
+ expected = $2.to_i - 1
22
+ msg = "wrong number of arguments (given #{given}, expected #{expected}) for mixin `#{name}`"
23
+ raise Bade::Runtime::ArgumentError.new(msg, render_binding.__location_stack)
24
+
25
+ when /\Aunknown keyword: (.*)\Z/
26
+ # handle unknown key-value parameter
27
+ key_name = $1
28
+ msg = "unknown key-value argument `#{key_name}` for mixin `#{name}`"
29
+ raise Bade::Runtime::ArgumentError.new(msg, render_binding.__location_stack)
29
30
 
30
- rescue Block::MissingBlockDefinitionError => e
31
- msg = case e.context
32
- when :call
33
- "Mixin `#{name}` requires block to get called of block `#{e.name}`"
34
- when :render
35
- "Mixin `#{name}` requires block to get rendered content of block `#{e.name}`"
36
- else
37
- raise ::ArgumentError, "Unknown context #{e.context} of error #{e}!"
38
- end
39
-
40
- raise Block::MissingBlockDefinitionError.new(e.name, e.context, msg)
31
+ when /\Amissing keyword: :?(.*)\Z/
32
+ key_name = $1
33
+ msg = "missing value for required key-value argument `#{key_name}` for mixin `#{name}`"
34
+ raise Bade::Runtime::ArgumentError.new(msg, render_binding.__location_stack)
35
+
36
+ else
37
+ raise
38
+ end
39
+ rescue Block::MissingBlockDefinitionError => e
40
+ msg = case e.context
41
+ when :call
42
+ "Mixin `#{name}` requires block to get called of block `#{e.name}`"
43
+ when :render
44
+ "Mixin `#{name}` requires block to get rendered content of block `#{e.name}`"
45
+ else
46
+ raise Bade::Runtime::ArgumentError.new("Unknown context #{e.context} of error #{e}!",
47
+ render_binding.__location_stack)
48
+ end
49
+
50
+ raise Block::MissingBlockDefinitionError.new(e.name, e.context, msg, render_binding.__location_stack)
51
+
52
+ rescue Exception => e
53
+ msg = "Exception raised during execution of mixin `#{name}`: #{e}"
54
+ raise Bade::Runtime::RuntimeError.wrap_existing_error(msg, e, render_binding.__location_stack)
55
+ end
41
56
  end
42
57
  end
43
58
  end