hom 0.4.0 → 1.3.1

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