sinatra-support 1.1.3 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.md +6 -0
- data/lib/sinatra/support.rb +1 -0
- data/lib/sinatra/support/compressedjs.rb +244 -0
- data/lib/sinatra/support/version.rb +1 -1
- data/test/fixtures/compressed_js/js/hello.js +1 -0
- data/test/fixtures/compressed_js/js/hi.js +1 -0
- data/test/fixtures/compressed_js/js/yo.coffee +1 -0
- data/test/helper.rb +18 -3
- data/test/test_compressed_js_app.rb +82 -0
- metadata +28 -1
data/HISTORY.md
CHANGED
data/lib/sinatra/support.rb
CHANGED
@@ -14,6 +14,7 @@ module Sinatra
|
|
14
14
|
autoload :I18nSupport, File.expand_path('../support/i18nsupport', __FILE__)
|
15
15
|
autoload :MultiRender, File.expand_path('../support/multirender', __FILE__)
|
16
16
|
autoload :CompassSupport, File.expand_path('../support/compasssupport', __FILE__)
|
17
|
+
autoload :CompressedJS, File.expand_path('../support/compressedjs', __FILE__)
|
17
18
|
|
18
19
|
module Support
|
19
20
|
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
# Serves compressed JS.
|
2
|
+
#
|
3
|
+
# == Usage example
|
4
|
+
#
|
5
|
+
# Assuming you have JavaScript files stored in +./app/js+, and you want to serve
|
6
|
+
# the compressed JS in +http://yoursite.com/js/compressed.js+:
|
7
|
+
#
|
8
|
+
# # CompressedJS is recommended to be used alongside JsSupport to serve
|
9
|
+
# # raw JS files in development mode. This will make your /app/js/*.js
|
10
|
+
# # accessible via http://yoursite.com/js/*.js.
|
11
|
+
#
|
12
|
+
# register Sinatra::JsSupport
|
13
|
+
# serve_js '/js', from: './app/js'
|
14
|
+
#
|
15
|
+
# Then load the {CompressedJS} plugin:
|
16
|
+
#
|
17
|
+
# register Sinatra::CompressedJS
|
18
|
+
#
|
19
|
+
# serve_compressed_js :app_js, # The name (used later in your views)
|
20
|
+
# :prefix => '/js', # Where the individual files can be accessed at
|
21
|
+
# :root => './app/js', # The root of your files
|
22
|
+
# :path => '/js/compressed.js', # The URL where the compressed JS will served at
|
23
|
+
# :files => # List of files
|
24
|
+
# Dir['./app/js/vendor/*.js'] +
|
25
|
+
# Dir['./app/js/app/**.js']
|
26
|
+
#
|
27
|
+
# Note that +:prefix+ and +:root+ are the same things passed onto {JsSupport#serve_js serve_js}.
|
28
|
+
#
|
29
|
+
# In your template view, add this before +</body>+:
|
30
|
+
#
|
31
|
+
# <%= settings.app_js.to_html %>
|
32
|
+
#
|
33
|
+
# (The name +app_js+ comes from the first parameter passed to
|
34
|
+
# {#serve_compressed_js}.)
|
35
|
+
#
|
36
|
+
# In development mode, this will probably output:
|
37
|
+
#
|
38
|
+
# <script src='/js/vendor/jquery.js?1293847189'></script>
|
39
|
+
# <script src='/js/app/application.js?1293847189'></script>
|
40
|
+
# <!-- This is {:prefix} + {files, stripped of :root} -->
|
41
|
+
#
|
42
|
+
# But in production mode:
|
43
|
+
#
|
44
|
+
# <script src='/js/compressed.js?1293847189'></script>
|
45
|
+
# <!-- This is {:path} given in serve_compressed_js -->
|
46
|
+
#
|
47
|
+
# == Caveats
|
48
|
+
#
|
49
|
+
# You will need the JsMin gem.
|
50
|
+
#
|
51
|
+
# # Gemfile
|
52
|
+
# gem "jsmin", "~> 1.0.1"
|
53
|
+
#
|
54
|
+
# CompressedJS supports CoffeeScript. If you do use CoffeeScript, be
|
55
|
+
# sure to add the approprate gem to your project.
|
56
|
+
#
|
57
|
+
# # Gemfile
|
58
|
+
# gem "coffee-script", require: "coffee_script"
|
59
|
+
#
|
60
|
+
# == Caching
|
61
|
+
#
|
62
|
+
# CompressedJS will cache compressed and combined scripts. This means that compression
|
63
|
+
# will only happen once in your application's runtime.
|
64
|
+
#
|
65
|
+
# == Why no support for CSS compression?
|
66
|
+
#
|
67
|
+
# If you use Sass/SCSS anyway, you can achieve the same thing by changing Sass's
|
68
|
+
# :output settings to :compressed. If you also use +@import+ in Sass/SCSS, you can
|
69
|
+
# easily consolidate all CSS into one file without any need for a Sinatra plugin.
|
70
|
+
#
|
71
|
+
# == Extending with another JS compressor
|
72
|
+
#
|
73
|
+
# This is unsupported, but you may change the JsFiles.compress function to use
|
74
|
+
# something else.
|
75
|
+
#
|
76
|
+
# # Sample custom compression (probably doesn't work)
|
77
|
+
# def JsFiles.compress(str)
|
78
|
+
# file = Tempfile.new { |f| f.write str }
|
79
|
+
# output = Tempfile.new
|
80
|
+
#
|
81
|
+
# system "closure-compiler #{file.path} #{output.path}"
|
82
|
+
# output.read
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
module Sinatra::CompressedJS
|
86
|
+
def self.registered(app)
|
87
|
+
app.set :jsfiles_cache_max_age, 86400*30 unless app.respond_to?(:jsfile_cache_max_age)
|
88
|
+
end
|
89
|
+
|
90
|
+
def serve_compressed_js(name, options={})
|
91
|
+
jsfiles = JsFiles.new(options)
|
92
|
+
|
93
|
+
set name.to_sym, jsfiles
|
94
|
+
|
95
|
+
serve_jsfiles options[:path], jsfiles
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
# Adds a route
|
100
|
+
def serve_jsfiles(path, jsfiles)
|
101
|
+
get path do
|
102
|
+
content_type :js
|
103
|
+
last_modified jsfiles.mtime
|
104
|
+
etag jsfiles.mtime.to_i
|
105
|
+
cache_control :public, :must_revalidate, :max_age => settings.jsfiles_cache_max_age
|
106
|
+
|
107
|
+
jsfiles.compressed
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# A list of JavaScript files.
|
113
|
+
#
|
114
|
+
# This is a general-purpose class usually used for minification
|
115
|
+
# of JS assets.
|
116
|
+
#
|
117
|
+
# This is often used with Sinatra, but can work with any other
|
118
|
+
# web framework.
|
119
|
+
#
|
120
|
+
# === Usage example
|
121
|
+
#
|
122
|
+
# files = Dir['public/js/jquery.*.js']
|
123
|
+
# files += Dir['public/js/app.*.js']
|
124
|
+
#
|
125
|
+
# js_files = JsFiles.new(:files => files,
|
126
|
+
# :prefix => '/javascript',
|
127
|
+
# :root => './app/js')
|
128
|
+
#
|
129
|
+
# js_files.mtime #=> (Time) 2010-09-02 8:00PM
|
130
|
+
#
|
131
|
+
# You can use #to_html in views:
|
132
|
+
#
|
133
|
+
# <!-- Shows <script> tags -->
|
134
|
+
# <%= js_files.to_html %>
|
135
|
+
#
|
136
|
+
# Getting the data (for rake tasks perhaps):
|
137
|
+
#
|
138
|
+
# File.open('public/scripts.js', 'w') do |f|
|
139
|
+
# f << js_files.combined
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
# File.open('public/scripts.min.js', 'w') do |f|
|
143
|
+
# f << js_files.compressed
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
class JsFiles
|
147
|
+
attr_reader :files
|
148
|
+
attr_reader :app
|
149
|
+
attr_reader :prefix
|
150
|
+
attr_reader :root
|
151
|
+
attr_reader :path
|
152
|
+
|
153
|
+
# Creates a JsFiles object based on the list of given files.
|
154
|
+
#
|
155
|
+
# @param files [Array] A list of string file paths.
|
156
|
+
# @example
|
157
|
+
#
|
158
|
+
# files = Dir['public/js/jquery.*.js']
|
159
|
+
# $js_files = JsFiles.new(files)
|
160
|
+
#
|
161
|
+
def initialize(options={})
|
162
|
+
@app = options[:app]
|
163
|
+
@files = options[:files]
|
164
|
+
@prefix = options[:prefix] || '/js/'
|
165
|
+
@path = options[:path] || @prefix + 'app.js'
|
166
|
+
@root = options[:root] || '/app/js'
|
167
|
+
@root = File.expand_path(@root)
|
168
|
+
|
169
|
+
raise "Files must be an array" unless @files.is_a?(Array)
|
170
|
+
end
|
171
|
+
|
172
|
+
# @group Metadata methods
|
173
|
+
|
174
|
+
# Returns the the modified time of the entire package.
|
175
|
+
#
|
176
|
+
# @return [Time] The last modified time of the most recent file.
|
177
|
+
#
|
178
|
+
def mtime
|
179
|
+
@files.map { |f| File.mtime(f) }.max
|
180
|
+
end
|
181
|
+
|
182
|
+
# Returns a list of the URLs for the package.
|
183
|
+
#
|
184
|
+
# @example
|
185
|
+
#
|
186
|
+
# -# This is the same as calling #to_html.
|
187
|
+
# - Main.js_files.hrefs.each do |href|
|
188
|
+
# %script{:src => href}
|
189
|
+
#
|
190
|
+
def hrefs
|
191
|
+
@files.map { |f|
|
192
|
+
path = File.expand_path(f)
|
193
|
+
path.gsub! /\.[^\.]*$/, ''
|
194
|
+
path.gsub! /^#{@root}/, ''
|
195
|
+
File.join @prefix, path + ".js?#{File.mtime(f).to_i}"
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
199
|
+
# Returns the <script> tags for the development version.
|
200
|
+
def to_development_html
|
201
|
+
hrefs.map { |href| "<script type='text/javascript' src='#{href}'></script>" }.join("\n")
|
202
|
+
end
|
203
|
+
|
204
|
+
# Returns the <script> tag for the production version.
|
205
|
+
def to_production_html
|
206
|
+
"<script type='text/javascript' src='%s?%s'></script>" % [path, mtime.to_i]
|
207
|
+
end
|
208
|
+
|
209
|
+
# Returns the <script> tags, using development or production as needed.
|
210
|
+
def to_html
|
211
|
+
production? ? to_production_html : to_development_html
|
212
|
+
end
|
213
|
+
|
214
|
+
# @group Output methods
|
215
|
+
|
216
|
+
# Returns the combined source of all the files.
|
217
|
+
def combined
|
218
|
+
@combined ||= @files.map { |file|
|
219
|
+
contents = File.open(file) { |f| f.read }
|
220
|
+
contents = coffee_compile(contents) if file =~ /\.coffee$/
|
221
|
+
contents
|
222
|
+
}.join("\n")
|
223
|
+
end
|
224
|
+
|
225
|
+
# Returns a combined, minifed source of all the files.
|
226
|
+
def compressed
|
227
|
+
require 'jsmin'
|
228
|
+
@compressed ||= self.class.compress(combined)
|
229
|
+
end
|
230
|
+
|
231
|
+
def self.compress(str)
|
232
|
+
JSMin.minify(str).strip
|
233
|
+
end
|
234
|
+
|
235
|
+
protected
|
236
|
+
def coffee_compile(str)
|
237
|
+
require 'coffee_script' unless defined?(::CoffeeScript)
|
238
|
+
CoffeeScript.compile(str)
|
239
|
+
end
|
240
|
+
|
241
|
+
def production?
|
242
|
+
app && app.production?
|
243
|
+
end
|
244
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
alert("hello");
|
@@ -0,0 +1 @@
|
|
1
|
+
alert("hi");
|
@@ -0,0 +1 @@
|
|
1
|
+
alert 2
|
data/test/helper.rb
CHANGED
@@ -19,11 +19,26 @@ class Test::Unit::TestCase
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.fixture_path(*a)
|
22
|
-
|
23
|
-
File.join root, a
|
22
|
+
fx *a
|
24
23
|
end
|
25
24
|
|
26
25
|
def fixture_path(*a)
|
27
|
-
|
26
|
+
fx *a
|
28
27
|
end
|
28
|
+
|
29
|
+
def save_and_open_page
|
30
|
+
f = Tempfile.new(['', '.html'])
|
31
|
+
path = f.path
|
32
|
+
f.close!
|
33
|
+
f.unlink
|
34
|
+
|
35
|
+
File.open(path, 'w') { |f| f.write last_response.body }
|
36
|
+
|
37
|
+
system "open \"#{path}\""
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def fx(*a)
|
42
|
+
root = File.expand_path('../fixtures', __FILE__)
|
43
|
+
File.join root, a
|
29
44
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require File.expand_path('../helper', __FILE__)
|
2
|
+
|
3
|
+
Encoding.default_external = 'utf-8'
|
4
|
+
|
5
|
+
class CompressedJSApp < Test::Unit::TestCase
|
6
|
+
include Rack::Test::Methods
|
7
|
+
|
8
|
+
class App < Sinatra::Base
|
9
|
+
register Sinatra::CompressedJS
|
10
|
+
register Sinatra::JsSupport
|
11
|
+
|
12
|
+
serve_js '/js', from: fx('compressed_js/js')
|
13
|
+
|
14
|
+
serve_compressed_js :app_js,
|
15
|
+
:path => '/js/app.js',
|
16
|
+
:prefix => '/js',
|
17
|
+
:root => fx('compressed_js/js'),
|
18
|
+
:files =>
|
19
|
+
Dir[fx('compressed_js/js/*.{js,coffee}')].sort
|
20
|
+
|
21
|
+
get('/to_development_html') { settings.app_js.to_development_html }
|
22
|
+
get('/to_production_html') { settings.app_js.to_production_html }
|
23
|
+
end
|
24
|
+
|
25
|
+
def app
|
26
|
+
App.new
|
27
|
+
end
|
28
|
+
|
29
|
+
COMPRESSED = "alert(\"hello\");alert(\"hi\");(function(){alert(2);}).call(this);"
|
30
|
+
|
31
|
+
test "JsFiles#files" do
|
32
|
+
assert_equal \
|
33
|
+
Dir[fx('compressed_js/js/*.{js,coffee}')].sort,
|
34
|
+
App.app_js.files
|
35
|
+
end
|
36
|
+
|
37
|
+
test "JsFiles#compressed" do
|
38
|
+
assert_equal COMPRESSED, App.app_js.compressed
|
39
|
+
end
|
40
|
+
|
41
|
+
test "JsFiles#mtime" do
|
42
|
+
assert App.app_js.mtime.to_i > 0
|
43
|
+
end
|
44
|
+
|
45
|
+
test "go" do
|
46
|
+
get '/js/hi.js'
|
47
|
+
control = 'alert("hi");'
|
48
|
+
|
49
|
+
assert_equal control, last_response.body.strip
|
50
|
+
end
|
51
|
+
|
52
|
+
test "coffeescript support" do
|
53
|
+
get '/js/yo.js'
|
54
|
+
control = 'alert(2);';
|
55
|
+
|
56
|
+
assert_equal control, last_response.body.strip
|
57
|
+
end
|
58
|
+
|
59
|
+
test "compressed" do
|
60
|
+
get '/js/app.js'
|
61
|
+
control = COMPRESSED
|
62
|
+
|
63
|
+
assert_equal control, last_response.body.strip
|
64
|
+
end
|
65
|
+
|
66
|
+
test "#to_development_html" do
|
67
|
+
get '/to_development_html'
|
68
|
+
|
69
|
+
control = /<script type='text\/javascript' src='\/js\/hello\.js\?[0-9]+'>/
|
70
|
+
assert_match control, last_response.body
|
71
|
+
|
72
|
+
control = /<script type='text\/javascript' src='\/js\/hi\.js\?[0-9]+'>/
|
73
|
+
assert_match control, last_response.body
|
74
|
+
end
|
75
|
+
|
76
|
+
test "#to_production_html" do
|
77
|
+
get '/to_production_html'
|
78
|
+
|
79
|
+
control = /<script type='text\/javascript' src='\/js\/app\.js\?[0-9]+'>/
|
80
|
+
assert_match control, last_response.body
|
81
|
+
end
|
82
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: sinatra-support
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.
|
5
|
+
version: 1.2.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Cyril David
|
@@ -91,6 +91,28 @@ dependencies:
|
|
91
91
|
version: "0"
|
92
92
|
type: :development
|
93
93
|
version_requirements: *id007
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: coffee-script
|
96
|
+
prerelease: false
|
97
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ~>
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 2.1.1
|
103
|
+
type: :development
|
104
|
+
version_requirements: *id008
|
105
|
+
- !ruby/object:Gem::Dependency
|
106
|
+
name: jsmin
|
107
|
+
prerelease: false
|
108
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ~>
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: 1.0.1
|
114
|
+
type: :development
|
115
|
+
version_requirements: *id009
|
94
116
|
description: Sinatra-support includes many helpers for forms, errors and many amazing things.
|
95
117
|
email:
|
96
118
|
- cyx.ucron@gmail.com
|
@@ -104,6 +126,7 @@ extra_rdoc_files: []
|
|
104
126
|
files:
|
105
127
|
- lib/sinatra/support/compasssupport.rb
|
106
128
|
- lib/sinatra/support/compat-1.8.6.rb
|
129
|
+
- lib/sinatra/support/compressedjs.rb
|
107
130
|
- lib/sinatra/support/country.rb
|
108
131
|
- lib/sinatra/support/countryhelpers.rb
|
109
132
|
- lib/sinatra/support/csssupport.rb
|
@@ -119,6 +142,9 @@ files:
|
|
119
142
|
- lib/sinatra/support/useragenthelpers.rb
|
120
143
|
- lib/sinatra/support/version.rb
|
121
144
|
- lib/sinatra/support.rb
|
145
|
+
- test/fixtures/compressed_js/js/hello.js
|
146
|
+
- test/fixtures/compressed_js/js/hi.js
|
147
|
+
- test/fixtures/compressed_js/js/yo.coffee
|
122
148
|
- test/fixtures/css/style-less.less
|
123
149
|
- test/fixtures/css/style-sass.sass
|
124
150
|
- test/fixtures/css/style-scss.scss
|
@@ -131,6 +157,7 @@ files:
|
|
131
157
|
- test/fixtures/multirender/views_2/home.haml
|
132
158
|
- test/helper.rb
|
133
159
|
- test/test_compass_app.rb
|
160
|
+
- test/test_compressed_js_app.rb
|
134
161
|
- test/test_country.rb
|
135
162
|
- test/test_css.rb
|
136
163
|
- test/test_date.rb
|