hom 0.4.0 → 1.3.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 80265a394bf1cecc27755bfcc583dbc81cb3ea51ffcb110fae6a61ecc3d0f0cd
4
+ data.tar.gz: 9ab3f813474864c3db170c4add2780309a2470f8bc4acca7c6daa2355bd27087
5
+ SHA512:
6
+ metadata.gz: 1d7d556b5749cd886a0731f39734e32cd34dde6ee8ffc0c07294034d0554c0f9bc2f6c35c51bf1f206b50bd9f03a6c01fae28bab158590f1792782f1bee341d6
7
+ data.tar.gz: 6e27e6d36d7648c968c8bec6c45a99c263e056945eacab2b4de3538220a40f5ad881e5cf30974e5561c0645044eb3ea9968cda6c2ea0e4ab148e1f1d207206c7
@@ -0,0 +1,57 @@
1
+ # 1.3.1
2
+
3
+ * Added metadata to gemspec
4
+
5
+ # 1.3.0
6
+
7
+ * HOM::NodeList#join now returns a new node list
8
+
9
+ * Added plus method to HOM::Element
10
+
11
+ * Added plus method to HOM::Entity
12
+
13
+ # 1.2.0
14
+
15
+ * Added html_safe? methods to HOM::Element and HOM::NodeList for compatibility with [erubis-auto](https://github.com/timcraft/erubis-auto)
16
+
17
+ # 1.1.0
18
+
19
+ * Added HOM::NodeList class
20
+
21
+ # 1.0.0
22
+
23
+ * Ruby 1.8.7 compatibility
24
+
25
+ * Removed support for rendering arbitrary objects by calling #html
26
+
27
+ # 0.4.0
28
+
29
+ * Deprecated support for rendering arbitrary objects by calling #html
30
+
31
+ * Added notion of undefined content, changing how elements with nil content are rendered:
32
+
33
+ With an element like this: `HOM::Element.new(:h1, {}, nil)`
34
+
35
+ Pre v0.4.0 rendering: `<h1>`
36
+
37
+ Post v0.4.0 rendering: `<h1></h1>`
38
+
39
+ # 0.3.0
40
+
41
+ * Added notion of undefined attribute values, nil is now rendered as an empty value:
42
+
43
+ With an element like this: `HOM::Element.new(:input, {:value => nil})`
44
+
45
+ Pre v0.3.0 rendering: `<input value>`
46
+
47
+ Post v0.3.0 rendering: `<input value="">`
48
+
49
+ * Removed Element#lookup method
50
+
51
+ # 0.2.0
52
+
53
+ * Replaced method missing attribute access with Element#lookup method
54
+
55
+ # 0.1.0
56
+
57
+ * First version!
@@ -0,0 +1,4 @@
1
+ Copyright (c) 2011-2020 TIMCRAFT
2
+
3
+ This is an Open Source project licensed under the terms of the LGPLv3 license.
4
+ Please see <http://www.gnu.org/licenses/lgpl-3.0.html> for license text.
data/README.md CHANGED
@@ -1,19 +1,37 @@
1
- HOM: A straightforward API for generating HTML
2
- ==============================================
1
+ # hom
3
2
 
4
- Motivation
5
- ----------
3
+ [![Gem Version](https://badge.fury.io/rb/hom.svg)](https://badge.fury.io/rb/hom) [![Build Status](https://api.travis-ci.org/timcraft/hom.svg?branch=master)](https://travis-ci.org/timcraft/hom)
4
+
5
+
6
+ A straightforward API for generating HTML.
7
+
8
+
9
+ ## Motivation
6
10
 
7
11
  HOM helps you implement HTML presentation logic in your code. Things like
8
12
  navigation links, select boxes, sets of checkboxes; anything with behaviour
9
13
  that is too complex for your templates.
10
14
 
11
- Usage
12
- -----
13
15
 
14
- Build up an object tree using `HOM::Element` objects. The first constuctor
15
- argument is a symbol representing the tag name. For example, here's how you'd
16
- represent a line break element:
16
+ ## Installation
17
+
18
+ $ gem install hom
19
+
20
+
21
+ ## Quick start
22
+
23
+ ```ruby
24
+ require 'hom'
25
+
26
+ puts HOM::Element.new(:h1, nil, 'hello world')
27
+ ```
28
+
29
+
30
+ ## Using HOM::Element
31
+
32
+ Create instances of HOM::Element to represent DOM elements. The first
33
+ constructor argument is a symbol representing the tag name. For example,
34
+ you can represent a line break element like this:
17
35
 
18
36
  ```ruby
19
37
  HOM::Element.new(:br)
@@ -32,8 +50,8 @@ HOM::Element.new(:input, [{type: :text, size: 30}, :disabled])
32
50
  ```
33
51
 
34
52
  The third constructor argument is the inner content, which can be a string,
35
- another element object, or an array of child items. For example, here's how
36
- you can represent elements with attributes:
53
+ another element object, or an array of child nodes. For example, here's how
54
+ you can represent various elements with inner content:
37
55
 
38
56
  ```ruby
39
57
  span = HOM::Element.new(:span, nil, '')
@@ -47,16 +65,67 @@ link = HOM::Element.new(:a, {target: :_blank, href: '/'}, image)
47
65
  list = HOM::Element.new(:ul, nil, (1..3).map { |n| HOM::Element.new(:li, nil, n) })
48
66
  ```
49
67
 
50
- There's also a `HOM::Entity` class which you can use to represent HTML entities;
51
- integer values for numeric entities and symbol/string values for named entities,
68
+ Calling #to_s on a HOM::Element object will return a string containing the
69
+ generated HTML markup. HOM::Element objects are safe to use directly in Rails
70
+ templates, all escaping is handled automatically.
71
+
72
+
73
+ ## Using HOM::Entity
74
+
75
+ Create instances of HOM::Entity to represent HTML entities. Use an integer
76
+ argument for numeric entities and a symbol/string argument for named entities,
52
77
  for example:
53
78
 
54
79
  ```ruby
55
- HOM::Element.new(:span, nil, HOM::Entity.new(160))
80
+ HOM::Entity.new(160)
81
+
82
+ HOM::Entity.new(:nbsp)
83
+ ```
84
+
85
+
86
+ ## Using HOM::NodeList
87
+
88
+ Use HOM::NodeList to group nodes together without having to wrap them in an
89
+ outer element. For example:
90
+
91
+ ```ruby
92
+ HOM::NodeList.new(['This is a ', HOM::Element.new(:strong, nil, 'Contrived'), ' example'])
93
+ ```
94
+
95
+ Calling #to_s on a HOM::NodeList object will return a string containing the
96
+ generated HTML markup. Calling #join will insert separator nodes, a bit like
97
+ Array#join, but returning HTML safe output.
98
+
99
+
100
+ ## XSS 101
101
+
102
+ Do you have helper methods that look like this:
56
103
 
57
- HOM::Element.new(:span, nil, HOM::Entity.new(:nbsp))
104
+ ```ruby
105
+ def user_name(user)
106
+ "<strong>#{user.name}</strong>".html_safe
107
+ end
108
+ ```
109
+
110
+ Bzzzt, that's a security vulnerability right there. If you're using Rails
111
+ you should have code that looks like this:
112
+
113
+ ```ruby
114
+ def user_name(user)
115
+ content_tag(:strong, user.name)
116
+ end
117
+ ```
118
+
119
+ The content_tag helper will automatically escape content not explicitly
120
+ marked as safe. HOM will do very much the same thing, the equivalent helper
121
+ method would look like this:
122
+
123
+ ```ruby
124
+ def user_name(user)
125
+ HOM::Element.new(:strong, nil, user.name)
126
+ end
58
127
  ```
59
128
 
60
- Calling `#to_s` on a `HOM::Element` object will return a string containing
61
- the generated markup. `HOM::Element` objects are safe to use directly in
62
- Rails templates, all escaping is handled automatically.
129
+ Moral of the story: building up fragments of HTML using string interpolation
130
+ and concatenation is highly error prone. Solution: use content_tag or HOM to
131
+ safely build your content, and audit your usage of html_safe.
@@ -1,13 +1,20 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'hom'
3
- s.version = '0.4.0'
3
+ s.version = '1.3.1'
4
+ s.license = 'LGPL-3.0'
4
5
  s.platform = Gem::Platform::RUBY
5
6
  s.authors = ['Tim Craft']
6
7
  s.email = ['mail@timcraft.com']
7
- s.homepage = 'http://github.com/timcraft/hom'
8
+ s.homepage = 'https://github.com/timcraft/hom'
8
9
  s.description = 'A straightforward API for generating HTML'
9
10
  s.summary = 'See description'
10
- s.files = Dir.glob('{lib,spec}/**/*') + %w(Rakefile README.md hom.gemspec)
11
- s.add_development_dependency('activesupport', ['>= 3.0.3'])
11
+ s.files = Dir.glob('lib/**/*.rb') + %w(LICENSE.txt README.md CHANGES.md hom.gemspec)
12
+ s.required_ruby_version = '>= 1.9.3'
12
13
  s.require_path = 'lib'
14
+ s.metadata = {
15
+ 'homepage' => 'https://github.com/timcraft/hom',
16
+ 'source_code_uri' => 'https://github.com/timcraft/hom',
17
+ 'bug_tracker_uri' => 'https://github.com/timcraft/hom/issues',
18
+ 'changelog_uri' => 'https://github.com/timcraft/hom/blob/main/CHANGES.md'
19
+ }
13
20
  end
data/lib/hom.rb CHANGED
@@ -25,6 +25,10 @@ module HOM
25
25
  def html_safe?
26
26
  true
27
27
  end
28
+
29
+ def +(object)
30
+ NodeList.new([self, object])
31
+ end
28
32
  end
29
33
 
30
34
  class Element
@@ -38,9 +42,53 @@ module HOM
38
42
  @content != Undefined
39
43
  end
40
44
 
45
+ def html_safe?
46
+ true
47
+ end
48
+
49
+ def to_s
50
+ Encoding.safe_encode(self)
51
+ end
52
+
53
+ def +(object)
54
+ NodeList.new([self, object])
55
+ end
56
+ end
57
+
58
+ class NodeList
59
+ def initialize(nodes)
60
+ @nodes = Array(nodes)
61
+ end
62
+
63
+ def html_safe?
64
+ true
65
+ end
66
+
41
67
  def to_s
42
68
  Encoding.safe_encode(self)
43
69
  end
70
+
71
+ def to_a
72
+ @nodes
73
+ end
74
+
75
+ def +(object)
76
+ self.class.new(@nodes + Array(object))
77
+ end
78
+
79
+ def join(separator)
80
+ self.class.new(intersperse(separator, @nodes))
81
+ end
82
+
83
+ private
84
+
85
+ def intersperse(separator, array)
86
+ array.inject([]) do |tmp, item|
87
+ tmp << separator unless tmp.empty?
88
+ tmp << item
89
+ tmp
90
+ end
91
+ end
44
92
  end
45
93
 
46
94
  class AttributeList
@@ -80,12 +128,10 @@ module HOM
80
128
  def self.encode(object)
81
129
  if object.is_a?(Array)
82
130
  object.map { |item| encode(item) }.join
131
+ elsif object.is_a?(NodeList)
132
+ object.to_a.map { |item| encode(item) }.join
83
133
  elsif object.is_a?(Element)
84
134
  encode_element(object)
85
- elsif object.respond_to?(:html) # TODO: REMOVE ME
86
- Kernel.warn '[hom] defining #html on custom objects is deprecated, map the objects to elements instead'
87
-
88
- object.html
89
135
  elsif object.respond_to?(:html_safe?) && object.html_safe?
90
136
  object.to_s
91
137
  else
metadata CHANGED
@@ -1,32 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
5
- prerelease:
4
+ version: 1.3.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Tim Craft
9
- autorequire:
8
+ autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-09-26 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: activesupport
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: 3.0.3
22
- type: :development
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: 3.0.3
11
+ date: 2020-11-03 00:00:00.000000000 Z
12
+ dependencies: []
30
13
  description: A straightforward API for generating HTML
31
14
  email:
32
15
  - mail@timcraft.com
@@ -34,35 +17,36 @@ executables: []
34
17
  extensions: []
35
18
  extra_rdoc_files: []
36
19
  files:
37
- - lib/hom.rb
38
- - spec/element_spec.rb
39
- - spec/entity_spec.rb
40
- - Rakefile
20
+ - CHANGES.md
21
+ - LICENSE.txt
41
22
  - README.md
42
23
  - hom.gemspec
43
- homepage: http://github.com/timcraft/hom
44
- licenses: []
45
- post_install_message:
24
+ - lib/hom.rb
25
+ homepage: https://github.com/timcraft/hom
26
+ licenses:
27
+ - LGPL-3.0
28
+ metadata:
29
+ homepage: https://github.com/timcraft/hom
30
+ source_code_uri: https://github.com/timcraft/hom
31
+ bug_tracker_uri: https://github.com/timcraft/hom/issues
32
+ changelog_uri: https://github.com/timcraft/hom/blob/main/CHANGES.md
33
+ post_install_message:
46
34
  rdoc_options: []
47
35
  require_paths:
48
36
  - lib
49
37
  required_ruby_version: !ruby/object:Gem::Requirement
50
- none: false
51
38
  requirements:
52
- - - ! '>='
39
+ - - ">="
53
40
  - !ruby/object:Gem::Version
54
- version: '0'
41
+ version: 1.9.3
55
42
  required_rubygems_version: !ruby/object:Gem::Requirement
56
- none: false
57
43
  requirements:
58
- - - ! '>='
44
+ - - ">="
59
45
  - !ruby/object:Gem::Version
60
46
  version: '0'
61
47
  requirements: []
62
- rubyforge_project:
63
- rubygems_version: 1.8.24
64
- signing_key:
65
- specification_version: 3
48
+ rubygems_version: 3.1.4
49
+ signing_key:
50
+ specification_version: 4
66
51
  summary: See description
67
52
  test_files: []
68
- has_rdoc:
data/Rakefile DELETED
@@ -1,8 +0,0 @@
1
- require 'rake/testtask'
2
-
3
- task :default => :spec
4
-
5
- Rake::TestTask.new(:spec) do |t|
6
- t.test_files = FileList['spec/*_spec.rb']
7
- t.warning = true
8
- end
@@ -1,71 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'active_support/core_ext/string/output_safety'
3
-
4
- require_relative '../lib/hom'
5
-
6
- describe 'Element' do
7
- before do
8
- @br = HOM::Element.new(:br)
9
- @i1 = HOM::Element.new(:input, :disabled)
10
- @i2 = HOM::Element.new(:input, {type: :text, size: 30, value: nil})
11
- @i3 = HOM::Element.new(:input, [{type: :text, size: 30}, :disabled])
12
- @h1 = HOM::Element.new(:h1, nil, '')
13
- @h2 = HOM::Element.new(:h2, nil, 'hello world')
14
- @h3 = HOM::Element.new(:h3, nil, 'a && b, x > y')
15
- @h4 = HOM::Element.new(:h4, nil, 1234567890)
16
- @h5 = HOM::Element.new(:h5, nil, HOM::Element.new(:b, nil, 'how bold'))
17
- @h6 = HOM::Element.new(:h6, nil, nil)
18
- @ul = HOM::Element.new(:ul, nil, (1..3).map { |n| HOM::Element.new(:li, nil, n) })
19
- end
20
-
21
- describe 'content query method' do
22
- it 'should return false if the content is undefined' do
23
- @br.content?.must_equal(false)
24
- end
25
-
26
- it 'should return true otherwise' do
27
- @h1.content?.must_equal(true)
28
- end
29
- end
30
-
31
- describe 'to_s method' do
32
- it 'should return a string containing the correct markup' do
33
- @br.to_s.must_equal('<br>')
34
- @i1.to_s.must_equal('<input disabled>')
35
- @i2.to_s.must_equal('<input type="text" size="30" value="">')
36
- @i3.to_s.must_equal('<input type="text" size="30" disabled>')
37
- @h1.to_s.must_equal('<h1></h1>')
38
- @h2.to_s.must_equal('<h2>hello world</h2>')
39
- @h3.to_s.must_equal('<h3>a &amp;&amp; b, x &gt; y</h3>')
40
- @h4.to_s.must_equal('<h4>1234567890</h4>')
41
- @h5.to_s.must_equal('<h5><b>how bold</b></h5>')
42
- @h6.to_s.must_equal('<h6></h6>')
43
- @ul.to_s.must_equal('<ul><li>1</li><li>2</li><li>3</li></ul>')
44
- end
45
-
46
- it 'should not encode content that has been marked as html safe' do
47
- HOM::Element.new(:span, nil, '<br>').to_s.must_equal('<span>&lt;br&gt;</span>')
48
- HOM::Element.new(:span, nil, '<br>'.html_safe).to_s.must_equal('<span><br></span>')
49
- end
50
-
51
- it 'should return content that is marked as html safe' do
52
- @br.to_s.html_safe?.must_equal(true)
53
- end
54
- end
55
-
56
- describe 'encoding objects with an html method' do # TODO: REMOVE ME
57
- it 'should emit a deprecation warning' do
58
- require 'mocha'
59
-
60
- object = Object.new
61
-
62
- def object.html; HOM::Element.new(:span, nil, 'html') end
63
-
64
- div = HOM::Element.new(:div, nil, object)
65
-
66
- Kernel.expects(:warn).with(regexp_matches(/defining #html on custom objects is deprecated/))
67
-
68
- div.to_s.must_equal('<div><span>html</span></div>')
69
- end
70
- end
71
- end
@@ -1,75 +0,0 @@
1
- require 'minitest/autorun'
2
-
3
- require_relative '../lib/hom'
4
-
5
- describe 'Named entity' do
6
- before do
7
- @entity = HOM::Entity.new(:nbsp)
8
- end
9
-
10
- describe 'value method' do
11
- it 'should return the symbol value' do
12
- @entity.value.must_equal(:nbsp)
13
- end
14
- end
15
-
16
- describe 'numeric query method' do
17
- it 'should return false' do
18
- @entity.numeric?.must_equal(false)
19
- end
20
- end
21
-
22
- describe 'named query method' do
23
- it 'should return true' do
24
- @entity.named?.must_equal(true)
25
- end
26
- end
27
-
28
- describe 'to_s method' do
29
- it 'should return the encoded html entity' do
30
- @entity.to_s.must_equal('&nbsp;')
31
- end
32
- end
33
-
34
- describe 'html_safe query method' do
35
- it 'should return true' do
36
- @entity.html_safe?.must_equal(true)
37
- end
38
- end
39
- end
40
-
41
- describe 'Numeric entity' do
42
- before do
43
- @entity = HOM::Entity.new(160)
44
- end
45
-
46
- describe 'value method' do
47
- it 'should return the integer value' do
48
- @entity.value.must_equal(160)
49
- end
50
- end
51
-
52
- describe 'numeric query method' do
53
- it 'should return true' do
54
- @entity.numeric?.must_equal(true)
55
- end
56
- end
57
-
58
- describe 'named query method' do
59
- it 'should return false' do
60
- @entity.named?.must_equal(false)
61
- end
62
- end
63
-
64
- describe 'to_s method' do
65
- it 'should return the encoded html entity' do
66
- @entity.to_s.must_equal('&#160;')
67
- end
68
- end
69
-
70
- describe 'html_safe query method' do
71
- it 'should return true' do
72
- @entity.html_safe?.must_equal(true)
73
- end
74
- end
75
- end