html-renderer 0.0.2 → 0.1.3

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: 4d2be4cf32a612a0e2fa528a0d50e85df36f732e40c408ed3183b6a041c60558
4
- data.tar.gz: 1500874bc627082bf07f2e0912ba5b2020cad6987cd9cd29c4add0abe0e5d0db
3
+ metadata.gz: d3c17a79e5d484dfafbdf2161683d28c8ee9d24b3ec099c7e392236fe167f547
4
+ data.tar.gz: 4c0cc61cc44691ab2e35b2c289f352fe17aec1d499cd01d86b6a01f4a3a9dab6
5
5
  SHA512:
6
- metadata.gz: eda1c880bebd51ed462ca2c07fcec4abfcb80cc30cc9b16b2c7366d4abc46637f3d3f778d36689e3cb6472b60fa28fda2282fea64c49262f6a4246c45468d2d9
7
- data.tar.gz: 26dec9aa2c27f6356101c92ed5aabf164249aaec89a99febbb55ecbd4aafe9db1e44d9e914344b49f4919f501cd01d568427f48e267db353d4d7952ba9f36b25
6
+ metadata.gz: 52f7781a488c72b42398dad8a8a10393a3ccc1eca7147696e94398d28633d57956133a05c026364c8125b5dfcdf333a6772ec44ee786ced02ceb130e2c6c1ce2
7
+ data.tar.gz: 228891adf55ef0e77c958399071c0eb2a4acbc2620e3681aa59b65b56bd47dc308e5cee5b968043603388cd92e44443b7906acf93963c69513d94cceafa3f0b4
data/.gemspec CHANGED
@@ -12,9 +12,10 @@ Gem::Specification.new do |s|
12
12
  s.email = "chris@ill-logic.com"
13
13
  s.authors = ["epitron"]
14
14
 
15
- s.files = `git ls`.lines.map(&:strip)
15
+ s.files = `git ls`.lines.map(&:strip)
16
16
  s.extra_rdoc_files = ["README.md", "LICENSE"]
17
-
18
- s.add_dependency "oga", "~> 2"
19
- s.add_development_dependency "ansi", "~> 1"
17
+
18
+ s.add_dependency "oga"
19
+ s.add_dependency "terminal-table", "~> 1.8"
20
+ s.add_dependency "term-ansicolor", "~> 1.7"
20
21
  end
@@ -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.2
1
+ 0.1.3
@@ -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
@@ -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)
@@ -102,7 +107,7 @@ public
102
107
  when 1 then title.bold.yellow
103
108
  when 2 then title.bold.cyan
104
109
  when 3 then title.bold.blue
105
- else title.purple
110
+ else title.magenta
106
111
  end
107
112
 
108
113
  "#{bar}\n #{title}\n#{bar}\n\n"
@@ -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)
@@ -96,6 +93,8 @@ private
96
93
  emphasis(render_children(node, state))
97
94
  when "sup"
98
95
  superscript(render_children(node, state))
96
+ when "sub"
97
+ subscript(render_children(node, state))
99
98
  when "u"
100
99
  underline(render_children(node, state))
101
100
  when "br"
@@ -118,7 +117,7 @@ private
118
117
  list_item(render_children(node, state), state.list_order)
119
118
 
120
119
  when "code"
121
- block_code(render_children(node, state))
120
+ block_code(render_children(node, state), nil)
122
121
  when "blockquote"
123
122
  block_quote(render_children(node, state))
124
123
 
@@ -149,20 +148,22 @@ private
149
148
  table(header, rows)
150
149
 
151
150
  when "html", "body", "nav", "span", "form", "label", "input", "button", "section", "fieldset",
152
- "menu", "article", "header", "time", "aside", "footer", "nobr", "wbr",
153
- "table", "tr", "td", "th", "thead", "tbody", "noscript", "select",
154
- "address"
151
+ "pre", "menu", "article", "header", "time", "aside", "footer", "nobr", "wbr",
152
+ "table", "tr", "td", "th", "tt", "thead", "tbody", "noscript", "select",
153
+ "address", "center", "small"
155
154
  render_children(node, state)
156
155
 
157
156
  when "head", "script", "link", "style"
158
- # skip it
159
-
157
+ #
158
+ # don't render anything
159
+ #
160
160
  else
161
- raise "Unrecognized HTML tag: #{node.name} -> #{node.inspect}"
161
+ # raise "Unrecognized HTML tag: #{node.name} -> #{node.inspect}"
162
+ $stderr.puts "Unrecognized HTML tag: #{node.name} -> #{node.inspect}"
163
+ render_children(node, state)
162
164
  end
163
165
 
164
- when Oga::XML::Comment
165
- # skip it
166
+ when Oga::XML::Comment, Oga::XML::Cdata
166
167
 
167
168
  else
168
169
  raise "Unhandled Oga node type: #{node.class}"
@@ -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
@@ -0,0 +1,105 @@
1
+ require 'strscan'
2
+
3
+ class Stack < Array
4
+ alias_method :top, :last
5
+ alias_method :peek, :last
6
+ end
7
+
8
+ class String
9
+ def recursive_inspect(depth)
10
+ (" "*depth)+inspect
11
+ end
12
+ end
13
+
14
+ class HTMLParser
15
+
16
+ OPEN_TAG_RE = %r{<([^>]+)>}
17
+ CLOSE_TAG_RE = %r{</([^>]+)>}
18
+ TEXT_RE = %r{[^<]+}
19
+ ATTR_RE = %r{(\w+)=(?:"([^"]+)"|'([^']+)'|(\w+))}
20
+
21
+ class Tag
22
+
23
+ attr_accessor :name, :attrs, :children
24
+
25
+ def self.from_str(s)
26
+ name, rest = s.split(/\s+/, 2)
27
+
28
+ if rest
29
+ attrs = rest.scan(HTMLParser::ATTR_RE).flatten.compact.each_slice(2).to_h
30
+ else
31
+ attrs = {}
32
+ end
33
+ new(name, attrs)
34
+ end
35
+
36
+ def initialize(name, attrs={}, children=[])
37
+ @name = name
38
+ @attrs = attrs
39
+ @children = children
40
+ end
41
+
42
+ def recursive_inspect(depth=0)
43
+ curdent = " "*depth
44
+ indent = " "*(depth+1)
45
+ "#{curdent}<#{name} #{attrs}>\n#{indent}#{children.map{|c| c.recursive_inspect(depth+1)}}\n#{curdent}</#{name}>"
46
+ end
47
+
48
+ end
49
+
50
+ def initialize(html)
51
+ @s = StringScanner.new(html)
52
+ # @s = html
53
+ end
54
+
55
+ def each_tag
56
+ until @s.eos?
57
+ if @s.scan(CLOSE_TAG_RE)
58
+ yield [:close_tag, @s.captures.first]
59
+ elsif @s.scan(OPEN_TAG_RE)
60
+ tag = Tag.from_str(@s.captures.first)
61
+ yield [:open_tag, tag]
62
+ elsif @s.scan(TEXT_RE)
63
+ yield [:text, @s.matched]
64
+ end
65
+ end
66
+ end
67
+
68
+ def as_tree
69
+ tree.map { |e| e.recursive_inspect }
70
+ end
71
+
72
+ def tree
73
+ stack = Stack.new
74
+ stack.push Tag.new("root")
75
+
76
+ each_tag do |type, elem|
77
+ case type
78
+ when :text
79
+ text = elem.strip
80
+ stack.top.children << text unless text.empty?
81
+ when :open_tag
82
+ stack.top.children << elem
83
+ stack.push elem
84
+ when :close_tag
85
+ stack.pop
86
+ else
87
+ raise "wat"
88
+ end
89
+ end
90
+
91
+ stack
92
+ end
93
+
94
+ end
95
+
96
+ unless file = ARGV.first
97
+ file = "test.html"
98
+ end
99
+
100
+ html = File.read(file)
101
+
102
+ r = HTMLParser.new(html)
103
+ r.each_tag{|t| p t}
104
+
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
File without changes
@@ -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,43 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: html-renderer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.3
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-05-22 00:00:00.000000000 Z
11
+ date: 2020-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oga
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: terminal-table
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: '2'
33
+ version: '1.8'
20
34
  type: :runtime
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: '2'
40
+ version: '1.8'
27
41
  - !ruby/object:Gem::Dependency
28
- name: ansi
42
+ name: term-ansicolor
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '1'
34
- type: :development
47
+ version: '1.7'
48
+ type: :runtime
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '1'
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.)
@@ -49,21 +63,25 @@ extra_rdoc_files:
49
63
  - LICENSE
50
64
  files:
51
65
  - ".gemspec"
66
+ - ".gitignore"
52
67
  - LICENSE
53
68
  - README.md
54
69
  - Rakefile
70
+ - TODO.md
55
71
  - VERSION
56
- - examples/ansi_renderer.rb
57
- - examples/debug_renderer.rb
58
- - examples/plain_text_renderer.rb
59
- - examples/test.html
60
72
  - lib/html-renderer.rb
73
+ - lib/html-renderer/ansi.rb
61
74
  - lib/html-renderer/base.rb
75
+ - lib/html-renderer/debug.rb
76
+ - lib/html-renderer/html_parser.rb
77
+ - lib/html-renderer/text.rb
78
+ - test/test.html
79
+ - test/test.rb
62
80
  homepage: http://github.com/epitron/html-renderer/
63
81
  licenses:
64
82
  - WTFPL
65
83
  metadata: {}
66
- post_install_message:
84
+ post_install_message:
67
85
  rdoc_options: []
68
86
  require_paths:
69
87
  - lib
@@ -78,9 +96,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
96
  - !ruby/object:Gem::Version
79
97
  version: '0'
80
98
  requirements: []
81
- rubyforge_project:
82
- rubygems_version: 2.7.6
83
- signing_key:
99
+ rubygems_version: 3.1.3
100
+ signing_key:
84
101
  specification_version: 4
85
102
  summary: HTML Renderer
86
103
  test_files: []
@@ -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