css_press 0.3.0

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 css_press.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ [:build, :install, :release].each do |task_name|
4
+ Rake::Task[task_name].prerequisites << :spec
5
+ end
6
+
7
+ require "rspec/core/rake_task"
8
+ RSpec::Core::RakeTask.new
9
+
10
+ task :default => :spec
data/Readme.md ADDED
@@ -0,0 +1,14 @@
1
+ # css_press
2
+
3
+ ## Main goals & principles
4
+
5
+ - Compress css, but without support of any kind comment hacks. There are better ways to do crossbrowser styling. For example, [IE conditional comments](http://paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/).
6
+ - Compression done with the help of real css parser ([csspool](https://github.com/tenderlove/csspool)). Not Regexps.
7
+ - Pure ruby.
8
+
9
+ ## Alternatives
10
+
11
+ - [rainpres](https://github.com/sprsquish/rainpress). Seems to be dead ☠.
12
+ - [css-compressor](https://github.com/codenothing/css-compressor). The best of the best. P☣P :(
13
+ - [yuicompressor](https://github.com/yui/yuicompressor). Java
14
+ - [ruby-yui-compressor](https://github.com/sstephenson/ruby-yui-compressor). Ruby wrapper for yuicompressor
data/css_press.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "css_press/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "css_press"
7
+ s.version = CssPress::VERSION
8
+ s.authors = ["stereobooster"]
9
+ s.email = ["stereobooster@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Compress CSS}
12
+ s.description = %q{Ruby gem for compressing CSS}
13
+
14
+ s.rubyforge_project = "css_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 "csspool-st", "3.1.2"
22
+
23
+ s.add_development_dependency "rake"
24
+ s.add_development_dependency "rspec"
25
+ end
@@ -0,0 +1,11 @@
1
+ {
2
+ "808080":"gray",
3
+ "008000":"green",
4
+ "800000":"maroon",
5
+ "000080":"navy",
6
+ "808000":"olive",
7
+ "ff0000":"red",
8
+ "c0c0c0":"silver",
9
+ "008080":"teal",
10
+ "f00":"red"
11
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "f0ffff":"azure",
3
+ "f5f5dc":"beige",
4
+ "ffe4c4":"bisque",
5
+ "a52a2a":"brown",
6
+ "ff7f50":"coral",
7
+ "ffd700":"gold",
8
+ "808080":"gray",
9
+ "008000":"green",
10
+ "4b0082":"indigo",
11
+ "fffff0":"ivory",
12
+ "f0e68c":"khaki",
13
+ "faf0e6":"linen",
14
+ "800000":"maroon",
15
+ "000080":"navy",
16
+ "808000":"olive",
17
+ "ffa500":"orange",
18
+ "da70d6":"orchid",
19
+ "cd853f":"peru",
20
+ "ffc0cb":"pink",
21
+ "dda0dd":"plum",
22
+ "800080":"purple",
23
+ "ff0000":"red",
24
+ "fa8072":"salmon",
25
+ "a0522d":"sienna",
26
+ "c0c0c0":"silver",
27
+ "fffafa":"snow",
28
+ "d2b48c":"tan",
29
+ "008080":"teal",
30
+ "ff6347":"tomato",
31
+ "ee82ee":"violet",
32
+ "f5deb3":"wheat",
33
+ "f00":"red"
34
+ }
@@ -0,0 +1,122 @@
1
+ {
2
+ "aliceblue":"f0f8ff",
3
+ "antiquewhite":"faebd7",
4
+ "aquamarine":"7fffd4",
5
+ "bisque":"ffe4c4",
6
+ "black":"000",
7
+ "blanchedalmond":"ffebcd",
8
+ "blueviolet":"8a2be2",
9
+ "burlywood":"deb887",
10
+ "cadetblue":"5f9ea0",
11
+ "chartreuse":"7fff00",
12
+ "chocolate":"d2691e",
13
+ "coral":"ff7f50",
14
+ "cornflowerblue":"6495ed",
15
+ "cornsilk":"fff8dc",
16
+ "crimson":"dc143c",
17
+ "cyan":"0ff",
18
+ "darkblue":"00008b",
19
+ "darkcyan":"008b8b",
20
+ "darkgoldenrod":"b8860b",
21
+ "darkgray":"a9a9a9",
22
+ "darkgreen":"006400",
23
+ "darkkhaki":"bdb76b",
24
+ "darkmagenta":"8b008b",
25
+ "darkolivegreen":"556b2f",
26
+ "darkorange":"ff8c00",
27
+ "darkorchid":"9932cc",
28
+ "darkred":"8b0000",
29
+ "darksalmon":"e9967a",
30
+ "darkseagreen":"8fbc8f",
31
+ "darkslateblue":"483d8b",
32
+ "darkslategray":"2f4f4f",
33
+ "darkturquoise":"00ced1",
34
+ "darkviolet":"9400d3",
35
+ "deeppink":"ff1493",
36
+ "deepskyblue":"00bfff",
37
+ "dimgray":"696969",
38
+ "dodgerblue":"1e90ff",
39
+ "firebrick":"b22222",
40
+ "floralwhite":"fffaf0",
41
+ "forestgreen":"228b22",
42
+ "fuchsia":"f0f",
43
+ "gainsboro":"dcdcdc",
44
+ "ghostwhite":"f8f8ff",
45
+ "goldenrod":"daa520",
46
+ "green":"008000",
47
+ "greenyellow":"adff2f",
48
+ "honeydew":"f0fff0",
49
+ "hotpink":"ff69b4",
50
+ "indianred ":"cd5c5c",
51
+ "indigo ":"4b0082",
52
+ "lavender":"e6e6fa",
53
+ "lavenderblush":"fff0f5",
54
+ "lawngreen":"7cfc00",
55
+ "lemonchiffon":"fffacd",
56
+ "lightblue":"add8e6",
57
+ "lightcoral":"f08080",
58
+ "lightcyan":"e0ffff",
59
+ "lightgoldenrodyellow":"fafad2",
60
+ "lightgrey":"d3d3d3",
61
+ "lightgreen":"90ee90",
62
+ "lightpink":"ffb6c1",
63
+ "lightsalmon":"ffa07a",
64
+ "lightseagreen":"20b2aa",
65
+ "lightskyblue":"87cefa",
66
+ "lightslategray":"789",
67
+ "lightsteelblue":"b0c4de",
68
+ "lightyellow":"ffffe0",
69
+ "lime":"0f0",
70
+ "limegreen":"32cd32",
71
+ "magenta":"f0f",
72
+ "maroon":"800000",
73
+ "mediumaquamarine":"66cdaa",
74
+ "mediumblue":"0000cd",
75
+ "mediumorchid":"ba55d3",
76
+ "mediumpurple":"9370d8",
77
+ "mediumseagreen":"3cb371",
78
+ "mediumslateblue":"7b68ee",
79
+ "mediumspringgreen":"00fa9a",
80
+ "mediumturquoise":"48d1cc",
81
+ "mediumvioletred":"c71585",
82
+ "midnightblue":"191970",
83
+ "mintcream":"f5fffa",
84
+ "mistyrose":"ffe4e1",
85
+ "moccasin":"ffe4b5",
86
+ "navajowhite":"ffdead",
87
+ "oldlace":"fdf5e6",
88
+ "olivedrab":"6b8e23",
89
+ "orange":"ffa500",
90
+ "orangered":"ff4500",
91
+ "orchid":"da70d6",
92
+ "palegoldenrod":"eee8aa",
93
+ "palegreen":"98fb98",
94
+ "paleturquoise":"afeeee",
95
+ "palevioletred":"d87093",
96
+ "papayawhip":"ffefd5",
97
+ "peachpuff":"ffdab9",
98
+ "powderblue":"b0e0e6",
99
+ "purple":"800080",
100
+ "rosybrown":"bc8f8f",
101
+ "royalblue":"4169e1",
102
+ "saddlebrown":"8b4513",
103
+ "salmon":"fa8072",
104
+ "sandybrown":"f4a460",
105
+ "seagreen":"2e8b57",
106
+ "seashell":"fff5ee",
107
+ "sienna":"a0522d",
108
+ "silver":"c0c0c0",
109
+ "skyblue":"87ceeb",
110
+ "slateblue":"6a5acd",
111
+ "slategray":"708090",
112
+ "springgreen":"00ff7f",
113
+ "steelblue":"4682b4",
114
+ "thistle":"d8bfd8",
115
+ "tomato":"ff6347",
116
+ "turquoise":"40e0d0",
117
+ "violet":"ee82ee",
118
+ "white":"fff",
119
+ "whitesmoke":"f5f5f5",
120
+ "yellow":"ff0",
121
+ "yellowgreen":"9acd32"
122
+ }
data/lib/css_press.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "css_press/version"
2
+ require "css_press/css"
3
+ require "css_press/min_css"
4
+ require "css_press/node"
5
+ require "css_press/color"
6
+
7
+ module CssPress
8
+ def self.press(text, options = {})
9
+ CssPress::Css.new(options).press text
10
+ end
11
+ end
@@ -0,0 +1,69 @@
1
+ require 'json'
2
+
3
+ module CSSPool
4
+ class Color
5
+ class << self
6
+
7
+ def load name
8
+ data = File.read(File.expand_path("../../colors/#{name}.json", __FILE__))
9
+ JSON.parse(data)
10
+ end
11
+
12
+ [:hex_to_short, :hex_to_safe, :long_to_hex].each do |name|
13
+ define_method name do |val|
14
+ @colors ||= {}
15
+ @colors[name] ||= load name.to_s
16
+ @colors[name][val]
17
+ end
18
+ end
19
+
20
+ def color_val value, result, hash
21
+ val = result.nil? ? value : result
22
+ if hash && val.length == 6 && val[0] == val[1] && val[2] == val[3] && val[4] == val[5] then
23
+ val = result = val[0] + val[2] + val[4]
24
+ end
25
+ if !result.nil? then
26
+ result = hash ? "##{val}" : val
27
+ end
28
+ result
29
+ end
30
+
31
+ def min_hex value
32
+ val = value.downcase
33
+ result = hex_to_short val
34
+ hash = result.nil?
35
+ color_val val, result, hash
36
+ end
37
+
38
+ def min_color value
39
+ val = value.downcase
40
+ result = long_to_hex val
41
+ hash = !result.nil?
42
+ color_val val, result, hash
43
+ end
44
+
45
+ def min_rgb value
46
+ rgb = [value.red, value.green, value.blue]
47
+ rgb.map! do |color|
48
+ color = color.to_s
49
+ if color =~ /\%$/ then
50
+ color = (color[0..-2].to_f / 100 * 256).round
51
+ else
52
+ color = color.to_i
53
+ end
54
+ if color > 255 then
55
+ raise ArgumentError.new "Color value should be [0..255] or [0%..100%]"
56
+ end
57
+ color
58
+ end
59
+ rgb = '%02x%02x%02x' % rgb
60
+ result = min_hex(rgb)
61
+ if result.nil? then
62
+ result = rgb
63
+ end
64
+ result
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,20 @@
1
+ require 'csspool'
2
+
3
+ module CssPress
4
+ class Css
5
+
6
+ DEFAULTS = {
7
+ }
8
+
9
+ def initialize (options = {})
10
+ @options = DEFAULTS.merge(options)
11
+ end
12
+
13
+ def press (css)
14
+ css_in = css.respond_to?(:read) ? css.read : css.dup
15
+ doc = CSSPool.CSS css_in
16
+ doc.min_css
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,280 @@
1
+ module CSSPool
2
+ module Visitors
3
+ class MinCSS < Visitor
4
+
5
+ CSS_IDENTIFIER_ILLEGAL_CHARACTERS =
6
+ (0..255).to_a.pack('U*').gsub(/[a-zA-Z0-9_-]/, '')
7
+ CSS_STRING_ESCAPE_MAP = {
8
+ "\\" => "\\\\",
9
+ "\"" => "\\\"",
10
+ "\n" => "\\a ", # CSS2 4.1.3 p3.2
11
+ "\r" => "\\\r",
12
+ "\f" => "\\\f"
13
+ }
14
+
15
+ def initialize
16
+ end
17
+
18
+ visitor_for CSS::Document do |target|
19
+ # Default media list is []
20
+ current_media_type = []
21
+
22
+ tokens = []
23
+
24
+ target.charsets.each do |char_set|
25
+ tokens << char_set.accept(self)
26
+ end
27
+
28
+ target.import_rules.each do |ir|
29
+ tokens << ir.accept(self)
30
+ end
31
+
32
+ target.rule_sets.each { |rs|
33
+ rule_sets = rs.accept(self)
34
+ if rule_sets != "" then
35
+ if rs.media != current_media_type
36
+ media = " " + rs.media.map do |medium|
37
+ medium.name.map{ |i| i.accept(self) }.join(' ')
38
+ end.join(',')
39
+ tokens << "@media#{media}{"
40
+ end
41
+
42
+ tokens << rule_sets
43
+
44
+ if rs.media != current_media_type
45
+ current_media_type = rs.media
46
+ tokens << "}"
47
+ end
48
+ end
49
+ }
50
+ tokens.join
51
+ end
52
+
53
+ visitor_for CSS::Charset do |target|
54
+ "@charset \"#{escape_css_string target.name}\";"
55
+ end
56
+
57
+ visitor_for CSS::ImportRule do |target|
58
+ media = ''
59
+ media = " " + target.media.map do |medium|
60
+ medium.name.map{ |i| i.accept(self) }.join(' ')
61
+ end.join(', ') if target.media.length > 0
62
+
63
+ "@import #{target.uri.accept(self)}#{media};"
64
+ end
65
+
66
+ visitor_for CSS::RuleSet do |target|
67
+
68
+ is_q = false
69
+ selectors = target.selectors.map do |sel|
70
+ selector = sel.accept self
71
+ if selector =~ /^q:(after|before)/ then
72
+ is_q = true
73
+ end
74
+ selector
75
+ end.join(",")
76
+
77
+ temp = {}
78
+ i = 0
79
+ target.declarations.each do |decl|
80
+ if temp.has_key?(decl.property) && !(decl.property == 'content' && is_q) then
81
+ target.declarations[temp[decl.property]] = nil
82
+ end
83
+ temp[decl.property] = i
84
+ i+=1
85
+ end
86
+ temp = nil
87
+ target.declarations.compact!
88
+
89
+ declarations = target.declarations.map { |decl| decl.nil? ? '' : decl.accept(self) }.join(";")
90
+ if declarations == "" then
91
+ ""
92
+ else
93
+ selectors + "{" + declarations + "}"
94
+ end
95
+ end
96
+
97
+ visitor_for CSS::Declaration do |target|
98
+ important = target.important? ? ' !important' : ''
99
+
100
+ "#{escape_css_identifier target.property}:" + target.expressions.map { |exp|
101
+
102
+ special_value = nil
103
+ property = target.property.downcase
104
+
105
+ if /(color|background|background-color)/ =~ property then
106
+ special_value = Color::min_color exp.to_s
107
+ end
108
+
109
+ if /border(\-(top|bottom|left|right))?/ =~ property then
110
+ if exp.to_s == 'none' then
111
+ special_value = '0'
112
+ else
113
+ special_value = Color::min_color exp.to_s
114
+ end
115
+ end
116
+
117
+ if special_value.nil? then
118
+ [exp.operator, exp.accept(self)].join
119
+ else
120
+ special_value
121
+ end
122
+ }.join(' ').strip + "#{important}"
123
+
124
+ end
125
+
126
+ visitor_for Terms::Ident do |target|
127
+ escape_css_identifier target.value
128
+ end
129
+
130
+ visitor_for Terms::Hash do |target|
131
+ value = Color::min_hex target.value
132
+ if value.nil? then
133
+ value = "##{target.value}"
134
+ end
135
+ value
136
+ end
137
+
138
+ visitor_for Selectors::MediaExpression do |target|
139
+ '(' + escape_css_string(target.name) + ':' +
140
+ target.value.map { |x| x.accept self }.join + ')'
141
+ end
142
+
143
+ visitor_for Terms::URI do |target|
144
+ "url(\"#{escape_css_string target.value}\")"
145
+ end
146
+
147
+ visitor_for Terms::Function do |target|
148
+ "#{escape_css_identifier target.name}(" +
149
+ target.params.map { |x|
150
+ [
151
+ x.operator,
152
+ x.accept(self)
153
+ ].compact.join(' ')
154
+ }.join + ')'
155
+ end
156
+
157
+ visitor_for Terms::Rgb do |target|
158
+ begin
159
+ value = Color::min_rgb target
160
+ rescue ArgumentError
161
+ params = [
162
+ target.red,
163
+ target.green,
164
+ target.blue
165
+ ].map { |c|
166
+ c.accept(self)
167
+ }.join ','
168
+
169
+ value = "rgb(#{params})"
170
+ end
171
+ value
172
+ end
173
+
174
+ visitor_for Terms::String do |target|
175
+ "\"#{escape_css_string target.value}\""
176
+ end
177
+
178
+ visitor_for Terms::Number do |target|
179
+ value = target.value
180
+ if value == 0 then
181
+ value = '0'
182
+ else
183
+ trunc = value.truncate.round
184
+ fract = value - trunc
185
+ value = [
186
+ trunc == 0 ? '' : trunc.to_s,
187
+ fract == 0 ? '' : fract.to_s.sub(/^0/, '')
188
+ ].join
189
+ end
190
+
191
+ [
192
+ target.unary_operator == :minus && target.value != 0 ? '-' : nil,
193
+ value,
194
+ target.value == 0 ? '' : target.type
195
+ ].compact.join
196
+ end
197
+
198
+ visitor_for Selector do |target|
199
+ target.simple_selectors.map { |ss| ss.accept self }.join
200
+ end
201
+
202
+ visitor_for Selectors::Simple, Selectors::Universal, Selectors::Type do |target|
203
+ combo = {
204
+ :s => ' ',
205
+ :+ => '+',
206
+ :> => '>'
207
+ }[target.combinator]
208
+
209
+ name = [nil, '*'].include?(target.name) ? target.name : escape_css_identifier(target.name)
210
+ [combo, name].compact.join +
211
+ target.additional_selectors.map { |as| as.accept self }.join
212
+ end
213
+
214
+ visitor_for Selectors::Id do |target|
215
+ "##{escape_css_identifier target.name}"
216
+ end
217
+
218
+ visitor_for Selectors::Class do |target|
219
+ ".#{escape_css_identifier target.name}"
220
+ end
221
+
222
+ visitor_for Selectors::PseudoClass do |target|
223
+ if target.extra.nil?
224
+ ":#{escape_css_identifier target.name}"
225
+ else
226
+ ":#{escape_css_identifier target.name}(#{escape_css_identifier target.extra})"
227
+ end
228
+ end
229
+
230
+ visitor_for Selectors::PseudoElement do |target|
231
+ if target.css2.nil?
232
+ "::#{escape_css_identifier target.name}"
233
+ else
234
+ ":#{escape_css_identifier target.name}"
235
+ end
236
+ end
237
+
238
+ visitor_for Selectors::Attribute do |target|
239
+ case target.match_way
240
+ when Selectors::Attribute::SET
241
+ "[#{escape_css_identifier target.name}]"
242
+ when Selectors::Attribute::EQUALS
243
+ "[#{escape_css_identifier target.name}=#{escape_attribute target.value}]"
244
+ when Selectors::Attribute::INCLUDES
245
+ "[#{escape_css_identifier target.name}~=#{escape_attribute target.value}]"
246
+ when Selectors::Attribute::DASHMATCH
247
+ "[#{escape_css_identifier target.name}|=#{escape_attribute target.value}]"
248
+ else
249
+ raise "no matching matchway"
250
+ end
251
+ end
252
+
253
+ private
254
+
255
+ def escape_css_identifier text
256
+ # CSS2 4.1.3 p2
257
+ unsafe_chars = /[#{Regexp.escape CSS_IDENTIFIER_ILLEGAL_CHARACTERS}]/
258
+ text.gsub(/^\d|^\-(?=\-|\d)|#{unsafe_chars}/um) do |char|
259
+ if ':()-\\ ='.include? char
260
+ "\\#{char}"
261
+ else # I don't trust others to handle space termination well.
262
+ "\\#{char.unpack('U').first.to_s(16).rjust(6, '0')}"
263
+ end
264
+ end
265
+ end
266
+
267
+ def escape_css_string text
268
+ text.gsub(/[\\"\n\r\f]/) {CSS_STRING_ESCAPE_MAP[$&]}
269
+ end
270
+
271
+ def escape_attribute text
272
+ if text.size == 0 || text =~ /[ \t\r\n\f"'`=<>]/ then
273
+ '"' + escape_css_string(text) + '"'
274
+ else
275
+ escape_css_string text
276
+ end
277
+ end
278
+ end
279
+ end
280
+ end
@@ -0,0 +1,7 @@
1
+ module CSSPool
2
+ class Node
3
+ def min_css
4
+ accept Visitors::MinCSS.new
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module CssPress
2
+ VERSION = "0.3.0"
3
+ end
@@ -0,0 +1,206 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative "../lib/css_press"
4
+
5
+ describe CssPress do
6
+ before :each do
7
+ end
8
+
9
+ it "should raise error on malformed css" do
10
+ expect { CssPress.press('a { b: c') }.to raise_error(Racc::ParseError)
11
+ expect { CssPress.press('a{;}') }.to raise_error(Racc::ParseError)
12
+ end
13
+
14
+ it "should remove unnecessary spaces" do
15
+ CssPress.press('a { b: c ; }').should eql 'a{b:c}'
16
+ # CssPress.press('a { b : c ; }').should eql 'a{b:c}'
17
+ end
18
+
19
+ # it "should remove unnecessary quotes from urls" do
20
+ # CssPress.press('a{b:url( "i.gif" )}').should eql 'a{b:url(i.gif)}'
21
+ # CssPress.press('a{b:url( " i.gif" )}').should eql 'a{b:url(" i.gif")}'
22
+ # end
23
+
24
+ it "should remove unnecessary quotes from attributes" do
25
+ CssPress.press('a[d="e"]{b:c}').should eql 'a[d=e]{b:c}'
26
+ CssPress.press('a[d="e f"]{b:c}').should eql 'a[d="e f"]{b:c}'
27
+ end
28
+
29
+ # it "should minify class attributes" do
30
+ # CssPress.press('a[class="x y z"]{b:c}').should eql 'a.x.y.z{b:c}'
31
+ # CssPress.press('a[class="x.y z"]{b:c}').should eql 'a[class="x.y z"]{b:c}'
32
+ # end
33
+
34
+ # it "should minify id attributes" do
35
+ # CssPress.press('a[id="x"]{b:c}').should eql 'a#x{b:c}'
36
+ # CssPress.press('a[id="x.y z"]{b:c}').should eql 'a[id="x.y z"]{b:c}'
37
+ # end
38
+
39
+ it "should minify color" do
40
+ CssPress.press('a{color:#aaaaaa}').should eql 'a{color:#aaa}'
41
+ CssPress.press('a{color:#AaaAaa}').should eql 'a{color:#aaa}'
42
+ CssPress.press('a{color:#ff0000}').should eql 'a{color:red}'
43
+ CssPress.press('a{color:#f00}').should eql 'a{color:red}'
44
+ CssPress.press('#f00{color:#f00}').should eql '#f00{color:red}'
45
+ CssPress.press('a{color:black}').should eql 'a{color:#000}'
46
+ CssPress.press('a{background:black}').should eql 'a{background:#000}'
47
+ CssPress.press('a{border:black}').should eql 'a{border:#000}'
48
+ CssPress.press('a{background-color:black}').should eql 'a{background-color:#000}'
49
+ CssPress.press('a{border-top:black}').should eql 'a{border-top:#000}'
50
+ CssPress.press('a{b:black}').should eql 'a{b:black}'
51
+ CssPress.press('a{color:rgb(0,0,0)}').should eql 'a{color:#000}'
52
+ CssPress.press('a{color:rgb(0%,0%,0%)}').should eql 'a{color:#000}'
53
+ CssPress.press('a{color:rgb(300,0,0)}').should eql 'a{color:rgb(300,0,0)}'
54
+ CssPress.press('a{color:rgb(101%,0%,0%)}').should eql 'a{color:rgb(101%,0,0)}'
55
+ end
56
+
57
+ it "should remove comments" do
58
+ CssPress.press('/* cooment*/a{b:c}').should eql 'a{b:c}'
59
+ CssPress.press('a/* cooment*/{b:c}').should eql 'a{b:c}'
60
+ CssPress.press('a{/* cooment*/b:c}').should eql 'a{b:c}'
61
+ CssPress.press('a{b:/* cooment */c}').should eql 'a{b:c}'
62
+ CssPress.press('a{b:c/* cooment */}').should eql 'a{b:c}'
63
+ CssPress.press('a{b:c/* cooment \*/}').should eql 'a{b:c}'
64
+ CssPress.press('a{b:"\"}\""/* cooment */}').should eql 'a{b:"\"}\""}'
65
+ end
66
+
67
+ it "should remove units from 0" do
68
+ CssPress.press('a{padding:0px}').should eql 'a{padding:0}'
69
+ end
70
+
71
+ it "should remove leading/trailing zeros from decimals" do
72
+ CssPress.press('a{padding:0.1%}').should eql 'a{padding:.1%}'
73
+ CssPress.press('a{padding:1.0%}').should eql 'a{padding:1%}'
74
+ CssPress.press('a{margin:-1.0%}').should eql 'a{margin:-1%}'
75
+ CssPress.press('a{margin:-0.1%}').should eql 'a{margin:-.1%}'
76
+ CssPress.press('a{margin:-0.0%}').should eql 'a{margin:0}'
77
+ end
78
+
79
+ it "should change none to 0" do
80
+ CssPress.press('a{border:none}').should eql 'a{border:0}'
81
+ CssPress.press('a{border-bottom:none}').should eql 'a{border-bottom:0}'
82
+ end
83
+
84
+ it "should remove duplicate rules" do
85
+ CssPress.press('a{x:y;x:z}').should eql 'a{x:z}'
86
+ CssPress.press('a{x:y1;b:b;x:z}').should eql 'a{b:b;x:z}'
87
+ CssPress.press('a{c:c;x:y;b:b;x:z}').should eql 'a{c:c;b:b;x:z}'
88
+ CssPress.press('a{c:c;x:y;b:b;x:z;d:d;x:x}').should eql 'a{c:c;b:b;d:d;x:x}'
89
+ CssPress.press('a{c:c;x:y;b:b;x:z;c:c;x:x}').should eql 'a{b:b;c:c;x:x}'
90
+ # Safari does not support the "quotes" property.
91
+ # CSS 2; used to remove quotes in case "none" fails below.
92
+ # CSS 2.1; will remove quotes if supported, and override the above.
93
+ # User-agents that don't understand "none" should ignore it, and keep the above value.
94
+ CssPress.press('q:before,q:after{content:"";content:none}').should eql 'q:before,q:after{content:"";content:none}'
95
+ end
96
+
97
+ # it "should remove unnecessary values from padding/margin" do
98
+ # CssPress.press('a{padding:0 0 0 0}').should eql 'a{padding:0}'
99
+ # CssPress.press('a{padding:0 0 10px 0}').should eql 'a{padding:0 0 10px}'
100
+ # CssPress.press('a{padding:0 auto 0 auto}').should eql 'a{padding:0 auto}'
101
+ # CssPress.press('a{background-position:0 0}').should eql 'a{background-position:0 0}'
102
+ # end
103
+
104
+ it "should remove empty rules" do
105
+ CssPress.press('a{}').should eql ''
106
+ CssPress.press('a{/*b:c*/}').should eql ''
107
+ CssPress.press('@media print{a{}}').should eql ''
108
+ CssPress.press('@media print{a{}b{c:d}}').should eql '@media print{b{c:d}}'
109
+ end
110
+
111
+ # it "should combine all background related properties" do
112
+ # css_in = 'a{
113
+ # background-color: #fff;
114
+ # background-image: url(image.gif);
115
+ # background-repeat: repeat-x;
116
+ # background-attachment: fixed;
117
+ # background-position: 0 0}'
118
+ # css_out = 'a{background:#fff url(image.gif) repeat-x fixed 0 0}'
119
+ # CssPress.press(css_in).should eql css_out
120
+ # end
121
+
122
+ # it "should combine all border related properties" do
123
+ # css_in = 'a{
124
+ # border-left-color: #000;
125
+ # border-left-style: solid;
126
+ # border-left-width: 2px;
127
+ # border-right-color: #000;
128
+ # border-right-style: solid;
129
+ # border-right-width: 2px;
130
+ # border-top-color: #000;
131
+ # border-top-style: solid;
132
+ # border-top-width: 3px}'
133
+ # css_out = 'a{border:solid #000;border-width:3px 2px 0}'
134
+ # CssPress.press(css_in).should eql css_out
135
+ # end
136
+
137
+ # it "should combine all border-radius related properties" do
138
+ # -moz- -webkit- -o-
139
+ # end
140
+
141
+ # it "should combine all font related properties" do
142
+ # css_in = 'a{
143
+ # font-style: italic;
144
+ # font-variant: small-caps;
145
+ # font-weight: 500;
146
+ # font-size: 1em;
147
+ # line-height: 24px;
148
+ # font-family: arial,sans-serif}'
149
+ # css_out = 'a{font:italic small-caps 500 1em/24px arial,sans-serif}'
150
+ # CssPress.press(css_in).should eql css_out
151
+ # end
152
+
153
+ # it "should minimize font-family" do
154
+ # end
155
+
156
+ # it "should combine all list related properties" do
157
+ # css_in = 'a{
158
+ # list-style-type: circle;
159
+ # list-style-position: inside;
160
+ # list-style-image: url(bullet.gif)}'
161
+ # css_out = 'a{list-style:inside circle url(bullet.gif)}'
162
+ # CssPress.press(css_in).should eql css_out
163
+ # end
164
+
165
+ # it "should combine all outline related properties" do
166
+ # css_in = 'a{
167
+ # outline-color: #fff;
168
+ # outline-style: dotted;
169
+ # outline-width: 1px}'
170
+ # css_out = 'a{outline:#fff dotted 1px}'
171
+ # CssPress.press(css_in).should eql css_out
172
+ # end
173
+
174
+ # it "should combine all margin/padding related properties" do
175
+ # css_in = 'a{margin-top:1px;margin-bottom:2px;margin-right:3px;margin-left:0px}'
176
+ # css_out = 'a{margin:1px 3px 2px 0}'
177
+ # CssPress.press(css_in).should eql css_out
178
+
179
+ # css_in = 'a{margin-top:1px;margin-bottom:1px;margin-right:1px;margin-left:1px}'
180
+ # css_out = 'a{margin:1px}'
181
+ # CssPress.press(css_in).should eql css_out
182
+
183
+ # css_in = 'a{padding-top:1px;padding-bottom:2px;padding-right:3px;padding-left:0px}'
184
+ # css_out = 'a{padding:1px 3px 2px 0}'
185
+ # CssPress.press(css_in).should eql css_out
186
+ # end
187
+
188
+ # it "should combine rules with the same selectors" do
189
+ # css_in = 'a{color:red}a{text-decoration:none}'
190
+ # css_out = 'a{color:red;text-decoration:none}'
191
+ # CssPress.press(css_in).should eql css_out
192
+ # end
193
+
194
+ # it "should combine rules with the same rulesets" do
195
+ # css_in = 'a{color:red}b{color:red}'
196
+ # css_out = 'a,b{color:red}'
197
+ # CssPress.press(css_in).should eql css_out
198
+ # end
199
+
200
+ # it "should inline import" do
201
+ # end
202
+
203
+ # it "should inline small images" do
204
+ # end
205
+
206
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: css_press
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - stereobooster
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-28 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: csspool-st
16
+ requirement: &29000628 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - =
20
+ - !ruby/object:Gem::Version
21
+ version: 3.1.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *29000628
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &29000352 !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: *29000352
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &29000076 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *29000076
47
+ description: Ruby gem for compressing CSS
48
+ email:
49
+ - stereobooster@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - Gemfile
56
+ - Rakefile
57
+ - Readme.md
58
+ - css_press.gemspec
59
+ - lib/colors/hex_to_safe.json
60
+ - lib/colors/hex_to_short.json
61
+ - lib/colors/long_to_hex.json
62
+ - lib/css_press.rb
63
+ - lib/css_press/color.rb
64
+ - lib/css_press/css.rb
65
+ - lib/css_press/min_css.rb
66
+ - lib/css_press/node.rb
67
+ - lib/css_press/version.rb
68
+ - spec/css_press_spec.rb
69
+ homepage: ''
70
+ licenses: []
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ segments:
82
+ - 0
83
+ hash: 419184687
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ segments:
91
+ - 0
92
+ hash: 419184687
93
+ requirements: []
94
+ rubyforge_project: css_press
95
+ rubygems_version: 1.8.15
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: Compress CSS
99
+ test_files: []