bade 0.2.4 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Bade.gemspec +9 -8
- data/Gemfile +12 -3
- data/README.md +3 -3
- data/lib/bade/ast/document.rb +1 -1
- data/lib/bade/ast/node/mixin_node.rb +3 -3
- data/lib/bade/ast/node/static_text_node.rb +4 -2
- data/lib/bade/ast/node/value_node.rb +14 -3
- data/lib/bade/ast/node.rb +12 -3
- data/lib/bade/ast/node_registrator.rb +3 -2
- data/lib/bade/ast/string_serializer.rb +3 -5
- data/lib/bade/generator.rb +74 -24
- data/lib/bade/parser/parser_constants.rb +4 -4
- data/lib/bade/parser/parser_lines.rb +21 -19
- data/lib/bade/parser/parser_mixin.rb +17 -11
- data/lib/bade/parser/parser_ruby_code.rb +17 -7
- data/lib/bade/parser/parser_tag.rb +4 -4
- data/lib/bade/parser/parser_text.rb +3 -3
- data/lib/bade/parser.rb +7 -3
- data/lib/bade/precompiled.rb +6 -3
- data/lib/bade/renderer.rb +69 -20
- data/lib/bade/ruby2_keywords.rb +3 -0
- data/lib/bade/ruby_extensions/string.rb +4 -8
- data/lib/bade/runtime/block.rb +51 -11
- data/lib/bade/runtime/globals_tracker.rb +88 -0
- data/lib/bade/runtime/mixin.rb +47 -32
- data/lib/bade/runtime/render_binding.rb +56 -13
- data/lib/bade/runtime/utils/where.rb +101 -0
- data/lib/bade/runtime.rb +79 -1
- data/lib/bade/version.rb +1 -1
- data/lib/bade.rb +1 -0
- metadata +33 -24
@@ -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
|
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 =
|
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
|
-
|
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)
|
data/lib/bade/precompiled.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
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 =
|
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 =
|
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
|
-
|
33
|
-
|
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
|
-
|
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
|
-
|
175
|
-
lambda_binding
|
176
|
-
|
177
|
-
|
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.
|
226
|
+
run_vars.compact! # remove nil values
|
199
227
|
|
200
|
-
|
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
|
@@ -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
|
-
|
86
|
+
case char
|
87
|
+
when SPACE_CHAR
|
92
88
|
count += 1
|
93
|
-
|
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 =
|
104
|
+
indent = min_val&.size || 0
|
109
105
|
gsub(/^[ \t]{#{indent}}/, '')
|
110
106
|
end
|
111
107
|
end
|
data/lib/bade/runtime/block.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
60
|
-
|
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
|
-
|
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
|
-
|
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,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'utils/where'
|
4
|
+
|
5
|
+
module Bade
|
6
|
+
module Runtime
|
7
|
+
# Tracks created global variables and constants in block.
|
8
|
+
class GlobalsTracker
|
9
|
+
# @return [Array<Symbol>]
|
10
|
+
attr_accessor :caught_variables
|
11
|
+
|
12
|
+
# @return [Array<[Object, :Symbol]>]
|
13
|
+
attr_accessor :caught_constants
|
14
|
+
|
15
|
+
# @return [Array<String>, nil]
|
16
|
+
attr_accessor :constants_location_prefixes
|
17
|
+
|
18
|
+
# @param [Array<String>, nil] constants_location_prefixes If given, only constants whose location starts with one
|
19
|
+
# of the prefixes will be removed. If nil, all constants
|
20
|
+
# will be removed.
|
21
|
+
def initialize(constants_location_prefixes: nil)
|
22
|
+
@caught_variables = []
|
23
|
+
@caught_constants = []
|
24
|
+
@constants_location_prefixes = constants_location_prefixes
|
25
|
+
end
|
26
|
+
|
27
|
+
# @yieldreturn [T]
|
28
|
+
# @return [T]
|
29
|
+
def catch
|
30
|
+
before_variables = global_variables
|
31
|
+
before_global_constants = Object.constants
|
32
|
+
before_binding_constants = Bade::Runtime::RenderBinding.constants(false)
|
33
|
+
|
34
|
+
res = nil
|
35
|
+
begin
|
36
|
+
res = yield
|
37
|
+
ensure
|
38
|
+
@caught_variables += global_variables - before_variables
|
39
|
+
|
40
|
+
@caught_constants += (Object.constants - before_global_constants)
|
41
|
+
.map { |name| [Object, name] }
|
42
|
+
@caught_constants += (Bade::Runtime::RenderBinding.constants(false) - before_binding_constants)
|
43
|
+
.map { |name| [Bade::Runtime::RenderBinding, name] }
|
44
|
+
end
|
45
|
+
|
46
|
+
res
|
47
|
+
end
|
48
|
+
|
49
|
+
def clear_all
|
50
|
+
clear_global_variables
|
51
|
+
clear_constants
|
52
|
+
end
|
53
|
+
|
54
|
+
def clear_constants
|
55
|
+
_filtered_constants.each do |(obj, name)|
|
56
|
+
obj.send(:remove_const, name)
|
57
|
+
end
|
58
|
+
@caught_constants = []
|
59
|
+
end
|
60
|
+
|
61
|
+
def clear_global_variables
|
62
|
+
@caught_variables.each do |name|
|
63
|
+
eval("#{name} = nil", binding, __FILE__, __LINE__)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Filteres caught constants by location prefixes and returns ones that should be removed.
|
68
|
+
#
|
69
|
+
# @return [Array<[Object, :Symbol]>]
|
70
|
+
def _filtered_constants
|
71
|
+
@caught_constants.select do |(obj, name)|
|
72
|
+
next unless obj.const_defined?(name)
|
73
|
+
next true if constants_location_prefixes.nil?
|
74
|
+
|
75
|
+
konst = obj.const_get(name)
|
76
|
+
begin
|
77
|
+
location = Bade.where_is(konst)
|
78
|
+
rescue ::ArgumentError
|
79
|
+
next
|
80
|
+
end
|
81
|
+
|
82
|
+
path = location.first
|
83
|
+
constants_location_prefixes&.any? { |prefix| path.start_with?(prefix) }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/bade/runtime/mixin.rb
CHANGED
@@ -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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|