html-renderer 0.0.4 → 0.1.4

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: ef89dd4c00345deca8c54a7ac62823dd8a506a0f941186cdd6d82ebd51ae7d47
4
- data.tar.gz: 4a2fd1e8b670ff87fd63b7e94a7e50af7bd66e73f94bb48b197b9f8374b8d196
3
+ metadata.gz: 663966745c8218ad48bbe7d05b18a2c3b28e744de5f29e1749206e636957c2e6
4
+ data.tar.gz: fde2480e07086d500cf4cd47fe15b3f5093d704bac2a0eca6fee2e1a47ddb77b
5
5
  SHA512:
6
- metadata.gz: b0dd0122febdc3018b1d2d1f38cd6fc19c23e2495989b6b8ccca1f5e7cf096d159a38aa85fdb600f48767d75827ce6f025282a9b0a206e74aa93c60e5c02bedc
7
- data.tar.gz: 8164fb8d54a3f2895bb288d32eb9e03716ff8bd3a40b68382385c499cae363c1d0ff685f77abeac96a83c0b313edfd9c9c3b013173d878ac46b155b28b84466c
6
+ metadata.gz: f260e527a4ea41de4c6d2a9bbef83054925c53a5d9243824fbb94f452a44ebd4a65df7df488299f38c36244a64e44654f3c64b8b2718f2461bcc45e5e3fa446e
7
+ data.tar.gz: e70eea4c85614825128afebd9d1cf77d9ac39d9676cc45103ee3e2bae0054f4ed261009848cda2c930a1296569225b21c2af8766fa609999c4ccd92ed2676061
data/.gemspec CHANGED
@@ -13,10 +13,9 @@ Gem::Specification.new do |s|
13
13
  s.authors = ["epitron"]
14
14
 
15
15
  s.files = `git ls`.lines.map(&:strip)
16
- s.executables = ['html2ansi']
17
16
  s.extra_rdoc_files = ["README.md", "LICENSE"]
18
-
19
- s.add_dependency "oga", "~> 2"
17
+
18
+ s.add_dependency "oga", ">= 2.0"
20
19
  s.add_dependency "terminal-table", "~> 1.8"
21
- # s.add_development "ansi", "~> 1"
20
+ s.add_dependency "term-ansicolor", "~> 1.7"
22
21
  end
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ /pkg/
data/README.md CHANGED
@@ -2,11 +2,29 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- Allows you to subclass `HTMLRenderer::Base`, add some methods, and then parse HTML to generate custom output.
5
+ An extensible HTML renderer.
6
6
 
7
- (Uses a similar API to the [RedCarpet](https://github.com/vmg/redcarpet) gem.)
7
+ Comes with two built-in renderers:
8
+ * `HTMLRenderer::ANSI` (outputs colored text to the termnial)
9
+ * `HTMLRenderer::Text` (outputs plain text)
8
10
 
9
- ## Examples
11
+ ## Usage
10
12
 
11
- * [HTML to Plain Text Renderer](https://github.com/epitron/html-renderer/blob/master/examples/plain_text_renderer.rb)
12
- * [HTML to ANSI Renderer](https://github.com/epitron/html-renderer/blob/master/examples/ansi_renderer.rb)
13
+ Render to ANSI:
14
+ ```
15
+ ansi_text = HTMLRenderer::ANSI.render("<b>hello html</b>")
16
+ ansi_text = HTMLRenderer::ANSI.render(open("file.html"))
17
+ ```
18
+
19
+ Render to plain text:
20
+ ```
21
+ plain_text = HTMLRenderer::Text.render(open("file.html"))
22
+ ```
23
+
24
+ ## Extending it
25
+
26
+ The API design uses the same philosophy as [RedCarpet](https://github.com/vmg/redcarpet).
27
+
28
+ To create a new renderer, subclass `HTMLRenderer::Base`, then add a method to handle each type of element. Whatever the method returns is output by the renderer.
29
+
30
+ Example renderer: [HTMLRenderer::ANSI](https://github.com/epitron/html-renderer/blob/master/lib/html-renderer/ansi.rb)
data/Rakefile CHANGED
@@ -1,14 +1,13 @@
1
- pkgname = "html-renderer"
2
- gem_version = File.read("VERSION").strip
1
+ gem = eval(File.read '.gemspec')
3
2
 
4
- gemfile = "#{pkgname}-#{gem_version}.gem"
3
+ gemfile = "#{gem.name}-#{gem.version}.gem"
5
4
 
6
5
  task :build do
7
6
  system "gem build .gemspec"
8
7
  system "mkdir pkg/" unless File.directory? "pkg"
9
8
  system "mv #{gemfile} pkg/"
10
9
  end
11
-
10
+
12
11
  task :release => :build do
13
12
  system "gem push pkg/#{gemfile}"
14
13
  end
@@ -18,3 +17,9 @@ task :gem => :build
18
17
  task :install => :build do
19
18
  system "gem install pkg/#{gemfile}"
20
19
  end
20
+
21
+ task :test do
22
+ Dir.chdir "test"
23
+ $: << "../lib"
24
+ load "test.rb"
25
+ end
data/TODO.md ADDED
@@ -0,0 +1,14 @@
1
+ # TODO list
2
+
3
+ ## Base class
4
+
5
+ ! add HTMLRenderer.reflow_paragraph
6
+ * #render takes options (and passes them to subclasses)
7
+ * :debug option (hide parse errors unless 'true')
8
+
9
+ ## ANSI renderer
10
+
11
+ * use HTMLRenderer.reflow_paragraph
12
+ * :wrap option (with optional terminal width)
13
+ * Better table renderer (with line-drawing)
14
+ * Follow `<table>` style attributes when drawing tables (eg: borders)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.1.4
@@ -1,16 +1,24 @@
1
1
  require 'html-renderer'
2
2
  require 'ansi/mixin'
3
3
  require 'terminal-table'
4
- require 'coderay'
5
4
 
6
- class String
7
- include ANSI::Mixin
5
+ ###########################################################################
8
6
 
9
- def grey; self.black.bold; end
7
+ module ANSI::Mixin
8
+ def grey; ANSI::Code.bold { ANSI::Code.black { to_s } }; end
10
9
  end
11
10
 
11
+ module HTMLRenderer::ANSIStrings
12
+ refine String do
13
+ include ANSI::Mixin
14
+ end
15
+ end
16
+
17
+ ###########################################################################
18
+
19
+ class HTMLRenderer::ANSI < HTMLRenderer::Base
12
20
 
13
- class ANSIRenderer < HTMLRenderer::Base
21
+ using HTMLRenderer::ANSIStrings
14
22
 
15
23
  private
16
24
 
@@ -32,6 +40,9 @@ private
32
40
  s&.downcase&.scan(/\w+/)&.join
33
41
  end
34
42
 
43
+ def subscript(s)
44
+ "[#{s}]"
45
+ end
35
46
 
36
47
  public
37
48
 
@@ -78,13 +89,7 @@ public
78
89
  end
79
90
 
80
91
  def block_code(code, language)
81
- language ||= :ruby
82
-
83
- language = language[1..-1] if language[0] == "." # strip leading "."
84
- language = :cpp if language == "C++"
85
-
86
- require 'coderay'
87
- "#{indent CodeRay.scan(code, language).term, 4}\n"
92
+ code.bold.cyan + "\n"
88
93
  end
89
94
 
90
95
  def block_quote(text)
@@ -174,7 +179,8 @@ public
174
179
 
175
180
  end
176
181
 
182
+ ###########################################################################
177
183
 
178
184
  if __FILE__ == $0
179
- puts ANSIRenderer.render(open(ARGV.first || "test.html"))
185
+ puts HTMLRenderer::ANSI.render(open(ARGV.first || "test.html"))
180
186
  end
@@ -1,30 +1,25 @@
1
1
  ######################################################################################
2
2
  require 'oga'
3
3
  ######################################################################################
4
- #
5
- # TODOs:
6
- # - Streaming output (yield every paragraph/div/header)
7
- # - Embed into 'c' tool (for rendering raw HTML blocks)
8
- #
9
- ######################################################################################
10
-
11
- class String
12
4
 
13
- def tighten
14
- gsub(/\s+/, ' ').strip
15
- end
5
+ module HTMLRenderer
16
6
 
17
- def blank?; !!self[/[^\s]/]; end
7
+ module STDLIBRefinements
8
+ refine String do
9
+ def tighten
10
+ gsub(/\s+/, ' ').strip
11
+ end
18
12
 
19
- end
13
+ def blank?; !!self[/[^\s]/]; end
14
+ end
20
15
 
21
- class NilClass
22
- def blank?; true; end
23
- end
16
+ refine NilClass do
17
+ def blank?; true; end
18
+ end
19
+ end
24
20
 
25
- ######################################################################################
21
+ using STDLIBRefinements
26
22
 
27
- module HTMLRenderer
28
23
 
29
24
  class State
30
25
  attr_accessor :list_order
@@ -65,14 +60,16 @@ private
65
60
  content.blank? ? normal_text(content) : nil
66
61
 
67
62
  when Oga::XML::Element
68
- case node.name
63
+ case node.name.downcase
69
64
  when "a"
70
65
  url = node["href"]
71
66
  title = node["title"]
72
67
  name = node["name"]
73
68
  content = render_children(node, state)
74
69
 
75
- if name and not url
70
+ if title.blank? and url.blank? and name.blank?
71
+ content
72
+ elsif name and not url
76
73
  anchor(name, title, content)
77
74
  else
78
75
  link(url, title, content)
@@ -151,23 +148,25 @@ private
151
148
  table(header, rows)
152
149
 
153
150
  when "html", "body", "nav", "span", "form", "label", "input", "button", "section", "fieldset",
154
- "menu", "article", "header", "time", "aside", "footer", "nobr", "wbr",
151
+ "pre", "menu", "article", "header", "time", "aside", "footer", "nobr", "wbr",
155
152
  "table", "tr", "td", "th", "tt", "thead", "tbody", "noscript", "select",
156
153
  "address", "center", "small"
157
154
  render_children(node, state)
158
155
 
159
156
  when "head", "script", "link", "style"
160
- # skip it
161
-
157
+ #
158
+ # don't render anything
159
+ #
162
160
  else
163
161
  # raise "Unrecognized HTML tag: #{node.name} -> #{node.inspect}"
164
- $stderr.puts "Unrecognized HTML tag: #{node.name} -> #{node.inspect}"
162
+ $stderr.puts "Unrecognized HTML tag: #{node.name} -> #{node.inspect}" if $VERBOSE
165
163
  render_children(node, state)
166
164
  end
167
165
 
168
- when Oga::XML::Comment
169
- # skip it
170
-
166
+ when Oga::XML::Comment, Oga::XML::Cdata, Oga::XML::ProcessingInstruction
167
+ #
168
+ # i'm not sure why you'd care about these, but here's a place to, if you do
169
+ #
171
170
  else
172
171
  raise "Unhandled Oga node type: #{node.class}"
173
172
  end
@@ -0,0 +1,9 @@
1
+ require 'html-renderer'
2
+
3
+ class HTMLRenderer::DebugRenderer < HTMLRenderer::Base
4
+
5
+ def method_missing(meth, *args)
6
+ "#{meth}(#{args})"
7
+ end
8
+
9
+ end
@@ -102,4 +102,4 @@ html = File.read(file)
102
102
  r = HTMLParser.new(html)
103
103
  r.each_tag{|t| p t}
104
104
 
105
- # puts r.as_tree
105
+ # puts r.as_tree
@@ -1,9 +1,10 @@
1
1
  require 'html-renderer'
2
2
 
3
3
  #
4
- # Everything-stripping renderer.
4
+ # Strips out everything but the plain text.
5
5
  #
6
- class PlainTextRenderer < HTMLRenderer::Base
6
+ class HTMLRenderer::Text < HTMLRenderer::Base
7
+
7
8
  # Methods where the first argument is the text content
8
9
  [
9
10
  # block-level calls
@@ -65,8 +66,3 @@ class PlainTextRenderer < HTMLRenderer::Base
65
66
  content + "\t"
66
67
  end
67
68
  end
68
-
69
-
70
- if __FILE__ == $0
71
- puts PlainTextRenderer.render(open("test.html"))
72
- end
data/lib/html-renderer.rb CHANGED
@@ -1 +1,6 @@
1
1
  require 'html-renderer/base'
2
+
3
+ module HTMLRenderer
4
+ autoload :ANSI, 'html-renderer/ansi'
5
+ autoload :Text, 'html-renderer/text'
6
+ end
File without changes
data/test/test.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'html-renderer'
2
+ require 'html-renderer/debug'
3
+
4
+ [
5
+ HTMLRenderer::ANSI,
6
+ HTMLRenderer::Text,
7
+ HTMLRenderer::DebugRenderer,
8
+ ].each do |renderer|
9
+ puts
10
+ puts "=== #{renderer} =============================="
11
+ puts
12
+ puts renderer.render(open("test.html"))
13
+ puts
14
+ puts
15
+ end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html-renderer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - epitron
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-05 00:00:00.000000000 Z
11
+ date: 2021-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oga
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '2'
19
+ version: '2.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '2'
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: terminal-table
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,35 +38,50 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: term-ansicolor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
41
55
  description: Easily implement an HTML renderer by creating a subclass and adding some
42
56
  methods, similar to RedCarpet. (Examples are included for rendering HTML to ANSI
43
57
  and plain text.)
44
58
  email: chris@ill-logic.com
45
- executables:
46
- - html2ansi
59
+ executables: []
47
60
  extensions: []
48
61
  extra_rdoc_files:
49
62
  - README.md
50
63
  - LICENSE
51
64
  files:
52
65
  - ".gemspec"
66
+ - ".gitignore"
53
67
  - LICENSE
54
68
  - README.md
55
69
  - Rakefile
70
+ - TODO.md
56
71
  - VERSION
57
- - bin/html2ansi
58
- - examples/ansi_renderer.rb
59
- - examples/debug_renderer.rb
60
- - examples/plain_text_renderer.rb
61
- - examples/test.html
62
72
  - lib/html-renderer.rb
73
+ - lib/html-renderer/ansi.rb
63
74
  - lib/html-renderer/base.rb
75
+ - lib/html-renderer/debug.rb
64
76
  - lib/html-renderer/html_parser.rb
77
+ - lib/html-renderer/text.rb
78
+ - test/test.html
79
+ - test/test.rb
65
80
  homepage: http://github.com/epitron/html-renderer/
66
81
  licenses:
67
82
  - WTFPL
68
83
  metadata: {}
69
- post_install_message:
84
+ post_install_message:
70
85
  rdoc_options: []
71
86
  require_paths:
72
87
  - lib
@@ -81,9 +96,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
96
  - !ruby/object:Gem::Version
82
97
  version: '0'
83
98
  requirements: []
84
- rubyforge_project:
85
- rubygems_version: 2.7.7
86
- signing_key:
99
+ rubygems_version: 3.2.21
100
+ signing_key:
87
101
  specification_version: 4
88
102
  summary: HTML Renderer
89
103
  test_files: []
data/bin/html2ansi DELETED
@@ -1,248 +0,0 @@
1
- #!/usr/bin/env ruby
2
- #######################################################################################
3
- require 'html-renderer'
4
- require 'terminal-table'
5
- require 'term/ansicolor'
6
- require 'coderay'
7
- #######################################################################################
8
-
9
- class String
10
- # include ANSI::Mixin
11
- include Term::ANSIColor
12
-
13
- def grey; self.black.bold; end
14
- end
15
-
16
- #######################################################################################
17
-
18
- def lesspipe(*args)
19
- if args.any? and args.last.is_a?(Hash)
20
- options = args.pop
21
- else
22
- options = {}
23
- end
24
-
25
- output = args.first if args.any?
26
-
27
- params = []
28
- params << "-R" unless options[:color] == false
29
- params << "-S" unless options[:wrap] == true
30
- params << "-F" unless options[:always] == true
31
- if options[:tail] == true
32
- params << "+\\>"
33
- $stderr.puts "Seeking to end of stream..."
34
- end
35
- params << "-X"
36
-
37
- IO.popen("less #{params * ' '}", "w") do |less|
38
- if output
39
- less.puts output
40
- else
41
- yield less
42
- end
43
- end
44
- rescue Errno::EPIPE, Interrupt
45
- # less just quit -- eat the exception.
46
- end
47
-
48
- #######################################################################################
49
-
50
- class ANSIRenderer < HTMLRenderer::Base
51
-
52
- private
53
-
54
- def indented?(text)
55
- indent_sizes = text.lines.map{ |line| if line =~ /^(\s+)/ then $1 else '' end }.map(&:size)
56
- indent_sizes.all? {|dent| dent > 0 }
57
- end
58
-
59
- def unwrap(text)
60
- return text unless indented? text
61
- text.lines.to_a.map(&:strip).join ' '
62
- end
63
-
64
- def indent(text,amount=2)
65
- text.lines.map{|line| " "*amount + line }.join
66
- end
67
-
68
- def smash(s)
69
- s&.downcase&.scan(/\w+/)&.join
70
- end
71
-
72
- def subscript(s)
73
- "[#{s}]"
74
- end
75
-
76
- public
77
-
78
- def normal_text(text)
79
- text
80
- end
81
-
82
- def underline(content)
83
- content.magenta.bold
84
- end
85
-
86
- def superscript(content)
87
- "^(#{content})"
88
- end
89
-
90
- def link(link, title, content)
91
- unless content&.[] /^Back /
92
- str = ""
93
- # str += "<15>#{content}</15>" if content
94
- str += content.white.bold if content
95
- if smash(link) != smash(content)
96
- # str += " <8>(</8><11>#{link}</11><8>)</8>"
97
- str += " #{"(".grey}#{link&.cyan&.bold}#{")".grey}"
98
- end
99
-
100
- str
101
- end
102
- end
103
-
104
- def anchor(name, title=nil, content=nil)
105
- result = "Anchor: ##{name}"
106
- result << " (#{title})" if title
107
- result << "\n"
108
- result << "#{content}\n" if content
109
- result
110
- end
111
-
112
- def image(link, title, content)
113
- link(link, nil, title)
114
- end
115
-
116
- def italic(text)
117
- text.yellow.bold
118
- end
119
-
120
- def block_code(code, language)
121
- language ||= :ruby
122
-
123
- language = language[1..-1] if language[0] == "." # strip leading "."
124
- language = :cpp if language == "C++"
125
-
126
- require 'coderay'
127
- "#{indent CodeRay.scan(code, language).term, 4}\n"
128
- end
129
-
130
- def block_quote(text)
131
- indent paragraph(text)
132
- end
133
-
134
- def codespan(code)
135
- code.cyan
136
- end
137
-
138
- def header(title, level, anchor=nil)
139
- bar = ("-"*(title.size+4)).grey
140
-
141
- title = case level
142
- when 1 then title.bold.yellow
143
- when 2 then title.bold.cyan
144
- when 3 then title.bold.blue
145
- else title.magenta
146
- end
147
-
148
- "#{bar}\n #{title}\n#{bar}\n\n"
149
- end
150
-
151
- def double_emphasis(text)
152
- text.bold.green
153
- end
154
-
155
- def emphasis(text)
156
- text.green
157
- end
158
-
159
- def linebreak
160
- "\n"
161
- end
162
-
163
- def paragraph(text)
164
- div(text) + "\n"
165
- end
166
-
167
- def div(text)
168
- "#{indented?(text) ? text : unwrap(text)}\n"
169
- end
170
-
171
- def list(content, list_type)
172
- case list_type
173
- when :ordered
174
- @counter = 0
175
- "#{content}\n"
176
- when :unordered
177
- "#{content}\n"
178
- end
179
- end
180
-
181
- def list_item(content, list_type)
182
- case list_type
183
- when :ordered
184
- @counter ||= 0
185
- @counter += 1
186
- # " <8>#{@counter}.</8> #{content.strip}\n".colorize
187
- " #{@counter.to_s.grey}. #{content.strip}\n"
188
- when :unordered
189
- # " <8>*</8> #{content.strip}\n".colorize
190
- " #{"*".grey} #{content.strip}\n"
191
- end
192
- end
193
-
194
- def definition_list(defs)
195
- defs.each do |dt, dd|
196
- puts "<15>#{dt}<7>:".colorize
197
- puts " #{dd}"
198
- puts
199
- end
200
- end
201
-
202
- def table(header, rows)
203
- if header
204
- table = Terminal::Table.new(headings: header, rows: rows)
205
- else
206
- table = Terminal::Table.new(rows: rows)
207
- end
208
- "#{table}\n\n"
209
- end
210
-
211
- def separator
212
- "_____________________________\n\n"
213
- end
214
-
215
- end
216
-
217
- #######################################################################################
218
-
219
- def render(stream, paged=false)
220
- output = ANSIRenderer.render(stream)
221
- if paged
222
- lesspipe { |less| less.puts output }
223
- else
224
- puts output
225
- end
226
- end
227
-
228
- #######################################################################################
229
-
230
- opts, args = ARGV.partition { |arg| arg[/^--?\w/] }
231
-
232
- if opts.include?("-h") or opts.include?("--help")
233
- puts "usage:"
234
- puts " html2ansi [options] <file.html>"
235
- puts " or"
236
- puts " curl http://host/path.html | html2ansi [options]"
237
- puts
238
- puts "options:"
239
- puts " -p Paged (redirect output to less)"
240
- puts
241
- else
242
- paged = opts.include?("-p") or opts.include?("--paged")
243
- if args.empty?
244
- render($stdin, paged)
245
- else
246
- args.each { |arg| render(open(arg), paged) }
247
- end
248
- end
@@ -1,14 +0,0 @@
1
- require 'html-renderer'
2
-
3
- class DebugRenderer < HTMLRenderer::Base
4
-
5
- def method_missing(meth, *args)
6
- "#{meth}(#{args})"
7
- end
8
-
9
- end
10
-
11
-
12
- if __FILE__ == $0
13
- puts DebugRenderer.render(open("test.html"))
14
- end