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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 57887705c24091d9cf76d5f1b7e41da4167077c9c61b5a408756af3804e0df1b
4
- data.tar.gz: e27fa7060204b4da1c95998451a186cf84492e4a896440baa9ce78eceaaf6f9c
3
+ metadata.gz: acd9834eee45bda437a281566e66300e5e5645dddb45850d571d506c27a94501
4
+ data.tar.gz: ebe9a74c98f952e049335357fda1e9268f7126fbb090cbf7bf4e8b4e1fbedc1f
5
5
  SHA512:
6
- metadata.gz: 3267b43294cac4d37620a16076fbb97eaaf7d6e8c639b1b83e7b7657e597739617f5ee051c83a2d2394758a9ab19f0d9dd66243ad36eb2c4057308fec64d9ec2
7
- data.tar.gz: 583b0c34f859915a57de3b7c1518ed7df16225eef381203c53b73fdf8664401567f564a5dd5c42b870b9b75d3c4f37f119dc7fae51b7707907ded372d97b52c7
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 Ruby code into beautiful, structured HTML with ease! 🚀
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' do
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
- plain item[:title]
80
+ item[:title]
59
81
  end
60
82
  p class: 'item-description' do
61
- plain item[:description]
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
- plain "Hello, #{@name}! 👋"
143
+ "Hello, #{@name}! 👋"
100
144
  end
101
145
  p class: 'welcome-message' do
102
- plain 'Welcome to the wonderful world of Ruby2html!'
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
- plain 'first component'
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
- plain @item
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
- plain 'second component'
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
- html = Ruby2html::Render.new(nil) do # nil is the context, you can use self or any other object
234
+ renderer = Ruby2html::Render.new(nil) do # nil is the context, you can use self or any other object
191
235
  html do
192
- h1 'Hello, World!'
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 html.render
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
@@ -9,4 +9,8 @@ class HomeController < ApplicationController
9
9
  }
10
10
  ]
11
11
  end
12
+
13
+ def rb_files
14
+ @value = 'value'
15
+ end
12
16
  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
+ %>
@@ -5,7 +5,8 @@
5
5
 
6
6
  <%=
7
7
  html(self) do
8
- h1(id: 4) { plain "ok" }
8
+ h1(id: 4) { "Inside" }
9
+ h2 "Inside 2", id: '44'
9
10
  h1 "ok"
10
11
  h1 "ok"
11
12
  h1 "ok"
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.
@@ -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
- attributes = args.first.is_a?(Hash) ? args.shift : {}
49
- content = args.first.to_s
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
- instance_exec(&block)
65
+ block_result = yield
65
66
  @current_output = prev_output
66
- tag_content << nested_content.string
67
- else
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?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ruby2html
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.0'
5
5
  end
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.0.0
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