html2text 0.4.0 → 0.5.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32afc21e326c44b7881358081161b9581c396b167fad44614a96cc0b6df91f23
4
- data.tar.gz: fe03a0811cbff965e6b720ad1fdfdd55c0aa1e03165c16c84de7ecac39d65c9d
3
+ metadata.gz: 1a1e6fcee8973815b391ca28bd156a878e36594e0bfbece01f7ff8c67f6cad6f
4
+ data.tar.gz: f515c6edb112deeae87f59b717aa4a2aed5d37b4b42db151fc49359f2b98d0b9
5
5
  SHA512:
6
- metadata.gz: e26ef2f826da8958c56a390bd4242461abdd26a110216ee3903c902e007b5fb26b38a8f358b420abe6eac480b4a452fedba90b75a36eb7f3f0c2bec4dad040a7
7
- data.tar.gz: 31515d14c3ca612f2eb9faaf52655639c3c0b72687fed89c41d83fad816af852854057e3ff0803e9f16e5e1d2b62657699cedef5b9240ab114826d936d0ed3c0
6
+ metadata.gz: 3972abc5f287146a5f43969fe3a37b83333559618b198ccc6ca3b105178c7cb37a03c9b44317428c8323c9b86e7e7a22a78276d9ddb7cccaab1819105e469a18
7
+ data.tar.gz: dcc2f39ebc4d772b47762cacb5de22ab16f386fbc4952c7fcf72ae66938fffcacad1fad7062714fdebc21a6b74c802224d02b796c099d2a00d1b3d13729f5d6d
data/CHANGELOG.md CHANGED
@@ -4,9 +4,19 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased]
7
+ ## [Unreleased](https://github.com/soundasleep/html2text_ruby/compare/v0.5.0...master)
8
8
 
9
- ## [0.4.0] - 2024-06-08
9
+ ## [0.5.0](https://github.com/soundasleep/html2text_ruby/compare/v0.4.0...v0.5.0) - 2026-07-08
10
+ ### Added
11
+ - Add a `wrap_links:` option to `Html2Text.convert` and `Html2Text.new` (default `true`); when `false`, hyperlinks render as `text: href` instead of markdown-style `[text](href)`. Only affects `<a href>` links — images and named anchors keep their `[bracketed]` format ([#40](https://github.com/soundasleep/html2text_ruby/pull/40))
12
+ - Specs covering subclass overrides of `prefix_whitespace`, `suffix_whitespace`, `iterate_over`, `wrap_link` and `image_text`, plus unit specs for `fix_newlines` and `replace_entities` ([#41](https://github.com/soundasleep/html2text_ruby/pull/41))
13
+
14
+ ### Changed
15
+ - Require Ruby 3.3+, since all earlier Rubies are EOL; CI now tests Ruby 3.3, 3.4 and 4.0 ([#42](https://github.com/soundasleep/html2text_ruby/pull/42))
16
+ - Reduce object allocations in `iterate_over` for ~1.6x faster conversion of large documents ([#41](https://github.com/soundasleep/html2text_ruby/pull/41))
17
+ - Update development dependencies (rubocop 1.88, nokogiri 1.19 in the lockfile), removing the transitive `rexml` dependency ([#42](https://github.com/soundasleep/html2text_ruby/pull/42))
18
+
19
+ ## [0.4.0](https://github.com/soundasleep/html2text_ruby/compare/0.3.1...v0.4.0) - 2024-06-08
10
20
  ### Added
11
21
  - Switch from Travis to Github Actions for Build and Test
12
22
  - Add rubocop for linting and cleanup existing violations ([#36](https://github.com/soundasleep/html2text_ruby/pull/36))
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- html2text ![Build](https://github.com/soundasleep/html2text_ruby/actions/workflows/build.yml/badge.svg) [![Gem Version](https://badge.fury.io/rb/html2text.svg)](https://rubygems.org/gems/html2text)
1
+ html2text ![Build](https://github.com/soundasleep/html2text_ruby/actions/workflows/build.yml/badge.svg) [![Gem Version](https://badge.fury.io/rb/html2text.svg)](https://badge.fury.io/rb/html2text)
2
2
  ---
3
3
 
4
4
  `html2text` is a very simple gem that uses DOM methods to convert HTML into a format similar to what would be
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Html2Text
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.0'
5
5
  end
data/lib/html2text.rb CHANGED
@@ -5,11 +5,12 @@ require 'nokogiri'
5
5
  class Html2Text
6
6
  attr_reader :doc
7
7
 
8
- def initialize(doc)
8
+ def initialize(doc, wrap_links: true)
9
9
  @doc = doc
10
+ @wrap_links = wrap_links
10
11
  end
11
12
 
12
- def self.convert(html)
13
+ def self.convert(html, wrap_links: true)
13
14
  html = html.to_s
14
15
 
15
16
  if office_document?(html)
@@ -27,7 +28,7 @@ class Html2Text
27
28
  html = fix_newlines(replace_entities(html))
28
29
  doc = Nokogiri::HTML(html)
29
30
 
30
- new(doc).convert
31
+ new(doc, wrap_links: wrap_links).convert
31
32
  end
32
33
 
33
34
  def self.fix_newlines(text)
@@ -50,6 +51,7 @@ class Html2Text
50
51
  end
51
52
 
52
53
  DO_NOT_TOUCH_WHITESPACE = '<do-not-touch-whitespace>'
54
+ IGNORED_TAGS = Set.new(%w[style head title meta script]).freeze
53
55
 
54
56
  def remove_leading_and_trailing_whitespace(text)
55
57
  # ignore any <pre> blocks, which we don't want to interact with
@@ -74,14 +76,14 @@ class Html2Text
74
76
  private
75
77
 
76
78
  def remove_unnecessary_empty_lines(text)
77
- text.gsub(/\n\n\n*/im, "\n\n")
79
+ text.gsub(/\n{3,}/, "\n\n")
78
80
  end
79
81
 
80
82
  def trimmed_whitespace(text)
81
83
  # Replace whitespace characters with a space (equivalent to \s)
82
84
  # and force any text encoding into UTF-8
83
85
  if text.valid_encoding?
84
- text.gsub(/[\t\n\f\r ]+/im, ' ')
86
+ text.gsub(/[\t\n\f\r ]+/, ' ')
85
87
  else
86
88
  text.force_encoding('WINDOWS-1252')
87
89
  trimmed_whitespace(text.encode('UTF-16be', invalid: :replace, replace: '?').encode('UTF-8'))
@@ -89,45 +91,36 @@ class Html2Text
89
91
  end
90
92
 
91
93
  def iterate_over(node)
92
- return "\n" if node.name.downcase == 'br' && next_node_is_text?(node)
93
-
94
94
  return trimmed_whitespace(node.text) if node.text?
95
95
 
96
- return '' if %w[style head title meta script].include?(node.name.downcase)
96
+ name = node.name&.downcase
97
97
 
98
- return "\n#{DO_NOT_TOUCH_WHITESPACE}#{node.text}#{DO_NOT_TOUCH_WHITESPACE}" if node.name.downcase == 'pre'
98
+ return '' if name.nil? || IGNORED_TAGS.include?(name)
99
99
 
100
- output = []
100
+ return "\n" if name == 'br' && next_node_is_text?(node)
101
101
 
102
- output << prefix_whitespace(node)
103
- output += node.children.map do |child|
104
- iterate_over(child) unless child.name.nil?
105
- end
106
- output << suffix_whitespace(node)
102
+ return "\n#{DO_NOT_TOUCH_WHITESPACE}#{node.text}#{DO_NOT_TOUCH_WHITESPACE}" if name == 'pre'
107
103
 
108
- output = output.compact.join || ''
104
+ return image_text(node) if name == 'img'
109
105
 
110
- unless node.name.nil?
111
- if node.name.downcase == 'a'
112
- output = wrap_link(node, output)
113
- elsif node.name.downcase == 'img'
114
- output = image_text(node)
115
- end
106
+ output = +''
107
+ output << (prefix_whitespace(node) || '')
108
+ node.children.each do |child|
109
+ output << iterate_over(child)
116
110
  end
111
+ output << (suffix_whitespace(node) || '')
112
+
113
+ output = wrap_link(node, output) if name == 'a'
117
114
 
118
115
  output
119
116
  end
120
117
 
121
- # rubocop:disable Lint/DuplicateBranch
122
118
  def prefix_whitespace(node)
123
119
  case node.name.downcase
124
120
  when 'hr'
125
121
  "\n---------------------------------------------------------------\n"
126
122
 
127
- when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul'
128
- "\n\n"
129
-
130
- when 'p'
123
+ when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', 'p'
131
124
  "\n\n"
132
125
 
133
126
  when 'tr'
@@ -147,20 +140,15 @@ class Html2Text
147
140
  '- '
148
141
  end
149
142
  end
150
- # rubocop:enable Lint/DuplicateBranch
151
143
 
152
- # rubocop:disable Lint/DuplicateBranch
153
144
  def suffix_whitespace(node)
154
145
  case node.name.downcase
155
- when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
156
- # add another line
157
- "\n\n"
158
-
159
- when 'p'
146
+ when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p'
160
147
  "\n\n"
161
148
 
162
149
  when 'br'
163
- "\n" if next_node_name(node) != 'div' && !next_node_name(node).nil?
150
+ next_name = next_node_name(node)
151
+ "\n" if !next_name.nil? && next_name != 'div'
164
152
 
165
153
  when 'li'
166
154
  "\n"
@@ -168,14 +156,14 @@ class Html2Text
168
156
  when 'div'
169
157
  if next_node_is_text?(node)
170
158
  "\n"
171
- elsif next_node_name(node) != 'div' && !next_node_name(node).nil?
172
- "\n"
159
+ else
160
+ next_name = next_node_name(node)
161
+ "\n" if !next_name.nil? && next_name != 'div'
173
162
  end
174
163
  end
175
164
  end
176
- # rubocop:enable Lint/DuplicateBranch
177
165
 
178
- # links are returned in [text](link) format
166
+ # links are returned in [text](link) format, or "text: link" with wrap_links: false
179
167
  def wrap_link(node, output)
180
168
  href = node.attribute('href')
181
169
  name = node.attribute('name')
@@ -202,6 +190,8 @@ class Html2Text
202
190
  href != "http://#{output}" && href != "https://#{output}"
203
191
  output = if output.empty?
204
192
  href
193
+ elsif !@wrap_links
194
+ "#{output}: #{href}"
205
195
  else
206
196
  "[#{output}](#{href})"
207
197
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html2text
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jevon Wright
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-06-08 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: nokogiri
@@ -159,7 +158,6 @@ licenses:
159
158
  - MIT
160
159
  metadata:
161
160
  rubygems_mfa_required: 'true'
162
- post_install_message:
163
161
  rdoc_options: []
164
162
  require_paths:
165
163
  - lib
@@ -167,15 +165,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
167
165
  requirements:
168
166
  - - ">="
169
167
  - !ruby/object:Gem::Version
170
- version: '3.0'
168
+ version: '3.3'
171
169
  required_rubygems_version: !ruby/object:Gem::Requirement
172
170
  requirements:
173
171
  - - ">="
174
172
  - !ruby/object:Gem::Version
175
173
  version: '0'
176
174
  requirements: []
177
- rubygems_version: 3.5.9
178
- signing_key:
175
+ rubygems_version: 4.0.10
179
176
  specification_version: 4
180
177
  summary: Convert HTML into plain text.
181
178
  test_files: []