https://github.com/timcraft/hom
A straightforward API for generating HTML
https://github.com/timcraft/hom
html ruby xss
Last synced: over 1 year ago
JSON representation
A straightforward API for generating HTML
- Host: GitHub
- URL: https://github.com/timcraft/hom
- Owner: timcraft
- License: other
- Created: 2011-08-19T14:03:47.000Z (almost 15 years ago)
- Default Branch: main
- Last Pushed: 2024-01-11T15:13:16.000Z (over 2 years ago)
- Last Synced: 2025-03-15T23:15:33.974Z (over 1 year ago)
- Topics: html, ruby, xss
- Language: Ruby
- Homepage:
- Size: 48.8 KB
- Stars: 2
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGES.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# hom
[](https://badge.fury.io/rb/hom) [](https://github.com/timcraft/hom/actions/workflows/test.yml)
A straightforward API for generating HTML.
## Motivation
HOM helps you implement HTML presentation logic in your code. Things like
navigation links, select boxes, sets of checkboxes; anything with behaviour
that is too complex for your templates.
## Installation
$ gem install hom
## Quick start
```ruby
require 'hom'
puts HOM::Element.new(:h1, nil, 'hello world')
```
## Using HOM::Element
Create instances of HOM::Element to represent DOM elements. The first
constructor argument is a symbol representing the tag name. For example,
you can represent a line break element like this:
```ruby
HOM::Element.new(:br)
```
The second constructor argument represents the element attributes, and can be
nil, a single symbol/string, a hash, or an array of hashes and symbols/strings.
For example, here's how you'd represent some input elements:
```ruby
HOM::Element.new(:input, :disabled)
HOM::Element.new(:input, {type: :text, size: 30})
HOM::Element.new(:input, [{type: :text, size: 30}, :disabled])
```
The third constructor argument is the inner content, which can be a string,
another element object, or an array of child nodes. For example, here's how
you can represent various elements with inner content:
```ruby
span = HOM::Element.new(:span, nil, '')
h1 = HOM::Element.new(:h1, {}, 'hello world')
image = HOM::Element.new(:img, {src: 'image.png', width: 100, height: 30})
link = HOM::Element.new(:a, {target: :_blank, href: '/'}, image)
list = HOM::Element.new(:ul, nil, (1..3).map { |n| HOM::Element.new(:li, nil, n) })
```
Calling #to_s on a HOM::Element object will return a string containing the
generated HTML markup. HOM::Element objects are safe to use directly in Rails
templates, all escaping is handled automatically.
## Using HOM::Entity
Create instances of HOM::Entity to represent HTML entities. Use an integer
argument for numeric entities and a symbol/string argument for named entities,
for example:
```ruby
HOM::Entity.new(160)
HOM::Entity.new(:nbsp)
```
## Using HOM::NodeList
Use HOM::NodeList to group nodes together without having to wrap them in an
outer element. For example:
```ruby
HOM::NodeList.new(['This is a ', HOM::Element.new(:strong, nil, 'Contrived'), ' example'])
```
Calling #to_s on a HOM::NodeList object will return a string containing the
generated HTML markup. Calling #join will insert separator nodes, a bit like
Array#join, but returning HTML safe output.
## XSS 101
Do you have helper methods that look like this:
```ruby
def user_name(user)
"#{user.name}".html_safe
end
```
Bzzzt, that's a security vulnerability right there. If you're using Rails
you should have code that looks like this:
```ruby
def user_name(user)
content_tag(:strong, user.name)
end
```
The content_tag helper will automatically escape content not explicitly
marked as safe. HOM will do very much the same thing, the equivalent helper
method would look like this:
```ruby
def user_name(user)
HOM::Element.new(:strong, nil, user.name)
end
```
Moral of the story: building up fragments of HTML using string interpolation
and concatenation is highly error prone. Solution: use content_tag or HOM to
safely build your content, and audit your usage of html_safe.