ruby2html 1.5.7 → 1.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4c498562007af49a60be8dd1d6940906d3d58f6eee36b9de93765da5ece5d1a0
4
- data.tar.gz: b82ef6779e2f18d5330e0280e487461d6c6d8da18464627015675b4853e6a0cf
3
+ metadata.gz: 5fe6d6acf3bfc4153070aed751386fd1c3ae93b1fa0eb7f852a3678fd17e2826
4
+ data.tar.gz: ad9fcb5b1b938959002439da8a82d613590068e2cad943f69810678e641dc99d
5
5
  SHA512:
6
- metadata.gz: 1a6c7fae2edab3ea80ce2dca50fff2802ed11919d0eff2c4875b64c9feb81812c4f5e1a7bcd1dcd2064c0d9103497f17eb55d563023d6a2f3847edd5e05ebdae
7
- data.tar.gz: 9fca95689d5bc91c3b19a154f218498065b79a7f463c520d1d0c84bc21cf4d4a9d5e7d41a4323ed745a322da14f37590160637de5a176e61451bac3beca78fbf
6
+ metadata.gz: a68922e47e1b82cb5eec9d37eeaa31a5ecbf3b1627dcbdd9af355516c3b5b6838b1cc7ef7e7df2c5d5935a4e8f075f73eef13ced4a696c9ab14cfe8c3e6c71b7
7
+ data.tar.gz: 6d4b7b4fe8438989ee4a501e5181bcaba9f86614ba66ef7a905414239bb311764b21a88c1690adee7164c357354ecdc1354ad1128ae427d4f4c601fa5786b978
data/README.md ADDED
@@ -0,0 +1,333 @@
1
+ # Ruby2html 🔮✨
2
+
3
+ Transform your view logic into elegant, semantic HTML with the power of pure Ruby! 🚀✨
4
+
5
+ ## 🌟 What is Ruby2html?
6
+
7
+ Ruby2html is a magical gem that allows you to write your views in pure Ruby and automatically converts them into clean, well-formatted HTML. Say goodbye to messy ERB templates and hello to the full power of Ruby in your views! 🎉
8
+
9
+ ## 🚀 Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+
14
+ ```ruby
15
+ gem 'ruby2html'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle install
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install ruby2html
25
+
26
+ ## 🎨 Usage
27
+
28
+ ### In your views
29
+
30
+ File: `app/views/your_view.html.rb`
31
+
32
+ ```ruby
33
+ div class: 'container' do
34
+ h1 'Welcome to Ruby2html! 🎉', class: 'main-title', 'data-controller': 'welcome'
35
+ link_to 'Home Sweet Home 🏠', root_path, class: 'btn btn-primary', 'data-turbo': false
36
+
37
+ @products.each do |product|
38
+ h2 class: 'item-title', id: "product-#{product[:id]}" do
39
+ product.title
40
+ end
41
+ p class: 'item-description' do
42
+ product.description
43
+ end
44
+ end
45
+ end
46
+
47
+ plain '<div>Inline html</div>'.html_safe
48
+
49
+ render partial: 'shared/navbar'
50
+ ```
51
+
52
+ ### (Optional) Nicely Format the HTML for source inspection
53
+
54
+ File: `config/environments/development.rb` or `config/environments/test.rb`
55
+ ```ruby
56
+ config.middleware.use Ruby2html::HtmlBeautifierMiddleware
57
+ ```
58
+
59
+ #### Or use your current .erb views
60
+
61
+ ### In your ApplicationController
62
+
63
+ File: `app/controllers/application_controller.rb`
64
+
65
+ ```ruby
66
+ # frozen_string_literal: true
67
+
68
+ class ApplicationController < ActionController::Base
69
+ include Ruby2html::RailsHelper # to access the <%= html %> helper
70
+ end
71
+ ```
72
+
73
+ File: `app/views/your_view.html.erb`
74
+
75
+ Replace your ERB with beautiful Ruby code:
76
+
77
+ ```erb
78
+ <%=
79
+ html(self) do
80
+ h1 "Welcome to Ruby2html! 🎉", class: 'main-title', 'data-controller': 'welcome'
81
+ div id: 'content', class: 'container' do
82
+ link_to 'Home Sweet Home 🏠', root_path, class: 'btn btn-primary', 'data-turbo': false
83
+ end
84
+
85
+ @items.each do |item|
86
+ h2 class: 'item-title', id: "item-#{item[:id]}" do
87
+ item.title
88
+ end
89
+ p class: 'item-description' do
90
+ item.description
91
+ end
92
+ end
93
+
94
+ plain "<div>Inline html</div>".html_safe
95
+
96
+ render partial: 'shared/navbar'
97
+ end
98
+ %>
99
+ ```
100
+
101
+ ### Benchmark
102
+
103
+ ```bash
104
+ ruby 3.3.4 (2024-07-09 revision be1089c8ec) +YJIT [x86_64-linux]
105
+ Warming up --------------------------------------
106
+ GET /benchmark/html (ERB)
107
+ 40.000 i/100ms
108
+ GET /benchmark/ruby (Ruby2html templates .html.rb)
109
+ 12.000 i/100ms
110
+ GET /benchmark/ruby (Ruby2html + view components)
111
+ 12.000 i/100ms
112
+ GET /benchmark/slim (Slim)
113
+ 46.000 i/100ms
114
+ GET /benchmark/phlex (Phlex)
115
+ 34.000 i/100ms
116
+ Calculating -------------------------------------
117
+ GET /benchmark/html (ERB)
118
+ 414.030 (± 2.4%) i/s - 24.840k in 60.032818s
119
+ GET /benchmark/ruby (Ruby2html templates .html.rb)
120
+ 124.973 (± 3.2%) i/s - 7.500k in 60.071485s
121
+ GET /benchmark/ruby (Ruby2html + view components)
122
+ 123.211 (± 4.1%) i/s - 7.380k in 60.000731s
123
+ GET /benchmark/slim (Slim)
124
+ 431.525 (± 9.0%) i/s - 25.668k in 60.103492s
125
+ GET /benchmark/phlex (Phlex)
126
+ 328.925 (± 7.0%) i/s - 19.618k in 60.019961s
127
+
128
+ Comparison:
129
+ GET /benchmark/slim (Slim): 431.5 i/s
130
+ GET /benchmark/html (ERB): 414.0 i/s - same-ish: difference falls within error
131
+ GET /benchmark/phlex (Phlex): 328.9 i/s - 1.31x slower
132
+ GET /benchmark/ruby (Ruby2html templates .html.rb): 125.0 i/s - 3.45x slower
133
+ GET /benchmark/ruby (Ruby2html + view components): 123.2 i/s - 3.50x slower
134
+ ```
135
+
136
+ ### With ViewComponents
137
+
138
+ Ruby2html seamlessly integrates with ViewComponents, offering flexibility in how you define your component's HTML structure. You can use the `call` method with Ruby2html syntax, or stick with traditional `.erb` template files.
139
+
140
+ File: `app/components/application_component.rb`
141
+
142
+ ```ruby
143
+ # frozen_string_literal: true
144
+
145
+ class ApplicationComponent < ViewComponent::Base
146
+ include Ruby2html::ComponentHelper
147
+ end
148
+ ```
149
+
150
+ #### Option 1: Using `call` method with Ruby2html
151
+
152
+ File: `app/components/greeting_component.rb`
153
+
154
+ ```ruby
155
+ # frozen_string_literal: true
156
+
157
+ class GreetingComponent < ApplicationComponent
158
+ def initialize(name)
159
+ @name = name
160
+ end
161
+
162
+ def call
163
+ html do
164
+ h1 class: 'greeting', 'data-user': @name do
165
+ "Hello, #{@name}! 👋"
166
+ end
167
+ p class: 'welcome-message' do
168
+ 'Welcome to the wonderful world of Ruby2html!'
169
+ end
170
+ end
171
+ end
172
+ end
173
+ ```
174
+
175
+ #### Option 2: Using traditional ERB template
176
+
177
+ File: `app/components/farewell_component.rb`
178
+
179
+ ```ruby
180
+ # frozen_string_literal: true
181
+
182
+ class FarewellComponent < ApplicationComponent
183
+ def initialize(name)
184
+ @name = name
185
+ end
186
+ end
187
+ ```
188
+
189
+ File: `app/components/farewell_component.html.rb`
190
+
191
+ ```rb
192
+ div class: 'farewell' do
193
+ h1 class: 'farewell-message' do
194
+ "Goodbye, #{@name}! 👋"
195
+ end
196
+ p class: 'farewell-text' do
197
+ 'We hope to see you again soon!'
198
+ end
199
+ end
200
+ ```
201
+
202
+ This flexibility allows you to:
203
+ - Use Ruby2html syntax for new components or when refactoring existing ones
204
+ - Keep using familiar ERB templates where preferred
205
+ - Mix and match approaches within your application as needed
206
+
207
+ ### More Component Examples
208
+
209
+ File: `app/components/first_component.rb`
210
+
211
+ ```ruby
212
+ # frozen_string_literal: true
213
+
214
+ class FirstComponent < ApplicationComponent
215
+ def initialize
216
+ @item = 'Hello, World!'
217
+ end
218
+
219
+ def call
220
+ html do
221
+ h1 id: 'first-component-title' do
222
+ 'first component'
223
+ end
224
+ div class: 'content-wrapper' do
225
+ h2 'A subheading'
226
+ end
227
+ p class: 'greeting-text', 'data-testid': 'greeting' do
228
+ @item
229
+ end
230
+ end
231
+ end
232
+ end
233
+ ```
234
+
235
+ File: `app/components/second_component.rb`
236
+
237
+ ```ruby
238
+ # frozen_string_literal: true
239
+
240
+ class SecondComponent < ApplicationComponent
241
+ def call
242
+ html do
243
+ h1 class: 'my-class', id: 'second-component-title', 'data-controller': 'second' do
244
+ 'second component'
245
+ end
246
+ link_to 'Home', root_path, class: 'nav-link', 'data-turbo-frame': false
247
+ end
248
+ end
249
+ end
250
+ ```
251
+
252
+ ## Without Rails
253
+ ```ruby
254
+ renderer = Ruby2html::Render.new(nil) do # context by default is nil, you can use self or any other object
255
+ html do
256
+ head do
257
+ title 'Ruby2html Example'
258
+ end
259
+ body do
260
+ h1 'Hello, World!'
261
+ end
262
+ end
263
+ end
264
+
265
+ puts renderer.render # => "<html><head><title>Ruby2html Example</title></head><body><h1>Hello, World!</h1></body></html>"
266
+ ```
267
+
268
+ ## 🐢 Gradual Adoption
269
+
270
+ One of the best features of Ruby2html is that you don't need to rewrite all your views at once! You can adopt it gradually, mixing Ruby2html with your existing ERB templates. This allows for a smooth transition at your own pace.
271
+
272
+ ### Mixed usage example
273
+
274
+ File: `app/views/your_mixed_view.html.erb`
275
+
276
+ ```erb
277
+ <h1>Welcome to our gradually evolving page!</h1>
278
+
279
+ <%= render partial: 'legacy_erb_partial' %>
280
+
281
+ <%=
282
+ html(self) do
283
+ div class: 'ruby2html-section' do
284
+ h2 "This section is powered by Ruby2html!"
285
+ p "Isn't it beautiful? 😍"
286
+ end
287
+ end
288
+ %>
289
+
290
+ <%= render ModernComponent.new %>
291
+
292
+ <footer>
293
+ <!-- More legacy ERB code -->
294
+ </footer>
295
+ ```
296
+
297
+ In this example, you can see how Ruby2html seamlessly integrates with existing ERB code. This approach allows you to:
298
+
299
+ - Keep your existing ERB templates and partials
300
+ - Gradually introduce Ruby2html in specific sections
301
+ - Use Ruby2html in new components while maintaining older ones
302
+ - Refactor your views at your own pace
303
+
304
+ Remember, there's no rush! You can keep your `.erb` files and Ruby2html code side by side until you're ready to fully transition. This flexibility ensures that adopting Ruby2html won't disrupt your existing workflow or require a massive rewrite of your application. 🌈
305
+
306
+ ## 🛠 Development
307
+
308
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
309
+
310
+ ## 🤝 Contributing
311
+
312
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sebyx07/ruby2html. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/sebyx07/ruby2html/blob/master/CODE_OF_CONDUCT.md).
313
+
314
+ ## 📜 License
315
+
316
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
317
+
318
+ ## 🌈 Code of Conduct
319
+
320
+ Everyone interacting in the Ruby2html project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/sebyx07/ruby2html/blob/master/CODE_OF_CONDUCT.md).
321
+
322
+ ## 🌟 Features
323
+
324
+ - Write views in pure Ruby 💎
325
+ - Seamless Rails integration 🛤️
326
+ - ViewComponent support with flexible template options 🧩
327
+ - Automatic HTML beautification 💅
328
+ - Easy addition of custom attributes and data attributes 🏷️
329
+ - Gradual adoption - mix with existing ERB templates 🐢
330
+ - Improved readability and maintainability 📚
331
+ - Full access to Ruby's power in your views 💪
332
+
333
+ Start writing your views in Ruby today and experience the magic of Ruby2html! ✨🔮
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ext/ruby2html/extconf.rb
4
+ require 'mkmf'
5
+
6
+ # Add optimization flags
7
+ $CFLAGS << ' -O3 -Wall -Wextra'
8
+
9
+ # Check for required headers
10
+ have_header('ruby.h')
11
+ have_header('ruby/encoding.h')
12
+
13
+ extension_name = 'ruby2html/ruby2html'
14
+ dir_config(extension_name)
15
+
16
+ create_makefile(extension_name)
@@ -0,0 +1,108 @@
1
+ // ext/ruby2html/ruby2html.c
2
+ #include <ruby.h>
3
+ #include <ruby/encoding.h>
4
+ #include <ctype.h>
5
+
6
+ static VALUE rb_mRuby2html;
7
+ static VALUE rb_cRenderer;
8
+
9
+ // Fast HTML escaping
10
+ static VALUE fast_escape_html(VALUE self, VALUE str) {
11
+ if (NIL_P(str)) return Qnil;
12
+
13
+ str = rb_String(str);
14
+ long len = RSTRING_LEN(str);
15
+ const char *ptr = RSTRING_PTR(str);
16
+
17
+ // First pass: calculate required buffer size
18
+ long new_len = len;
19
+ for (long i = 0; i < len; i++) {
20
+ switch (ptr[i]) {
21
+ case '&': new_len += 4; break; // &amp;
22
+ case '<': new_len += 3; break; // &lt;
23
+ case '>': new_len += 3; break; // &gt;
24
+ case '"': new_len += 5; break; // &quot;
25
+ case '\'': new_len += 5; break; // &#39;
26
+ }
27
+ }
28
+
29
+ if (new_len == len) return str;
30
+
31
+ VALUE result = rb_str_new(NULL, new_len);
32
+ char *out = RSTRING_PTR(result);
33
+ long pos = 0;
34
+
35
+ // Second pass: actual escaping
36
+ for (long i = 0; i < len; i++) {
37
+ switch (ptr[i]) {
38
+ case '&':
39
+ memcpy(out + pos, "&amp;", 5);
40
+ pos += 5;
41
+ break;
42
+ case '<':
43
+ memcpy(out + pos, "&lt;", 4);
44
+ pos += 4;
45
+ break;
46
+ case '>':
47
+ memcpy(out + pos, "&gt;", 4);
48
+ pos += 4;
49
+ break;
50
+ case '"':
51
+ memcpy(out + pos, "&quot;", 6);
52
+ pos += 6;
53
+ break;
54
+ case '\'':
55
+ memcpy(out + pos, "&#39;", 5);
56
+ pos += 5;
57
+ break;
58
+ default:
59
+ out[pos++] = ptr[i];
60
+ }
61
+ }
62
+
63
+ rb_str_set_len(result, pos);
64
+ rb_enc_associate(result, rb_enc_get(str));
65
+ return result;
66
+ }
67
+
68
+ // Fast attribute string builder
69
+ static VALUE fast_attributes_to_s(VALUE self, VALUE hash) {
70
+ if (NIL_P(hash) || RHASH_EMPTY_P(hash)) return rb_str_new2("");
71
+
72
+ VALUE result = rb_str_buf_new(64); // Pre-allocate with reasonable size
73
+ VALUE keys = rb_funcall(hash, rb_intern("keys"), 0);
74
+ long len = RARRAY_LEN(keys);
75
+
76
+ for (long i = 0; i < len; i++) {
77
+ VALUE key = rb_ary_entry(keys, i);
78
+ VALUE value = rb_hash_aref(hash, key);
79
+
80
+ if (!NIL_P(value)) {
81
+ rb_str_cat2(result, " ");
82
+ rb_str_append(result, rb_String(key));
83
+ rb_str_cat2(result, "=\"");
84
+ rb_str_append(result, fast_escape_html(self, rb_String(value)));
85
+ rb_str_cat2(result, "\"");
86
+ }
87
+ }
88
+
89
+ return result;
90
+ }
91
+
92
+ // Fast string buffer concatenation
93
+ static VALUE fast_buffer_append(VALUE self, VALUE buffer, VALUE str) {
94
+ if (!NIL_P(str)) {
95
+ rb_funcall(buffer, rb_intern("<<"), 1, rb_String(str));
96
+ }
97
+ return Qnil;
98
+ }
99
+
100
+ void Init_ruby2html(void) {
101
+ rb_mRuby2html = rb_define_module("Ruby2html");
102
+
103
+ rb_cRenderer = rb_define_class_under(rb_mRuby2html, "Render", rb_cObject);
104
+
105
+ rb_define_method(rb_cRenderer, "fast_escape_html", fast_escape_html, 1);
106
+ rb_define_method(rb_cRenderer, "fast_attributes_to_s", fast_attributes_to_s, 1);
107
+ rb_define_method(rb_cRenderer, "fast_buffer_append", fast_buffer_append, 2);
108
+ }
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ begin
4
+ require 'ruby2html/ruby2html'
5
+ rescue LoadError
6
+ puts 'ruby2html not installed'
7
+ end
8
+
3
9
  module Ruby2html
4
10
  class Render
5
11
  HTML5_TAGS = %w[
@@ -13,16 +19,58 @@ module Ruby2html
13
19
  ].freeze
14
20
 
15
21
  VOID_ELEMENTS = %w[area base br col embed hr img input link meta param source track wbr].freeze
16
-
17
22
  COMMON_RAILS_METHOD_HELPERS = %w[link_to image_tag form_with button_to].freeze
18
23
 
24
+ # Pre-generate all HTML tag methods as a single string
25
+ METHOD_DEFINITIONS = HTML5_TAGS.map do |tag|
26
+ method_name = tag.tr('-', '_')
27
+ is_void = VOID_ELEMENTS.include?(tag)
28
+ <<-RUBY
29
+ def #{method_name}(*args, **options, &block)
30
+ content = args.first.is_a?(String) ? args.shift : nil
31
+ estimated_size = #{tag.length * 2 + 5}
32
+ estimated_size += 32 if options.any?
33
+ estimated_size += content.length if content
34
+ tag_content = String.new(capacity: estimated_size)
35
+ tag_content << '<#{tag}'
36
+ fast_buffer_append(tag_content, fast_attributes_to_s(options))
37
+ #{if is_void
38
+ 'tag_content << \' />\''
39
+ else
40
+ <<-TAG_LOGIC
41
+ tag_content << '>'
42
+ if block
43
+ prev_output = @current_output
44
+ nested_content = String.new(capacity: 1024)
45
+ @current_output = nested_content
46
+ block_result = block.call
47
+ @current_output = prev_output
48
+ if block_result.is_a?(String)
49
+ fast_buffer_append(tag_content, fast_escape_html(block_result))
50
+ else
51
+ fast_buffer_append(tag_content, nested_content)
52
+ end
53
+ elsif content
54
+ fast_buffer_append(tag_content, fast_escape_html(content))
55
+ end
56
+ tag_content << '</#{tag}>'
57
+ TAG_LOGIC
58
+ end}
59
+ fast_buffer_append(@current_output, tag_content)
60
+ end
61
+ RUBY
62
+ end.join("\n")
63
+
64
+ # Evaluate all method definitions at once
65
+ class_eval(METHOD_DEFINITIONS, __FILE__, __LINE__ + 1)
66
+
19
67
  attr_reader :output
20
68
  attr_accessor :current_output
21
69
 
22
70
  def initialize(context = nil, &root)
23
71
  @context = context
24
72
  @root = root
25
- @output = StringIO.new
73
+ @output = String.new(capacity: 4096)
26
74
  @current_output = @output
27
75
  end
28
76
 
@@ -31,73 +79,41 @@ module Ruby2html
31
79
  return result unless annotate_rendered_view_with_filenames?
32
80
 
33
81
  template_path = template_path.sub("#{Rails.root}/", '')
34
-
35
- "<!-- BEGIN #{template_path} -->#{result}<!-- END #{template_path} -->".html_safe
82
+ comment_start = "<!-- BEGIN #{template_path} -->"
83
+ comment_end = "<!-- END #{template_path} -->"
84
+
85
+ final_result = String.new(capacity: result.length + comment_start.length + comment_end.length)
86
+ final_result << comment_start
87
+ final_result << result
88
+ final_result << comment_end
89
+ final_result.html_safe
36
90
  end if defined?(ActionView)
37
91
 
38
92
  def render(*args, **options, &block)
39
93
  set_instance_variables
40
94
 
41
- return plain @context.render(*args, **options, &block) if !args.empty? || !options.empty? || block_given?
95
+ return plain @context.render(*args, **options, &block) if !args.empty? || !options.empty? || block_given?
42
96
 
43
97
  instance_exec(&@root)
44
- result = @output.string
45
-
98
+ result = @output
46
99
  result = ActiveSupport::SafeBuffer.new(result) if defined?(ActiveSupport)
47
-
48
100
  result
49
101
  end
50
102
 
51
- HTML5_TAGS.each do |tag|
52
- define_method(tag.tr('-', '_')) do |*args, **options, &block|
53
- html!(tag, *args, **options, &block)
54
- end
55
- end
56
-
57
103
  def respond_to?(method_name, include_private = false)
58
- HTML5_TAGS.include?(method_name) || super
59
- end
60
-
61
- def html!(name, *args, **options)
62
- content = args.first.is_a?(String) ? args.shift : nil
63
- attributes = options
64
-
65
- tag_content = StringIO.new
66
- tag_content << "<#{name}"
67
- tag_content << attributes_to_s(attributes)
68
-
69
- if VOID_ELEMENTS.include?(name)
70
- tag_content << ' />'
71
- else
72
- tag_content << '>'
73
-
74
- if block_given?
75
- prev_output = @current_output
76
- nested_content = StringIO.new
77
- @current_output = nested_content
78
- block_result = yield
79
- @current_output = prev_output
80
- tag_content << (block_result.is_a?(String) ? escape_html(block_result) : nested_content.string)
81
- elsif content
82
- tag_content << escape_html(content)
83
- end
84
-
85
- tag_content << "</#{name}>"
86
- end
87
-
88
- @current_output << tag_content.string
104
+ HTML5_TAGS.include?(method_name.to_s.tr('_', '-')) || super
89
105
  end
90
106
 
91
107
  def plain(text)
92
108
  if defined?(ActiveSupport) && (text.is_a?(ActiveSupport::SafeBuffer) || text.html_safe?)
93
- @current_output << text
109
+ fast_buffer_append(@current_output, text)
94
110
  else
95
- @current_output << escape_html(text.to_s)
111
+ fast_buffer_append(@current_output, fast_escape_html(text.to_s))
96
112
  end
97
113
  end
98
114
 
99
115
  def component(component_output)
100
- @current_output << component_output
116
+ fast_buffer_append(@current_output, component_output)
101
117
  end
102
118
 
103
119
  private
@@ -120,18 +136,8 @@ module Ruby2html
120
136
  end
121
137
  end if defined?(ActionView)
122
138
 
123
- def attributes_to_s(attributes)
124
- return '' if attributes.empty?
125
-
126
- result = StringIO.new
127
- attributes.compact.each do |k, v|
128
- result << " #{k}=\"#{escape_html(v)}\""
129
- end
130
- result.string
131
- end
132
-
133
139
  def escape_html(text)
134
- CGI.escapeHTML(text.to_s)
140
+ fast_escape_html(text.to_s)
135
141
  end
136
142
 
137
143
  def annotate_rendered_view_with_filenames?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ruby2html
4
- VERSION = '1.5.7'
4
+ VERSION = '1.6.0'
5
5
  end
Binary file
data/ruby2html.gemspec CHANGED
@@ -8,13 +8,13 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ['sebi']
9
9
  spec.email = ['gore.sebyx@yahoo.com']
10
10
 
11
- spec.summary = 'Transform Ruby code into beautiful, structured HTML'
11
+ spec.summary = 'Transform Ruby code into beautiful, structured HTML with C-optimized performance'
12
12
  spec.description = 'Ruby2HTML empowers developers to write view logic in pure Ruby, ' \
13
13
  'seamlessly converting it into clean, well-formatted HTML. ' \
14
14
  'Enhance your templating workflow, improve readability, and ' \
15
15
  'leverage the full power of Ruby in your views. ' \
16
16
  'Features include Rails integration, custom component support, ' \
17
- 'and automatic HTML beautification.'
17
+ 'automatic HTML beautification, and C-optimized rendering performance.'
18
18
  spec.homepage = 'https://github.com/sebyx07/ruby2html'
19
19
  spec.license = 'MIT'
20
20
  spec.required_ruby_version = '>= 3.0.0'
@@ -22,12 +22,22 @@ Gem::Specification.new do |spec|
22
22
  spec.metadata['homepage_uri'] = spec.homepage
23
23
  spec.metadata['source_code_uri'] = spec.homepage
24
24
 
25
- # Specify which files should be added to the gem when it is released.
26
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27
- gemspec = File.basename(__FILE__)
25
+ # Include C extension
26
+ spec.extensions = ['ext/ruby2html/extconf.rb']
28
27
 
29
- spec.files = Dir.glob('{lib}/gem/**/*') + [gemspec]
30
- spec.require_paths = ['lib/gem']
28
+ # Include both lib and ext directories
29
+ spec.files = Dir.glob('{lib,ext}/{**/*,*}') +
30
+ ['README.md', File.basename(__FILE__)]
31
31
 
32
+ # Set require paths for both the gem and extension
33
+ spec.require_paths = %w[lib/gem lib]
34
+
35
+ # Runtime dependencies
32
36
  spec.add_dependency 'htmlbeautifier', '>= 1.4'
37
+
38
+ # Development dependencies
39
+ spec.add_development_dependency 'rake', '~> 13.0'
40
+ spec.add_development_dependency 'rake-compiler', '~> 1.2'
41
+ spec.add_development_dependency 'minitest', '~> 5.14'
42
+ spec.add_development_dependency 'benchmark-ips', '~> 2.10'
33
43
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby2html
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.7
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - sebi
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-11-01 00:00:00.000000000 Z
10
+ date: 2025-02-09 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: htmlbeautifier
@@ -24,16 +23,77 @@ dependencies:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
25
  version: '1.4'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '13.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '13.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rake-compiler
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.2'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.2'
54
+ - !ruby/object:Gem::Dependency
55
+ name: minitest
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '5.14'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '5.14'
68
+ - !ruby/object:Gem::Dependency
69
+ name: benchmark-ips
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '2.10'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '2.10'
27
82
  description: Ruby2HTML empowers developers to write view logic in pure Ruby, seamlessly
28
83
  converting it into clean, well-formatted HTML. Enhance your templating workflow,
29
84
  improve readability, and leverage the full power of Ruby in your views. Features
30
- include Rails integration, custom component support, and automatic HTML beautification.
85
+ include Rails integration, custom component support, automatic HTML beautification,
86
+ and C-optimized rendering performance.
31
87
  email:
32
88
  - gore.sebyx@yahoo.com
33
89
  executables: []
34
- extensions: []
90
+ extensions:
91
+ - ext/ruby2html/extconf.rb
35
92
  extra_rdoc_files: []
36
93
  files:
94
+ - README.md
95
+ - ext/ruby2html/extconf.rb
96
+ - ext/ruby2html/ruby2html.c
37
97
  - lib/gem/ruby2html.rb
38
98
  - lib/gem/ruby2html/component_helper.rb
39
99
  - lib/gem/ruby2html/html_beautifier_middleware.rb
@@ -46,6 +106,7 @@ files:
46
106
  - lib/gem/ruby2html/railtie.rb
47
107
  - lib/gem/ruby2html/render.rb
48
108
  - lib/gem/ruby2html/version.rb
109
+ - lib/ruby2html/ruby2html.so
49
110
  - ruby2html.gemspec
50
111
  homepage: https://github.com/sebyx07/ruby2html
51
112
  licenses:
@@ -53,10 +114,10 @@ licenses:
53
114
  metadata:
54
115
  homepage_uri: https://github.com/sebyx07/ruby2html
55
116
  source_code_uri: https://github.com/sebyx07/ruby2html
56
- post_install_message:
57
117
  rdoc_options: []
58
118
  require_paths:
59
119
  - lib/gem
120
+ - lib
60
121
  required_ruby_version: !ruby/object:Gem::Requirement
61
122
  requirements:
62
123
  - - ">="
@@ -68,8 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
129
  - !ruby/object:Gem::Version
69
130
  version: '0'
70
131
  requirements: []
71
- rubygems_version: 3.5.17
72
- signing_key:
132
+ rubygems_version: 3.6.3
73
133
  specification_version: 4
74
- summary: Transform Ruby code into beautiful, structured HTML
134
+ summary: Transform Ruby code into beautiful, structured HTML with C-optimized performance
75
135
  test_files: []