sinatra-minify 0.0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.rvmrc +1 -0
- data/README.md +108 -5
- data/Rakefile +38 -2
- data/VERSION +1 -1
- data/lib/sinatra/minify.rb +14 -1
- data/lib/sinatra/minify/builder.rb +91 -79
- data/lib/sinatra/minify/helpers.rb +14 -0
- data/sinatra-minify.gemspec +22 -6
- data/test/fixtures/exampleapp/app.rb +30 -0
- data/test/fixtures/exampleapp/config/assets.yml +6 -0
- data/test/fixtures/exampleapp/public/css/style-default.css +86 -0
- data/test/fixtures/exampleapp/public/js/script-1.js +1 -0
- data/test/fixtures/exampleapp/public/js/script-2.js +1 -0
- data/test/helper.rb +14 -0
- data/test/test_minify.rb +52 -0
- data/vendor/jsmin-1.0.1/HISTORY +9 -0
- data/vendor/jsmin-1.0.1/lib/jsmin.rb +249 -0
- metadata +21 -10
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.1@sinatra-minify
|
data/README.md
CHANGED
@@ -1,10 +1,15 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
sinatra-minify
|
2
|
+
==============
|
3
3
|
|
4
|
-
|
4
|
+
Quick-start guide
|
5
|
+
-----------------
|
6
|
+
|
7
|
+
First, install the `sinatra-minify` gem.
|
8
|
+
|
9
|
+
Add these to your app's main file:
|
5
10
|
|
6
11
|
require 'sinatra/minify'
|
7
|
-
class Main
|
12
|
+
class Main < Sinatra::Base
|
8
13
|
register Sinatra::Minify
|
9
14
|
end
|
10
15
|
|
@@ -12,4 +17,102 @@ Add this to your `Rakefile`:
|
|
12
17
|
|
13
18
|
load 'vendor/sinatra-minify/lib/tasks.rake'
|
14
19
|
|
15
|
-
|
20
|
+
Now add your JS/CSS packages in `config/assets.yml` (relative to your app's root path).
|
21
|
+
The files are are assumed to be in `public/js` and `public/css` by default.
|
22
|
+
|
23
|
+
js:
|
24
|
+
base:
|
25
|
+
- jquery-1.4.2.js
|
26
|
+
- underscore-0.6.0.js
|
27
|
+
- app/*.js # Wildcards are allowed! ;)
|
28
|
+
css:
|
29
|
+
base:
|
30
|
+
- common.css
|
31
|
+
- app.*.css
|
32
|
+
homepage:
|
33
|
+
- home.*.css
|
34
|
+
|
35
|
+
Now add the helpers to your templates:
|
36
|
+
|
37
|
+
...
|
38
|
+
<%= css_assets 'base' %>
|
39
|
+
<%= css_assets 'homepage' %>
|
40
|
+
</head>
|
41
|
+
<body>
|
42
|
+
...
|
43
|
+
<%= js_assets 'base' %>
|
44
|
+
</body>
|
45
|
+
</html>
|
46
|
+
<!-- The 'base' and 'homepage' above are the names of the
|
47
|
+
packages as defined in your config/assets.yml. -->
|
48
|
+
|
49
|
+
This will include the scripts and stylesheets as individual `<script>` and `<link>` tags.
|
50
|
+
To include the minified files instead, switch to the production environment and build
|
51
|
+
the minified files by typing `rake minify:build`.
|
52
|
+
|
53
|
+
Usage tips
|
54
|
+
==========
|
55
|
+
|
56
|
+
Building minified files
|
57
|
+
-----------------------
|
58
|
+
|
59
|
+
Minified files are built by typing:
|
60
|
+
|
61
|
+
rake minify:build
|
62
|
+
|
63
|
+
This creates files called `<package_name>.min.js` (and `.css`) in your `public/js` and
|
64
|
+
`public/css` folders.
|
65
|
+
|
66
|
+
NOTE: Building of minified files is NOT done automatically! You must call this explicitly.
|
67
|
+
Add it to your Capistrano deploy scripts or something.
|
68
|
+
|
69
|
+
Adding sinatra-minify as a dependency (Monk)
|
70
|
+
--------------------------------------------
|
71
|
+
|
72
|
+
If your using Monk (or otherwise using the `dependency` gem), simply add the
|
73
|
+
`sinatra-minify` GitHub repo to your dependencies file.
|
74
|
+
|
75
|
+
echo sinatra-minify git://github.com/sinefunc/sinatra-minify.git >> dependencies
|
76
|
+
dep vendor sinatra-minify
|
77
|
+
|
78
|
+
Changing JS/CSS paths
|
79
|
+
---------------------
|
80
|
+
|
81
|
+
By default, sinatra-minify looks at `public/js` and `public/css` for your JS and CSS files,
|
82
|
+
respectively. You can change them with:
|
83
|
+
|
84
|
+
class Main < Sinatra::Base
|
85
|
+
register Sinatra::Minify
|
86
|
+
|
87
|
+
set :js_path, 'public/javascripts'
|
88
|
+
set :js_url, '/javascripts'
|
89
|
+
|
90
|
+
set :css_path, 'public/stylesheets'
|
91
|
+
set :css_url, '/stylesheets'
|
92
|
+
|
93
|
+
Forcing minification
|
94
|
+
--------------------
|
95
|
+
|
96
|
+
Minifying happens in the production environment only by default. You can force this behavior
|
97
|
+
by enabling the `force_minify` option in your app:
|
98
|
+
|
99
|
+
class Main < Sinatra::Base
|
100
|
+
register Sinatra::Minify
|
101
|
+
|
102
|
+
# Always minify
|
103
|
+
enable :force_minify
|
104
|
+
|
105
|
+
You can also define your own behavior for checking whether to minify or not.
|
106
|
+
|
107
|
+
class Main < Sinatra::Base
|
108
|
+
register Sinatra::Minify
|
109
|
+
def self.minify?
|
110
|
+
prodiction? or staging?
|
111
|
+
end
|
112
|
+
|
113
|
+
Ignore minified files in source control
|
114
|
+
---------------------------------------
|
115
|
+
|
116
|
+
It'd be good practice to add `*.min.{css,js}` to your `.gitignore` file (or similar,
|
117
|
+
for those not using Git).
|
118
|
+
|
data/Rakefile
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
1
4
|
begin
|
2
5
|
require 'jeweler'
|
3
6
|
Jeweler::Tasks.new do |s|
|
@@ -7,10 +10,43 @@ begin
|
|
7
10
|
s.summary = "CSS/JS compressor for Sinatra"
|
8
11
|
s.homepage = "http://www.github.com/sinefunc/sinatra-minify"
|
9
12
|
s.description = "sinatra-minify is an extension for Sinatra to compress assets."
|
10
|
-
s.
|
13
|
+
s.add_development_dependency 'rack-test'
|
11
14
|
end
|
12
15
|
Jeweler::GemcutterTasks.new
|
13
16
|
rescue LoadError
|
14
|
-
puts "Jeweler not available. Install it with:
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rake/testtask'
|
21
|
+
Rake::TestTask.new(:test) do |test|
|
22
|
+
test.libs << 'lib' << 'test'
|
23
|
+
test.pattern = 'test/**/test_*.rb'
|
24
|
+
test.verbose = true
|
15
25
|
end
|
16
26
|
|
27
|
+
begin
|
28
|
+
require 'rcov/rcovtask'
|
29
|
+
Rcov::RcovTask.new do |test|
|
30
|
+
test.libs << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
rescue LoadError
|
35
|
+
task :rcov do
|
36
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
task :test => :check_dependencies
|
41
|
+
|
42
|
+
task :default => :test
|
43
|
+
|
44
|
+
require 'rake/rdoctask'
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
46
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
47
|
+
|
48
|
+
rdoc.rdoc_dir = 'rdoc'
|
49
|
+
rdoc.title = "sinatra-minify #{version}"
|
50
|
+
rdoc.rdoc_files.include('README*')
|
51
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
52
|
+
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.1
|
data/lib/sinatra/minify.rb
CHANGED
@@ -1,14 +1,27 @@
|
|
1
1
|
require 'sinatra/base'
|
2
|
-
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'jsmin'
|
5
|
+
rescue LoadError
|
6
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'vendor/jsmin-1.0.1/lib/jsmin')
|
7
|
+
end
|
3
8
|
|
4
9
|
module Sinatra
|
5
10
|
module Minify
|
11
|
+
autoload :Builder, 'sinatra/minify/builder'
|
12
|
+
autoload :Helpers, 'sinatra/minify/helpers'
|
13
|
+
|
6
14
|
def self.registered( app )
|
7
15
|
app.helpers Helpers
|
8
16
|
app.set :js_url, '/js' # => http://site.com/js
|
9
17
|
app.set :js_path, '/public/js' # => ~/myproject/public/js
|
10
18
|
app.set :css_url, '/css'
|
11
19
|
app.set :css_path, '/public/css'
|
20
|
+
app.disable :force_minify
|
21
|
+
end
|
22
|
+
|
23
|
+
def minify?
|
24
|
+
production? or force_minify
|
12
25
|
end
|
13
26
|
end
|
14
27
|
register Minify
|
@@ -1,29 +1,40 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
1
3
|
module Sinatra
|
2
4
|
module Minify
|
3
|
-
|
4
|
-
|
5
|
-
|
5
|
+
class Builder
|
6
|
+
# Returns the root path of the main Sinatra application.
|
7
|
+
# Mimins the root_path functionality of Monk.`
|
8
|
+
def root_path(*args)
|
9
|
+
File.join(File.dirname(settings.app_file), *args)
|
6
10
|
end
|
7
|
-
|
8
|
-
|
11
|
+
|
12
|
+
# Deletes all minified files.
|
13
|
+
def clean
|
14
|
+
[:js, :css].each do |type|
|
15
|
+
assets_config(type).keys.each do |set|
|
16
|
+
prefix = type == :js ? settings.js_path : settings.css_path
|
17
|
+
path = root_path File.join(prefix, "#{set}.min.#{type}")
|
18
|
+
File.unlink path if File.exists? path
|
19
|
+
end
|
20
|
+
end
|
9
21
|
end
|
10
|
-
end
|
11
22
|
|
12
|
-
|
23
|
+
# Rebuilds the minified .min.js and .min.css files.
|
13
24
|
def build
|
14
25
|
out = []
|
15
26
|
[:js, :css].each do |type|
|
16
27
|
assets_config(type).keys.each do |set|
|
17
28
|
prefix = type == :js ? settings.js_path : settings.css_path
|
18
|
-
path = root_path
|
19
|
-
File.open(path, 'w')
|
29
|
+
path = root_path(prefix, "#{set}.min.#{type}")
|
30
|
+
File.open(path, 'w') { |f| f.write compress(type, set) }
|
20
31
|
out << path
|
21
32
|
end
|
22
33
|
end
|
23
34
|
out
|
24
35
|
end
|
25
36
|
|
26
|
-
def initialize(
|
37
|
+
def initialize(app_class = ::Main)
|
27
38
|
@app_class = app_class
|
28
39
|
end
|
29
40
|
|
@@ -34,13 +45,15 @@ module Sinatra
|
|
34
45
|
# Returns the file sets for a given type as defined in the `assets.yml` config file.
|
35
46
|
#
|
36
47
|
# Params:
|
37
|
-
# - `type` (Symbol/string) - Can be either `:
|
48
|
+
# - `type` (Symbol/string) - Can be either `:js` or `:css`
|
38
49
|
#
|
39
50
|
def assets_config(type)
|
40
|
-
YAML
|
51
|
+
YAML.load_file(root_path("config/assets.yml"))[type.to_s]
|
41
52
|
end
|
42
53
|
|
43
54
|
# Returns HTML code with `<script>` tags to include the scripts in a given `set`.
|
55
|
+
# In a production environment, this tries to include the minified version of the
|
56
|
+
# files. If it doesn't exist, it falls back to the original files.
|
44
57
|
#
|
45
58
|
# Params:
|
46
59
|
# - `set` (String) - The set name, as defined in `config/assets.yml`.
|
@@ -50,22 +63,25 @@ module Sinatra
|
|
50
63
|
# <%= js_assets 'base' %>
|
51
64
|
#
|
52
65
|
def js_assets( set )
|
53
|
-
|
54
|
-
|
66
|
+
min_file = root_path(settings.js_path, "#{set}.min.js")
|
67
|
+
min_path = "/#{settings.js_url}/#{set}.min.js".squeeze("/")
|
68
|
+
if settings.minify? and File.exists? min_file
|
69
|
+
mtime = File.mtime(min_file).to_i
|
70
|
+
"<script src='#{min_path}?#{mtime}' type='text/javascript'></script>\n"
|
55
71
|
else
|
56
72
|
js_assets_all set
|
57
73
|
end
|
58
74
|
end
|
59
75
|
|
60
|
-
def js_assets_all(
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
65
|
-
ret
|
76
|
+
def js_assets_all(set)
|
77
|
+
assets(:js, set).map { |script|
|
78
|
+
"<script src='#{script[:url]}' type='text/javascript'></script>"
|
79
|
+
}.join("\n")
|
66
80
|
end
|
67
81
|
|
68
82
|
# Returns HTML code with `<link>` tags to include the stylesheets in a given `set`.
|
83
|
+
# In a production environment, this tries to include the minified version of the
|
84
|
+
# files. If it doesn't exist, it falls back to the original files.
|
69
85
|
#
|
70
86
|
# Params:
|
71
87
|
# - `set` (String) - The set name, as defined in `config/assets.yml`.
|
@@ -75,50 +91,52 @@ module Sinatra
|
|
75
91
|
# <%= css_assets 'base' %>
|
76
92
|
#
|
77
93
|
def css_assets( set )
|
78
|
-
|
79
|
-
|
94
|
+
min_file = root_path settings.css_path, "#{set}.min.css"
|
95
|
+
min_path = "/#{settings.css_url}/#{set}.min.css".squeeze("/")
|
96
|
+
if settings.minify? and File.exists? min_file
|
97
|
+
mtime = File.mtime(file).to_i
|
98
|
+
"<link rel='stylesheet' href='#{min_path}?#{mtime}' media='screen' />\n"
|
80
99
|
else
|
81
100
|
css_assets_all set
|
82
101
|
end
|
83
102
|
end
|
84
103
|
|
85
104
|
def css_assets_all(set)
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
end
|
90
|
-
ret
|
105
|
+
assets(:css, set).map { |sheet|
|
106
|
+
"<link rel='stylesheet' href='#{sheet[:url]}' media='screen' />"
|
107
|
+
}.join("\n")
|
91
108
|
end
|
92
109
|
|
93
110
|
# Returns the raw consolidated CSS/JS contents of a given type/set
|
94
|
-
def combine(
|
95
|
-
assets(type, set).map { |asset| File.open(asset[:path]).read }.join
|
111
|
+
def combine(type, set)
|
112
|
+
assets(type, set).map { |asset| File.open(asset[:path]).read }.join("\n").strip
|
96
113
|
end
|
97
114
|
|
98
115
|
# Returns compressed code
|
99
|
-
def compress(
|
100
|
-
code = combine
|
116
|
+
def compress(type, set)
|
117
|
+
code = combine(type, set)
|
101
118
|
if type == :js
|
102
119
|
minify_js code
|
103
120
|
elsif type == :css
|
104
121
|
minify_css code
|
105
122
|
else
|
106
|
-
raise
|
123
|
+
raise ArgumentError, "type should be one of :js or :css"
|
107
124
|
end
|
108
125
|
end
|
109
126
|
|
110
127
|
def minify_css( src )
|
111
|
-
src.gsub!
|
112
|
-
src.gsub!
|
113
|
-
src.gsub!
|
114
|
-
src.gsub!
|
115
|
-
src.gsub!
|
116
|
-
src.gsub!
|
117
|
-
src
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
128
|
+
src.gsub! /\s+/, " "
|
129
|
+
src.gsub! /\/\*(.*?)\*\//, ""
|
130
|
+
src.gsub! /\} /, "}\n"
|
131
|
+
src.gsub! /\n$/, ""
|
132
|
+
src.gsub! /[ \t]*\{[ \t]*/, "{"
|
133
|
+
src.gsub! /;[ \t]*\}/, "}"
|
134
|
+
src.gsub! /[ \t]*([,|{|}|>|:|;])[ \t]*/,"\\1" # Tersify
|
135
|
+
src.gsub! /[ \t]*\n[ \t]*/, "" # Hardcore mode (no NLs)
|
136
|
+
src.strip
|
137
|
+
end
|
138
|
+
|
139
|
+
def minify_js(src)
|
122
140
|
JSMin.minify src
|
123
141
|
end
|
124
142
|
|
@@ -132,13 +150,9 @@ module Sinatra
|
|
132
150
|
# get_path :js
|
133
151
|
# # Possible value: "/home/rsc/myproject/public/js"
|
134
152
|
#
|
135
|
-
def get_path(
|
136
|
-
|
137
|
-
|
138
|
-
else
|
139
|
-
path = settings.css_path
|
140
|
-
end
|
141
|
-
root_path(path.split('/').inject([]) { |arr, item| arr << item unless item.empty?; arr })
|
153
|
+
def get_path(type)
|
154
|
+
path = (type == :js) ? settings.js_path : settings.css_path
|
155
|
+
root_path path.squeeze('/')
|
142
156
|
end
|
143
157
|
|
144
158
|
# Returns the URL for a given filename and a type.
|
@@ -149,18 +163,10 @@ module Sinatra
|
|
149
163
|
# Example:
|
150
164
|
# get_url :js, '/path/to/file.js'
|
151
165
|
#
|
152
|
-
def get_url(
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
prefix = settings.css_url
|
157
|
-
end
|
158
|
-
# Remove the js_path from it (/home/rsc/project/public/js/aa/lol.js => aa/lol.js)
|
159
|
-
url = File.join(prefix, filename.split(get_path type).join(''))
|
160
|
-
|
161
|
-
# Remove duplicate slashes
|
162
|
-
url = url.split('/').inject([]) { |arr, item| arr << item unless item.empty?; arr }
|
163
|
-
'/' + url.join('/')
|
166
|
+
def get_url(type, filename)
|
167
|
+
prefix = (type == :js) ? settings.js_url : settings.css_url
|
168
|
+
path = filename.gsub(/^#{Regexp.escape(get_path(type))}/, '')
|
169
|
+
File.join(prefix, path).squeeze('/')
|
164
170
|
end
|
165
171
|
|
166
172
|
# Returns a list of assets of a given type for a given set.
|
@@ -184,28 +190,34 @@ module Sinatra
|
|
184
190
|
# See also:
|
185
191
|
# - js_assets
|
186
192
|
#
|
187
|
-
def assets(
|
188
|
-
# type is either js or css
|
189
|
-
specs = (
|
190
|
-
path
|
191
|
-
|
192
|
-
done = []
|
193
|
+
def assets(type, set)
|
194
|
+
# type is either :js or :css
|
195
|
+
specs = assets_config(type)[set]
|
196
|
+
path = get_path(type)
|
197
|
+
done = []
|
193
198
|
# `specs` will be a list of filespecs. Find all files that
|
194
199
|
# match all specs.
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
200
|
+
[specs].flatten.inject([]) do |ret, spec|
|
201
|
+
filepath = "#{path}/#{spec}"
|
202
|
+
files = Dir[filepath]
|
203
|
+
|
204
|
+
# Add it anyway if it doesn't match anything
|
205
|
+
unless files.any? || done.include?(filepath) || filepath.include?('*')
|
206
|
+
ret << { :url => get_url(type, filepath), :path => filepath }
|
207
|
+
done << filepath
|
208
|
+
end
|
209
|
+
|
210
|
+
files.each do |filename|
|
211
|
+
unless done.include? filename
|
212
|
+
ret << {
|
213
|
+
:url => [get_url(type, filename), File.mtime(filename).to_i].join('?'),
|
214
|
+
:path => filename
|
215
|
+
}
|
216
|
+
done << filename
|
205
217
|
end
|
206
218
|
end
|
219
|
+
ret
|
207
220
|
end
|
208
|
-
ret
|
209
221
|
end
|
210
222
|
end
|
211
223
|
end
|
data/sinatra-minify.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{sinatra-minify}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.1.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["sinefunc"]
|
12
|
-
s.date = %q{2010-04-
|
12
|
+
s.date = %q{2010-04-23}
|
13
13
|
s.description = %q{sinatra-minify is an extension for Sinatra to compress assets.}
|
14
14
|
s.email = %q{info@sinefunc.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -17,31 +17,47 @@ Gem::Specification.new do |s|
|
|
17
17
|
]
|
18
18
|
s.files = [
|
19
19
|
".gitignore",
|
20
|
+
".rvmrc",
|
20
21
|
"README.md",
|
21
22
|
"Rakefile",
|
22
23
|
"VERSION",
|
23
24
|
"lib/sinatra/minify.rb",
|
24
25
|
"lib/sinatra/minify/builder.rb",
|
26
|
+
"lib/sinatra/minify/helpers.rb",
|
25
27
|
"lib/tasks.rake",
|
26
|
-
"sinatra-minify.gemspec"
|
28
|
+
"sinatra-minify.gemspec",
|
29
|
+
"test/fixtures/exampleapp/app.rb",
|
30
|
+
"test/fixtures/exampleapp/config/assets.yml",
|
31
|
+
"test/fixtures/exampleapp/public/css/style-default.css",
|
32
|
+
"test/fixtures/exampleapp/public/js/script-1.js",
|
33
|
+
"test/fixtures/exampleapp/public/js/script-2.js",
|
34
|
+
"test/helper.rb",
|
35
|
+
"test/test_minify.rb",
|
36
|
+
"vendor/jsmin-1.0.1/HISTORY",
|
37
|
+
"vendor/jsmin-1.0.1/lib/jsmin.rb"
|
27
38
|
]
|
28
39
|
s.homepage = %q{http://www.github.com/sinefunc/sinatra-minify}
|
29
40
|
s.rdoc_options = ["--charset=UTF-8"]
|
30
41
|
s.require_paths = ["lib"]
|
31
42
|
s.rubygems_version = %q{1.3.6}
|
32
43
|
s.summary = %q{CSS/JS compressor for Sinatra}
|
44
|
+
s.test_files = [
|
45
|
+
"test/fixtures/exampleapp/app.rb",
|
46
|
+
"test/helper.rb",
|
47
|
+
"test/test_minify.rb"
|
48
|
+
]
|
33
49
|
|
34
50
|
if s.respond_to? :specification_version then
|
35
51
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
36
52
|
s.specification_version = 3
|
37
53
|
|
38
54
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
39
|
-
s.
|
55
|
+
s.add_development_dependency(%q<rack-test>, [">= 0"])
|
40
56
|
else
|
41
|
-
s.add_dependency(%q<
|
57
|
+
s.add_dependency(%q<rack-test>, [">= 0"])
|
42
58
|
end
|
43
59
|
else
|
44
|
-
s.add_dependency(%q<
|
60
|
+
s.add_dependency(%q<rack-test>, [">= 0"])
|
45
61
|
end
|
46
62
|
end
|
47
63
|
|
@@ -0,0 +1,30 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'sinatra/base'
|
6
|
+
require 'sinatra/minify'
|
7
|
+
|
8
|
+
# ROOT_DIR = File.dirname(__FILE__)
|
9
|
+
|
10
|
+
class App < Sinatra::Base
|
11
|
+
set :app_file, __FILE__
|
12
|
+
|
13
|
+
register Sinatra::Minify
|
14
|
+
|
15
|
+
get '/' do
|
16
|
+
"Hello"
|
17
|
+
end
|
18
|
+
|
19
|
+
get "/foo" do
|
20
|
+
output = ""
|
21
|
+
output << js_assets('base')
|
22
|
+
end
|
23
|
+
|
24
|
+
# Doesn't stop Sinatra::Application from running by default
|
25
|
+
def self.run?
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
App.run! if $0 == __FILE__
|
@@ -0,0 +1,86 @@
|
|
1
|
+
/* Reset */
|
2
|
+
div, dl, dt, dd, ul, ol, li, form,
|
3
|
+
fieldset, input, th, td { margin: 0; padding: 0; }
|
4
|
+
pre, p, blockquote, h1, h2, h3, h4, h5,
|
5
|
+
h6 { margin: 1em 0 1em 0; }
|
6
|
+
blockquote { border-left: solid 2px #ccc; padding: 0 1em; margin-left: 0.2em; color: #888; }
|
7
|
+
h1 { font-size: 1.4em; }
|
8
|
+
h2 { font-size: 1.3em; }
|
9
|
+
h3 { font-size: 1.2em; }
|
10
|
+
h4 { font-size: 1.1em; }
|
11
|
+
h5 { font-size: 0.9em; }
|
12
|
+
h6 { font-size: 0.9em; }
|
13
|
+
ol, ul { margin-left: 2em; }
|
14
|
+
|
15
|
+
/* Body & wrapper */
|
16
|
+
html, body { margin: 0; padding: 0; }
|
17
|
+
body, td, input, textarea { font-family: arial, helvetica, sans-serif; font-size: 1em; }
|
18
|
+
body { font-size: 0.85em; line-height: 1.6em; background: #6ba241; color: #333; }
|
19
|
+
#all { margin: 0 auto; width: auto; position: relative; }
|
20
|
+
|
21
|
+
/* Links */
|
22
|
+
a { color: #393; text-decoration: none; font-weight: bold; padding: 1px; }
|
23
|
+
a:visited { color: #393; }
|
24
|
+
a:hover { color: #393; text-decoration: underline; }
|
25
|
+
a img { border: 0; }
|
26
|
+
|
27
|
+
/* Common layout */
|
28
|
+
#what-we-do, #who-we-are, #content { overflow: hidden; }
|
29
|
+
#header>.c, #what-we-do>.c,
|
30
|
+
#who-we-are>.c, #footer>.c { width: 940px; margin: 0 auto; overflow: hidden; }
|
31
|
+
|
32
|
+
/* Common styling */
|
33
|
+
#header { background: #f8fbf4 url(bg-header.png) center bottom repeat-x; padding: 10px 0 130px 0; }
|
34
|
+
#what-we-do { background: #f0f6e9; padding: 30px 0 0 0; }
|
35
|
+
#who-we-are { background: #6ba241 url(bg-stripe.png) center top repeat-x; padding: 90px 0 30px 0; color: #d3e3c6; text-shadow: 1px 1px #5c843d; }
|
36
|
+
#footer { background: #444; padding: 50px 0 50px 0; color: #bbb; }
|
37
|
+
|
38
|
+
/* Header */
|
39
|
+
#header { overflow: hidden; }
|
40
|
+
#header #logo { float: left; margin-right: 75px; margin-left: 75px; }
|
41
|
+
#header h1 { background: url(text.png) 0 0 no-repeat; width: 511px; height: 95px; text-indent: -9999px; margin: 0; padding: 0; display: block; float: left; }
|
42
|
+
#contact-header { border-bottom: solid 1px #ccc; margin-bottom: 90px; padding: 0 0 4px 0; text-align: right; color: #aaa;
|
43
|
+
font-size: 0.9em; }
|
44
|
+
#contact-header em { margin: 0 12px 0 10px; color: #ccc; }
|
45
|
+
#contact-header a { color: #888; text-decoration: underline; }
|
46
|
+
#contact-header a:hover { color: #6b6; }
|
47
|
+
|
48
|
+
/* Content */
|
49
|
+
#content h2 { float: left; width: 240px; }
|
50
|
+
#content ul, #content li { margin: 0; padding: 0; display: block; }
|
51
|
+
#what-we-do>.c ul { float: left; width: 700px; overflow: hidden; }
|
52
|
+
|
53
|
+
/* What we do */
|
54
|
+
#what-we-do li { float: left; width: 340px; }
|
55
|
+
#what-we-do li.left { margin-right: 20px; }
|
56
|
+
|
57
|
+
#what-we-do li h3 { font-size: 1.4em; }
|
58
|
+
#what-we-do li h4 { font-family: georgia, times, serif; font-style: italic; color: #777; font-weight: normal;
|
59
|
+
font-size: 1.2em; line-height: 1.4em; margin: 0.8em 0 0 0; }
|
60
|
+
#what-we-do li p { margin: 3px 0 2em 0; }
|
61
|
+
#what-we-do #do-build,
|
62
|
+
#what-we-do #do-scale { padding-bottom: 1.5em; }
|
63
|
+
|
64
|
+
/* What we do: h2 */
|
65
|
+
#what-we-do h2 { background: url(text.png) 0 -400px no-repeat; height: 18px; text-indent: -9999px; margin: 0; padding: 0;
|
66
|
+
display: block; }
|
67
|
+
|
68
|
+
/* What we do: h3 */
|
69
|
+
#what-we-do h3 { background: url(text.png) 0 0 no-repeat; height: 21px; text-indent: -9999px; margin: 0; padding: 0;
|
70
|
+
display: block; }
|
71
|
+
#do-build h3 { background-position: 0 -200px; }
|
72
|
+
#do-scale h3 { background-position: 0 -250px; }
|
73
|
+
#do-craft h3 { background-position: 0 -300px; }
|
74
|
+
#do-train h3 { background-position: 0 -350px; }
|
75
|
+
|
76
|
+
/* Who we are */
|
77
|
+
#who-we-are>.c div { float: left; width: 560px; overflow: hidden; }
|
78
|
+
#who-we-are h3 { font-size: 1.4em; line-height: 1.5em; color: white; background: url(text.png) 0 -550px no-repeat;
|
79
|
+
width: 521px; height: 73px; text-indent: -9999px; margin: 0; padding: 0; display: block; padding-bottom: 7px; }
|
80
|
+
#who-we-are h2 { background: url(text.png) 0 -450px no-repeat; height: 18px; text-indent: -9999px; margin: 0; padding: 0;
|
81
|
+
display: block; }
|
82
|
+
|
83
|
+
/* Footer */
|
84
|
+
#footer { text-align: center; }
|
85
|
+
#footer a { font-size: 1.3em; color: white; font-weight: normal; }
|
86
|
+
#footer span { display: block; font-size: 1.2em; color: #888; margin-bottom: 3px; font-family: georgia; font-style: italic; }
|
@@ -0,0 +1 @@
|
|
1
|
+
aoeu = 234 /* Test */;
|
@@ -0,0 +1 @@
|
|
1
|
+
aoeu = 234 /* Test */;
|
data/test/helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
#require 'shoulda'
|
4
|
+
require 'contest'
|
5
|
+
require 'rack/test'
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
8
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
9
|
+
|
10
|
+
require 'fixtures/exampleapp/app'
|
11
|
+
|
12
|
+
class Test::Unit::TestCase
|
13
|
+
include Rack::Test::Methods
|
14
|
+
end
|
data/test/test_minify.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestMinify < Test::Unit::TestCase
|
4
|
+
def app
|
5
|
+
App
|
6
|
+
end
|
7
|
+
|
8
|
+
def output
|
9
|
+
last_response.body
|
10
|
+
end
|
11
|
+
|
12
|
+
def builder
|
13
|
+
Sinatra::Minify::Builder.new app
|
14
|
+
end
|
15
|
+
|
16
|
+
should "rock pants off" do
|
17
|
+
get '/'
|
18
|
+
assert_match "Hello", output
|
19
|
+
end
|
20
|
+
|
21
|
+
should "Include all scripts" do
|
22
|
+
get '/foo'
|
23
|
+
assert_match /\/js\/script-1.js\?/, output
|
24
|
+
assert_match /\/js\/script-2.js\?/, output
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "In a production environment" do
|
28
|
+
def setup
|
29
|
+
app.enable :force_minify
|
30
|
+
end
|
31
|
+
|
32
|
+
def teardown
|
33
|
+
app.disable :force_minify
|
34
|
+
end
|
35
|
+
|
36
|
+
should "Include the minified script" do
|
37
|
+
get '/foo'
|
38
|
+
assert_match /\/js\/base.min.js\?/, output
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "Building files" do
|
43
|
+
def setup
|
44
|
+
builder.clean
|
45
|
+
builder.build
|
46
|
+
end
|
47
|
+
|
48
|
+
should "Build properly" do
|
49
|
+
assert true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,249 @@
|
|
1
|
+
#--
|
2
|
+
# jsmin.rb - Ruby implementation of Douglas Crockford's JSMin.
|
3
|
+
#
|
4
|
+
# This is a port of jsmin.c, and is distributed under the same terms, which are
|
5
|
+
# as follows:
|
6
|
+
#
|
7
|
+
# Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
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 all
|
17
|
+
# copies or substantial portions of the Software.
|
18
|
+
#
|
19
|
+
# The Software shall be used for Good, not Evil.
|
20
|
+
#
|
21
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
22
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
23
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
24
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
25
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
26
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
27
|
+
# SOFTWARE.
|
28
|
+
#++
|
29
|
+
|
30
|
+
require 'strscan'
|
31
|
+
|
32
|
+
# = JSMin
|
33
|
+
#
|
34
|
+
# Ruby implementation of Douglas Crockford's JavaScript minifier, JSMin.
|
35
|
+
#
|
36
|
+
# Author:: Ryan Grove (mailto:ryan@wonko.com)
|
37
|
+
# Version:: 1.0.1 (2008-11-10)
|
38
|
+
# Copyright:: Copyright (c) 2008 Ryan Grove. All rights reserved.
|
39
|
+
# Website:: http://github.com/rgrove/jsmin/
|
40
|
+
#
|
41
|
+
# == Example
|
42
|
+
#
|
43
|
+
# require 'rubygems'
|
44
|
+
# require 'jsmin'
|
45
|
+
#
|
46
|
+
# File.open('example.js', 'r') {|file| puts JSMin.minify(file) }
|
47
|
+
#
|
48
|
+
module JSMin
|
49
|
+
CHR_APOS = "'".freeze
|
50
|
+
CHR_ASTERISK = '*'.freeze
|
51
|
+
CHR_BACKSLASH = '\\'.freeze
|
52
|
+
CHR_CR = "\r".freeze
|
53
|
+
CHR_FRONTSLASH = '/'.freeze
|
54
|
+
CHR_LF = "\n".freeze
|
55
|
+
CHR_QUOTE = '"'.freeze
|
56
|
+
CHR_SPACE = ' '.freeze
|
57
|
+
|
58
|
+
if RUBY_VERSION >= '1.9'
|
59
|
+
ORD_LF = "\n".freeze
|
60
|
+
ORD_SPACE = ' '.freeze
|
61
|
+
ORD_TILDE = '~'.freeze
|
62
|
+
else
|
63
|
+
ORD_LF = "\n"[0].freeze
|
64
|
+
ORD_SPACE = ' '[0].freeze
|
65
|
+
ORD_TILDE = '~'[0].freeze
|
66
|
+
end
|
67
|
+
|
68
|
+
class << self
|
69
|
+
|
70
|
+
# Reads JavaScript from +input+ (which can be a String or an IO object) and
|
71
|
+
# returns a String containing minified JS.
|
72
|
+
def minify(input)
|
73
|
+
@js = StringScanner.new(input.is_a?(IO) ? input.read : input.to_s)
|
74
|
+
|
75
|
+
@a = "\n"
|
76
|
+
@b = nil
|
77
|
+
@lookahead = nil
|
78
|
+
@output = ''
|
79
|
+
|
80
|
+
action_get
|
81
|
+
|
82
|
+
while !@a.nil? do
|
83
|
+
case @a
|
84
|
+
when CHR_SPACE
|
85
|
+
if alphanum?(@b)
|
86
|
+
action_output
|
87
|
+
else
|
88
|
+
action_copy
|
89
|
+
end
|
90
|
+
|
91
|
+
when CHR_LF
|
92
|
+
if @b == CHR_SPACE
|
93
|
+
action_get
|
94
|
+
elsif @b =~ /[{\[\(+-]/
|
95
|
+
action_output
|
96
|
+
else
|
97
|
+
if alphanum?(@b)
|
98
|
+
action_output
|
99
|
+
else
|
100
|
+
action_copy
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
else
|
105
|
+
if @b == CHR_SPACE
|
106
|
+
if alphanum?(@a)
|
107
|
+
action_output
|
108
|
+
else
|
109
|
+
action_get
|
110
|
+
end
|
111
|
+
elsif @b == CHR_LF
|
112
|
+
if @a =~ /[}\]\)\\"+-]/
|
113
|
+
action_output
|
114
|
+
else
|
115
|
+
if alphanum?(@a)
|
116
|
+
action_output
|
117
|
+
else
|
118
|
+
action_get
|
119
|
+
end
|
120
|
+
end
|
121
|
+
else
|
122
|
+
action_output
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
@output
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
# Corresponds to action(1) in jsmin.c.
|
133
|
+
def action_output
|
134
|
+
@output << @a
|
135
|
+
action_copy
|
136
|
+
end
|
137
|
+
|
138
|
+
# Corresponds to action(2) in jsmin.c.
|
139
|
+
def action_copy
|
140
|
+
@a = @b
|
141
|
+
|
142
|
+
if @a == CHR_APOS || @a == CHR_QUOTE
|
143
|
+
loop do
|
144
|
+
@output << @a
|
145
|
+
@a = get
|
146
|
+
|
147
|
+
break if @a == @b
|
148
|
+
|
149
|
+
if @a[0] <= ORD_LF
|
150
|
+
raise "JSMin parse error: unterminated string literal: #{@a}"
|
151
|
+
end
|
152
|
+
|
153
|
+
if @a == CHR_BACKSLASH
|
154
|
+
@output << @a
|
155
|
+
@a = get
|
156
|
+
|
157
|
+
if @a[0] <= ORD_LF
|
158
|
+
raise "JSMin parse error: unterminated string literal: #{@a}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
action_get
|
165
|
+
end
|
166
|
+
|
167
|
+
# Corresponds to action(3) in jsmin.c.
|
168
|
+
def action_get
|
169
|
+
@b = nextchar
|
170
|
+
|
171
|
+
if @b == CHR_FRONTSLASH && (@a == CHR_LF || @a =~ /[\(,=:\[!&|?{};]/)
|
172
|
+
@output << @a
|
173
|
+
@output << @b
|
174
|
+
|
175
|
+
loop do
|
176
|
+
@a = get
|
177
|
+
|
178
|
+
if @a == CHR_FRONTSLASH
|
179
|
+
break
|
180
|
+
elsif @a == CHR_BACKSLASH
|
181
|
+
@output << @a
|
182
|
+
@a = get
|
183
|
+
elsif @a[0] <= ORD_LF
|
184
|
+
raise "JSMin parse error: unterminated regular expression " +
|
185
|
+
"literal: #{@a}"
|
186
|
+
end
|
187
|
+
|
188
|
+
@output << @a
|
189
|
+
end
|
190
|
+
|
191
|
+
@b = nextchar
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# Returns true if +c+ is a letter, digit, underscore, dollar sign,
|
196
|
+
# backslash, or non-ASCII character.
|
197
|
+
def alphanum?(c)
|
198
|
+
c.is_a?(String) && !c.empty? && (c[0] > ORD_TILDE || c =~ /[0-9a-z_$\\]/i)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Returns the next character from the input. If the character is a control
|
202
|
+
# character, it will be translated to a space or linefeed.
|
203
|
+
def get
|
204
|
+
c = @lookahead.nil? ? @js.getch : @lookahead
|
205
|
+
@lookahead = nil
|
206
|
+
|
207
|
+
return c if c.nil? || c == CHR_LF || c[0] >= ORD_SPACE
|
208
|
+
return "\n" if c == CHR_CR
|
209
|
+
return ' '
|
210
|
+
end
|
211
|
+
|
212
|
+
# Gets the next character, excluding comments.
|
213
|
+
def nextchar
|
214
|
+
c = get
|
215
|
+
return c unless c == CHR_FRONTSLASH
|
216
|
+
|
217
|
+
case peek
|
218
|
+
when CHR_FRONTSLASH
|
219
|
+
loop do
|
220
|
+
c = get
|
221
|
+
return c if c[0] <= ORD_LF
|
222
|
+
end
|
223
|
+
|
224
|
+
when CHR_ASTERISK
|
225
|
+
get
|
226
|
+
loop do
|
227
|
+
case get
|
228
|
+
when CHR_ASTERISK
|
229
|
+
if peek == CHR_FRONTSLASH
|
230
|
+
get
|
231
|
+
return ' '
|
232
|
+
end
|
233
|
+
|
234
|
+
when nil
|
235
|
+
raise 'JSMin parse error: unterminated comment'
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
else
|
240
|
+
return c
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Gets the next character without getting it.
|
245
|
+
def peek
|
246
|
+
@lookahead = get
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
- 0
|
8
7
|
- 1
|
9
|
-
|
8
|
+
- 1
|
9
|
+
version: 0.1.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- sinefunc
|
@@ -14,22 +14,20 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-04-
|
17
|
+
date: 2010-04-23 00:00:00 +08:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
21
|
+
name: rack-test
|
22
22
|
prerelease: false
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
segments:
|
28
|
-
- 1
|
29
28
|
- 0
|
30
|
-
|
31
|
-
|
32
|
-
type: :runtime
|
29
|
+
version: "0"
|
30
|
+
type: :development
|
33
31
|
version_requirements: *id001
|
34
32
|
description: sinatra-minify is an extension for Sinatra to compress assets.
|
35
33
|
email: info@sinefunc.com
|
@@ -41,13 +39,24 @@ extra_rdoc_files:
|
|
41
39
|
- README.md
|
42
40
|
files:
|
43
41
|
- .gitignore
|
42
|
+
- .rvmrc
|
44
43
|
- README.md
|
45
44
|
- Rakefile
|
46
45
|
- VERSION
|
47
46
|
- lib/sinatra/minify.rb
|
48
47
|
- lib/sinatra/minify/builder.rb
|
48
|
+
- lib/sinatra/minify/helpers.rb
|
49
49
|
- lib/tasks.rake
|
50
50
|
- sinatra-minify.gemspec
|
51
|
+
- test/fixtures/exampleapp/app.rb
|
52
|
+
- test/fixtures/exampleapp/config/assets.yml
|
53
|
+
- test/fixtures/exampleapp/public/css/style-default.css
|
54
|
+
- test/fixtures/exampleapp/public/js/script-1.js
|
55
|
+
- test/fixtures/exampleapp/public/js/script-2.js
|
56
|
+
- test/helper.rb
|
57
|
+
- test/test_minify.rb
|
58
|
+
- vendor/jsmin-1.0.1/HISTORY
|
59
|
+
- vendor/jsmin-1.0.1/lib/jsmin.rb
|
51
60
|
has_rdoc: true
|
52
61
|
homepage: http://www.github.com/sinefunc/sinatra-minify
|
53
62
|
licenses: []
|
@@ -78,5 +87,7 @@ rubygems_version: 1.3.6
|
|
78
87
|
signing_key:
|
79
88
|
specification_version: 3
|
80
89
|
summary: CSS/JS compressor for Sinatra
|
81
|
-
test_files:
|
82
|
-
|
90
|
+
test_files:
|
91
|
+
- test/fixtures/exampleapp/app.rb
|
92
|
+
- test/helper.rb
|
93
|
+
- test/test_minify.rb
|