multi_css 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/vendor/cssminify/.gitignore +9 -0
  2. data/vendor/cssminify/.travis.yml +7 -0
  3. data/vendor/cssminify/CHANGES.md +12 -0
  4. data/vendor/cssminify/Gemfile +4 -0
  5. data/vendor/cssminify/LICENSE.md +22 -0
  6. data/vendor/cssminify/README.md +64 -0
  7. data/vendor/cssminify/cssminify.gemspec +30 -0
  8. data/vendor/cssminify/lib/cssminify.rb +34 -0
  9. data/vendor/cssminify/lib/cssminify/cssmin.rb +383 -0
  10. data/vendor/cssminify/lib/cssminify/version.rb +5 -0
  11. data/vendor/cssminify/spec/cssminify_spec.rb +257 -0
  12. data/vendor/cssminify/spec/sample.css +100 -0
  13. data/vendor/cssminify/spec/spec_helper.rb +4 -0
  14. data/vendor/cssminify/spec/tests/background-position.css +2 -0
  15. data/vendor/cssminify/spec/tests/background-position.css.min +1 -0
  16. data/vendor/cssminify/spec/tests/border-none.css +5 -0
  17. data/vendor/cssminify/spec/tests/border-none.css.min +1 -0
  18. data/vendor/cssminify/spec/tests/box-model-hack.css +9 -0
  19. data/vendor/cssminify/spec/tests/box-model-hack.css.min +1 -0
  20. data/vendor/cssminify/spec/tests/bug2527974.css +10 -0
  21. data/vendor/cssminify/spec/tests/bug2527974.css.min +1 -0
  22. data/vendor/cssminify/spec/tests/bug2527991.css +19 -0
  23. data/vendor/cssminify/spec/tests/bug2527991.css.min +1 -0
  24. data/vendor/cssminify/spec/tests/bug2527998.css +4 -0
  25. data/vendor/cssminify/spec/tests/bug2527998.css.min +1 -0
  26. data/vendor/cssminify/spec/tests/bug2528034.css +5 -0
  27. data/vendor/cssminify/spec/tests/bug2528034.css.min +1 -0
  28. data/vendor/cssminify/spec/tests/bug2528093.css +3 -0
  29. data/vendor/cssminify/spec/tests/bug2528093.css.min +1 -0
  30. data/vendor/cssminify/spec/tests/charset-media.css +9 -0
  31. data/vendor/cssminify/spec/tests/charset-media.css.min +1 -0
  32. data/vendor/cssminify/spec/tests/color-simple.css +8 -0
  33. data/vendor/cssminify/spec/tests/color-simple.css.min +1 -0
  34. data/vendor/cssminify/spec/tests/color.css +46 -0
  35. data/vendor/cssminify/spec/tests/color.css.min +1 -0
  36. data/vendor/cssminify/spec/tests/comment.css +3 -0
  37. data/vendor/cssminify/spec/tests/comment.css.min +1 -0
  38. data/vendor/cssminify/spec/tests/concat-charset.css +15 -0
  39. data/vendor/cssminify/spec/tests/concat-charset.css.min +1 -0
  40. data/vendor/cssminify/spec/tests/dataurl-base64-doublequotes.css +23 -0
  41. data/vendor/cssminify/spec/tests/dataurl-base64-doublequotes.css.min +1 -0
  42. data/vendor/cssminify/spec/tests/dataurl-base64-eof.css +10 -0
  43. data/vendor/cssminify/spec/tests/dataurl-base64-eof.css.min +1 -0
  44. data/vendor/cssminify/spec/tests/dataurl-base64-linebreakindata.css +34 -0
  45. data/vendor/cssminify/spec/tests/dataurl-base64-linebreakindata.css.min +1 -0
  46. data/vendor/cssminify/spec/tests/dataurl-base64-noquotes.css +26 -0
  47. data/vendor/cssminify/spec/tests/dataurl-base64-noquotes.css.min +1 -0
  48. data/vendor/cssminify/spec/tests/dataurl-base64-singlequotes.css +23 -0
  49. data/vendor/cssminify/spec/tests/dataurl-base64-singlequotes.css.min +1 -0
  50. data/vendor/cssminify/spec/tests/dataurl-base64-twourls.css +27 -0
  51. data/vendor/cssminify/spec/tests/dataurl-base64-twourls.css.min +1 -0
  52. data/vendor/cssminify/spec/tests/dataurl-dbquote-font.css +30 -0
  53. data/vendor/cssminify/spec/tests/dataurl-dbquote-font.css.min +5 -0
  54. data/vendor/cssminify/spec/tests/dataurl-nonbase64-doublequotes.css +13 -0
  55. data/vendor/cssminify/spec/tests/dataurl-nonbase64-doublequotes.css.min +1 -0
  56. data/vendor/cssminify/spec/tests/dataurl-nonbase64-noquotes.css +11 -0
  57. data/vendor/cssminify/spec/tests/dataurl-nonbase64-noquotes.css.min +1 -0
  58. data/vendor/cssminify/spec/tests/dataurl-nonbase64-singlequotes.css +15 -0
  59. data/vendor/cssminify/spec/tests/dataurl-nonbase64-singlequotes.css.min +2 -0
  60. data/vendor/cssminify/spec/tests/dataurl-noquote-multiline-font.css +31 -0
  61. data/vendor/cssminify/spec/tests/dataurl-noquote-multiline-font.css.min +3 -0
  62. data/vendor/cssminify/spec/tests/dataurl-realdata-doublequotes.css +90 -0
  63. data/vendor/cssminify/spec/tests/dataurl-realdata-doublequotes.css.min +1 -0
  64. data/vendor/cssminify/spec/tests/dataurl-realdata-noquotes.css +90 -0
  65. data/vendor/cssminify/spec/tests/dataurl-realdata-noquotes.css.min +1 -0
  66. data/vendor/cssminify/spec/tests/dataurl-realdata-singlequotes.css +90 -0
  67. data/vendor/cssminify/spec/tests/dataurl-realdata-singlequotes.css.min +1 -0
  68. data/vendor/cssminify/spec/tests/dataurl-realdata-yuiapp.css +106 -0
  69. data/vendor/cssminify/spec/tests/dataurl-realdata-yuiapp.css.min +1 -0
  70. data/vendor/cssminify/spec/tests/dataurl-singlequote-font.css +30 -0
  71. data/vendor/cssminify/spec/tests/dataurl-singlequote-font.css.min +3 -0
  72. data/vendor/cssminify/spec/tests/decimals.css +3 -0
  73. data/vendor/cssminify/spec/tests/decimals.css.min +1 -0
  74. data/vendor/cssminify/spec/tests/dollar-header.css +7 -0
  75. data/vendor/cssminify/spec/tests/dollar-header.css.min +3 -0
  76. data/vendor/cssminify/spec/tests/font-face.css +6 -0
  77. data/vendor/cssminify/spec/tests/font-face.css.min +1 -0
  78. data/vendor/cssminify/spec/tests/ie5mac.css +5 -0
  79. data/vendor/cssminify/spec/tests/ie5mac.css.min +1 -0
  80. data/vendor/cssminify/spec/tests/media-empty-class.css +16 -0
  81. data/vendor/cssminify/spec/tests/media-empty-class.css.min +1 -0
  82. data/vendor/cssminify/spec/tests/media-multi.css +3 -0
  83. data/vendor/cssminify/spec/tests/media-multi.css.min +1 -0
  84. data/vendor/cssminify/spec/tests/media-test.css +3 -0
  85. data/vendor/cssminify/spec/tests/media-test.css.min +1 -0
  86. data/vendor/cssminify/spec/tests/opacity-filter.css +14 -0
  87. data/vendor/cssminify/spec/tests/opacity-filter.css.min +1 -0
  88. data/vendor/cssminify/spec/tests/preserve-case.css +15 -0
  89. data/vendor/cssminify/spec/tests/preserve-case.css.min +1 -0
  90. data/vendor/cssminify/spec/tests/preserve-new-line.css +6 -0
  91. data/vendor/cssminify/spec/tests/preserve-new-line.css.min +3 -0
  92. data/vendor/cssminify/spec/tests/preserve-strings.css +7 -0
  93. data/vendor/cssminify/spec/tests/preserve-strings.css.min +1 -0
  94. data/vendor/cssminify/spec/tests/pseudo-first.css +16 -0
  95. data/vendor/cssminify/spec/tests/pseudo-first.css.min +1 -0
  96. data/vendor/cssminify/spec/tests/pseudo.css +4 -0
  97. data/vendor/cssminify/spec/tests/pseudo.css.min +1 -0
  98. data/vendor/cssminify/spec/tests/special-comments.css +13 -0
  99. data/vendor/cssminify/spec/tests/special-comments.css.min +9 -0
  100. data/vendor/cssminify/spec/tests/star-underscore-hacks.css +5 -0
  101. data/vendor/cssminify/spec/tests/star-underscore-hacks.css.min +1 -0
  102. data/vendor/cssminify/spec/tests/string-in-comment.css +8 -0
  103. data/vendor/cssminify/spec/tests/string-in-comment.css.min +1 -0
  104. data/vendor/cssminify/spec/tests/webkit-transform.css +2 -0
  105. data/vendor/cssminify/spec/tests/webkit-transform.css.min +1 -0
  106. data/vendor/cssminify/spec/tests/zeros.css +12 -0
  107. data/vendor/cssminify/spec/tests/zeros.css.min +1 -0
  108. metadata +223 -0
@@ -0,0 +1,9 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ coverage
6
+ rdoc
7
+ doc
8
+ .yardoc
9
+ .rspec
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - jruby-19mode # JRuby in 1.9 mode
6
+ - rbx-19mode
7
+ script: bundle exec rspec spec
@@ -0,0 +1,12 @@
1
+ ### 1.0.2 (30 June 2012)
2
+
3
+ * Removed unnecessary Bundler dependency
4
+
5
+ ### 1.0.1 (30 June 2012)
6
+
7
+ * Updated cssmin.rb to 1.0.1
8
+ * Updated tests
9
+
10
+ ## 1.0.0 (29 June 2012)
11
+
12
+ First release
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in cssminify.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Matthias Siegel (matthias.siegel@gmail.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ Note: the included Ruby port of YUI compressor has a different license. See the [source code](https://github.com/matthiassiegel/cssminify/blob/master/lib/cssminify/cssmin.rb) for details.
@@ -0,0 +1,64 @@
1
+ # CSSminify [![Build Status](https://secure.travis-ci.org/matthiassiegel/cssminify.png)](http://travis-ci.org/matthiassiegel/cssminify)
2
+
3
+ CSS minification with YUI compressor, but as native Ruby port.
4
+
5
+ The CSSminify gem provides CSS compression using YUI compressor. Instead of wrapping around the Java or Javascript version of YUI compressor it uses a native [Ruby port](https://github.com/matthiassiegel/cssmin) of the CSS engine. Therefore this gem has no dependencies.
6
+
7
+ In basic benchmarks the Ruby version performed about as good as the Java jar. It currently passes all CSS test cases included with the YUI compressor Java source code.
8
+
9
+ Main motivation for the Ruby port and this gem was to reduce dependencies like Java.
10
+
11
+ ## Installation
12
+ Install CSSminify from RubyGems:
13
+
14
+ gem install cssminify
15
+
16
+ Or include it in your project's Gemfile:
17
+
18
+ gem 'cssminify'
19
+
20
+ ## Usage
21
+
22
+ require 'cssminify'
23
+
24
+ CSSminify.compress('/* a comment */ .test { display: block; }')
25
+ # => minified CSS
26
+
27
+ CSSminify.compress(File.read('path/to/styles.css'))
28
+ # => minified CSS
29
+
30
+ CSSminify.compress(File.open('path/to/styles.css'))
31
+ # => minified CSS
32
+
33
+ # Alternatively use instance method...
34
+ compressor = CSSminify.new
35
+ compressor.compress(File.read("path/to/styles.css"))
36
+ # => minified CSS
37
+
38
+ Files or strings are acceptable as input.
39
+
40
+ You can pass in a second argument to control the maximum output line length (default 5000 characters):
41
+
42
+ CSSminify.compress(File.read("path/to/styles.css"), 200)
43
+
44
+ Note: in most cases line length will only be approximated.
45
+
46
+ ## Rails asset pipeline
47
+ Rails 3.1 integrated [Sprockets](https://github.com/sstephenson/sprockets) to provide asset packaging and minimising out of the box. For CSS compression it relies on the [yui-compressor gem](https://github.com/sstephenson/ruby-yui-compressor) which requires Java. To use CSSminify instead, edit your config/application.rb file:
48
+
49
+ config.assets.css_compressor = CSSminify.new
50
+
51
+ ## Compatibility
52
+ Tested with Ruby 1.9.2, 1.9.3, jruby-19mode, rbx-19mode
53
+
54
+ ## Changelog
55
+ See [CHANGES](https://github.com/matthiassiegel/cssminify/blob/master/CHANGES.md).
56
+
57
+ ## Copyright
58
+
59
+ ### CSSminify gem and documentation
60
+ Copyright (c) 2012 Matthias Siegel (matthias.siegel@gmail.com)
61
+ See [LICENSE](https://github.com/matthiassiegel/cssminify/blob/master/LICENSE.md) for details.
62
+
63
+ ### YUI compressor
64
+ See [file](https://github.com/matthiassiegel/cssminify/blob/master/lib/cssminify/cssmin.rb).
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "cssminify/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "cssminify"
7
+ s.version = CSSminify::VERSION
8
+ s.author = "Matthias Siegel"
9
+ s.email = "matthias.siegel@gmail.com"
10
+ s.homepage = "https://github.com/matthiassiegel/cssminify"
11
+ s.summary = "CSS minification with YUI compressor, but as native Ruby port."
12
+ s.description = <<-EOF
13
+ The CSSminify gem provides CSS compression using YUI compressor. Instead of wrapping around the Java or Javascript version of YUI compressor it uses a native Ruby port of the CSS engine. Therefore this gem has no dependencies.
14
+ EOF
15
+
16
+ s.extra_rdoc_files = [
17
+ "CHANGES.md",
18
+ "LICENSE.md",
19
+ "README.md"
20
+ ]
21
+
22
+ s.license = "MIT"
23
+ s.rubyforge_project = "cssminify"
24
+
25
+ s.files = `git ls-files`.split("\n")
26
+ s.test_files = `git ls-files -- spec/*`.split("\n")
27
+ s.require_paths = ["lib"]
28
+
29
+ s.add_development_dependency "rspec", "~> 2.7"
30
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+
3
+ require "cssminify/cssmin"
4
+ require "cssminify/version"
5
+
6
+ class CSSminify
7
+
8
+ def initialize
9
+ end
10
+
11
+
12
+ #
13
+ # Compress CSS with YUI
14
+ #
15
+ # @param [String, #read] CSS String or IO-like object that supports #read
16
+ # @param [Integer] length Maximum line length
17
+ # @return [String] Compressed CSS
18
+ def self.compress(source, length = 5000)
19
+ self.new.compress(source, length)
20
+ end
21
+
22
+
23
+ #
24
+ # Compress CSS with YUI
25
+ #
26
+ # @param [String, #read] CSS String or IO-like object that supports #read
27
+ # @param [Integer] length Maximum line length
28
+ # @return [String] Compressed CSS
29
+ def compress(source = '', length = 5000)
30
+ source = source.respond_to?(:read) ? source.read : source.to_s
31
+
32
+ CssCompressor.compress(source, length)
33
+ end
34
+ end
@@ -0,0 +1,383 @@
1
+ #
2
+ # cssmin.rb - 1.0.1
3
+ # Author: Matthias Siegel - https://github.com/matthiassiegel/cssmin
4
+ # This is a Ruby port of the CSS minification tool
5
+ # distributed with YUICompressor, based on the original Java
6
+ # code and the Javascript port by Stoyan Stefanov.
7
+ # Permission is hereby granted to use the Ruby version under the same
8
+ # conditions as YUICompressor (original YUICompressor note below).
9
+ #
10
+ #
11
+ # YUI Compressor
12
+ # http://developer.yahoo.com/yui/compressor/
13
+ # Author: Julien Lecomte - http://www.julienlecomte.net/
14
+ # Author: Isaac Schlueter - http://foohack.com/
15
+ # Author: Stoyan Stefanov - http://phpied.com/
16
+ # Copyright (c) 2011 Yahoo! Inc. All rights reserved.
17
+ # The copyrights embodied in the content of this file are licensed
18
+ # by Yahoo! Inc. under the BSD (revised) open source license.
19
+ #
20
+
21
+ module CssCompressor
22
+
23
+ def self.compress(css, linebreakpos = 5000)
24
+
25
+ #
26
+ # Support for various input types
27
+ #
28
+ if css.respond_to?(:read)
29
+ css = css.read
30
+ elsif css.respond_to?(:path)
31
+ css = File.read(css.path)
32
+ end
33
+
34
+ @@preservedTokens = []
35
+ comments = []
36
+ startIndex = 0
37
+
38
+ #
39
+ # Extract data urls
40
+ #
41
+ css = extractDataUrls(css)
42
+
43
+ #
44
+ # Collect all comment blocks...
45
+ #
46
+ while (startIndex = css.index(/\/\*/, startIndex)) != nil
47
+ endIndex = css.index(/\*\//, startIndex + 2)
48
+ endIndex = css.length if endIndex.nil?
49
+
50
+ comments << css[(startIndex + 2)...endIndex]
51
+
52
+ css = css[0...(startIndex + 2)] + '___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_' + (comments.length - 1).to_s + '___' + css[endIndex..-1]
53
+ startIndex += 2
54
+ end
55
+
56
+ #
57
+ # Preserve strings so their content doesn't get accidentally minified
58
+ #
59
+ css = css.gsub(/("([^\\"]|\\.|\\)*")|('([^\\']|\\.|\\)*')/) { |match|
60
+ quote = match[0, 1]
61
+ match = match[1...-1]
62
+
63
+ #
64
+ # Maybe the string contains a comment-like substring?
65
+ # One, maybe more? put'em back then
66
+ #
67
+ unless match.index('___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_').nil?
68
+ comments.each_index { |i| match = match.gsub(/___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{i}___/, comments[i]) }
69
+ end
70
+
71
+ #
72
+ # Minify alpha opacity in filter strings
73
+ #
74
+ match = match.gsub(/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/i, 'alpha(opacity=')
75
+
76
+ @@preservedTokens << match
77
+
78
+ quote + "___YUICSSMIN_PRESERVED_TOKEN_" + (@@preservedTokens.length - 1).to_s + "___" + quote
79
+ }
80
+
81
+ #
82
+ # Strings are safe, now wrestle the comments
83
+ #
84
+ for i in 0...comments.length
85
+ token = comments[i]
86
+ placeholder = /___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{i}___/
87
+
88
+ #
89
+ # ! in the first position of the comment means preserve
90
+ # so push to the preserved tokens keeping the !
91
+ #
92
+ if token[0] === '!'
93
+ @@preservedTokens << token
94
+ css = css.gsub(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (@@preservedTokens.length - 1).to_s + "___")
95
+ next
96
+ end
97
+
98
+ #
99
+ # \ in the last position looks like hack for Mac/IE5
100
+ # shorten that to /*\*/ and the next one to /**/
101
+ #
102
+ if token[(token.length - 1)..-1] === '\\'
103
+ @@preservedTokens << '\\'
104
+ css = css.gsub(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (@@preservedTokens.length - 1).to_s + "___")
105
+
106
+ i += 1 # Attn: advancing the loop
107
+
108
+ @@preservedTokens << ''
109
+ css = css.gsub(/___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{i}___/, "___YUICSSMIN_PRESERVED_TOKEN_" + (@@preservedTokens.length - 1).to_s + "___")
110
+ next
111
+ end
112
+
113
+ #
114
+ # Keep empty comments after child selectors (IE7 hack)
115
+ # E.g. html >/**/ body
116
+ #
117
+ if token.length == 0
118
+ startIndex = css.index(placeholder)
119
+
120
+ if startIndex and startIndex > 2
121
+ if css[startIndex - 3] === '>'
122
+ @@preservedTokens << ''
123
+ css = css.gsub(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (@@preservedTokens.length - 1).to_s + "___")
124
+ end
125
+ end
126
+ end
127
+
128
+ #
129
+ # In all other cases kill the comment
130
+ #
131
+ css = css.gsub(/\/\*___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_#{i}___\*\//, '')
132
+ end
133
+
134
+ #
135
+ # Shorten all whitespace strings to single spaces
136
+ #
137
+ css = css.gsub(/\s+/, ' ')
138
+
139
+ #
140
+ # Remove the spaces before the things that should not have spaces before them.
141
+ # But, be careful not to turn "p :link {...}" into "p:link{...}"
142
+ # Swap out any pseudo-class colons with the token, and then swap back.
143
+ #
144
+ css = css.gsub(/(^|\})(([^\{:])+:)+([^\{]*\{)/) { |m| m.gsub(/:/, '___YUICSSMIN_PSEUDOCLASSCOLON___') }
145
+ css = css.gsub(/\s+([!{};:>+\(\)\],])/) { $1.to_s }
146
+ css = css.gsub(/___YUICSSMIN_PSEUDOCLASSCOLON___/, ':')
147
+
148
+ #
149
+ # Retain space for special IE6 cases
150
+ #
151
+ css = css.gsub(/:first-(line|letter)(\{|,)/i) { ":first-#{$1.to_s.downcase} #{$2.to_s}" }
152
+
153
+ #
154
+ # No space after the end of a preserved comment
155
+ #
156
+ css = css.gsub(/\*\/\s+/, '*/')
157
+
158
+ #
159
+ # If there is a @charset, then only allow one, and push to the top of the file.
160
+ #
161
+ css = css.gsub(/^(.*)(@charset "[^"]*";)/i) { $2.to_s + $1.to_s }
162
+ css = css.gsub(/^(\s*@charset [^;]+;\s*)+/i) { $1.to_s }
163
+
164
+ #
165
+ # Put the space back in some cases, to support stuff like
166
+ # @media screen and (-webkit-min-device-pixel-ratio:0){
167
+ #
168
+ css = css.gsub(/\band\(/i, 'and (')
169
+
170
+ #
171
+ # Remove the spaces after the things that should not have spaces after them.
172
+ #
173
+ css = css.gsub(/([!{}:;>+\(\[,])\s+/) { $1.to_s }
174
+
175
+ #
176
+ # Remove unnecessary semicolons
177
+ #
178
+ css = css.gsub(/;+\}/, '}')
179
+
180
+ #
181
+ # Replace 0(px,em,%) with 0
182
+ #
183
+ css = css.gsub(/(^|[^0-9])(?:0?\.)?0(?:px|em|%|in|cm|mm|pc|pt|ex|deg|g?rad|m?s|k?hz)/i) { $1.to_s + '0' }
184
+
185
+ #
186
+ # Replace 0 0 0 0; with 0
187
+ #
188
+ css = css.gsub(/:0 0 0 0(;|\})/) { ':0' + $1.to_s }
189
+ css = css.gsub(/:0 0 0(;|\})/) { ':0' + $1.to_s }
190
+ css = css.gsub(/:0 0(;|\})/) { ':0' + $1.to_s }
191
+
192
+ #
193
+ # Replace background-position:0; with background-position:0 0;
194
+ # Same for transform-origin
195
+ #
196
+ css = css.gsub(/(background-position|transform-origin|webkit-transform-origin|moz-transform-origin|o-transform-origin|ms-transform-origin):0(;|\})/i) { "#{$1.to_s.downcase}:0 0#{$2.to_s}" }
197
+
198
+ #
199
+ # Replace 0.6 to .6, but only when preceded by : or a white-space
200
+ #
201
+ css = css.gsub(/(:|\s)0+\.(\d+)/) { "#{$1.to_s}.#{$2.to_s}" }
202
+
203
+ #
204
+ # Shorten colors from rgb(51,102,153) to #336699
205
+ # This makes it more likely that it'll get further compressed in the next step.
206
+ #
207
+ css = css.gsub(/rgb\s*\(\s*([0-9,\s]+)\s*\)(\d+%)?/i) {
208
+ rgbcolors = $1.to_s.split(',')
209
+ i = 0
210
+
211
+ while i < rgbcolors.length
212
+ rgbcolors[i] = rgbcolors[i].to_i.to_s(16)
213
+
214
+ if rgbcolors[i].length === 1
215
+ rgbcolors[i] = '0' + rgbcolors[i]
216
+ end
217
+
218
+ i += 1
219
+ end
220
+
221
+ unless $2.to_s.empty?
222
+ rgbcolors << (' ' + $2.to_s)
223
+ end
224
+
225
+ '#' + rgbcolors.join('')
226
+ }
227
+
228
+ #
229
+ # Shorten colors from #AABBCC to #ABC. Note that we want to make sure
230
+ # the color is not preceded by either ", " or =. Indeed, the property
231
+ # filter: chroma(color="#FFFFFF");
232
+ # would become
233
+ # filter: chroma(color="#FFF");
234
+ # which makes the filter break in IE.
235
+ # We also want to make sure we're only compressing #AABBCC patterns inside { }, not id selectors ( #FAABAC {} )
236
+ # We also want to avoid compressing invalid values (e.g. #AABBCCD to #ABCD)
237
+ #
238
+ rest = css
239
+ new_css = ''
240
+
241
+ while m = rest.match(/(\=\s*?["']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(:?\}|[^0-9a-f{][^{]*?\})/i) do
242
+ #
243
+ # Normal color value
244
+ #
245
+ if m[1].nil?
246
+ #
247
+ # Color value that can be shortened
248
+ #
249
+ if m[2].to_s.downcase == m[3].to_s.downcase && m[4].to_s.downcase == m[5].to_s.downcase && m[6].to_s.downcase == m[7].to_s.downcase
250
+ color = '#' + m[2].to_s.downcase + m[4].to_s.downcase + m[6].to_s.downcase
251
+ shift = 7
252
+
253
+ #
254
+ # Color value that can't be shortened
255
+ #
256
+ else
257
+ color = '#' + m[2].to_s.downcase + m[3].to_s.downcase + m[4].to_s.downcase + m[5].to_s.downcase + m[6].to_s.downcase + m[7].to_s.downcase
258
+ shift = 7
259
+ end
260
+
261
+ #
262
+ # Filter property that needs to stay the way it is
263
+ #
264
+ else
265
+ color = m[1].to_s + '#' + m[2].to_s + m[3].to_s + m[4].to_s + m[5].to_s + m[6].to_s + m[7].to_s
266
+ shift = color.length
267
+ end
268
+
269
+ new_css += m.pre_match + color
270
+ rest.slice!(rest.index(m.pre_match || 0), m.pre_match.length + shift)
271
+
272
+ end
273
+ css = new_css + rest
274
+
275
+ #
276
+ # border: none -> border:0
277
+ #
278
+ css = css.gsub(/(border|border-top|border-right|border-bottom|border-left|outline|background):none(;|\})/i) { "#{$1.to_s.downcase}:0#{$2.to_s}" }
279
+
280
+ #
281
+ # Shorter opacity IE filter
282
+ #
283
+ css = css.gsub(/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/i, 'alpha(opacity=')
284
+
285
+ #
286
+ # Remove empty rules.
287
+ #
288
+ css = css.gsub(/[^\};\{\/]+\{\}/, '')
289
+
290
+ #
291
+ # Some source control tools don't like it when files containing lines longer
292
+ # than, say 8000 characters, are checked in. The linebreak option is used in
293
+ # that case to split long lines after a specific column.
294
+ #
295
+ if linebreakpos
296
+ startIndex = 0
297
+ i = 0
298
+ while i < css.length
299
+ i = i + 1
300
+ if css[i - 1] === '}' && i - startIndex > linebreakpos
301
+ css = css.slice(0, i) + "\n" + css.slice(i, css.length - i)
302
+ startIndex = i
303
+ end
304
+ end
305
+ end
306
+
307
+ #
308
+ # Replace multiple semi-colons in a row by a single one
309
+ #
310
+ css = css.gsub(/;;+/, ';')
311
+
312
+ #
313
+ # Restore preserved comments and strings
314
+ #
315
+ for i in 0...@@preservedTokens.length do
316
+ css = css.gsub(/___YUICSSMIN_PRESERVED_TOKEN_#{i}___/) { @@preservedTokens[i] }
317
+ end
318
+
319
+ #
320
+ # Remove leading and trailing whitespace
321
+ #
322
+ css = css.chomp.strip
323
+ end
324
+
325
+
326
+
327
+
328
+ private
329
+
330
+
331
+ #
332
+ # Utility method to replace all data urls with tokens before we start
333
+ # compressing, to avoid performance issues running some of the subsequent
334
+ # regexes against large strings chunks.
335
+ #
336
+ # @param [String] css The input css
337
+ # @returns [String] The processed css
338
+ #
339
+ def self.extractDataUrls(css)
340
+ new_css = ''
341
+
342
+ while m = css.match(/url\(\s*(["']?)data\:/i) do
343
+ startIndex = m.begin(0) + 4 # "url(".length()
344
+ terminator = m[1] # ', " or empty (not quoted)
345
+ terminator = ')' if terminator.empty?
346
+ foundTerminator = false
347
+ endIndex = m.end(0) - 1
348
+
349
+ while !foundTerminator && endIndex + 1 <= css.length
350
+ endIndex = css.index(terminator, endIndex + 1)
351
+
352
+ #
353
+ # endIndex == 0 doesn't really apply here
354
+ #
355
+ if endIndex > 0 && css[endIndex - 1] != '\\'
356
+ foundTerminator = true
357
+ endIndex = css.index(')', endIndex) if terminator != ')'
358
+ end
359
+ end
360
+
361
+ new_css += css[0...m.begin(0)]
362
+
363
+ if foundTerminator
364
+ token = css[startIndex...endIndex]
365
+ token = token.gsub(/\s+/, '')
366
+ @@preservedTokens << token
367
+
368
+ new_css += "url(___YUICSSMIN_PRESERVED_TOKEN_" + (@@preservedTokens.length - 1).to_s + "___)"
369
+
370
+ #
371
+ # No end terminator found, re-add the whole match
372
+ #
373
+ else
374
+ new_css += css[m.begin(0)...m.end(0)]
375
+ end
376
+
377
+ css = css[(endIndex + 1)..-1]
378
+ end
379
+
380
+ css = new_css + css
381
+ end
382
+
383
+ end