rblade 2.0.2 → 3.0.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +24 -0
  3. data/CHANGELOG.md +11 -0
  4. data/README.md +83 -16
  5. data/REFERENCE.md +4 -2
  6. data/do +4 -4
  7. data/docker-compose.yml +4 -1
  8. data/lib/rblade/compiler/compiles_comments.rb +2 -2
  9. data/lib/rblade/compiler/compiles_components.rb +26 -5
  10. data/lib/rblade/compiler/compiles_injections.rb +81 -0
  11. data/lib/rblade/compiler/compiles_statements.rb +69 -64
  12. data/lib/rblade/compiler/compiles_verbatim.rb +1 -1
  13. data/lib/rblade/compiler/statements/compiles_component_helpers.rb +17 -13
  14. data/lib/rblade/compiler/statements/compiles_conditionals.rb +18 -18
  15. data/lib/rblade/compiler/statements/compiles_form.rb +8 -8
  16. data/lib/rblade/compiler/statements/compiles_html_attributes.rb +2 -2
  17. data/lib/rblade/compiler/statements/compiles_inline_ruby.rb +1 -1
  18. data/lib/rblade/compiler/statements/compiles_loops.rb +11 -11
  19. data/lib/rblade/compiler/statements/compiles_once.rb +3 -3
  20. data/lib/rblade/compiler/statements/compiles_stacks.rb +5 -5
  21. data/lib/rblade/compiler/tokenizes_components.rb +30 -31
  22. data/lib/rblade/compiler/tokenizes_statements.rb +29 -30
  23. data/lib/rblade/compiler.rb +20 -19
  24. data/lib/rblade/component_store.rb +20 -20
  25. data/lib/rblade/helpers/attributes_manager.rb +10 -9
  26. data/lib/rblade/helpers/class_manager.rb +1 -1
  27. data/lib/rblade/helpers/slot_manager.rb +2 -2
  28. data/lib/rblade/helpers/stack_manager.rb +3 -3
  29. data/lib/rblade/helpers/style_manager.rb +1 -1
  30. data/lib/rblade/helpers/tokenizer.rb +5 -5
  31. data/lib/rblade/rails_template.rb +9 -2
  32. data/lib/rblade/railtie.rb +34 -2
  33. data/rblade.gemspec +4 -1
  34. metadata +50 -8
  35. data/lib/rblade/compiler/compiles_prints.rb +0 -83
  36. data/lib/rblade/compiler/compiles_ruby.rb +0 -59
@@ -3,7 +3,7 @@
3
3
  module RBlade
4
4
  class CompilesStatements
5
5
  class CompilesStacks
6
- def compileStack args
6
+ def compile_stack(args)
7
7
  if args&.count != 1
8
8
  raise RBladeTemplateError.new "Stack statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
9
9
  end
@@ -11,7 +11,7 @@ module RBlade
11
11
  "@_rblade_stack_manager.initialize_stack(#{args[0]}, @output_buffer);_stacks.push(#{args[0]});"
12
12
  end
13
13
 
14
- def compilePrepend args
14
+ def compile_prepend(args)
15
15
  if args&.count != 1
16
16
  raise RBladeTemplateError.new "Prepend statement: wrong number of arguments (given #{args&.count || 0}, expecting 1)"
17
17
  end
@@ -19,7 +19,7 @@ module RBlade
19
19
  "@_rblade_stack_manager.prepend(#{args[0]}, @output_buffer) do;"
20
20
  end
21
21
 
22
- def compilePrependIf args
22
+ def compile_prepend_if(args)
23
23
  if args&.count != 2
24
24
  raise RBladeTemplateError.new "Prepend if statement: wrong number of arguments (given #{args&.count}, expecting 2)"
25
25
  end
@@ -27,7 +27,7 @@ module RBlade
27
27
  "(#{args[0]}) && @_rblade_stack_manager.prepend(#{args[1]}, @output_buffer) do;"
28
28
  end
29
29
 
30
- def compilePush args
30
+ def compile_push(args)
31
31
  if args&.count != 1
32
32
  raise RBladeTemplateError.new "Push statement: wrong number of arguments (given #{args&.count}, expecting 1)"
33
33
  end
@@ -35,7 +35,7 @@ module RBlade
35
35
  "@_rblade_stack_manager.push(#{args[0]}, @output_buffer) do;"
36
36
  end
37
37
 
38
- def compilePushIf args
38
+ def compile_push_if(args)
39
39
  if args&.count != 2
40
40
  raise RBladeTemplateError.new "Push if statement: wrong number of arguments (given #{args&.count || 0}, expecting 2)"
41
41
  end
@@ -8,7 +8,7 @@ module RBlade
8
8
  tokens.map! do |token|
9
9
  next(token) if token.type != :unprocessed
10
10
 
11
- segments = tokenizeComponentTags token.value
11
+ segments = tokenize_component_tags token.value
12
12
 
13
13
  i = 0
14
14
  while i < segments.count
@@ -22,9 +22,9 @@ module RBlade
22
22
  i += 1
23
23
  elsif segments[i] == "<" && segments[i + 1]&.match?(/x[-:]/)
24
24
  name = segments[i + 1][2..]
25
- raw_attributes = (segments[i + 2] != ">") ? tokenizeAttributes(segments[i + 2]) : nil
25
+ raw_attributes = (segments[i + 2] != ">") ? tokenize_attributes(segments[i + 2]) : nil
26
26
 
27
- attributes = processAttributes raw_attributes
27
+ attributes = process_attributes raw_attributes
28
28
 
29
29
  if raw_attributes.nil?
30
30
  segments.delete_at i + 1
@@ -54,7 +54,7 @@ module RBlade
54
54
 
55
55
  private
56
56
 
57
- def processAttributes raw_attributes
57
+ def process_attributes(raw_attributes)
58
58
  attributes = []
59
59
  i = 0
60
60
  while i < raw_attributes.count
@@ -84,7 +84,7 @@ module RBlade
84
84
  end
85
85
 
86
86
  # If the entire value is a single interpolated string, make this a ruby value
87
- if attribute[:value]&.match?(/\A\{\{([^}]|(?!\}\})\})*\}\}\Z/)
87
+ if attribute[:value]&.match?(/\A\{\{([^}]++|(?!\}\})\})*\}\}\z/)
88
88
  attribute[:type] = "ruby"
89
89
  attribute[:name] = name
90
90
  attribute[:value] = attribute[:value][2..-3]
@@ -112,75 +112,74 @@ module RBlade
112
112
  attributes
113
113
  end
114
114
 
115
- def tokenizeComponentTags value
115
+ def tokenize_component_tags(value)
116
116
  value.split(%r/
117
117
  # Opening and self-closing tags
118
118
  (?:
119
119
  (<)
120
- \s*
121
- (x[-\:][\w\-\:\.]*)
120
+ \s*+
121
+ (x[-\:][\w\-\:\.]++)
122
122
  ((?:
123
- \s+
123
+ \s++
124
124
  (?:
125
125
  (?:
126
- @class(\( (?: (?>[^()]+) | \g<-1> )* \))
126
+ @class(\( (?: [^()]++ | \g<-1> )*+ \))
127
127
  )
128
128
  |
129
129
  (?:
130
- @style(\( (?: (?>[^()]+)| \g<-1> )* \))
130
+ @style(\( (?: [^()]++ | \g<-1> )*+ \))
131
131
  )
132
132
  |
133
133
  (
134
- \{\{\s*attributes.*?\s*\}\}
134
+ \{\{ \s*+ attributes (?:[^}]++|\})*? \}\}
135
135
  )
136
136
  |
137
137
  (?:
138
- [\w\-:.@%]+
138
+ [\w\-:.@%]++
139
139
  (?:
140
140
  =
141
141
  (?:
142
- "(?:[^"{]*?|(?<!@)\{\{.*?\}\}|\{)*"
142
+ "(?> [^"{]++ | (?<!@)\{\{ (?:[^}]++|\})*? \}\} | \{ )*+"
143
143
  |
144
- '(?:[^'{]*?|(?<!@)\{\{.*?\}\}|\{)*'
144
+ '(?> [^'{]++ | (?<!@)\{\{ (?:[^}]++|\})*? \}\} | \{ )*+'
145
145
  |
146
- (?:[^'"=<>\s\/{]+|(?<!@)\{\{.*?\}\}|\{)*
146
+ (?> [^'"=<>\s\/{]++ | (?<!@)\{\{ (?:[^}]++|\})*? \}\} | \{ )++
147
147
  )
148
148
  )?
149
149
  )
150
150
  )
151
- )*)
152
- \s*
153
- (?<![=\-])
151
+ )*+)
152
+ \s*+
154
153
  (\/?>)
155
154
  )
156
155
  |
157
156
  # Closing tags
158
157
  (?:
159
158
  (<\/)
160
- \s*
161
- (x[-\:][\w\-\:\.]*)
162
- \s*
159
+ \s*+
160
+ (x[-\:][\w\-\:\.]++)
161
+ \s*+
163
162
  >
164
163
  )
165
164
  |
166
165
  (<\/\/>)
167
- /xm)
166
+ /x)
168
167
  end
169
168
 
170
- def tokenizeAttributes segment
169
+ def tokenize_attributes(segment)
171
170
  segment.scan(%r/
172
171
  (?<=\s|^)
173
172
  (?:
174
173
  (?:
175
- (@class)(\( (?: (?>[^()]+) | \g<-1> )* \))
174
+ (@class)(\( (?: (?>[^()]+) | \g<-1> )*+ \))
176
175
  )
177
176
  |
178
177
  (?:
179
- (@style)(\( (?: (?>[^()]+)| \g<-1> )* \))
178
+ (@style)(\( (?: (?>[^()]+)| \g<-1> )*+ \))
180
179
  )
181
180
  |
182
181
  (?:
183
- (\{\{)\s*(attributes.*?)\s*(\}\})
182
+ (\{\{) \s*+ (attributes(?:[^}\s]++|\}|\s)*?) \s*+ (\}\})
184
183
  )
185
184
  |
186
185
  (?:
@@ -188,17 +187,17 @@ module RBlade
188
187
  (?:
189
188
  (=)
190
189
  (?:
191
- "((?:[^"{]*?|(?<!@)\{\{.*?\}\}|\{)*)"
190
+ "((?> [^"{]++ | (?<!@)\{\{ (?:[^}]++|\})*? \}\} | \{ )*+)"
192
191
  |
193
- '((?:[^'{]*?|(?<!@)\{\{.*?\}\}|\{)*)'
192
+ '((?> [^'{]++ | (?<!@)\{\{ (?:[^}]++|\})*? \}\} | \{ )*+)'
194
193
  |
195
- ((?:[^'"=<>\s\/{]+|(?<!@)\{\{.*?\}\}|\{)*)
194
+ ((?> [^'"=<>\s\/{]++ | (?<!@)\{\{(?:[^}]++|\})*?\}\} | \{ )*+)
196
195
  )
197
196
  )?
198
197
  )
199
198
  )
200
199
  (?=\s|$)
201
- /xm).flatten.compact
200
+ /x).flatten.compact
202
201
  end
203
202
  end
204
203
  end
@@ -14,27 +14,27 @@ module RBlade
14
14
  (?:
15
15
  (?:
16
16
  (@@)
17
- (\w+(?!\w)[!\?]?)
17
+ (\w++[!\?]?)
18
18
  )
19
19
  |
20
20
  (?:
21
21
  (@)
22
- (\w+(?!\w)[!\?]?)
23
- (?:([ \t]*)
24
- (\(.*?\))
22
+ (\w++[!\?]?)
23
+ (?:([ \t]*+)
24
+ (\([^)]*+\))
25
25
  )?
26
26
  )
27
27
  )
28
28
  (\s)?
29
- /mx)
29
+ /x)
30
30
 
31
- parseSegments! segments
31
+ parse_segments! segments
32
32
  end.flatten!
33
33
  end
34
34
 
35
35
  private
36
36
 
37
- def parseSegments! segments
37
+ def parse_segments!(segments)
38
38
  i = 0
39
39
  while i < segments.count
40
40
  segment = segments[i]
@@ -46,12 +46,13 @@ module RBlade
46
46
 
47
47
  i += 1
48
48
  elsif segment == "@"
49
- if CompilesStatements.has_handler(segments[i + 1])
50
- tokenizeStatement! segments, i
51
- handleSpecialCases! segments, i
49
+ statement_handle = segments[i + 1].downcase.tr "_", ""
50
+ if CompilesStatements.has_handler(statement_handle)
51
+ tokenize_statement! statement_handle, segments, i
52
+ handle_special_cases! segments, i
52
53
 
53
- segments.delete_at(i + 1) if segments[i + 1]&.match?(/\A\s\Z/)
54
- if segments[i - 1].is_a?(Token) && segments[i - 1].type == :unprocessed && segments[i - 1].value.match?(/\A\s\Z/)
54
+ segments.delete_at(i + 1) if segments[i + 1]&.match?(/\A\s\z/)
55
+ if segments[i - 1].is_a?(Token) && segments[i - 1].type == :unprocessed && segments[i - 1].value.match?(/\A\s\z/)
55
56
  segments.delete_at i - 1
56
57
  i -= 1
57
58
  end
@@ -60,7 +61,7 @@ module RBlade
60
61
  segments[i] = Token.new(type: :unprocessed, value: segments[i] + segments[i + 1])
61
62
  segments.delete_at i + 1
62
63
 
63
- if segments.count > i + 2 && segments[i + 1].match?(/\A[ \t]*\Z/) && segments[i + 2][0] == "("
64
+ if segments.count > i + 2 && segments[i + 1].match?(/\A[ \t]*+\z/) && segments[i + 2][0] == "("
64
65
  segments[i].value += segments[i + 1] + segments[i + 2]
65
66
  segments.delete_at i + 1
66
67
  segments.delete_at i + 1
@@ -83,19 +84,19 @@ module RBlade
83
84
  segments
84
85
  end
85
86
 
86
- def tokenizeStatement!(segments, i)
87
- statement_data = {name: segments[i + 1]}
88
- statement_name = segments.delete_at i + 1
87
+ def tokenize_statement!(handle, segments, i)
88
+ segments.delete_at i + 1
89
+ statement_data = {name: handle}
89
90
 
90
91
  # Remove optional whitespace
91
- if segments.count > i + 2 && segments[i + 1].match?(/\A[ \t]*\Z/) && segments[i + 2][0] == "("
92
+ if segments.count > i + 2 && segments[i + 1].match?(/\A[ \t]*+\z/) && segments[i + 2][0] == "("
92
93
  segments.delete_at i + 1
93
94
  end
94
95
 
95
96
  if segments.count > i + 1 && segments[i + 1][0] == "("
96
- arguments = tokenizeArguments! statement_name, segments, i + 1
97
+ arguments = tokenize_arguments! handle, segments, i + 1
97
98
 
98
- if !arguments.nil?
99
+ unless arguments.nil?
99
100
  statement_data[:arguments] = arguments
100
101
  end
101
102
  end
@@ -103,9 +104,8 @@ module RBlade
103
104
  segments[i] = Token.new(type: :statement, value: statement_data)
104
105
  end
105
106
 
106
- def handleSpecialCases!(segments, i)
107
- case segments[i][:value][:name]
108
- when "case"
107
+ def handle_special_cases!(segments, i)
108
+ if segments[i][:value][:name] == "case"
109
109
  # Remove any whitespace before a when statement
110
110
  until segments[i + 1].nil? || segments[i + 1] == "@"
111
111
  segments.delete_at i + 1
@@ -113,12 +113,12 @@ module RBlade
113
113
  end
114
114
  end
115
115
 
116
- def tokenizeArguments!(statement_name, segments, segment_index)
117
- success = expandSegmentToEndParenthesis! segments, segment_index
116
+ def tokenize_arguments!(statement_handle, segments, segment_index)
117
+ success = expand_segment_to_end_parenthesis! segments, segment_index
118
118
 
119
119
  # If no matching parentheses were found, so we combine the argument string with the next segment
120
- if !success
121
- if !segments[segment_index + 1].nil?
120
+ unless success
121
+ unless segments[segment_index + 1].nil?
122
122
  segments[segment_index] <<= segments[segment_index + 1]
123
123
  segments.delete_at segment_index + 1
124
124
  end
@@ -130,21 +130,20 @@ module RBlade
130
130
  argument_string = segments[segment_index][1..-2]
131
131
 
132
132
  # Special case for the props statement: remove the wrapping braces if they exist
133
- if statement_name == "props"
133
+ if statement_handle == "props"
134
134
  if argument_string.start_with?("{") && argument_string.end_with?("}")
135
135
  argument_string = argument_string[1..-2]
136
136
  end
137
137
  end
138
138
 
139
- arguments = Tokenizer.extractCommaSeparatedValues argument_string
139
+ arguments = Tokenizer.extract_comma_separated_values argument_string
140
140
  segments.delete_at segment_index
141
141
 
142
142
  arguments
143
143
  end
144
144
 
145
- def expandSegmentToEndParenthesis! segments, segment_index
145
+ def expand_segment_to_end_parenthesis!(segments, segment_index)
146
146
  parentheses_difference = 0
147
- tokens = nil
148
147
 
149
148
  loop do
150
149
  tokens = Ripper.lex(segments[segment_index]).map { |token| token[1] }
@@ -2,8 +2,7 @@
2
2
 
3
3
  require "rblade/compiler/compiles_comments"
4
4
  require "rblade/compiler/compiles_components"
5
- require "rblade/compiler/compiles_prints"
6
- require "rblade/compiler/compiles_ruby"
5
+ require "rblade/compiler/compiles_injections"
7
6
  require "rblade/compiler/compiles_verbatim"
8
7
  require "rblade/compiler/compiles_statements"
9
8
  require "rblade/compiler/tokenizes_components"
@@ -12,57 +11,59 @@ require "active_support/core_ext/string/output_safety"
12
11
 
13
12
  Token = Struct.new(:type, :value)
14
13
 
15
- if !defined?(h)
16
- require "erb/escape"
17
- define_method(:h, ERB::Escape.instance_method(:html_escape))
18
- end
19
-
20
14
  module RBlade
21
- def self.escape_quotes string
22
- string.gsub(/['\\\x0]/, '\\\\\0')
15
+ def self.escape_quotes(string)
16
+ string&.gsub(/['\\\x0]/, '\\\\\0')
23
17
  end
24
18
 
25
19
  class RBladeTemplateError < StandardError; end
26
20
 
27
- # Register a new custom directive by providing a class and method that will compile the directive into ruby code.
21
+ # Register a new custom directive by providing a proc that will return a value to be output
28
22
  #
29
23
  # @param [String] name The directive tag without the "@", e.g. "if" for the "@if" directive
30
- # @param [Proc] block The block that will return the compiled ruby code for the directive. Any arguments will be passed to this Proc as an array.
24
+ # @param [Proc] block The block that will return the compiled ruby code for the directive. Can accept `:args`, `:tokens` and `:token_index` as arguments.
31
25
  # @return [void]
32
26
  def self.register_directive_handler(name, &)
33
27
  CompilesStatements.register_handler(name, &)
34
28
  end
35
29
 
30
+ # Register a new custom directive by providing a proc that will return ruby code to add to the template. The code must end in a semi-colon.
31
+ #
32
+ # @param [String] name The directive tag without the "@", e.g. "if" for the "@if" directive
33
+ # @param [Proc] block The block that will return the compiled ruby code for the directive. Can accept `:args`, `:tokens` and `:token_index` as arguments.
34
+ # @return [void]
35
+ def self.register_raw_directive_handler(name, &)
36
+ CompilesStatements.register_raw_handler(name, &)
37
+ end
38
+
36
39
  class Compiler
37
- def self.compileString(string_template, component_store)
40
+ def self.compile_string(string_template, component_store)
38
41
  tokens = [Token.new(:unprocessed, string_template)]
39
42
 
40
43
  CompilesVerbatim.new.compile! tokens
41
44
  CompilesComments.new.compile! tokens
42
- CompilesRuby.new.compile! tokens
43
45
  TokenizesComponents.new.tokenize! tokens
44
- CompilesPrints.new.compile! tokens
46
+ CompilesInjections.new.compile! tokens
45
47
  TokenizesStatements.new.tokenize! tokens
46
48
  CompilesStatements.new.compile! tokens
47
49
 
48
50
  component_compiler = CompilesComponents.new(component_store)
49
51
  component_compiler.compile! tokens
50
52
  component_compiler.ensure_all_tags_closed
51
-
52
- compileTokens tokens
53
+ compile_tokens tokens
53
54
  end
54
55
 
55
- def self.compileAttributeString(string_template)
56
+ def self.compile_attribute_string(string_template)
56
57
  tokens = [Token.new(:unprocessed, string_template)]
57
58
 
58
59
  CompilesComments.compile!(tokens)
59
60
  CompilesRuby.compile! tokens
60
61
  CompilesPrints.compile!(tokens)
61
62
 
62
- compileTokens tokens
63
+ compile_tokens tokens
63
64
  end
64
65
 
65
- def self.compileTokens tokens
66
+ def self.compile_tokens(tokens)
66
67
  output = +""
67
68
 
68
69
  i = 0
@@ -14,7 +14,7 @@ module RBlade
14
14
  def component(full_name)
15
15
  # If this is a relative path, prepend with the previous component name's base
16
16
  if full_name.start_with? "."
17
- full_name = @component_name_stack.last.gsub(/\.[^\.]+\Z/, "") + full_name
17
+ full_name = @component_name_stack.last.sub(/[^.]++\z/, "") + full_name.delete_prefix(".")
18
18
  end
19
19
 
20
20
  # Ensure each component is only compiled once
@@ -24,14 +24,7 @@ module RBlade
24
24
 
25
25
  @component_name_stack << full_name
26
26
 
27
- namespace = nil
28
- name = full_name
29
-
30
- if name.match? "::"
31
- namespace, name = full_name.split("::")
32
- end
33
-
34
- method_name = compile_component full_name, File.read(find_component_file(namespace, name))
27
+ method_name = compile_component full_name, File.read(find_component_file(full_name, @component_name_stack))
35
28
  @component_name_stack.pop
36
29
 
37
30
  method_name
@@ -43,31 +36,37 @@ module RBlade
43
36
  path << "/"
44
37
  end
45
38
 
46
- @@template_paths[namespace] ||= []
47
- @@template_paths[namespace] << path
39
+ template_paths[namespace] ||= []
40
+ template_paths[namespace] << path
48
41
  end
49
42
 
50
43
  def view_name(view_name)
51
44
  @component_name_stack.push view_name
52
45
  end
53
46
 
47
+ def current_view_name
48
+ @component_name_stack.last
49
+ end
50
+
54
51
  def get
55
52
  @component_definitions
56
53
  end
57
54
 
58
- private
55
+ def self.find_component_file(name, name_stack = nil)
56
+ if name.match? "::"
57
+ namespace, name = name.split("::", 2)
58
+ end
59
59
 
60
- def find_component_file(namespace, name)
61
60
  file_path = name.tr ".", "/"
62
61
 
63
- @@template_paths[namespace]&.each do |base_path|
62
+ template_paths[namespace]&.each do |base_path|
64
63
  FILE_EXTENSIONS.each do |extension|
65
64
  if File.exist? base_path + file_path + extension
66
65
  return "#{base_path}#{file_path}#{extension}"
67
66
  end
68
67
  if File.exist? base_path + file_path + "/index" + extension
69
68
  # Account for index files for relative components
70
- @component_name_stack << @component_name_stack.pop + ".index"
69
+ name_stack << name_stack.pop + ".index" if name_stack
71
70
  return "#{base_path}#{file_path}/index#{extension}"
72
71
  end
73
72
  end
@@ -75,6 +74,9 @@ module RBlade
75
74
 
76
75
  raise RBladeTemplateError.new "Unknown component #{namespace}::#{name}"
77
76
  end
77
+ delegate :find_component_file, to: :class
78
+
79
+ private
78
80
 
79
81
  def compile_component(name, template)
80
82
  escaped_name = name.gsub(/[^0-9a-zA-Z_]/) do |match|
@@ -82,15 +84,13 @@ module RBlade
82
84
  (match == ".") ? "__" : "_#{match.unpack1("H*")}_"
83
85
  end
84
86
 
85
- compiled_component = RBlade::Compiler.compileString(template, self)
86
-
87
- slot_assignment = compiled_component.match?(/\Wslot\W/) ? "slot=" : ""
87
+ compiled_component = RBlade::Compiler.compile_string(template, self)
88
88
 
89
- @component_definitions << "def self._rblade_component_#{escaped_name}(attributes,&);#{slot_assignment}if block_given?;RBlade::SlotManager.new(@output_buffer.capture(->(name, slot_attributes, &slot_block)do;attributes[name]=RBlade::SlotManager.new(@output_buffer.capture(&slot_block), slot_attributes);end,&));end;_stacks=[];@output_buffer.raw_buffer<<@output_buffer.capture do;#{compiled_component}@output_buffer.raw_buffer.prepend(@_rblade_stack_manager.get(_stacks));end;end;"
89
+ @component_definitions << "def self._rblade_component_#{escaped_name}(attributes,&);slot=if block_given?;RBlade::SlotManager.new(@output_buffer.capture(->(name, slot_attributes, &slot_block)do;attributes[name]=RBlade::SlotManager.new(@output_buffer.capture(&slot_block), slot_attributes);end,&));end;_stacks=[];@output_buffer.raw_buffer<<@output_buffer.capture do;#{compiled_component}@output_buffer.raw_buffer.prepend(@_rblade_stack_manager.get(_stacks));end;end;"
90
90
 
91
91
  @component_method_names[name] = "_rblade_component_#{escaped_name}"
92
92
  end
93
93
 
94
- @@template_paths = {}
94
+ cattr_accessor :template_paths, default: {}
95
95
  end
96
96
  end
@@ -2,8 +2,9 @@
2
2
 
3
3
  module RBlade
4
4
  class AttributesManager
5
- @attributes = {}
6
- def initialize attributes
5
+ delegate :delete, to: :@attributes
6
+
7
+ def initialize(attributes)
7
8
  @attributes = attributes
8
9
  end
9
10
 
@@ -37,11 +38,11 @@ module RBlade
37
38
  true
38
39
  end
39
40
 
40
- def to_str attributes = nil
41
+ def to_str(attributes = nil)
41
42
  attributes ||= @attributes
42
43
 
43
44
  attributes.map do |key, value|
44
- (value == true) ? key : "#{key}=\"#{h(value)}\""
45
+ (value == true) ? key : "#{key}=\"#{CGI.escape_html(value.to_s)}\""
45
46
  end.join(" ")
46
47
  end
47
48
 
@@ -72,7 +73,7 @@ module RBlade
72
73
  def class(new_classes)
73
74
  new_classes = ClassManager.new(new_classes).to_s
74
75
  attributes = @attributes.dup
75
- attributes[:class] = mergeClasses attributes[:class], new_classes
76
+ attributes[:class] = merge_classes attributes[:class], new_classes
76
77
 
77
78
  AttributesManager.new attributes
78
79
  end
@@ -82,12 +83,12 @@ module RBlade
82
83
 
83
84
  @attributes.each do |key, value|
84
85
  if key == :class && !new_attributes[key].nil?
85
- new_attributes[key] = mergeClasses(new_attributes[key], value.to_s)
86
+ new_attributes[key] = merge_classes(new_attributes[key], value.to_s)
86
87
  next
87
88
  end
88
89
 
89
90
  if key == :style && !new_attributes[key].nil?
90
- new_attributes[key] = mergeStyles(new_attributes[key], value.to_s)
91
+ new_attributes[key] = merge_styles(new_attributes[key], value.to_s)
91
92
  next
92
93
  end
93
94
 
@@ -105,7 +106,7 @@ module RBlade
105
106
 
106
107
  private
107
108
 
108
- def mergeClasses(classes_1, classes_2)
109
+ def merge_classes(classes_1, classes_2)
109
110
  if classes_1.nil?
110
111
  return classes_2
111
112
  end
@@ -122,7 +123,7 @@ module RBlade
122
123
  classes_combined
123
124
  end
124
125
 
125
- def mergeStyles(styles_1, styles_2)
126
+ def merge_styles(styles_1, styles_2)
126
127
  if styles_1.nil?
127
128
  return styles_2
128
129
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RBlade
4
4
  class ClassManager
5
- def initialize classes
5
+ def initialize(classes)
6
6
  if classes.is_a? String
7
7
  @classes = classes
8
8
  elsif classes.is_a? Array
@@ -4,7 +4,7 @@ require "rblade/helpers/attributes_manager"
4
4
 
5
5
  module RBlade
6
6
  class SlotManager
7
- def initialize content, attributes = nil
7
+ def initialize(content, attributes = nil)
8
8
  @content = content
9
9
  @attributes = attributes && AttributesManager.new(attributes)
10
10
  end
@@ -30,7 +30,7 @@ module RBlade
30
30
  end
31
31
 
32
32
  # Wraps var in a slot manager if it's a string
33
- def self.wrap var
33
+ def self.wrap(var)
34
34
  var.is_a?(String) ? new(var) : var
35
35
  end
36
36
 
@@ -40,7 +40,7 @@ module RBlade
40
40
  @stack = +""
41
41
  end
42
42
 
43
- def set_before_stack before_stack
43
+ def set_before_stack(before_stack)
44
44
  @before_stack = before_stack
45
45
  end
46
46
 
@@ -52,11 +52,11 @@ module RBlade
52
52
  to_s
53
53
  end
54
54
 
55
- def push code
55
+ def push(code)
56
56
  @stack << code
57
57
  end
58
58
 
59
- def prepend code
59
+ def prepend(code)
60
60
  @prepends << code
61
61
  end
62
62
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module RBlade
4
4
  class StyleManager
5
- def initialize styles
5
+ def initialize(styles)
6
6
  if styles.is_a? String
7
7
  @styles = styles.strip
8
8
  unless @styles == "" || @styles.end_with?(";")