ruby2html 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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