blowmage / html_slice

Enable Ruby classes the ability to generate reusable pieces of html

Repository from Github https://github.comblowmage/html_sliceRepository from Github https://github.comblowmage/html_slice

HtmlSlice

Gem Version

HtmlSlice

Enable Ruby classes the ability to generate reusable pieces of html

class MyController < ApplicationController
  include HtmlSlice

  def index
    html_slice :say_hello do
      h1 "hello #{pizza}"
    end
  end

  def pizza
    "🍕"
  end
end

# index.html.erb

<%= raw @html_slice[:say_hello] %>

Features

  • Generate HTML dynamically in instance scope: unlike Markaby, HtmlSlice self points to the class instance that are using it, make easier to reuse code and make abstractions (see https://github.com/markaby/markaby?tab=readme-ov-file#label-A+Note+About+instance_eval).
  • HtmlSlice uses include instead of inheritance. This means we can "plug" it in anywhere—Rails controllers, services, Sinatra apps, Roda apps—or create specific view classes if needed.
  • Can be used to generate all application html or only html partials (slices 🍕).
  • Lightweight, use HtmlSlice without performance penalties.
  • Escapes HTML content to prevent XSS vulnerabilities.

Installation

Install the gem and add to the application's Gemfile by executing:

$ bundle add html_slice

If bundler is not being used to manage dependencies, install the gem by executing:

$ gem install html_slice

Usage

Include HtmlSlice in any Ruby class to generate HTML dynamically.

require 'html_slice'

class HelloView
  include HtmlSlice

  def to_html
    html_slice do
      h1 'hello world'
      text
      div do
        _ '<b> some raw html </b>'
      end 
    end
  end

  def text
    tag :p, %q(
      Lorem ipsum dolor sit amet
    )
  end
end

puts HelloView.new.to_html
# <h1>hello world</h1><p>Lorem ipsum dolor sit amet</p><div><b> some raw html </b></div>
Explanation
  • The html_slice method starts the HTML generation process creating an @html_slice instance variable and returning its content.
  • Each time we call the html tag methods, the method append the generated html in @html_slice.
  • Tags like div, h1, and ul are dynamically defined as methods, enabling you to structure HTML seamlessly.
  • Tags that are not defined as methods can be generated using the tag method (*only the most common tags are dinamically defined as methods, except "p", "head" and "body")
  • Use the _ method to append raw content to the @html_slice.

Adding Attributes

HTML attributes can be added to tags as a hash:

div id: "main", class: "highlighted" do
  span "Hello world"
end

"_" in html attributes is converted to "-"

div x_data: "{ hello: 'world' }" do # x-data="{ hello: 'world' }"
  span "Hello world"
end

The @html_slice instance variable

The @html_slice holds a hash where every key maps to a html string generated calling the "tag methods", html slice default key is :default

require 'html_slice'

class HelloView
  include HtmlSlice

  def to_html
    html_slice do # @html_slice[:default] = ''
      h1 'hello world' # @html_slice[:default] << '<h1>hello world</h1>'
      text # @html_slice[:default] << '<p>Lorem ipsum dolor sit amet</p>'
      div do
        _ '<b> some raw html </b>'
      end 
    end

    html_slice :some_key do # @html_slice[:some_key] = ''
      h1 'hello world' # @html_slice[:some_key] << '<h1>hello world</h1>'
      text # @html_slice[:some_key] << '<p>Lorem ipsum dolor sit amet</p>'
      div do
        _ '<b> some raw html </b>'
      end 
    end
  end

  def text
    tag :p, %q(
      Lorem ipsum dolor sit amet
    )
  end
end

HelloView.new.to_html

⚠️ Important: Tag methods and our instance methods that use the tag methods must only be called inside an html_slice block

Rails examples

Rendering pure html slices:
class ApplicationController
  include HtmlSlice

  def html(&block) 
    html_slice(&block).html_safe
  end
end

# Imagine a Rails controller
class MyController < ApplicationController
  before_action :set_items

  def index
    render html: (html do
      h1 'hello world'

      div class: 'to-do' do
        to_do_list
      end
    end)
  end
  # "<h1>hello world</h1><div class='to-do'><ul><li>Clean the house</li><li>Study Ruby</li><li>Play sports</li></ul></div>"

  private

  def to_do_list
    ul do
      @items.each do |item|
        li item
      end
    end
  end

  def set_items
    @items ||= ['Clean the house', 'Study Ruby', 'Play sports']
  end
end
Rendering partials using html slice keys:
class MyController < ApplicationController
  include HtmlSlice

  def index
    html_slice :say_hello do
      h1 "hello #{pizza}"
    end
  end

  def pizza
    "🍕"
  end
end

# index.html.erb

<%= raw @html_slice[:say_hello] %>
Rendering entire html pages with html_layout:
class ApplicationController
  include HtmlSlice

  def layout
    html_layout { # Same as html_slice but wrap the content in a <!DOCTYPE html><html>...</html> structure
      tag :head do
        meta charset: 'utf-8'

        custom_head
      end

      tag :body do
        yield
      end
    }.html_safe
  end
end

# Imagine a Rails controller
class MyController < ApplicationController
  before_action :set_items

  def index
    render html: (layout do
      h1 'hello world'

      div class: 'to-do' do
        to_do_list
      end
    end)
  end
  # "<!DOCTYPE html><html><head><meta charset='utf-8'/><title>Hello HtmlSlice</title></head><body><h1>hello world</h1><div class='to-do'><ul><li>Clean the house</li><li>Study Ruby</li><li>Play sports</li></ul></div></body></html>"

  def custom_head
    title 'Hello HtmlSlice'
  end

  private

  def to_do_list
    ul do
      @items.each do |item|
        li item
      end
    end
  end

  def set_items
    @items ||= ['Clean the house', 'Study Ruby', 'Play sports']
  end
end
Using Rails view helpers

We must use the _ method that render raw content

class HelloController < ApplicationController                 
  def index                                                 
    render html: (html do                                     
      h1 'Hello#h_slice'                                      
      tag :p, 'Find me in app/controllers/hello_controller.rb'
                                                              
      _ helpers.link_to('oi')                                 
                                                              
      _ (helpers.form_for 'user' do |f|                       
        f.text_field('name')                                  
      end)                                                    
    end)                                                      
  end                                                                                                             
end                                                           
                                                

Benchmarks

Rendering a div with h1 100 times (cpu time):

                                             user     system      total        real
html_slice                               0.000390   0.000000   0.000390 (  0.000390)
papercraft                               0.000495   0.000077   0.000572 (  0.000567)
markaby                                  0.001794   0.000000   0.001794 (  0.001795)

Development

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.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/henrique-ft/html_slice. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

Code of Conduct

Everyone interacting in the HtmlSlice project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

About

Enable Ruby classes the ability to generate reusable pieces of html


Languages

Language:Ruby 98.2%Language:Shell 1.2%Language:HTML 0.6%