html_press 0.0.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.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ /.project
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in html_press.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/Readme.md ADDED
@@ -0,0 +1,66 @@
1
+ #html_press
2
+
3
+ ## Alternatives
4
+
5
+ ###Ruby
6
+
7
+ - https://github.com/completelynovel/html_compressor
8
+ - https://github.com/MadRabbit/frontcompiler
9
+
10
+ ###Other
11
+
12
+ - http://code.google.com/p/htmlcompressor/
13
+ - smarty `strip` tag
14
+ - W3 total cache (WP plugin from smashingmagazine contains html minifier)
15
+
16
+ ## TODO
17
+
18
+ - bin
19
+ - Support other minifiers (Closure, YUI compressor)
20
+ - htmlTydi
21
+
22
+ ## Usage
23
+
24
+ ### Jekyll
25
+
26
+ Gemfile
27
+
28
+ ```ruby
29
+ gem "jekyll"
30
+ gem "html_press"
31
+ ```
32
+
33
+ _plugins/strip_tag.rb
34
+
35
+ ```ruby
36
+ module Jekyll
37
+ class StripTag < Liquid::Block
38
+ begin
39
+ require 'html_press'
40
+ def render(context)
41
+ text = super
42
+ HtmlPress.compress text
43
+ end
44
+ rescue LoadError => e
45
+ p "Unable to load 'html_press'"
46
+ end
47
+ end
48
+ end
49
+
50
+ Liquid::Template.register_tag('strip', Jekyll::StripTag)
51
+ ```
52
+
53
+ In templates
54
+
55
+ ```liquid
56
+ {% strip %}
57
+ here goes text...
58
+ {% endstrip %}
59
+ ```
60
+
61
+ Run
62
+
63
+ ```
64
+ bundle install
65
+ bundle exec jelyll
66
+ ```
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "html_press/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "html_press"
7
+ s.version = HtmlPress::VERSION
8
+ s.authors = ["stereobooster"]
9
+ s.email = ["stereobooster@gmail.com"]
10
+ s.homepage = "https://github.com/stereobooster/html_press"
11
+ s.summary = %q{Compress html}
12
+ s.description = %q{Ruby gem for compressing html}
13
+
14
+ s.rubyforge_project = "html_press"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # s.add_dependency "nokogiri"
22
+
23
+ s.add_development_dependency "rspec"
24
+ s.add_development_dependency "rake"
25
+
26
+ s.add_runtime_dependency "rainpress"
27
+ s.add_runtime_dependency "uglifier"
28
+ end
@@ -0,0 +1,181 @@
1
+ module HtmlPress
2
+ class Html
3
+
4
+ def self.compress text
5
+ Html.new.compile text
6
+ end
7
+
8
+ def compile (html)
9
+
10
+ out = html + ""
11
+
12
+ @replacement_hash = 'MINIFYHTML' + Time.now.to_i.to_s
13
+ @placeholders = []
14
+ @strip_crlf = false
15
+
16
+ # replace SCRIPTs (and minify) with placeholders
17
+ out.gsub! /\s*(<script\b[^>]*?>[\s\S]*?<\/script>)\s*/i do |m|
18
+ m.gsub!(/^\s+|\s+$/, '')
19
+ js = m.gsub(/\s*<script\b[^>]*?>([\s\S]*?)<\/script>\s*/i , "\\1")
20
+ begin
21
+ js_compressed = HtmlPress.js_compressor js
22
+ m.gsub!(js, js_compressed)
23
+ rescue Exception => e
24
+ # p e.message
25
+ end
26
+ reserve m
27
+ end
28
+
29
+ # replace STYLEs (and minify) with placeholders
30
+ out.gsub! /\s*(<style\b[^>]*?>[\s\S]*?<\/style>)\s*/i do |m|
31
+ m.gsub!(/^\s+|\s+$/, '')
32
+ css = m.gsub(/\s*<style\b[^>]*?>([\s\S]*?)<\/style>\s*/i, "\\1")
33
+ begin
34
+ css_compressed = HtmlPress.css_compressor css
35
+ m.gsub!(css, css_compressed)
36
+ rescue Exception => e
37
+ # p e.message
38
+ end
39
+ reserve m
40
+ end
41
+
42
+ # IE conditional comments
43
+ out.gsub! /\s*(<!--\[[^\]]+\]>[\s\S]*?<!\[[^\]]+\]-->)\s*/ do |m|
44
+ m.gsub!(/^\s+|\s+$/, '')
45
+ comment = m.gsub(/\s*<!--\[[^\]]+\]>([\s\S]*?)<!\[[^\]]+\]-->\s*/, "\\1")
46
+ comment_compressed = Html.new.compile(comment)
47
+ m.gsub!(comment, comment_compressed)
48
+ reserve m
49
+ end
50
+
51
+ # remove out comments (not containing IE conditional comments).
52
+ out.gsub! /<!--([\s\S]*?)-->/ do |m|
53
+ ''
54
+ end
55
+
56
+ # replace PREs with placeholders
57
+ out.gsub! /\s*(<pre\b[^>]*?>[\s\S]*?<\/pre>)\s*/i do |m|
58
+ pre = m.gsub(/\s*<pre\b[^>]*?>([\s\S]*?)<\/pre>\s*/i, "\\1")
59
+ pre_compressed = pre.gsub(/\s+$/, '')
60
+ m.gsub!(pre, pre_compressed)
61
+ reserve m
62
+ end
63
+
64
+ # replace TEXTAREAs with placeholders
65
+ out.gsub! /\s*(<textarea\b[^>]*?>[\s\S]*?<\/textarea>)\s*/i do |m|
66
+ reserve m
67
+ end
68
+
69
+ # trim each line.
70
+ # @todo take into account attribute values that span multiple lines.
71
+ out.gsub!(/^\s+|\s+$/m, '')
72
+
73
+ re = '\\s+(<\\/?(?:area|base(?:font)?|blockquote|body' +
74
+ '|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form' +
75
+ '|frame(?:set)?|h[1-6]|head|hr|out|legend|li|link|map|menu|meta' +
76
+ '|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h|r|foot|itle)' +
77
+ '|ul)\\b[^>]*>)'
78
+
79
+ re = Regexp.new(re)
80
+ out.gsub!(re, '\\1')
81
+
82
+ # remove ws outside of all elements
83
+ out.gsub! />([^<]+)</ do |m|
84
+ m.gsub(/^\s+|\s+$/, ' ')
85
+ end
86
+
87
+ # use newlines before 1st attribute in open tags (to limit line lengths)
88
+ # out.gsub!(/(<[a-z\-:]+)\s+([^>]+>)/i, "\\1\n\\2")
89
+
90
+ # match attributes
91
+ out.gsub! /<[a-z\-:]+\s([^>]+)>/i do |m|
92
+ reserve attrs(m, '[a-z\-:]+', true)
93
+ end
94
+
95
+ out.gsub!(/[\r\n]+/, @strip_crlf ? ' ' : "\n")
96
+
97
+ out.gsub!(/\s+/, ' ')
98
+
99
+ # fill placeholders
100
+ re = Regexp.new('%' + @replacement_hash + '%(\d+)%')
101
+ out.gsub! re do |m|
102
+ m.gsub!(re, "\\1")
103
+ @placeholders[m.to_i]
104
+ end
105
+
106
+ out
107
+ end
108
+
109
+ def reserve(content)
110
+ @placeholders.push content
111
+ '%' + @replacement_hash + '%' + (@placeholders.size - 1).to_s + '%'
112
+ end
113
+
114
+ def attrs (m, tag_name, r)
115
+ re = "<(" + tag_name + ")(\s[^>]+)?>"
116
+ re = Regexp.new(re, true)
117
+ attributes = m.gsub(re, "\\2")
118
+ if r
119
+ tag = m.gsub(re, "\\1")
120
+ else
121
+ tag = tag_name
122
+ end
123
+
124
+ if attributes.size > 0
125
+ attributes_compressed = attributes.gsub(/\s*([a-z\-_]+(="[^"]*")?(='[^']*')?)\s*/i, " \\1")
126
+
127
+ attributes_compressed.gsub! /([a-z\-_]+="[^"]*")/ do |k|
128
+ attr k, "\"", tag
129
+ end
130
+
131
+ attributes_compressed.gsub! /([a-z\-_]+='[^']*')/ do |k|
132
+ attr k, "'", tag
133
+ end
134
+
135
+ return m.gsub(attributes, attributes_compressed)
136
+ end
137
+
138
+ return m
139
+ end
140
+
141
+ def attr(attribute, delimiter, tag)
142
+ re = "([a-z\\-_]+)(=" + delimiter + "[^" + delimiter + "]*" + delimiter + ")?"
143
+ re = Regexp.new re
144
+ value = attribute.gsub(re, "\\2")
145
+
146
+ if tag == "script"
147
+ name = attribute.gsub(re, "\\1")
148
+ if name == "type" || name == "language"
149
+ return ""
150
+ end
151
+ end
152
+
153
+ if value.size != 0
154
+
155
+ name = attribute.gsub(re, "\\1")
156
+
157
+ re = "^=" + delimiter + "|" + delimiter + "$"
158
+ re = Regexp.new re
159
+ value.gsub!(re, "")
160
+
161
+ if name == "style"
162
+ value = HtmlPress.css_compressor value
163
+ end
164
+
165
+ if name == "class"
166
+ value.gsub!(/\s+/, " ")
167
+ value.gsub!(/^\s+|\s+$/, "")
168
+ end
169
+
170
+ # if name == "onclick"
171
+ # value = HtmlPress.js_compressor value
172
+ # end
173
+
174
+ attribute = name + "=" + delimiter + value + delimiter
175
+ end
176
+
177
+ attribute
178
+ end
179
+
180
+ end
181
+ end
@@ -0,0 +1,12 @@
1
+ module HtmlPress
2
+ begin
3
+ require 'rainpress'
4
+ def self.css_compressor (text)
5
+ Rainpress.compress(text).gsub(/^\s+/m, '')
6
+ end
7
+ rescue LoadError => e
8
+ def self.css_compressor (text)
9
+ text
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module HtmlPress
2
+ begin
3
+ require 'uglifier'
4
+ def self.js_compressor (text)
5
+ Uglifier.new.compile(text).gsub(/;$/,'')
6
+ end
7
+ rescue LoadError => e
8
+ def self.js_compressor (text)
9
+ text
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module HtmlPress
2
+ VERSION = "0.0.1"
3
+ end
data/lib/html_press.rb ADDED
@@ -0,0 +1,10 @@
1
+ require "html_press/version"
2
+ require "html_press/rainpress"
3
+ require "html_press/uglifier"
4
+ require "html_press/html"
5
+
6
+ module HtmlPress
7
+ def self.compress(text)
8
+ self::Html.new.compile text
9
+ end
10
+ end
@@ -0,0 +1,98 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative "../lib/html_press"
4
+
5
+ describe HtmlPress do
6
+ before :each do
7
+ end
8
+
9
+ it "should leave only one whitespace between inline tags" do
10
+ HtmlPress.compress("<p>lorem <b>ipsum</b> <i>dolor</i> </p>").should eql "<p>lorem <b>ipsum</b> <i>dolor</i></p>"
11
+ end
12
+
13
+ it "should leave no whitespaces between block tags" do
14
+ HtmlPress.compress("<div></div> \t\r\n <div></div>").should eql "<div></div><div></div>"
15
+ end
16
+
17
+ it "should leave only one whitespace in text" do
18
+ HtmlPress.compress("<p>a a</p>").should eql "<p>a a</p>"
19
+ end
20
+
21
+ it "should leave newlines in pre tags and remove trailing spaces" do
22
+ HtmlPress.compress("<pre>a \t </pre>").should eql "<pre>a</pre>"
23
+ HtmlPress.compress("<pre>qwe \nasd </pre>").should eql "<pre>qwe\nasd</pre>"
24
+ end
25
+
26
+ it "should leave textareas as is" do
27
+ text = "<textarea> \t </textarea>"
28
+ HtmlPress.compress(text).should eql text
29
+ end
30
+
31
+ it "should compress js in script tags" do
32
+ script = " (function(undefined){ \t\n var long_name = ' '; }()) \n \r"
33
+ compressed_script = "<script>" + HtmlPress.js_compressor(script) + "</script>"
34
+ script = " <script>" + script + "</script> "
35
+ HtmlPress.compress(script).should eql compressed_script
36
+ end
37
+
38
+ it "should compress css in style tags" do
39
+ style = " div { margin: 0px 0px; \n} "
40
+ compressed_style = "<style>" + HtmlPress.css_compressor(style) + "</style>"
41
+ style = " <style>" + style + "</style> "
42
+ HtmlPress.compress(style).should eql compressed_style
43
+ end
44
+
45
+ it "should remove html comments" do
46
+ HtmlPress.compress("<p></p><!-- comment --><p></p>").should eql "<p></p><p></p>"
47
+ end
48
+
49
+ it "should leave IE conditional comments" do
50
+ text = "<!--[if IE]><html class=\"ie\"><![endif]--><div></div>"
51
+ HtmlPress.compress(text).should eql text
52
+ end
53
+
54
+ it "should remove unnecessary whitespaces between attributes" do
55
+ HtmlPress.compress("<p class=\"a\" id=\"b\"></p>").should eql "<p class=\"a\" id=\"b\"></p>"
56
+ end
57
+
58
+ it "should leave whitespaces everywhere else" do
59
+ text = "<a onclick=\"alert(' ')\" unknown_attr=' a a'>a</a>"
60
+ HtmlPress.compress(text).should eql text
61
+ end
62
+
63
+ it "should work with special utf-8 symbols" do
64
+ HtmlPress.compress("✪<p></p> <p></p>").should eql "✪<p></p><p></p>"
65
+ end
66
+
67
+ it "should work with tags in upper case" do
68
+ HtmlPress.compress("<P> </p>").should eql "<P></p>"
69
+ end
70
+
71
+ it "should remove whitespaces between IE conditional comments" do
72
+ text = "<p></p> <!--[if IE]><html class=\"ie\"> <![endif]--> <!--[if IE]><html class=\"ie1\"><![endif]-->"
73
+ text2 = "<p></p><!--[if IE]><html class=\"ie\"><![endif]--><!--[if IE]><html class=\"ie1\"><![endif]-->"
74
+ HtmlPress.compress(text).should eql text2
75
+ end
76
+
77
+ it "should treat text inside IE conditional comments as it was without comments" do
78
+ text = "<div class=\"a\" id=\"b\"> </div> <p></p>"
79
+ text2 = HtmlPress.compress(text)
80
+ text = "<!--[if IE]>" + text + "<![endif]-->"
81
+ text2 = "<!--[if IE]>" + text2 + "<![endif]-->"
82
+ HtmlPress.compress(text).should eql text2
83
+ end
84
+
85
+ it "should remove unnecessary whitespaces in html attributes (class)" do
86
+ HtmlPress.compress("<p class=\"a b\"></p>").should eql "<p class=\"a b\"></p>"
87
+ HtmlPress.compress("<p class='a b'></p>").should eql "<p class='a b'></p>"
88
+ end
89
+
90
+ it "should remove unnecessary whitespaces in html attributes (style)" do
91
+ HtmlPress.compress("<p style=\"display: none;\"></p>").should eql "<p style=\"display:none;\"></p>"
92
+ end
93
+
94
+ # it "should remove unnecessary attributes" do
95
+ # HtmlPress.compress("<script type=\"text/javascript\">var a;</script>").should eql "<script>var a;</script>"
96
+ # end
97
+
98
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: html_press
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - stereobooster
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-04 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &19832364 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *19832364
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &20531592 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *20531592
36
+ - !ruby/object:Gem::Dependency
37
+ name: rainpress
38
+ requirement: &20756364 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *20756364
47
+ - !ruby/object:Gem::Dependency
48
+ name: uglifier
49
+ requirement: &21077148 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *21077148
58
+ description: Ruby gem for compressing html
59
+ email:
60
+ - stereobooster@gmail.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - .gitignore
66
+ - Gemfile
67
+ - Rakefile
68
+ - Readme.md
69
+ - html_press.gemspec
70
+ - lib/html_press.rb
71
+ - lib/html_press/html.rb
72
+ - lib/html_press/rainpress.rb
73
+ - lib/html_press/uglifier.rb
74
+ - lib/html_press/version.rb
75
+ - spec/html_press_spec.rb
76
+ homepage: https://github.com/stereobooster/html_press
77
+ licenses: []
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project: html_press
96
+ rubygems_version: 1.8.15
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: Compress html
100
+ test_files: []