htmlbeautifier 1.1.0 → 1.1.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.
- checksums.yaml +4 -4
- data/README.md +28 -7
- data/Rakefile +7 -0
- data/bin/htmlbeautifier +4 -4
- data/lib/htmlbeautifier.rb +5 -5
- data/lib/htmlbeautifier/builder.rb +37 -53
- data/lib/htmlbeautifier/html_parser.rb +38 -31
- data/lib/htmlbeautifier/parser.rb +19 -32
- data/lib/htmlbeautifier/ruby_indenter.rb +19 -0
- data/lib/htmlbeautifier/version.rb +2 -2
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b82dd8d2489286ab4474e1690d0a47ff91ffce8
|
4
|
+
data.tar.gz: e20a70c076be7e6eda31e456b0fd56715c1554ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9da8945658fddb13a0af61e5d61e05b381ffdb8168247d22fe6026043c41822cce4bce45910e844cb8f5183f01a790836a209802531cd4e13a1bbd67b0092877
|
7
|
+
data.tar.gz: 224c74e0769b2e208505cd0d1461f4c971ed9a264f2ed78bf27c6311c5fa037e40295b8beb607fed7edf114e354138805cec3e766432b9a3a8e08e0b66a86950
|
data/README.md
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
HTML Beautifier
|
2
|
-
===============
|
1
|
+
# HTML Beautifier
|
3
2
|
|
4
3
|
A normaliser/beautifier for HTML that also understands embedded Ruby.
|
5
4
|
Ideal for tidying up Rails templates.
|
6
5
|
|
7
|
-
What it does
|
8
|
-
------------
|
6
|
+
## What it does
|
9
7
|
|
10
8
|
* Normalises hard tabs to spaces
|
11
9
|
* Removes trailing spaces
|
@@ -18,8 +16,7 @@ What it does
|
|
18
16
|
* Indents the left-hand margin of JavaScript and CSS blocks to match the
|
19
17
|
indentation level of the code
|
20
18
|
|
21
|
-
Usage
|
22
|
-
-----
|
19
|
+
## Usage
|
23
20
|
|
24
21
|
### From the command line
|
25
22
|
|
@@ -35,7 +32,7 @@ or to operate on standard input and output:
|
|
35
32
|
$ htmlbeautifier < input > output
|
36
33
|
```
|
37
34
|
|
38
|
-
|
35
|
+
### In your code
|
39
36
|
|
40
37
|
```ruby
|
41
38
|
require 'htmlbeautifier'
|
@@ -48,3 +45,27 @@ You can also specify the number of spaces to indent (the default is 2):
|
|
48
45
|
```ruby
|
49
46
|
beautiful = HtmlBeautifier.beautify(messy, tab_stops: 4)
|
50
47
|
```
|
48
|
+
|
49
|
+
## Installation
|
50
|
+
|
51
|
+
This is a Ruby gem.
|
52
|
+
To install the command-line tool (you may need `sudo`):
|
53
|
+
|
54
|
+
```sh
|
55
|
+
$ gem install htmlbeautifier
|
56
|
+
```
|
57
|
+
|
58
|
+
To use the gem with Bundler, add to your `Gemfile`:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
gem 'htmlbeautifier'
|
62
|
+
```
|
63
|
+
|
64
|
+
## Contributing
|
65
|
+
|
66
|
+
1. Follow [these guidelines][git-commit] when writing commit messages (briefly,
|
67
|
+
the first line should begin with a capital letter, use the imperative mood,
|
68
|
+
be no more than 50 characters, and not end with a period).
|
69
|
+
2. Include tests.
|
70
|
+
|
71
|
+
[git-commit]:http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
data/Rakefile
CHANGED
data/bin/htmlbeautifier
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
2
|
+
require "htmlbeautifier"
|
3
|
+
require "optparse"
|
4
|
+
require "fileutils"
|
5
5
|
|
6
6
|
def beautify(name, input, output, options)
|
7
7
|
output.puts HtmlBeautifier.beautify(input, options)
|
@@ -11,7 +11,7 @@ end
|
|
11
11
|
|
12
12
|
executable = File.basename(__FILE__)
|
13
13
|
|
14
|
-
options = {:
|
14
|
+
options = { tab_stops: 2 }
|
15
15
|
parser = OptionParser.new do |opts|
|
16
16
|
opts.banner = "Usage: #{executable} [options] [file ...]"
|
17
17
|
opts.separator <<END
|
data/lib/htmlbeautifier.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "htmlbeautifier/builder"
|
2
|
+
require "htmlbeautifier/html_parser"
|
3
|
+
require "htmlbeautifier/version"
|
4
4
|
|
5
5
|
module HtmlBeautifier
|
6
|
-
|
6
|
+
#
|
7
7
|
# Returns a beautified HTML/HTML+ERB document as a String.
|
8
8
|
# html must be an object that responds to +#to_s+.
|
9
9
|
#
|
@@ -13,7 +13,7 @@ module HtmlBeautifier
|
|
13
13
|
# is false, i.e. continue to process the rest of the document.
|
14
14
|
#
|
15
15
|
def self.beautify(html, options = {})
|
16
|
-
|
16
|
+
"".tap { |output|
|
17
17
|
HtmlParser.new.scan html.to_s, Builder.new(output, options)
|
18
18
|
}
|
19
19
|
end
|
@@ -1,17 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require "htmlbeautifier/parser"
|
2
|
+
require "htmlbeautifier/ruby_indenter"
|
2
3
|
|
3
4
|
module HtmlBeautifier
|
4
5
|
class Builder
|
5
|
-
|
6
|
-
RUBY_INDENT =
|
7
|
-
%r{ ^ ( if | unless | while | begin | elsif | else )\b
|
8
|
-
| \b ( do | \{ ) ( \s* \| [^\|]+ \| )? $
|
9
|
-
}x
|
10
|
-
RUBY_OUTDENT =
|
11
|
-
%r{ ^ ( end | elsif | else |\} ) \b
|
12
|
-
}x
|
13
|
-
ELEMENT_CONTENT = %r{ (?:[^<>]|<%.*?%>)* }mx
|
14
|
-
|
15
6
|
DEFAULT_OPTIONS = {
|
16
7
|
tab_stops: 2,
|
17
8
|
stop_on_errors: false
|
@@ -19,20 +10,21 @@ module HtmlBeautifier
|
|
19
10
|
|
20
11
|
def initialize(output, options = {})
|
21
12
|
options = DEFAULT_OPTIONS.merge(options)
|
13
|
+
@tab = " " * options[:tab_stops]
|
14
|
+
@stop_on_errors = options[:stop_on_errors]
|
22
15
|
@level = 0
|
23
16
|
@new_line = false
|
24
|
-
@tab = ' ' * options[:tab_stops]
|
25
|
-
@stop_on_errors = options[:stop_on_errors]
|
26
|
-
@output = output
|
27
17
|
@empty = true
|
28
18
|
@ie_cc_levels = []
|
19
|
+
@output = output
|
20
|
+
@embedded_indenter = RubyIndenter.new
|
29
21
|
end
|
30
22
|
|
31
23
|
private
|
32
24
|
|
33
25
|
def error(text)
|
34
26
|
return unless @stop_on_errors
|
35
|
-
raise
|
27
|
+
raise text
|
36
28
|
end
|
37
29
|
|
38
30
|
def indent
|
@@ -44,75 +36,62 @@ module HtmlBeautifier
|
|
44
36
|
@level = [@level - 1, 0].max
|
45
37
|
end
|
46
38
|
|
47
|
-
def emit(
|
48
|
-
if @new_line && !@empty
|
49
|
-
|
50
|
-
end
|
51
|
-
@output << s
|
39
|
+
def emit(*strings)
|
40
|
+
@output << ("\n" + @tab * @level) if @new_line && !@empty
|
41
|
+
@output << strings.join("")
|
52
42
|
@new_line = false
|
53
43
|
@empty = false
|
54
44
|
end
|
55
45
|
|
56
|
-
def new_line(*
|
46
|
+
def new_line(*)
|
57
47
|
@new_line = true
|
58
48
|
end
|
59
49
|
|
60
50
|
def embed(opening, code, closing)
|
61
|
-
lines = code.split(
|
62
|
-
outdent if lines
|
63
|
-
emit opening
|
64
|
-
indent if lines
|
51
|
+
lines = code.split(%r{\n}).map(&:strip)
|
52
|
+
outdent if @embedded_indenter.outdent?(lines)
|
53
|
+
emit opening, code, closing
|
54
|
+
indent if @embedded_indenter.indent?(lines)
|
65
55
|
end
|
66
56
|
|
67
57
|
def foreign_block(opening, code, closing)
|
68
58
|
emit opening
|
69
|
-
unless code.strip.empty?
|
70
|
-
|
59
|
+
emit_reindented_block_content code unless code.strip.empty?
|
60
|
+
emit closing
|
61
|
+
end
|
71
62
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
indentation = lines.first[/^ +/]
|
63
|
+
def emit_reindented_block_content(code)
|
64
|
+
lines = code.strip.split(%r{\n})
|
65
|
+
indentation = lines.first[%r{^\s+}]
|
76
66
|
|
67
|
+
indent
|
68
|
+
new_line
|
69
|
+
lines.each do |line|
|
70
|
+
emit line.rstrip.sub(%r{^#{indentation}}, "")
|
77
71
|
new_line
|
78
|
-
lines.each do |line|
|
79
|
-
emit line.rstrip.sub(/^#{indentation}/, '')
|
80
|
-
new_line
|
81
|
-
end
|
82
|
-
|
83
|
-
outdent
|
84
72
|
end
|
85
|
-
|
73
|
+
outdent
|
86
74
|
end
|
87
75
|
|
88
76
|
def preformatted_block(opening, content, closing)
|
89
77
|
new_line
|
90
|
-
emit opening
|
91
|
-
emit content
|
92
|
-
emit closing
|
78
|
+
emit opening, content, closing
|
93
79
|
new_line
|
94
80
|
end
|
95
81
|
|
96
82
|
def standalone_element(e)
|
97
83
|
emit e
|
98
|
-
new_line if e =~
|
84
|
+
new_line if e =~ %r{^<br[^\w]}
|
99
85
|
end
|
100
86
|
|
101
|
-
def
|
87
|
+
def close_element(e)
|
102
88
|
outdent
|
103
89
|
emit e
|
104
|
-
new_line
|
105
90
|
end
|
106
91
|
|
107
|
-
def
|
92
|
+
def close_block_element(e)
|
93
|
+
close_element e
|
108
94
|
new_line
|
109
|
-
emit e
|
110
|
-
indent
|
111
|
-
end
|
112
|
-
|
113
|
-
def close_element(e)
|
114
|
-
outdent
|
115
|
-
emit e
|
116
95
|
end
|
117
96
|
|
118
97
|
def open_element(e)
|
@@ -120,6 +99,11 @@ module HtmlBeautifier
|
|
120
99
|
indent
|
121
100
|
end
|
122
101
|
|
102
|
+
def open_block_element(e)
|
103
|
+
new_line
|
104
|
+
open_element e
|
105
|
+
end
|
106
|
+
|
123
107
|
def close_ie_cc(e)
|
124
108
|
if @ie_cc_levels.empty?
|
125
109
|
error "Unclosed conditional comment"
|
@@ -137,7 +121,7 @@ module HtmlBeautifier
|
|
137
121
|
|
138
122
|
def text(t)
|
139
123
|
emit t.chomp
|
140
|
-
new_line if t.end_with?
|
124
|
+
new_line if t.end_with?("\n")
|
141
125
|
end
|
142
126
|
end
|
143
127
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "htmlbeautifier/parser"
|
2
2
|
|
3
3
|
module HtmlBeautifier
|
4
4
|
class HtmlParser < Parser
|
@@ -14,38 +14,45 @@ module HtmlBeautifier
|
|
14
14
|
pre | section | table | tbody | td | tfoot | th | thead | tr | ul | video
|
15
15
|
)}mix
|
16
16
|
|
17
|
+
MAPPINGS = [
|
18
|
+
[%r{(<%-?=?)(.*?)(-?%>)}om,
|
19
|
+
:embed],
|
20
|
+
[%r{<!--\[.*?\]>}om,
|
21
|
+
:open_ie_cc],
|
22
|
+
[%r{<!\[.*?\]-->}om,
|
23
|
+
:close_ie_cc],
|
24
|
+
[%r{<!--.*?-->}om,
|
25
|
+
:standalone_element],
|
26
|
+
[%r{<!.*?>}om,
|
27
|
+
:standalone_element],
|
28
|
+
[%r{(<script#{ELEMENT_CONTENT}>)(.*?)(</script>)}omi,
|
29
|
+
:foreign_block],
|
30
|
+
[%r{(<style#{ELEMENT_CONTENT}>)(.*?)(</style>)}omi,
|
31
|
+
:foreign_block],
|
32
|
+
[%r{(<pre#{ELEMENT_CONTENT}>)(.*?)(</pre>)}omi,
|
33
|
+
:preformatted_block],
|
34
|
+
[%r{(<textarea#{ELEMENT_CONTENT}>)(.*?)(</textarea>)}omi,
|
35
|
+
:preformatted_block],
|
36
|
+
[%r{<#{HTML_VOID_ELEMENTS}(?: #{ELEMENT_CONTENT})?/?>}om,
|
37
|
+
:standalone_element],
|
38
|
+
[%r{</#{HTML_BLOCK_ELEMENTS}>}om,
|
39
|
+
:close_block_element],
|
40
|
+
[%r{<#{HTML_BLOCK_ELEMENTS}(?: #{ELEMENT_CONTENT})?>}om,
|
41
|
+
:open_block_element],
|
42
|
+
[%r{</#{ELEMENT_CONTENT}>}om,
|
43
|
+
:close_element],
|
44
|
+
[%r{<#{ELEMENT_CONTENT}>}om,
|
45
|
+
:open_element],
|
46
|
+
[%r{\s*\r?\n\s*}om,
|
47
|
+
:new_line],
|
48
|
+
[%r{[^<]+},
|
49
|
+
:text]]
|
50
|
+
|
17
51
|
def initialize
|
18
52
|
super do |p|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
:open_ie_cc
|
23
|
-
p.map %r{<!\[.*?\]-->}m,
|
24
|
-
:close_ie_cc
|
25
|
-
p.map %r{<!--.*?-->}m,
|
26
|
-
:standalone_element
|
27
|
-
p.map %r{<!.*?>}m,
|
28
|
-
:standalone_element
|
29
|
-
p.map %r{(<script#{ELEMENT_CONTENT}>)(.*?)(</script>)}mi,
|
30
|
-
:foreign_block
|
31
|
-
p.map %r{(<style#{ELEMENT_CONTENT}>)(.*?)(</style>)}mi,
|
32
|
-
:foreign_block
|
33
|
-
p.map %r{(<pre#{ELEMENT_CONTENT}>)(.*?)(</pre>)}mi,
|
34
|
-
:preformatted_block
|
35
|
-
p.map %r{<#{HTML_VOID_ELEMENTS}(?: #{ELEMENT_CONTENT})?/?>}m,
|
36
|
-
:standalone_element
|
37
|
-
p.map %r{</#{HTML_BLOCK_ELEMENTS}>}m,
|
38
|
-
:close_block_element
|
39
|
-
p.map %r{<#{HTML_BLOCK_ELEMENTS}(?: #{ELEMENT_CONTENT})?>}m,
|
40
|
-
:open_block_element
|
41
|
-
p.map %r{</#{ELEMENT_CONTENT}>}m,
|
42
|
-
:close_element
|
43
|
-
p.map %r{<#{ELEMENT_CONTENT}>}m,
|
44
|
-
:open_element
|
45
|
-
p.map %r{\s*\r?\n\s*}m,
|
46
|
-
:new_line
|
47
|
-
p.map %r{[^<]+},
|
48
|
-
:text
|
53
|
+
MAPPINGS.each do |regexp, method|
|
54
|
+
p.map regexp, method
|
55
|
+
end
|
49
56
|
end
|
50
57
|
end
|
51
58
|
end
|
@@ -1,19 +1,8 @@
|
|
1
|
-
require
|
1
|
+
require "strscan"
|
2
2
|
|
3
3
|
module HtmlBeautifier
|
4
4
|
class Parser
|
5
|
-
|
6
|
-
def self.debug_block(&blk)
|
7
|
-
@debug_block = blk
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.debug(match, method)
|
11
|
-
if defined? @debug_block
|
12
|
-
@debug_block.call(match, method)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def initialize(&blk)
|
5
|
+
def initialize
|
17
6
|
@maps = []
|
18
7
|
yield self if block_given?
|
19
8
|
end
|
@@ -24,9 +13,7 @@ module HtmlBeautifier
|
|
24
13
|
|
25
14
|
def scan(subject, receiver)
|
26
15
|
@scanner = StringScanner.new(subject)
|
27
|
-
until @scanner.eos?
|
28
|
-
dispatch(receiver)
|
29
|
-
end
|
16
|
+
dispatch(receiver) until @scanner.eos?
|
30
17
|
end
|
31
18
|
|
32
19
|
def source_so_far
|
@@ -34,28 +21,28 @@ module HtmlBeautifier
|
|
34
21
|
end
|
35
22
|
|
36
23
|
def source_line_number
|
37
|
-
[source_so_far.chomp.split(
|
24
|
+
[source_so_far.chomp.split(%r{\n}).count, 1].max
|
38
25
|
end
|
39
26
|
|
40
27
|
private
|
28
|
+
|
41
29
|
def dispatch(receiver)
|
42
|
-
@maps.
|
43
|
-
|
44
|
-
|
45
|
-
i = 1
|
46
|
-
while @scanner[i]
|
47
|
-
params << @scanner[i]
|
48
|
-
i += 1
|
49
|
-
end
|
50
|
-
params = [@scanner[0]] if params.empty?
|
51
|
-
self.class.debug(@scanner[0], method)
|
52
|
-
receiver.__send__(method, *params)
|
53
|
-
return
|
54
|
-
end
|
55
|
-
end
|
56
|
-
raise "Unmatched sequence"
|
30
|
+
_, method = @maps.find { |pattern, _| @scanner.scan(pattern) }
|
31
|
+
raise "Unmatched sequence" unless method
|
32
|
+
receiver.__send__(method, *extract_params(@scanner))
|
57
33
|
rescue => ex
|
58
34
|
raise "#{ex.message} on line #{source_line_number}"
|
59
35
|
end
|
36
|
+
|
37
|
+
def extract_params(scanner)
|
38
|
+
return [scanner[0]] unless scanner[1]
|
39
|
+
params = []
|
40
|
+
i = 1
|
41
|
+
while scanner[i]
|
42
|
+
params << scanner[i]
|
43
|
+
i += 1
|
44
|
+
end
|
45
|
+
params
|
46
|
+
end
|
60
47
|
end
|
61
48
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module HtmlBeautifier
|
2
|
+
class RubyIndenter
|
3
|
+
INDENT_KEYWORDS = %w[ if elsif else unless while until begin for ]
|
4
|
+
OUTDENT_KEYWORDS = %w[ elsif else end ]
|
5
|
+
RUBY_INDENT = %r{
|
6
|
+
^ ( #{INDENT_KEYWORDS.join("|")} )\b
|
7
|
+
| \b ( do | \{ ) ( \s* \| [^\|]+ \| )? $
|
8
|
+
}xo
|
9
|
+
RUBY_OUTDENT = %r{ ^ ( #{OUTDENT_KEYWORDS.join("|")} | \} ) \b }xo
|
10
|
+
|
11
|
+
def outdent?(lines)
|
12
|
+
lines.first =~ RUBY_OUTDENT
|
13
|
+
end
|
14
|
+
|
15
|
+
def indent?(lines)
|
16
|
+
lines.last =~ RUBY_INDENT
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: htmlbeautifier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Battley
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.30.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.30.0
|
41
55
|
description: A normaliser/beautifier for HTML that also understands embedded Ruby.
|
42
56
|
email: pbattley@gmail.com
|
43
57
|
executables:
|
@@ -52,6 +66,7 @@ files:
|
|
52
66
|
- lib/htmlbeautifier/builder.rb
|
53
67
|
- lib/htmlbeautifier/html_parser.rb
|
54
68
|
- lib/htmlbeautifier/parser.rb
|
69
|
+
- lib/htmlbeautifier/ruby_indenter.rb
|
55
70
|
- lib/htmlbeautifier/version.rb
|
56
71
|
homepage: http://github.com/threedaymonk/htmlbeautifier
|
57
72
|
licenses:
|
@@ -73,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
88
|
version: '0'
|
74
89
|
requirements: []
|
75
90
|
rubyforge_project:
|
76
|
-
rubygems_version: 2.
|
91
|
+
rubygems_version: 2.4.5
|
77
92
|
signing_key:
|
78
93
|
specification_version: 4
|
79
94
|
summary: HTML/ERB beautifier
|