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
@@ -2,8 +2,8 @@
2
2
 
3
3
  module RBlade
4
4
  class Tokenizer
5
- def self.extractCommaSeparatedValues segment
6
- unless segment.match?(/,\s*\z/)
5
+ def self.extract_comma_separated_values(segment)
6
+ unless segment.match?(/,\s*+\z/)
7
7
  # Add a comma to the end to delimit the end of the last argument
8
8
  segment += ","
9
9
  end
@@ -17,7 +17,7 @@ module RBlade
17
17
  bracket_count = {
18
18
  "[]": 0,
19
19
  "{}": 0,
20
- "()": 0
20
+ "()": 0,
21
21
  }
22
22
  tokens.each do |token|
23
23
  case token[1]
@@ -48,7 +48,7 @@ module RBlade
48
48
  end
49
49
  current_line = token[0][0]
50
50
  end
51
- argument <<= segment_lines[current_line - 1].slice(current_index...token[0][1])
51
+ argument << segment_lines[current_line - 1].slice(current_index...token[0][1])
52
52
  argument.strip!
53
53
 
54
54
  arguments.push argument
@@ -57,7 +57,7 @@ module RBlade
57
57
  end
58
58
  end
59
59
 
60
- return nil if arguments.count == 1 && arguments.first == ""
60
+ return nil if arguments.count == 1 && arguments[0] == ""
61
61
 
62
62
  arguments
63
63
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rails"
4
3
  require "rblade/compiler"
5
4
  require "rblade/component_store"
6
5
  require "rblade/helpers/attributes_manager"
@@ -25,7 +24,15 @@ module RBlade
25
24
  component_store.view_name("view::#{view_name}")
26
25
  end
27
26
 
28
- -"_stacks=[];@_rblade_once_tokens=[];@_rblade_stack_manager=RBlade::StackManager.new;#{component_store.get}#{RBlade::Compiler.compileString(source, component_store)}@output_buffer.raw_buffer.prepend(@_rblade_stack_manager.get(_stacks))"
27
+ preamble = +"_stacks=[];@_rblade_once_tokens=[];@_rblade_stack_manager=RBlade::StackManager.new;"
28
+ if RBlade.direct_component_rendering
29
+ # If the attributes and slot are already set, we don't need to assign them
30
+ unless template&.locals&.include?("attributes") && template.locals.include?("slot")
31
+ preamble << "attributes=RBlade::AttributesManager.new(local_assigns);slot||=yield if block_given?;slot=attributes.delete(:slot) if slot.blank?;"
32
+ end
33
+ end
34
+
35
+ -"#{preamble}#{component_store.get}#{RBlade::Compiler.compile_string(source, component_store)}@output_buffer.raw_buffer.prepend(@_rblade_stack_manager.get(_stacks));@output_buffer;"
29
36
  end
30
37
  end
31
38
  end
@@ -2,16 +2,48 @@
2
2
 
3
3
  require "rails"
4
4
  require "rblade/rails_template"
5
- require "rblade/component_store"
6
5
 
7
6
  module RBlade
7
+ # Enables support for rendering RBlade components directly. This should be enabled if you want to use RBlade components within ERB or other templating languages.
8
+ #
9
+ # When enabled, attributes is set from local_assigns, the slot variable is set from the given block, and @props statements will look for content using content_for
10
+ mattr_accessor :direct_component_rendering, default: false
11
+
12
+ # The name of the view helper method used for rendering RBlade components in other templates
13
+ mattr_accessor :component_helper_method_name, default: :component
14
+
8
15
  class Railtie < ::Rails::Railtie
9
- initializer :rblade, before: :load_config_initializers do |app|
16
+ initializer :rblade, after: :load_config_initializers do |app|
10
17
  ActionView::Template.register_template_handler(:rblade, RBlade::RailsTemplate.new)
18
+ setup_component_view_helper(ActionView::Helpers)
11
19
 
12
20
  RBlade::ComponentStore.add_path(Rails.root.join("app", "views", "components"))
13
21
  RBlade::ComponentStore.add_path(Rails.root.join("app", "views", "layouts"), "layout")
14
22
  RBlade::ComponentStore.add_path(Rails.root.join("app", "views"), "view")
15
23
  end
24
+
25
+ def setup_component_view_helper(mod)
26
+ mod.send(:define_method, RBlade.component_helper_method_name) do |component_name, current_view = nil, **attributes, &block|
27
+ # If this is a relative path, prepend with the previous component name's base
28
+ if !current_view.nil? && component_name.start_with?(".")
29
+ component_name = current_view.sub(/[^\.]++\z/, "") + component_name.delete_prefix(".")
30
+ end
31
+
32
+ path = RBlade::ComponentStore.find_component_file(component_name)
33
+
34
+ # Find the relative template path without the file type
35
+ view_paths.each do |view_path|
36
+ break unless path.delete_prefix!(view_path.to_s).nil?
37
+ end
38
+ path.sub!(/(?:\.[^.]++)?\.rblade\z/, "")
39
+
40
+ locals = {
41
+ slot: block.nil? ? attributes.delete(:slot) || -"" : capture(&block),
42
+ attributes: RBlade::AttributesManager.new(attributes),
43
+ }
44
+
45
+ render template: path, locals:
46
+ end
47
+ end
16
48
  end
17
49
  end
data/rblade.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "rblade"
3
- s.version = "2.0.2"
3
+ s.version = "3.0.0"
4
4
  s.summary = "A component-first templating engine for Rails"
5
5
  s.description = "RBlade is a simple, yet powerful templating engine for Ruby on Rails, inspired by Laravel Blade."
6
6
  s.authors = ["Simon J"]
@@ -15,5 +15,8 @@ Gem::Specification.new do |s|
15
15
  s.add_development_dependency "minitest", "~> 5.0"
16
16
  s.add_development_dependency "minitest-reporters", "~> 1.1"
17
17
  s.add_development_dependency "standard", ">= 1.3"
18
+ s.add_development_dependency "rubocop", ">= 1.73"
18
19
  s.add_development_dependency "rails", ">= 7.0"
20
+ s.add_development_dependency "benchmark-ips"
21
+ s.add_development_dependency "kalibera"
19
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rblade
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon J
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-10 00:00:00.000000000 Z
11
+ date: 2025-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '1.73'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '1.73'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rails
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,34 @@ dependencies:
66
80
  - - ">="
67
81
  - !ruby/object:Gem::Version
68
82
  version: '7.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: benchmark-ips
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: kalibera
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
69
111
  description: RBlade is a simple, yet powerful templating engine for Ruby on Rails,
70
112
  inspired by Laravel Blade.
71
113
  email: 2857218+mwnciau@users.noreply.github.com
@@ -75,6 +117,7 @@ extra_rdoc_files: []
75
117
  files:
76
118
  - ".github/workflows/ruby.yml"
77
119
  - ".gitignore"
120
+ - ".rubocop.yml"
78
121
  - ".standard.yml"
79
122
  - CHANGELOG.md
80
123
  - Gemfile
@@ -95,8 +138,7 @@ files:
95
138
  - lib/rblade/compiler.rb
96
139
  - lib/rblade/compiler/compiles_comments.rb
97
140
  - lib/rblade/compiler/compiles_components.rb
98
- - lib/rblade/compiler/compiles_prints.rb
99
- - lib/rblade/compiler/compiles_ruby.rb
141
+ - lib/rblade/compiler/compiles_injections.rb
100
142
  - lib/rblade/compiler/compiles_statements.rb
101
143
  - lib/rblade/compiler/compiles_verbatim.rb
102
144
  - lib/rblade/compiler/statements/compiles_component_helpers.rb
@@ -124,7 +166,7 @@ licenses:
124
166
  - MIT
125
167
  metadata:
126
168
  source_code_uri: https://github.com/mwnciau/rblade
127
- post_install_message:
169
+ post_install_message:
128
170
  rdoc_options: []
129
171
  require_paths:
130
172
  - lib
@@ -139,8 +181,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
181
  - !ruby/object:Gem::Version
140
182
  version: '0'
141
183
  requirements: []
142
- rubygems_version: 3.0.3.1
143
- signing_key:
184
+ rubygems_version: 3.4.20
185
+ signing_key:
144
186
  specification_version: 4
145
187
  summary: A component-first templating engine for Rails
146
188
  test_files: []
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RBlade
4
- class CompilesPrints
5
- def compile!(tokens)
6
- compile_unsafe_prints!(tokens)
7
- compile_regular_prints!(tokens)
8
- end
9
-
10
- private
11
-
12
- def compile_regular_prints!(tokens)
13
- compile_prints! tokens, "{{", "}}", true
14
- compile_prints! tokens, "<%=", "%>", true
15
- end
16
-
17
- def compile_unsafe_prints!(tokens)
18
- compile_prints! tokens, "{!!", "!!}"
19
- compile_prints! tokens, "<%==", "%>"
20
- end
21
-
22
- def compile_prints!(tokens, start_token, end_token, escape_html = false)
23
- tokens.map! do |token|
24
- next(token) if token.type != :unprocessed
25
-
26
- start_token_escaped = Regexp.escape start_token
27
- end_token_escaped = Regexp.escape end_token
28
- segments = token.value.split(/(?:(@)(#{start_token_escaped}.+?#{end_token_escaped})|(#{start_token_escaped})\s*(.+?)\s*(#{end_token_escaped}))/m)
29
-
30
- i = 0
31
- while i < segments.count
32
- if segments[i] == "@"
33
- segments.delete_at i
34
- segments[i] = Token.new(type: :raw_text, value: segments[i])
35
-
36
- i += 1
37
- elsif segments[i] == start_token
38
- segments.delete_at i
39
- segments.delete_at i + 1
40
-
41
- segments[i] = create_token(segments[i], escape_html)
42
-
43
- i += 1
44
- elsif !segments[i].nil? && segments[i] != ""
45
- segments[i] = Token.new(type: :unprocessed, value: segments[i])
46
-
47
- i += 1
48
- else
49
- segments.delete_at i
50
- end
51
- end
52
-
53
- segments
54
- end.flatten!
55
- end
56
-
57
- def create_token(expression, escape_html)
58
- # Don't try to print ends
59
- if expression.match?(/\A\s*(?:}|end(?![[:alnum:]_]|[^\0-\177]))/i)
60
- return Token.new(:print, "#{expression};")
61
- end
62
-
63
- segment_value = if escape_html
64
- "@output_buffer.append=#{expression};"
65
- # If this is a block, don't wrap in parentheses
66
- elsif expression.match?(/
67
- (?:\{|do)\s*
68
- (
69
- \|\s*
70
- [a-zA-Z0-9_]+\s*
71
- (,\s*[a-zA-Z0-9_]+)?\s*
72
- \|\s*
73
- )?
74
- \Z/x)
75
- "@output_buffer.safe_expr_append=#{expression};"
76
- else
77
- "@output_buffer.raw_buffer<<(#{expression}).to_s;"
78
- end
79
-
80
- Token.new(:print, segment_value)
81
- end
82
- end
83
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RBlade
4
- class CompilesRuby
5
- def compile!(tokens)
6
- tokens.map! do |token|
7
- next(token) if token.type != :unprocessed
8
-
9
- segments = token.value.split(/
10
- # @ escapes blade style tags
11
- (@)(@ruby.+?@end_?ruby)
12
- |
13
- # <%% and %%> are escape ERB style tags
14
- (<%%)(.+?)(%%>)
15
- |
16
- \s?(?<!\w)(@ruby)\s+(.+?)[\s;]*(@end_?ruby)(?!\w)\s?
17
- |
18
- (<%)(?!=)\s*(.+?)[\s;]*(%>)
19
- /xmi)
20
-
21
- i = 0
22
- while i < segments.count
23
- if segments[i] == "@"
24
- segments.delete_at i
25
- segments[i] = Token.new(type: :raw_text, value: segments[i])
26
-
27
- i += 1
28
- elsif segments[i] == "<%%"
29
- segments.delete_at i
30
- segments.delete_at i + 1
31
- segments[i] = Token.new(type: :raw_text, value: "<%#{segments[i]}%>")
32
-
33
- i += 1
34
- elsif segments[i].downcase == "@ruby" || segments[i] == "<%"
35
- segments.delete_at i
36
- segments.delete_at i + 1
37
-
38
- segments[i].strip!
39
- if segments[i][-1] != ";"
40
- segments[i] << ";"
41
- end
42
-
43
- segments[i] = Token.new(type: :ruby, value: segments[i])
44
-
45
- i += 1
46
- elsif !segments[i].nil? && segments[i] != ""
47
- segments[i] = Token.new(type: :unprocessed, value: segments[i])
48
-
49
- i += 1
50
- else
51
- segments.delete_at i
52
- end
53
- end
54
-
55
- segments
56
- end.flatten!
57
- end
58
- end
59
- end