ruby2html 1.0.0 → 1.1.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 +4 -4
- data/README.md +63 -14
- data/app/controllers/benchmark_controller.rb +48 -0
- data/app/controllers/home_controller.rb +4 -0
- data/app/views/benchmark/normal_html.html.erb +31 -0
- data/app/views/benchmark/ruby_2html.html.erb +35 -0
- data/app/views/home/index.html.erb +2 -1
- data/config/routes.rb +5 -0
- data/lib/gem/ruby2html/render.rb +10 -9
- data/lib/gem/ruby2html/version.rb +1 -1
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: acd9834eee45bda437a281566e66300e5e5645dddb45850d571d506c27a94501
|
4
|
+
data.tar.gz: ebe9a74c98f952e049335357fda1e9268f7126fbb090cbf7bf4e8b4e1fbedc1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4dc38bb961568de810742b8e8c2a8c9231abcbc0244bf0334350b3949eef3e1d81d2f907ab2565bc1acc6b0b6751ccabdc2c04b9855996e72e0ef0c117eaf8fa
|
7
|
+
data.tar.gz: 5e200ab5fd3f5a0941c7d7a32e5729e5a9f249d01158b1906a2797d0b0e8309bf403e0aaf5bd5a8416ef9cf42a8d56c0150bc2a9d5f0ca63bfe987ba8c777dca
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Ruby2html 🔮✨
|
2
2
|
|
3
|
-
Transform your
|
3
|
+
Transform your view logic into elegant, semantic HTML with the power of pure Ruby! 🚀✨
|
4
4
|
|
5
5
|
## 🌟 What is Ruby2html?
|
6
6
|
|
@@ -39,6 +39,30 @@ end
|
|
39
39
|
|
40
40
|
### In your views
|
41
41
|
|
42
|
+
File: `app/views/your_view.html.rb`
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
div class: 'container' do
|
46
|
+
h1 'Welcome to Ruby2html! 🎉', class: 'main-title', 'data-controller': 'welcome'
|
47
|
+
link_to 'Home Sweet Home 🏠', root_path, class: 'btn btn-primary', 'data-turbo': false
|
48
|
+
|
49
|
+
@items.each do |item|
|
50
|
+
h2 class: 'item-title', id: "item-#{item[:id]}" do
|
51
|
+
item[:title]
|
52
|
+
end
|
53
|
+
p class: 'item-description' do
|
54
|
+
item[:description]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
plain '<div>Inline html</div>'.html_safe
|
60
|
+
|
61
|
+
render partial: 'shared/navbar'
|
62
|
+
```
|
63
|
+
|
64
|
+
#### Or use your current .erb views
|
65
|
+
|
42
66
|
File: `app/views/your_view.html.erb`
|
43
67
|
|
44
68
|
Replace your ERB with beautiful Ruby code:
|
@@ -46,27 +70,47 @@ Replace your ERB with beautiful Ruby code:
|
|
46
70
|
```erb
|
47
71
|
<%=
|
48
72
|
html(self) do
|
49
|
-
h1 class: 'main-title', 'data-controller': 'welcome'
|
50
|
-
"Welcome to Ruby2html! 🎉"
|
51
|
-
end
|
73
|
+
h1 "Welcome to Ruby2html! 🎉", class: 'main-title', 'data-controller': 'welcome'
|
52
74
|
div id: 'content', class: 'container' do
|
53
75
|
link_to 'Home Sweet Home 🏠', root_path, class: 'btn btn-primary', 'data-turbo': false
|
54
76
|
end
|
55
77
|
|
56
78
|
@items.each do |item|
|
57
79
|
h2 class: 'item-title', id: "item-#{item[:id]}" do
|
58
|
-
|
80
|
+
item[:title]
|
59
81
|
end
|
60
82
|
p class: 'item-description' do
|
61
|
-
|
83
|
+
item[:description]
|
62
84
|
end
|
63
85
|
end
|
64
86
|
|
87
|
+
plain "<div>Inline html</div>".html_safe
|
88
|
+
|
65
89
|
render partial: 'shared/navbar'
|
66
90
|
end
|
67
91
|
%>
|
68
92
|
```
|
69
93
|
|
94
|
+
### Benchmark
|
95
|
+
|
96
|
+
```bash
|
97
|
+
ruby 3.3.3 (2024-06-12 revision f1c7b6f435) +YJIT [x86_64-linux]
|
98
|
+
Warming up --------------------------------------
|
99
|
+
GET /benchmark/html (ERB)
|
100
|
+
1.000 i/100ms
|
101
|
+
GET /benchmark/ruby (Ruby2html)
|
102
|
+
1.000 i/100ms
|
103
|
+
Calculating -------------------------------------
|
104
|
+
GET /benchmark/html (ERB)
|
105
|
+
20.163 (±19.8%) i/s - 95.000 in 5.062853s
|
106
|
+
GET /benchmark/ruby (Ruby2html)
|
107
|
+
19.362 (±15.5%) i/s - 92.000 in 5.006433s
|
108
|
+
|
109
|
+
Comparison:
|
110
|
+
GET /benchmark/html (ERB): 20.2 i/s
|
111
|
+
GET /benchmark/ruby (Ruby2html): 19.4 i/s - same-ish: difference falls within error
|
112
|
+
```
|
113
|
+
|
70
114
|
### With ViewComponents
|
71
115
|
|
72
116
|
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.
|
@@ -96,10 +140,10 @@ class GreetingComponent < ApplicationComponent
|
|
96
140
|
def call
|
97
141
|
html(self) do
|
98
142
|
h1 class: 'greeting', 'data-user': @name do
|
99
|
-
|
143
|
+
"Hello, #{@name}! 👋"
|
100
144
|
end
|
101
145
|
p class: 'welcome-message' do
|
102
|
-
|
146
|
+
'Welcome to the wonderful world of Ruby2html!'
|
103
147
|
end
|
104
148
|
end
|
105
149
|
end
|
@@ -155,13 +199,13 @@ class FirstComponent < ApplicationComponent
|
|
155
199
|
def call
|
156
200
|
html(self) do
|
157
201
|
h1 id: 'first-component-title' do
|
158
|
-
|
202
|
+
'first component'
|
159
203
|
end
|
160
204
|
div class: 'content-wrapper' do
|
161
205
|
h2 'A subheading'
|
162
206
|
end
|
163
207
|
p class: 'greeting-text', 'data-testid': 'greeting' do
|
164
|
-
|
208
|
+
@item
|
165
209
|
end
|
166
210
|
end
|
167
211
|
end
|
@@ -177,7 +221,7 @@ class SecondComponent < ApplicationComponent
|
|
177
221
|
def call
|
178
222
|
html(self) do
|
179
223
|
h1 class: 'my-class', id: 'second-component-title', 'data-controller': 'second' do
|
180
|
-
|
224
|
+
'second component'
|
181
225
|
end
|
182
226
|
link_to 'Home', root_path, class: 'nav-link', 'data-turbo-frame': false
|
183
227
|
end
|
@@ -187,13 +231,18 @@ end
|
|
187
231
|
|
188
232
|
## Without Rails
|
189
233
|
```ruby
|
190
|
-
|
234
|
+
renderer = Ruby2html::Render.new(nil) do # nil is the context, you can use self or any other object
|
191
235
|
html do
|
192
|
-
|
236
|
+
head do
|
237
|
+
title 'Ruby2html Example'
|
238
|
+
end
|
239
|
+
body do
|
240
|
+
h1 'Hello, World!'
|
241
|
+
end
|
193
242
|
end
|
194
243
|
end
|
195
244
|
|
196
|
-
puts
|
245
|
+
puts renderer.render # => "<html><head><title>Ruby2html Example</title></head><body><h1>Hello, World!</h1></body></html>"
|
197
246
|
```
|
198
247
|
|
199
248
|
## 🐢 Gradual Adoption
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class BenchmarkController < ApplicationController
|
4
|
+
def normal_html
|
5
|
+
@complex_data = generate_complex_data
|
6
|
+
end
|
7
|
+
|
8
|
+
def ruby_2html
|
9
|
+
@complex_data = generate_complex_data
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def generate_complex_data
|
14
|
+
{
|
15
|
+
users: 50.times.map do |i|
|
16
|
+
{
|
17
|
+
id: i + 1,
|
18
|
+
name: Faker::Name.name,
|
19
|
+
email: Faker::Internet.email,
|
20
|
+
address: {
|
21
|
+
street: Faker::Address.street_address,
|
22
|
+
city: Faker::Address.city,
|
23
|
+
country: Faker::Address.country
|
24
|
+
},
|
25
|
+
orders: rand(1..5).times.map do
|
26
|
+
{
|
27
|
+
id: Faker::Alphanumeric.alphanumeric(number: 10),
|
28
|
+
total: Faker::Commerce.price(range: 10..1000.0),
|
29
|
+
items: rand(1..10).times.map do
|
30
|
+
{
|
31
|
+
name: Faker::Commerce.product_name,
|
32
|
+
price: Faker::Commerce.price(range: 5..500.0),
|
33
|
+
quantity: rand(1..5)
|
34
|
+
}
|
35
|
+
end
|
36
|
+
}
|
37
|
+
end
|
38
|
+
}
|
39
|
+
end,
|
40
|
+
stats: {
|
41
|
+
total_users: 50,
|
42
|
+
average_orders_per_user: rand(1.0..5.0).round(2),
|
43
|
+
most_expensive_item: Faker::Commerce.product_name,
|
44
|
+
most_popular_country: Faker::Address.country
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<h1>Benchmark: Normal HTML (ERB)</h1>
|
2
|
+
|
3
|
+
<h2>User Statistics</h2>
|
4
|
+
<ul>
|
5
|
+
<li>Total Users: <%= @complex_data[:stats][:total_users] %></li>
|
6
|
+
<li>Average Orders per User: <%= @complex_data[:stats][:average_orders_per_user] %></li>
|
7
|
+
<li>Most Expensive Item: <%= @complex_data[:stats][:most_expensive_item] %></li>
|
8
|
+
<li>Most Popular Country: <%= @complex_data[:stats][:most_popular_country] %></li>
|
9
|
+
</ul>
|
10
|
+
|
11
|
+
<h2>User List</h2>
|
12
|
+
<% @complex_data[:users].each do |user| %>
|
13
|
+
<div class="user-card">
|
14
|
+
<h3><%= user[:name] %></h3>
|
15
|
+
<p>Email: <%= user[:email] %></p>
|
16
|
+
<p>Address: <%= "#{user[:address][:street]}, #{user[:address][:city]}, #{user[:address][:country]}" %></p>
|
17
|
+
|
18
|
+
<h4>Orders</h4>
|
19
|
+
<% user[:orders].each do |order| %>
|
20
|
+
<div class="order">
|
21
|
+
<p>Order ID: <%= order[:id] %></p>
|
22
|
+
<p>Total: $<%= order[:total] %></p>
|
23
|
+
<ul>
|
24
|
+
<% order[:items].each do |item| %>
|
25
|
+
<li><%= item[:name] %> - $<%= item[:price] %> (Quantity: <%= item[:quantity] %>)</li>
|
26
|
+
<% end %>
|
27
|
+
</ul>
|
28
|
+
</div>
|
29
|
+
<% end %>
|
30
|
+
</div>
|
31
|
+
<% end %>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<%=
|
2
|
+
html(self) do
|
3
|
+
h1 'Benchmark: Ruby2html'
|
4
|
+
|
5
|
+
h2 'User Statistics'
|
6
|
+
ul do
|
7
|
+
li { plain "Total Users: #{@complex_data[:stats][:total_users]}" }
|
8
|
+
li { plain "Average Orders per User: #{@complex_data[:stats][:average_orders_per_user]}" }
|
9
|
+
li { plain "Most Expensive Item: #{@complex_data[:stats][:most_expensive_item]}" }
|
10
|
+
li { plain "Most Popular Country: #{@complex_data[:stats][:most_popular_country]}" }
|
11
|
+
end
|
12
|
+
|
13
|
+
h2 'User List'
|
14
|
+
@complex_data[:users].each do |user|
|
15
|
+
div class: 'user-card' do
|
16
|
+
h3 user[:name]
|
17
|
+
p { plain "Email: #{user[:email]}" }
|
18
|
+
p { plain "Address: #{user[:address][:street]}, #{user[:address][:city]}, #{user[:address][:country]}" }
|
19
|
+
|
20
|
+
h4 'Orders'
|
21
|
+
user[:orders].each do |order|
|
22
|
+
div class: 'order' do
|
23
|
+
p { plain "Order ID: #{order[:id]}" }
|
24
|
+
p { plain "Total: $#{order[:total]}" }
|
25
|
+
ul do
|
26
|
+
order[:items].each do |item|
|
27
|
+
li { plain "#{item[:name]} - $#{item[:price]} (Quantity: #{item[:quantity]})" }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
%>
|
data/config/routes.rb
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
Rails.application.routes.draw do
|
4
4
|
root to: 'home#index'
|
5
|
+
get '/benchmark/html', to: 'benchmark#normal_html'
|
6
|
+
get '/benchmark/ruby', to: 'benchmark#ruby_2html'
|
7
|
+
|
8
|
+
get '/rb_files', to: 'home#rb_files'
|
9
|
+
|
5
10
|
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
|
6
11
|
|
7
12
|
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
|
data/lib/gem/ruby2html/render.rb
CHANGED
@@ -39,14 +39,15 @@ module Ruby2html
|
|
39
39
|
end
|
40
40
|
|
41
41
|
HTML5_TAGS.each do |tag|
|
42
|
-
define_method(tag) do |*args, &block|
|
43
|
-
html!(tag, *args, &block)
|
42
|
+
define_method(tag) do |*args, **options, &block|
|
43
|
+
html!(tag, *args, **options, &block)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
def html!(name, *args, &block)
|
48
|
-
|
49
|
-
|
47
|
+
def html!(name, *args, **options, &block)
|
48
|
+
content = args.first.is_a?(String) ? args.shift : nil
|
49
|
+
attributes = options
|
50
|
+
|
50
51
|
tag_content = StringIO.new
|
51
52
|
tag_content << '<'
|
52
53
|
tag_content << name
|
@@ -61,10 +62,10 @@ module Ruby2html
|
|
61
62
|
prev_output = @current_output
|
62
63
|
nested_content = StringIO.new
|
63
64
|
@current_output = nested_content
|
64
|
-
|
65
|
+
block_result = yield
|
65
66
|
@current_output = prev_output
|
66
|
-
tag_content << nested_content.string
|
67
|
-
|
67
|
+
tag_content << (block_result.is_a?(String) ? escape_html(block_result) : nested_content.string)
|
68
|
+
elsif content
|
68
69
|
tag_content << escape_html(content)
|
69
70
|
end
|
70
71
|
|
@@ -105,7 +106,7 @@ module Ruby2html
|
|
105
106
|
define_method(method) do |*args, &block|
|
106
107
|
plain @context.send(method, *args, &block)
|
107
108
|
end
|
108
|
-
end
|
109
|
+
end if defined?(ActionView)
|
109
110
|
|
110
111
|
def attributes_to_s(attributes)
|
111
112
|
return '' if attributes.empty?
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby2html
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sebi
|
@@ -37,6 +37,7 @@ files:
|
|
37
37
|
- app/components/first_component.rb
|
38
38
|
- app/components/second_component.rb
|
39
39
|
- app/controllers/application_controller.rb
|
40
|
+
- app/controllers/benchmark_controller.rb
|
40
41
|
- app/controllers/concerns/.keep
|
41
42
|
- app/controllers/home_controller.rb
|
42
43
|
- app/helpers/application_helper.rb
|
@@ -44,6 +45,8 @@ files:
|
|
44
45
|
- app/mailers/application_mailer.rb
|
45
46
|
- app/models/application_record.rb
|
46
47
|
- app/models/concerns/.keep
|
48
|
+
- app/views/benchmark/normal_html.html.erb
|
49
|
+
- app/views/benchmark/ruby_2html.html.erb
|
47
50
|
- app/views/home/index.html.erb
|
48
51
|
- app/views/layouts/application.html.erb
|
49
52
|
- app/views/layouts/mailer.html.erb
|