xhochy-rainpress 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +50 -0
- data/Rakefile +170 -0
- data/VERSION.yml +4 -0
- data/bin/rainpress +128 -0
- data/lib/rainpress.rb +244 -0
- data/lib/rainpress_test.rb +238 -0
- metadata +58 -0
data/README.rdoc
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
== About
|
2
|
+
|
3
|
+
Rainpress is a compressor for CSS. It's written in ruby, but should not be
|
4
|
+
limited to ruby projects.
|
5
|
+
|
6
|
+
Rainpress does not apply common compression algorithms like gzip, it removes
|
7
|
+
unnecessary characters and replaces some attributes with a shorter equivalent
|
8
|
+
name.
|
9
|
+
|
10
|
+
== Simple Usage
|
11
|
+
|
12
|
+
require 'rubygems'
|
13
|
+
require 'rainpress'
|
14
|
+
compressed_style_text = Rainpress.compress style_text
|
15
|
+
|
16
|
+
== License
|
17
|
+
|
18
|
+
Copyright (c) 2007-2008 Uwe L. Korn
|
19
|
+
|
20
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
21
|
+
of this software and associated documentation files (the "Software"), to deal
|
22
|
+
in the Software without restriction, including without limitation the rights
|
23
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
24
|
+
copies of the Software, and to permit persons to whom the Software is
|
25
|
+
furnished to do so, subject to the following conditions:
|
26
|
+
|
27
|
+
The above copyright notice and this permission notice shall be included in
|
28
|
+
all copies or substantial portions of the Software.
|
29
|
+
|
30
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
31
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
32
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
33
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
34
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
35
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
36
|
+
THE SOFTWARE.
|
37
|
+
|
38
|
+
Remark(not part of the license text): This is a MIT-style license
|
39
|
+
|
40
|
+
== Links
|
41
|
+
|
42
|
+
* {Rainpress Website}[http://rainpress.xhochy.com/]
|
43
|
+
* {Git repository}[http://github.com/xhochy/rainpress/tree/master]
|
44
|
+
* {Bugtracker}[https://bugs.launchpad.net/rainpress/]
|
45
|
+
* {Wiki}[http://code.google.com/p/rainpress/w/list]
|
46
|
+
* {Translations}[https://translations.launchpad.net/rainpress/]
|
47
|
+
* {XhochY Weblog (for Announcements about Rainpress)}[http://xhochy.org/en/]
|
48
|
+
* {Mailinglist}[http://groups.google.com/group/xy-oss-projects-discussion]
|
49
|
+
* {Freshmeat Record}[http://freshmeat.net/projects/rainpress]
|
50
|
+
* {Ohloh listing}[http://www.ohloh.net/projects/12620/]
|
data/Rakefile
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#####################################
|
3
|
+
## The main Rakefile for Rainpress ##
|
4
|
+
#####################################
|
5
|
+
#
|
6
|
+
#--
|
7
|
+
# Copyright (c) 2007-2008 Uwe L. Korn
|
8
|
+
#
|
9
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
10
|
+
# of this software and associated documentation files (the "Software"), to deal
|
11
|
+
# in the Software without restriction, including without limitation the rights
|
12
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
13
|
+
# copies of the Software, and to permit persons to whom the Software is
|
14
|
+
# furnished to do so, subject to the following conditions:
|
15
|
+
#
|
16
|
+
# The above copyright notice and this permission notice shall be included in
|
17
|
+
# all copies or substantial portions of the Software.
|
18
|
+
#
|
19
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
20
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
21
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
22
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
23
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
24
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
25
|
+
# THE SOFTWARE.
|
26
|
+
#++
|
27
|
+
#
|
28
|
+
# Author:: Uwe L. Korn <uwelk@xhochy.org>
|
29
|
+
# Copyright:: Copyright (c) 2007-2008 Uwe L. Korn
|
30
|
+
# License:: MIT-style License (see Rainpress)
|
31
|
+
|
32
|
+
## Includes ##
|
33
|
+
|
34
|
+
# Use the prewritten :clean Task from rake
|
35
|
+
require 'rake/clean'
|
36
|
+
# Use the gettext-utility functions for pot and mo generation
|
37
|
+
require 'gettext/utils'
|
38
|
+
|
39
|
+
require 'rubygems'
|
40
|
+
require 'rake'
|
41
|
+
require 'rake/testtask'
|
42
|
+
require 'rake/rdoctask'
|
43
|
+
require 'spec/rake/spectask'
|
44
|
+
|
45
|
+
Dir['tasks/**/*.rake'].each { |rake| load rake }
|
46
|
+
|
47
|
+
## Config ##
|
48
|
+
|
49
|
+
doc = {
|
50
|
+
# The location of all important Rainpress source files
|
51
|
+
'Files' => FileList['*.rb', File.join('rainpress', '*.rb')],
|
52
|
+
# The title of the API Documentation
|
53
|
+
'Title' => 'Rainpress'
|
54
|
+
}
|
55
|
+
|
56
|
+
## Tasks ##
|
57
|
+
|
58
|
+
# Run the unit tests via rcov, so that we see which code is covered by
|
59
|
+
# the unit tests and which code needs additional tests written for. Our
|
60
|
+
# aim is that the tests for Rainpress should cover *all* code, if not
|
61
|
+
# it shouldn't be checked in before there are not enough tests.
|
62
|
+
#
|
63
|
+
# But remember: 100% Code coverage does not mean that the programm is 100%
|
64
|
+
# correct!
|
65
|
+
desc 'Run unit tests'
|
66
|
+
task :test do
|
67
|
+
sh 'rcov rainpress_test.rb'
|
68
|
+
end
|
69
|
+
|
70
|
+
desc 'Build pot-file from sourcecode'
|
71
|
+
task :build_pot => [File.join('locale', 'rainpress.pot')]
|
72
|
+
|
73
|
+
desc 'Complie *.po-files to binary mo\'s'
|
74
|
+
task :build_mo do
|
75
|
+
GetText::create_mofiles(true, 'locale', 'locale')
|
76
|
+
end
|
77
|
+
|
78
|
+
# The API documentation should only be changed if there is a source code file
|
79
|
+
# which last modification time is higher than the modification time of the
|
80
|
+
# index.html which is always regenerated during the API documentation building
|
81
|
+
# process.
|
82
|
+
desc 'Generate the sourcecode documentation'
|
83
|
+
task :doc => [File.join('doc', 'index.html')]
|
84
|
+
|
85
|
+
# If we want to build all, this just means we want to build the API
|
86
|
+
# documentation and run the unit tests.
|
87
|
+
task :all => [:doc, :test]
|
88
|
+
|
89
|
+
# By default we build the task :all
|
90
|
+
task :default => [:all]
|
91
|
+
|
92
|
+
## XhochY specific Tasks ##
|
93
|
+
|
94
|
+
# This tasks is only used for the continous builds on xhochy.com, don't change!
|
95
|
+
# The location is fixed and the only place where this script has permission to
|
96
|
+
# write to.
|
97
|
+
# The output is visible via
|
98
|
+
# - http://rainpress.xhochy.com/test/ (The code coverage reports of the unittests)
|
99
|
+
# - http://rainpress.xhochy.com/doc/ (The API documentation)
|
100
|
+
task :publish_to_rainpress_xhochy_com => [:doc, :test]
|
101
|
+
task :publish_to_rainpress_xhochy_com do
|
102
|
+
sh 'rm -rf /srv/www/port80/rainpress.xhochy.com/doc/'
|
103
|
+
sh 'rm -rf /srv/www/port80/rainpress.xhochy.com/coverage/'
|
104
|
+
sh 'cp -r doc/ coverage/ /srv/www/port80/rainpress.xhochy.com'
|
105
|
+
end
|
106
|
+
|
107
|
+
## clean Task ##
|
108
|
+
|
109
|
+
# Delete the API Documentation
|
110
|
+
CLEAN.include('doc')
|
111
|
+
# Delete the code coverage report
|
112
|
+
CLEAN.include('coverage')
|
113
|
+
# The flowing commands will delete the Debian-Package temporary files
|
114
|
+
CLEAN.include('build-stamp')
|
115
|
+
CLEAN.include('configure-stamp')
|
116
|
+
CLEAN.include(File.join('debian', 'rainpress'))
|
117
|
+
CLEAN.include(File.join('debian', 'rainpress-doc'))
|
118
|
+
CLEAN.include(File.join('debian', 'files'))
|
119
|
+
# Delete all binary translations (*.mo-files, not the *.po-files)
|
120
|
+
CLEAN.include(File.join('locale', '*', 'LC_MESSAGES'));
|
121
|
+
|
122
|
+
## Deb(ian) Package Tasks ##
|
123
|
+
|
124
|
+
# Build a source Debian package package that could be either used for building
|
125
|
+
# a "binary" Debian package via pbuilder or for uploads in a APT repository.
|
126
|
+
desc 'Build debian-source-package'
|
127
|
+
task :source_deb => [:build_mo] do
|
128
|
+
sh 'debuild -S -I.svn -us -uc'
|
129
|
+
end
|
130
|
+
task :source_deb => [:clean]
|
131
|
+
|
132
|
+
# Builds a "binary" Debian package using the fakeroot command, packages created
|
133
|
+
# this way only tell us that the generation process has no problems. If you want
|
134
|
+
# to check if all build dependecies are remarked in debian/control, you should
|
135
|
+
# generate a source Debian package via `rake source_deb` and then use pbuilder
|
136
|
+
# to build the "binary" package via `sudo pbuilder *.dsc`. Only this will ensure
|
137
|
+
# that the package could be build on standard configurations, since pbuilder
|
138
|
+
# builds the package in a clean chroot-environment.
|
139
|
+
desc 'Build debian-package using fakeroot'
|
140
|
+
task :binary_deb_fakeroot do
|
141
|
+
sh 'dpkg-buildpackage -rfakeroot -us -uc'
|
142
|
+
end
|
143
|
+
task :binary_deb_fakeroot => [:source_deb]
|
144
|
+
|
145
|
+
## File Tasks ##
|
146
|
+
|
147
|
+
# Builds the PO-template out of the ruby source code, at the moment we only have
|
148
|
+
# i18n strings in the rainpress.rb, we will ignore other i18n strings in other
|
149
|
+
# files. If there are any changes in the PO-template, the new version should be
|
150
|
+
# uploaded to https://translations.launchpad.net/rainpress/ so that there's
|
151
|
+
# always the up-to-date version, so that the translation keeps up with the
|
152
|
+
# development.
|
153
|
+
file File.join('locale', 'rainpress.pot') => 'bin/rainpress' do
|
154
|
+
rm_f File.join('locale', 'rainpress.pot')
|
155
|
+
sh 'rgettext bin/rainpress -o ' + File.join('locale', 'rainpress.pot')
|
156
|
+
puts '!!! Remember to upload the updated pot-file to Launchpad/Translations !!!'
|
157
|
+
end
|
158
|
+
|
159
|
+
# Build the API documentation using RDoc, the include diagrams are made with
|
160
|
+
# graphviz, so this needs to installed on the developemnt system too.
|
161
|
+
file File.join('doc', 'index.html') => doc['Files'] do
|
162
|
+
sh "rm -rf doc"
|
163
|
+
|
164
|
+
cmd = 'rdoc --title ' + doc['Title']
|
165
|
+
cmd+= ' --all --diagram --image-format png --inline-source --charset UTF-8 '
|
166
|
+
cmd+= '--op doc/ --tab-width 4'
|
167
|
+
sh cmd
|
168
|
+
end
|
169
|
+
|
170
|
+
task :release => [:build_mo]
|
data/VERSION.yml
ADDED
data/bin/rainpress
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
##############################################
|
3
|
+
# This is the Rainpress standalone excutable #
|
4
|
+
##############################################
|
5
|
+
#
|
6
|
+
#--
|
7
|
+
# Copyright (c) 2007-2008 Uwe L. Korn
|
8
|
+
#
|
9
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
10
|
+
# of this software and associated documentation files (the "Software"), to deal
|
11
|
+
# in the Software without restriction, including without limitation the rights
|
12
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
13
|
+
# copies of the Software, and to permit persons to whom the Software is
|
14
|
+
# furnished to do so, subject to the following conditions:
|
15
|
+
#
|
16
|
+
# The above copyright notice and this permission notice shall be included in
|
17
|
+
# all copies or substantial portions of the Software.
|
18
|
+
#
|
19
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
20
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
21
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
22
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
23
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
24
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
25
|
+
# THE SOFTWARE.
|
26
|
+
#++
|
27
|
+
#
|
28
|
+
# Author:: Uwe L. Korn <uwelk@xhochy.org>
|
29
|
+
# Copyright:: Copyright (c) 2007-2008 Uwe L. Korn
|
30
|
+
# License:: MIT-style License (see Rainpress)
|
31
|
+
|
32
|
+
require 'getoptlong'
|
33
|
+
require 'gettext'
|
34
|
+
# Do not include rainpress/packer via global include, this might include
|
35
|
+
# a false file, we want the Packer version which is shipped with this file.
|
36
|
+
require File.join(File.dirname(__FILE__), *%w[.. lib rainpress])
|
37
|
+
|
38
|
+
## Var Init ##
|
39
|
+
|
40
|
+
opts = GetoptLong.new(
|
41
|
+
['--help', '-h', GetoptLong::NO_ARGUMENT],
|
42
|
+
['--input', '-i', GetoptLong::REQUIRED_ARGUMENT],
|
43
|
+
['--output', '-o', GetoptLong::REQUIRED_ARGUMENT],
|
44
|
+
['--keep-comments', '-c', GetoptLong::NO_ARGUMENT],
|
45
|
+
['--keep-newlines', '-n', GetoptLong::NO_ARGUMENT],
|
46
|
+
['--keep-spaces', '-s', GetoptLong::NO_ARGUMENT],
|
47
|
+
['--leave-spaces', '-k', GetoptLong::NO_ARGUMENT],
|
48
|
+
['--skip-misc', '-m', GetoptLong::NO_ARGUMENT]
|
49
|
+
)
|
50
|
+
|
51
|
+
$infile = nil
|
52
|
+
$outfile = nil
|
53
|
+
|
54
|
+
GetText::bindtextdomain('rainpress', File.join(File.dirname(__FILE__), *%w[.. locale]))
|
55
|
+
|
56
|
+
## Functions ##
|
57
|
+
|
58
|
+
# Explain to the user how to use Rainpress
|
59
|
+
#
|
60
|
+
# After displaying this usage information exit the program.
|
61
|
+
# The messages in this functions are the only things to translate. The
|
62
|
+
# translation files could be found in the locales/ directory, but translation
|
63
|
+
# should be done via https://translations.launchpad.net/rainpress/ . The
|
64
|
+
# translations done there could be exported and merged into the software. We
|
65
|
+
# use Launchpad since it provides a nice interface for the translation process.
|
66
|
+
def usage
|
67
|
+
puts 'Rainpress -- CSS compressor |'
|
68
|
+
puts '----------------------------|'
|
69
|
+
puts ''
|
70
|
+
puts '--help, -h ' + GetText::_('Display this help')
|
71
|
+
puts '--input, -i <file> ' + GetText::_('The CSS-file to be compressed, if not set stdin is used')
|
72
|
+
puts '--output, -o <file> ' + GetText::_('The output file, if not set, stdout is used')
|
73
|
+
puts '--keep-comments, -c ' + GetText::_('Do not remove comments')
|
74
|
+
puts '--keep-newlines, -n ' + GetText::_('Do not remove line breaks')
|
75
|
+
puts '--keep-spaces, -s ' + GetText::_('Do not remove multiple spaces')
|
76
|
+
puts '--leave-colors, -k ' + GetText::_('Do not change color names')
|
77
|
+
puts '--skip-misc, -m ' + GetText::_('Skip all miscellaneous tasks')
|
78
|
+
exit
|
79
|
+
end
|
80
|
+
|
81
|
+
## Main ##
|
82
|
+
|
83
|
+
# The options that will be passed to the compress method
|
84
|
+
$options = {}
|
85
|
+
|
86
|
+
opts.each do |opt, arg|
|
87
|
+
case opt
|
88
|
+
when '--help'
|
89
|
+
usage()
|
90
|
+
when '--input'
|
91
|
+
$infile = arg
|
92
|
+
when '--output'
|
93
|
+
$outfile = arg
|
94
|
+
when '--keep-comments'
|
95
|
+
$options[:preserveComments] = true
|
96
|
+
when '--keep-newlines'
|
97
|
+
$options[:preserveNewlines] = true
|
98
|
+
when '--keep-spaces'
|
99
|
+
$options[:preserveSpaces] = true
|
100
|
+
when '--leave-colors'
|
101
|
+
$options[:preserveColors] = true
|
102
|
+
when '--skip-misc'
|
103
|
+
$options[:skipMisc] = true
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Check if a input file is set, if not than read from stdin
|
108
|
+
if $infile == nil
|
109
|
+
$input = STDIN.read
|
110
|
+
else
|
111
|
+
$input = File.read($infile)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Create a new Rainpress::Packer instance which we'll use for compressing
|
115
|
+
packer = Rainpress::Packer.new
|
116
|
+
# Compress the inputted text
|
117
|
+
$output = packer.compress($input, $options)
|
118
|
+
|
119
|
+
# Check if a output file is set, if not write to stdout
|
120
|
+
if $outfile == nil
|
121
|
+
puts $output
|
122
|
+
else
|
123
|
+
# TODO: Is there no Ruby equivalent to PHP's file_put_contents ?
|
124
|
+
File.open($outfile, 'w') do |f|
|
125
|
+
f.write $output
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
data/lib/rainpress.rb
ADDED
@@ -0,0 +1,244 @@
|
|
1
|
+
# == About
|
2
|
+
#
|
3
|
+
# Rainpress is a compressor for CSS. It's written in ruby, but should not be
|
4
|
+
# limited to ruby projects.
|
5
|
+
#
|
6
|
+
# Rainpress does not apply common compression algorithms like gzip, it removes
|
7
|
+
# unnecessary characters and replaces some attributes with a shorter equivalent
|
8
|
+
# name.
|
9
|
+
#
|
10
|
+
# Copyright:: Copyright (c) 2007-2008 Uwe L. Korn
|
11
|
+
#
|
12
|
+
# == License
|
13
|
+
#
|
14
|
+
# Copyright (c) 2007-2008 Uwe L. Korn
|
15
|
+
#
|
16
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
17
|
+
# of this software and associated documentation files (the "Software"), to deal
|
18
|
+
# in the Software without restriction, including without limitation the rights
|
19
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
20
|
+
# copies of the Software, and to permit persons to whom the Software is
|
21
|
+
# furnished to do so, subject to the following conditions:
|
22
|
+
#
|
23
|
+
# The above copyright notice and this permission notice shall be included in
|
24
|
+
# all copies or substantial portions of the Software.
|
25
|
+
#
|
26
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
27
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
28
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
29
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
30
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
31
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
32
|
+
# THE SOFTWARE.
|
33
|
+
#
|
34
|
+
# Remark(not part of the license text): This is a MIT-style license
|
35
|
+
#
|
36
|
+
# == Links
|
37
|
+
#
|
38
|
+
# * {Rainpress Website}[http://rainpress.xhochy.com/]
|
39
|
+
# * {SVN repository}[http://code.google.com/p/rainpress/source]
|
40
|
+
# * {Bugtracker}[https://bugs.launchpad.net/rainpress/]
|
41
|
+
# * {Wiki}[http://code.google.com/p/rainpress/w/list]
|
42
|
+
# * {Translations}[https://translations.launchpad.net/rainpress/]
|
43
|
+
# * {XhochY Weblog (for Announcements about Rainpress)}[http://xhochy.org/en/]
|
44
|
+
# * {Mailinglist}[http://groups.google.com/group/xy-oss-projects-discussion]
|
45
|
+
# * {Continous Integration Builds and Tests}[http://cruisecontrol-rb.xhochy.com/builds/rainpress]
|
46
|
+
# * {Freshmeat Record}[http://freshmeat.net/projects/rainpress]
|
47
|
+
# * {Ohloh listing}[http://www.ohloh.net/projects/12620/]
|
48
|
+
module Rainpress
|
49
|
+
|
50
|
+
# == Information
|
51
|
+
#
|
52
|
+
# This is the main class of Rainpress, create an instance of it to compress
|
53
|
+
# your CSS-styles.
|
54
|
+
#
|
55
|
+
# Author:: Uwe L. Korn <uwelk@xhochy.org>
|
56
|
+
#
|
57
|
+
# == Simple Usage
|
58
|
+
#
|
59
|
+
# packer = Rainpress::Packer.new
|
60
|
+
# compressed_style = packer.compress(style)
|
61
|
+
class Packer
|
62
|
+
|
63
|
+
# Use always this functions if you want to compress your CSS-style
|
64
|
+
#
|
65
|
+
# <b>Options:</b>
|
66
|
+
#
|
67
|
+
# * <tt>:preserveComments</tt> - if set to true, comments will not be
|
68
|
+
# removed
|
69
|
+
# * <tt>:preserveNewline</tt> - if set to true, newlines will not be removed
|
70
|
+
# * <tt>:preserveSpaces</tt> - if set to true, spaces will not be removed
|
71
|
+
# * <tt>:preserveColors</tt> - if set to true, colors will not be modified
|
72
|
+
# * <tt>:skipMisc</tt> - if set to true, miscellaneous compression parts
|
73
|
+
# will be skipped
|
74
|
+
def compress(style, options = {})
|
75
|
+
# remove comments
|
76
|
+
style = remove_comments(style) unless options[:preserveComments]
|
77
|
+
|
78
|
+
# remove newlines
|
79
|
+
style = remove_newlines(style) unless options[:preserveNewlines]
|
80
|
+
|
81
|
+
# remove unneeded spaces
|
82
|
+
style = remove_spaces(style) unless options[:preserveSpaces]
|
83
|
+
|
84
|
+
# replace colours with shorter names
|
85
|
+
style = shorten_colors(style) unless options[:preserveColors]
|
86
|
+
|
87
|
+
# make all other things
|
88
|
+
style = do_misc(style) unless options[:skipMisc]
|
89
|
+
|
90
|
+
style
|
91
|
+
end
|
92
|
+
|
93
|
+
# Remove all comments out of the CSS-Document
|
94
|
+
#
|
95
|
+
# Only /* text */ comments are supported.
|
96
|
+
# Attention: If you are doing css hacks for IE using the comment tricks,
|
97
|
+
# they will be removed using this function. Please consider for IE css style
|
98
|
+
# corrections the usage of conditionals comments in your (X)HTML document.
|
99
|
+
def remove_comments(script)
|
100
|
+
input = script
|
101
|
+
script = ''
|
102
|
+
|
103
|
+
while input.length > 0 do
|
104
|
+
pos = input.index("/*");
|
105
|
+
|
106
|
+
# No more comments
|
107
|
+
if pos == nil
|
108
|
+
script += input
|
109
|
+
input = '';
|
110
|
+
else # Comment beginning at pos
|
111
|
+
script += input[0..(pos-1)] if pos > 0 # only append text if there is some
|
112
|
+
input = input[(pos+2)..-1]
|
113
|
+
# Comment ending at pos
|
114
|
+
pos = input.index("*/")
|
115
|
+
input = input[(pos+2)..-1]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# return
|
120
|
+
script
|
121
|
+
end
|
122
|
+
|
123
|
+
# Remove all newline characters
|
124
|
+
#
|
125
|
+
# We take care of Windows(\r\n), Unix(\n) and Mac(\r) newlines.
|
126
|
+
def remove_newlines(script)
|
127
|
+
script.gsub(/\n|\r/,'')
|
128
|
+
end
|
129
|
+
|
130
|
+
# Remove unneeded spaces
|
131
|
+
#
|
132
|
+
# 1. Turn mutiple spaces into a single
|
133
|
+
# 2. Remove spaces around ;:{},
|
134
|
+
# 3. Remove tabs
|
135
|
+
def remove_spaces(script)
|
136
|
+
script = script.gsub(/(\s(\s)+)/, ' ')
|
137
|
+
script = script.gsub(/\s*;\s*/,';')
|
138
|
+
script = script.gsub(/\s*:\s*/,':')
|
139
|
+
script = script.gsub(/\s*\{\s*/,'{')
|
140
|
+
script = script.gsub(/\s*\}\s*/,'}')
|
141
|
+
script = script.gsub(/\s*,\s*/,',')
|
142
|
+
script.gsub("\t",'');
|
143
|
+
end
|
144
|
+
|
145
|
+
# Replace color values with their shorter equivalent
|
146
|
+
#
|
147
|
+
# 1. Turn rgb(,,)-colors into #-values
|
148
|
+
# 2. Shorten #AABBCC down to #ABC
|
149
|
+
# 3. Replace names with their shorter hex-equivalent
|
150
|
+
# * white -> #fff
|
151
|
+
# * black -> #000
|
152
|
+
# 4. Replace #-values with their shorter name
|
153
|
+
# * #f00 -> red
|
154
|
+
def shorten_colors(style)
|
155
|
+
# rgb(50,101,152) to #326598
|
156
|
+
style = style.gsub(/rgb\s*\(\s*([0-9,\s]+)\s*\)/) do |match|
|
157
|
+
out = '#'
|
158
|
+
$1.split(',').each do |num|
|
159
|
+
if num.to_i < 16
|
160
|
+
out += '0'
|
161
|
+
end
|
162
|
+
out += num.to_i.to_s(16) # convert to hex
|
163
|
+
end
|
164
|
+
out
|
165
|
+
end
|
166
|
+
# Convert #AABBCC to #ABC, keep if preceed by a '='
|
167
|
+
style = style.gsub(/([^\"'=\s])(\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/) do |match|
|
168
|
+
out = match
|
169
|
+
if ($3.downcase == $4.downcase) and ($5.downcase == $6.downcase) and ($7.downcase == $8.downcase)
|
170
|
+
out = $1 + '#' + $3.downcase + $5.downcase + $7.downcase
|
171
|
+
end
|
172
|
+
out
|
173
|
+
end
|
174
|
+
|
175
|
+
# At the moment we assume that colours only appear before ';' or '}' and
|
176
|
+
# after a ':', if there could be an occurence of a color before or after
|
177
|
+
# an other character, submit either a bug report or, better, a patch that
|
178
|
+
# enables Rainpress to take care of this.
|
179
|
+
|
180
|
+
# shorten several names to numbers
|
181
|
+
## shorten white -> #fff
|
182
|
+
style = style.gsub(/:[\s]*white[\s]*;/, ':#fff;')
|
183
|
+
style = style.gsub(/:[\s]*white[\s]*\}/, ':#fff}')
|
184
|
+
## shorten black -> #000
|
185
|
+
style = style.gsub(/:[\s]*black[\s]*;/, ':#000;')
|
186
|
+
style = style.gsub(/:[\s]*black[\s]*\}/, ':#000}')
|
187
|
+
# shotern several numbers to names
|
188
|
+
## shorten #f00 or #ff0000 -> red
|
189
|
+
style = style.gsub(/:[\s]*#([fF]00|[fF]{2}0000);/, ':red;')
|
190
|
+
style = style.gsub(/:[\s]*#([fF]00|[fF]{2}0000)\}/, ':red}')
|
191
|
+
|
192
|
+
style
|
193
|
+
end
|
194
|
+
|
195
|
+
# Do miscellaneous compression methods on the style.
|
196
|
+
def do_misc(script)
|
197
|
+
# Replace 0(pt,px,em,%) with 0 but only when preceded by : or a white-space
|
198
|
+
script = script.gsub(/([\s:]+)(0)(px|em|%|in|cm|mm|pc|pt|ex)/) do |match|
|
199
|
+
match.gsub(/(px|em|%|in|cm|mm|pc|pt|ex)/,'')
|
200
|
+
end
|
201
|
+
# Replace :0 0 0 0(;|}) with :0(;|})
|
202
|
+
script = script.gsub(':0 0 0 0;', ':0;')
|
203
|
+
script = script.gsub(':0 0 0 0}', ':0}')
|
204
|
+
# Replace :0 0 0(;|}) with :0(;|})
|
205
|
+
script = script.gsub(':0 0 0;', ':0;')
|
206
|
+
script = script.gsub(':0 0 0}', ':0}')
|
207
|
+
# Replace :0 0(;|}) with :0(;|})
|
208
|
+
script = script.gsub(':0 0}', ':0}')
|
209
|
+
script = script.gsub(':0 0;', ':0;')
|
210
|
+
# Replace background-position:0; with background-position:0 0;
|
211
|
+
script = script.gsub('background-position:0;', 'background-position:0 0;');
|
212
|
+
# Replace 0.6 to .6, but only when preceded by : or a white-space
|
213
|
+
script = script.gsub(/[:\s]0+\.(\d+)/) do |match|
|
214
|
+
match.sub('0', '') # only first '0' !!
|
215
|
+
end
|
216
|
+
# Replace multiple ';' with a single ';'
|
217
|
+
script = script.gsub(/[;]+/, ';')
|
218
|
+
# Replace ;} with }
|
219
|
+
script = script.gsub(';}', '}')
|
220
|
+
|
221
|
+
# Do not include again:
|
222
|
+
# -> reported as bug #282496 in Launchpad
|
223
|
+
# # Replace background-color: with background:
|
224
|
+
# # script = script.gsub('background-color:', 'background:')
|
225
|
+
|
226
|
+
# Replace font-weight:normal; with 400
|
227
|
+
script = script.gsub(/font-weight[\s]*:[\s]*normal[\s]*;/,'font-weight:400;')
|
228
|
+
script = script.gsub(/font-weight[\s]*:[\s]*normal[\s]*\}/,'font-weight:400}')
|
229
|
+
script = script.gsub(/font[\s]*:[\s]*normal[\s;\}]*/) do |match|
|
230
|
+
match.sub('normal', '400')
|
231
|
+
end
|
232
|
+
# Replace font-weight:bold; with 700
|
233
|
+
script = script.gsub(/font-weight[\s]*:[\s]*bold[\s]*;/,'font-weight:700;')
|
234
|
+
script = script.gsub(/font-weight[\s]*:[\s]*bold[\s]*\}/,'font-weight:700}')
|
235
|
+
script = script.gsub(/font[\s]*:[\s]*bold[\s;\}]*/) do |match|
|
236
|
+
match.sub('bold', '700')
|
237
|
+
end
|
238
|
+
|
239
|
+
script
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
@@ -0,0 +1,238 @@
|
|
1
|
+
##############################
|
2
|
+
# Test for Rainpress::Packer #
|
3
|
+
##############################
|
4
|
+
#
|
5
|
+
#--
|
6
|
+
# Copyright (c) 2007-2008 Uwe L. Korn
|
7
|
+
#
|
8
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
|
+
# of this software and associated documentation files (the "Software"), to deal
|
10
|
+
# in the Software without restriction, including without limitation the rights
|
11
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12
|
+
# copies of the Software, and to permit persons to whom the Software is
|
13
|
+
# furnished to do so, subject to the following conditions:
|
14
|
+
#
|
15
|
+
# The above copyright notice and this permission notice shall be included in
|
16
|
+
# all copies or substantial portions of the Software.
|
17
|
+
#
|
18
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
21
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24
|
+
# THE SOFTWARE.
|
25
|
+
#++
|
26
|
+
#
|
27
|
+
# Author:: Uwe L. Korn <uwelk@xhochy.org>
|
28
|
+
# Copyright:: Copyright (c) 2007-2008 Uwe L. Korn
|
29
|
+
# License:: MIT-style License (see Rainpress)require 'test/unit'
|
30
|
+
|
31
|
+
require 'test/unit'
|
32
|
+
require File.join(File.dirname(__FILE__), 'rainpress.rb')
|
33
|
+
|
34
|
+
module Rainpress
|
35
|
+
# This class keeps all Tests for the class Rainpress::Packer
|
36
|
+
#
|
37
|
+
# Author:: Uwe L. Korn <uwelk@xhochy.org>
|
38
|
+
class TestPacker < Test::Unit::TestCase
|
39
|
+
|
40
|
+
# Create an instace of Rainpress::Packer for use in the tests
|
41
|
+
def setup
|
42
|
+
@packer = Rainpress::Packer.new
|
43
|
+
end
|
44
|
+
|
45
|
+
# Test Rainpress::Packer.remove_comments
|
46
|
+
def test_remove_comments
|
47
|
+
options = {
|
48
|
+
:preserveComments => false,
|
49
|
+
:preserveNewlines => true,
|
50
|
+
:preserveSpaces => true,
|
51
|
+
:preserveColors => true,
|
52
|
+
:skipMisc => true
|
53
|
+
}
|
54
|
+
|
55
|
+
# plain comment -> ''
|
56
|
+
input = '/* sss */';
|
57
|
+
assert_equal('', @packer.compress(input, options))
|
58
|
+
|
59
|
+
# no comment -> no change
|
60
|
+
input = 'sss';
|
61
|
+
assert_equal('sss', @packer.compress(input, options))
|
62
|
+
|
63
|
+
# comment floating in text
|
64
|
+
input = 's/*ss*/ss';
|
65
|
+
assert_equal('sss', @packer.compress(input, options))
|
66
|
+
|
67
|
+
# empty string
|
68
|
+
input = ''
|
69
|
+
assert_equal('', @packer.compress(input, options))
|
70
|
+
end
|
71
|
+
|
72
|
+
# Test Rainpress::Packer.remove_newlines
|
73
|
+
def test_remove_newlines
|
74
|
+
options = {
|
75
|
+
:preserveComments => true,
|
76
|
+
:preserveNewlines => false,
|
77
|
+
:preserveSpaces => true,
|
78
|
+
:preserveColors => true,
|
79
|
+
:skipMisc => true
|
80
|
+
}
|
81
|
+
|
82
|
+
# plain unix-newline
|
83
|
+
input = "\n"
|
84
|
+
assert_equal('', @packer.compress(input, options))
|
85
|
+
|
86
|
+
# plain windows newline
|
87
|
+
input = "\r\n"
|
88
|
+
assert_equal('', @packer.compress(input, options))
|
89
|
+
|
90
|
+
# no newline
|
91
|
+
input = "rn"
|
92
|
+
assert_equal('rn', @packer.compress(input, options))
|
93
|
+
|
94
|
+
# newlines floatin in text
|
95
|
+
input = "sss\n||\r\nsss"
|
96
|
+
assert_equal('sss||sss', @packer.compress(input, options))
|
97
|
+
|
98
|
+
# empty string
|
99
|
+
input = ''
|
100
|
+
assert_equal('', @packer.compress(input, options))
|
101
|
+
end
|
102
|
+
|
103
|
+
# Test Rainpress::Packer.remove_spaces
|
104
|
+
def test_remove_spaces
|
105
|
+
options = {
|
106
|
+
:preserveComments => true,
|
107
|
+
:preserveNewlines => true,
|
108
|
+
:preserveSpaces => false,
|
109
|
+
:preserveColors => true,
|
110
|
+
:skipMisc => true
|
111
|
+
}
|
112
|
+
|
113
|
+
# (a) Turn mutiple Spaces into a single, but not less
|
114
|
+
input = ' ' # 2 spaces
|
115
|
+
assert_equal(' ', @packer.compress(input, options))
|
116
|
+
input = ' ' # 3 spaces
|
117
|
+
assert_equal(' ', @packer.compress(input, options))
|
118
|
+
|
119
|
+
# (b) remove spaces around ;:{},
|
120
|
+
input = ' ; '
|
121
|
+
assert_equal(';', @packer.compress(input, options))
|
122
|
+
input = ' : '
|
123
|
+
assert_equal(':', @packer.compress(input, options))
|
124
|
+
input = ' { '
|
125
|
+
assert_equal('{', @packer.compress(input, options))
|
126
|
+
input = ' } '
|
127
|
+
assert_equal('}', @packer.compress(input, options))
|
128
|
+
input = ' , '
|
129
|
+
assert_equal(',', @packer.compress(input, options))
|
130
|
+
# (c) remove tabs
|
131
|
+
input = "\t"
|
132
|
+
assert_equal('', @packer.compress(input, options))
|
133
|
+
end
|
134
|
+
|
135
|
+
# Test Rainpress::Packer.shorten_colors
|
136
|
+
def test_shorten_colors
|
137
|
+
options = {
|
138
|
+
:preserveComments => true,
|
139
|
+
:preserveNewlines => true,
|
140
|
+
:preserveSpaces => true,
|
141
|
+
:preserveColors => false,
|
142
|
+
:skipMisc => true
|
143
|
+
}
|
144
|
+
# rgb(50,101,152) to #326598
|
145
|
+
input = 'color:rgb(12,101,152)'
|
146
|
+
assert_equal('color:#0c6598', @packer.compress(input, options))
|
147
|
+
|
148
|
+
# #AABBCC to #ABC
|
149
|
+
input = 'color:#AAbBCC'
|
150
|
+
assert_equal('color:#abc', @packer.compress(input, options))
|
151
|
+
# Keep chroma(color="#FFFFFF"); ... due to IE
|
152
|
+
input = 'chroma(color="#FFFFFF");'
|
153
|
+
assert_equal('chroma(color="#FFFFFF");', @packer.compress(input, options))
|
154
|
+
|
155
|
+
# shorten several names to numbers
|
156
|
+
input = 'color:white;'
|
157
|
+
assert_equal('color:#fff;', @packer.compress(input, options))
|
158
|
+
input = 'color: white}'
|
159
|
+
assert_equal('color:#fff}', @packer.compress(input, options))
|
160
|
+
|
161
|
+
# shotern several numbers to names
|
162
|
+
input = 'color:#ff0000;'
|
163
|
+
assert_equal('color:red;', @packer.compress(input, options))
|
164
|
+
input = 'color:#F00;'
|
165
|
+
assert_equal('color:red;', @packer.compress(input, options))
|
166
|
+
end
|
167
|
+
|
168
|
+
# Test Rainpress::Packer.do_misc
|
169
|
+
def test_do_misc
|
170
|
+
options = {
|
171
|
+
:preserveComments => true,
|
172
|
+
:preserveNewlines => true,
|
173
|
+
:preserveSpaces => true,
|
174
|
+
:preserveColors => true,
|
175
|
+
:skipMisc => false
|
176
|
+
}
|
177
|
+
# Replace 0(pt,px,em,%) with 0
|
178
|
+
input = ' 0px'
|
179
|
+
assert_equal(' 0', @packer.compress(input, options))
|
180
|
+
input = ' 0em'
|
181
|
+
assert_equal(' 0', @packer.compress(input, options))
|
182
|
+
input = ' 0pt'
|
183
|
+
assert_equal(' 0', @packer.compress(input, options))
|
184
|
+
input = ' 0%'
|
185
|
+
assert_equal(' 0', @packer.compress(input, options))
|
186
|
+
input = ' 0in'
|
187
|
+
assert_equal(' 0', @packer.compress(input, options))
|
188
|
+
input = ' 0cm '
|
189
|
+
assert_equal(' 0 ', @packer.compress(input, options))
|
190
|
+
input = ':0mm'
|
191
|
+
assert_equal(':0', @packer.compress(input, options))
|
192
|
+
input = ' 0pc'
|
193
|
+
assert_equal(' 0', @packer.compress(input, options))
|
194
|
+
input = ' 0ex'
|
195
|
+
assert_equal(' 0', @packer.compress(input, options))
|
196
|
+
input = ' 10ex'
|
197
|
+
assert_equal(' 10ex', @packer.compress(input, options))
|
198
|
+
|
199
|
+
# Replace 0 0 0 0; with 0.
|
200
|
+
input = ':0 0;'
|
201
|
+
assert_equal(':0;', @packer.compress(input, options))
|
202
|
+
input = ':0 0 0;'
|
203
|
+
assert_equal(':0;', @packer.compress(input, options))
|
204
|
+
input = ':0 0 0 0;'
|
205
|
+
assert_equal(':0;', @packer.compress(input, options))
|
206
|
+
input = ':0 0 0 0}'
|
207
|
+
assert_equal(':0}', @packer.compress(input, options))
|
208
|
+
# Keep 'background-position:0 0;' !!
|
209
|
+
input = 'background-position:0 0;'
|
210
|
+
assert_equal('background-position:0 0;', @packer.compress(input, options))
|
211
|
+
|
212
|
+
# Replace 0.6 to .6, but only when preceded by : or a white-space
|
213
|
+
input = ' 0.6'
|
214
|
+
assert_equal(' .6', @packer.compress(input, options))
|
215
|
+
input = ':0.06'
|
216
|
+
assert_equal(':.06', @packer.compress(input, options))
|
217
|
+
input = '10.6'
|
218
|
+
assert_equal('10.6', @packer.compress(input, options))
|
219
|
+
|
220
|
+
# Replace ;;;; with ;
|
221
|
+
input = 'ss;;;ss'
|
222
|
+
assert_equal('ss;ss', @packer.compress(input, options))
|
223
|
+
|
224
|
+
# Replace ;} with }
|
225
|
+
input = 'ss;sss;}ss'
|
226
|
+
assert_equal('ss;sss}ss', @packer.compress(input, options))
|
227
|
+
|
228
|
+
# Replace font-weight:normal; with 400, bold with 700
|
229
|
+
input = 'font-weight: normal;'
|
230
|
+
assert_equal('font-weight:400;', @packer.compress(input, options))
|
231
|
+
input = 'font: normal;'
|
232
|
+
assert_equal('font: 400;', @packer.compress(input, options))
|
233
|
+
input = 'font: bold 1px;'
|
234
|
+
assert_equal('font: 700 1px;', @packer.compress(input, options))
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
end
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xhochy-rainpress
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Uwe L. Korn
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-06-05 00:00:00 -07:00
|
13
|
+
default_executable: rainpress
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Rainpress does not apply common compression algorithms like gzip, it removes unnecessary characters and replaces some attributes with a shorter equivalent name
|
17
|
+
email: uwelk@xhochy.org
|
18
|
+
executables:
|
19
|
+
- rainpress
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- README.rdoc
|
26
|
+
- Rakefile
|
27
|
+
- VERSION.yml
|
28
|
+
- bin/rainpress
|
29
|
+
- lib/rainpress.rb
|
30
|
+
- lib/rainpress_test.rb
|
31
|
+
has_rdoc: false
|
32
|
+
homepage: http://rainpress.xhochy.com/
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options:
|
35
|
+
- --charset=UTF-8
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: "0"
|
43
|
+
version:
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
version:
|
50
|
+
requirements: []
|
51
|
+
|
52
|
+
rubyforge_project:
|
53
|
+
rubygems_version: 1.2.0
|
54
|
+
signing_key:
|
55
|
+
specification_version: 3
|
56
|
+
summary: Rainpress is a compressor for CSS. It's written in ruby, but should not be limited to ruby projects.
|
57
|
+
test_files: []
|
58
|
+
|