sinatra-support 1.1.3 → 1.2.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/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
|