stapler 0.1.0 → 0.4.1
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/README.md +35 -12
- data/lib/stapler.rb +7 -6
- data/lib/stapler/asset.rb +37 -0
- data/lib/stapler/bundle.rb +41 -0
- data/lib/stapler/bundle/key.rb +12 -0
- data/lib/stapler/bundle/serialized_key.rb +38 -0
- data/lib/stapler/config.rb +57 -4
- data/lib/stapler/middleware.rb +49 -14
- data/lib/stapler/rails.rb +65 -0
- data/lib/stapler/utils.rb +54 -0
- metadata +34 -57
- data/lib/stapler/compressor.rb +0 -40
- data/lib/stapler/helper.rb +0 -35
- data/lib/stapler/stapler.rb +0 -33
data/README.md
CHANGED
@@ -1,31 +1,54 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
== DESCRIPTION:
|
1
|
+
Stapler
|
2
|
+
=======
|
4
3
|
|
5
4
|
Stapler uses YUI Compressor to automatically compress cached assets in Rails
|
6
5
|
|
7
|
-
== FEATURES/PROBLEMS:
|
8
6
|
|
9
|
-
|
7
|
+
Features/Problems
|
8
|
+
-----------------
|
9
|
+
|
10
|
+
* Support both CSS and Javascript
|
11
|
+
|
10
12
|
|
11
|
-
|
13
|
+
Requirements
|
14
|
+
------------
|
12
15
|
|
13
16
|
* yuicompressor gem
|
14
17
|
|
15
|
-
|
18
|
+
TODO
|
19
|
+
------------
|
20
|
+
|
21
|
+
* warnings if the bundle URL is longer than 2048 chars (for IE)
|
22
|
+
* make sure that Config.secret is not a class variable
|
23
|
+
* logging
|
24
|
+
* specs
|
25
|
+
* pass 404 errors to the underlying app
|
26
|
+
|
27
|
+
Install
|
28
|
+
-------
|
16
29
|
|
17
30
|
* gem install stapler
|
18
31
|
|
19
|
-
== REFERENCES:
|
20
32
|
|
21
|
-
|
22
|
-
|
33
|
+
References
|
34
|
+
----------
|
35
|
+
|
36
|
+
* YUI Compressor - <http://developer.yahoo.com/yui/compressor/>
|
37
|
+
* yuicompressor gem - <http://github.com/mjijackson/yuicompressor>
|
38
|
+
|
39
|
+
|
40
|
+
Author
|
41
|
+
------
|
42
|
+
|
43
|
+
Michael Rykov :: missingfeature.com :: @michaelrykov
|
44
|
+
|
23
45
|
|
24
|
-
|
46
|
+
License
|
47
|
+
-------
|
25
48
|
|
26
49
|
(The MIT License)
|
27
50
|
|
28
|
-
Copyright (c) 2009 Michael Rykov
|
51
|
+
Copyright (c) 2009 Michael Rykov
|
29
52
|
|
30
53
|
Permission is hereby granted, free of charge, to any person obtaining
|
31
54
|
a copy of this software and associated documentation files (the
|
data/lib/stapler.rb
CHANGED
@@ -5,12 +5,13 @@
|
|
5
5
|
$:.unshift File.dirname(__FILE__)
|
6
6
|
|
7
7
|
require 'yuicompressor'
|
8
|
+
require 'stapler/utils'
|
9
|
+
require 'stapler/asset'
|
10
|
+
require 'stapler/bundle/key'
|
11
|
+
require 'stapler/bundle'
|
8
12
|
require 'stapler/config'
|
9
|
-
require 'stapler/compressor'
|
10
|
-
require 'stapler/stapler'
|
11
|
-
require 'stapler/helper'
|
12
13
|
require 'stapler/middleware'
|
13
14
|
|
14
|
-
if defined?(
|
15
|
-
|
16
|
-
end
|
15
|
+
if defined?(Rails)
|
16
|
+
require 'stapler/rails'
|
17
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) Michael Rykov
|
3
|
+
#++
|
4
|
+
|
5
|
+
module Stapler
|
6
|
+
class Asset
|
7
|
+
FORBIDDEN_PATHS = %w(.. WEB-INF META-INF)
|
8
|
+
REWRITE_KEYS = %w(PATH_INFO REQUEST_PATH REQUEST_URI)
|
9
|
+
|
10
|
+
def initialize(config, path)
|
11
|
+
@config = config
|
12
|
+
@path = Utils.groom_path(path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def response(env)
|
16
|
+
if forbidden?
|
17
|
+
@config.rack_file.not_found
|
18
|
+
else
|
19
|
+
@config.rack_file.call(rewrite_env(env))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def forbidden?
|
25
|
+
FORBIDDEN_PATHS.any? { |fp| @path.include?(fp) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def rewrite_env(env)
|
29
|
+
out = env.dup
|
30
|
+
REWRITE_KEYS.each do |key|
|
31
|
+
next unless out[key].is_a?(String)
|
32
|
+
out[key] = out[key].gsub(@config.path_regex, @path)
|
33
|
+
end
|
34
|
+
out
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) Michael Rykov
|
3
|
+
#++
|
4
|
+
require 'rack/utils'
|
5
|
+
require 'rack/file'
|
6
|
+
|
7
|
+
module Stapler
|
8
|
+
class Bundle
|
9
|
+
def initialize(config, bundle)
|
10
|
+
@config = config
|
11
|
+
@paths = Key.to_paths(bundle.to_s)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Collect asset responses and build the collective response
|
15
|
+
def response(env)
|
16
|
+
if not @paths.is_a?(Array)
|
17
|
+
@config.rack_file.not_found
|
18
|
+
else
|
19
|
+
@paths.inject([200, {}, '']) do |sum, path|
|
20
|
+
# Fetch the response
|
21
|
+
item = Stapler::Asset.new(@config, path).response(env)
|
22
|
+
|
23
|
+
# Add the file title
|
24
|
+
sum[2] << "\n\n\n/***** #{path} *****/\n\n\n"
|
25
|
+
|
26
|
+
if item[0] != 200
|
27
|
+
sum[2] << "/* [#{item[0]}] Asset problem */\n\n\n"
|
28
|
+
else
|
29
|
+
# Headers are merged
|
30
|
+
sum[1].merge!(item[1])
|
31
|
+
# Body is concatenated
|
32
|
+
sum[2] << Stapler::Utils.response_body(item)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return the response
|
36
|
+
sum
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) Michael Rykov
|
3
|
+
#++
|
4
|
+
|
5
|
+
module Stapler
|
6
|
+
class Bundle
|
7
|
+
class SerializedKey; end
|
8
|
+
@@asset_id = Time.now.to_i.to_s
|
9
|
+
|
10
|
+
class << SerializedKey
|
11
|
+
def to_key(paths)
|
12
|
+
key = Utils.url_encode(paths.map { |a| Utils.groom_path(a) })
|
13
|
+
File.join(key, signature(key), @@asset_id)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_paths(bundle)
|
17
|
+
key, signature = bundle.split(/[\.\/]/, 3)
|
18
|
+
url_decode_with_signature(key, signature)
|
19
|
+
rescue Utils::BadString
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
# Security signature for URLs #
|
25
|
+
def signature(key)
|
26
|
+
Digest::SHA1.hexdigest("#{key}#{Config.secret}")[0...8]
|
27
|
+
end
|
28
|
+
|
29
|
+
def url_decode_with_signature(key, key_signature)
|
30
|
+
if signature(key.to_s) == key_signature.to_s
|
31
|
+
Utils.url_decode(key)
|
32
|
+
else
|
33
|
+
raise BadString, "Invalid signature"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/stapler/config.rb
CHANGED
@@ -5,11 +5,64 @@
|
|
5
5
|
#++
|
6
6
|
|
7
7
|
module Stapler
|
8
|
-
|
9
|
-
|
8
|
+
class Config
|
9
|
+
PREFIX = 'stapler'
|
10
|
+
WHITELIST_DIR = %w(javascripts stylesheets)
|
11
|
+
WHITELIST_RE = Regexp.union(
|
12
|
+
%r{^/javascripts/.*\.js($|\?)},
|
13
|
+
%r{^/stylesheets/.*\.css($|\?)}
|
14
|
+
)
|
10
15
|
|
11
|
-
|
12
|
-
|
16
|
+
STAPLIZE_RE = Regexp.union(
|
17
|
+
%r{/javascripts/.*\.js($|\?)},
|
18
|
+
%r{/stylesheets/.*\.css($|\?)}
|
19
|
+
)
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def stapleable_path?(source)
|
23
|
+
source =~ WHITELIST_RE
|
24
|
+
end
|
25
|
+
|
26
|
+
def stapleable_dir?(dir)
|
27
|
+
WHITELIST_DIR.include?(dir)
|
28
|
+
end
|
29
|
+
|
30
|
+
def staplize_url(url)
|
31
|
+
url.gsub(STAPLIZE_RE, "/#{PREFIX}\\0")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
DEFAULT_ROOT = defined?(Rails) ? Rails.public_path : 'public'
|
36
|
+
DEFAULT_PREFIX = 'stapler'
|
37
|
+
|
38
|
+
attr_accessor :path_regex, :bundle_regex, :rack_file,
|
39
|
+
:perform_caching, :perform_compress
|
40
|
+
|
41
|
+
def initialize(opts = {})
|
42
|
+
# The root directory of where all the public files are stored
|
43
|
+
asset_dir = opts[:public_path] || DEFAULT_ROOT
|
44
|
+
|
45
|
+
# The path prefix and correcsponding RegEx for stapled assets
|
46
|
+
path_prefix = opts[:path_prefix] || DEFAULT_PREFIX
|
47
|
+
@path_regex = %r(^/#{path_prefix}/(.+)$)
|
48
|
+
@bundle_regex = %r(^/#{path_prefix}/bundle/(.+)$)
|
49
|
+
|
50
|
+
# Rack::File will pull all the source files
|
51
|
+
@rack_file = Rack::File.new(asset_dir)
|
52
|
+
|
53
|
+
# Should we write stapled results and where?
|
54
|
+
@perform_caching = opts[:cache_assets] || false
|
55
|
+
|
56
|
+
# Should we compress stapled results
|
57
|
+
@perform_compress = opts[:compress_assets] || false
|
58
|
+
|
59
|
+
# Bundle URL signature secret
|
60
|
+
@@secret = opts[:secret] || 'nakedemperor'
|
61
|
+
end
|
62
|
+
|
63
|
+
# FIXME: This should not be class variable
|
64
|
+
def self.secret
|
65
|
+
@@secret
|
13
66
|
end
|
14
67
|
end
|
15
68
|
end
|
data/lib/stapler/middleware.rb
CHANGED
@@ -1,35 +1,70 @@
|
|
1
|
+
require 'rack/utils'
|
2
|
+
require 'rack/file'
|
3
|
+
|
1
4
|
module Stapler
|
2
5
|
class Middleware
|
3
|
-
|
4
|
-
|
5
|
-
def initialize(app)
|
6
|
+
def initialize(app, opts = {})
|
6
7
|
@app = app
|
8
|
+
@config = Stapler::Config.new(opts)
|
7
9
|
end
|
8
10
|
|
9
11
|
def call(env)
|
10
|
-
|
11
|
-
puts "LOOKING AT PATH #{path}"
|
12
|
+
path_info = env["PATH_INFO"]
|
12
13
|
|
13
|
-
if
|
14
|
-
|
14
|
+
if path_info =~ @config.bundle_regex
|
15
|
+
_call_bundle(env, Rack::Utils.unescape($1))
|
16
|
+
elsif path_info =~ @config.path_regex
|
17
|
+
_call_asset(env, Rack::Utils.unescape($1))
|
15
18
|
else
|
16
19
|
@app.call(env)
|
17
20
|
end
|
18
21
|
end
|
19
22
|
|
20
23
|
private
|
21
|
-
def
|
22
|
-
|
24
|
+
def _call_bundle(env, path)
|
25
|
+
bundle = Stapler::Bundle.new(@config, path)
|
26
|
+
staple_response(bundle.response(env), "bundle/#{path}")
|
27
|
+
end
|
28
|
+
|
29
|
+
def _call_asset(env, path)
|
30
|
+
assets = Stapler::Asset.new(@config, path)
|
31
|
+
staple_response(assets.response(env), path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def staple_response(response, asset_path)
|
35
|
+
if response[0] == 200
|
36
|
+
# Pull out the body
|
37
|
+
body = Stapler::Utils.response_body(response)
|
38
|
+
|
39
|
+
# Compress the body and update response
|
40
|
+
body = compress(body, asset_path) if @config.perform_compress
|
41
|
+
|
42
|
+
# Prepare the response and headers
|
43
|
+
response[1]['Content-Length'] = Rack::Utils.bytesize(body).to_s
|
44
|
+
response[2] = body
|
45
|
+
|
46
|
+
# Add cache headers for Rack::Cache, etc
|
47
|
+
response[1].merge!(cache_headers(asset_path))
|
48
|
+
end
|
49
|
+
|
50
|
+
response
|
51
|
+
end
|
23
52
|
|
24
|
-
|
25
|
-
|
53
|
+
def compress(content, path)
|
54
|
+
# Compress using the path as an indicator for format
|
55
|
+
if path =~ /\.css$/
|
56
|
+
YUICompressor.compress_css(content)
|
57
|
+
elsif path =~ /\.js$/
|
58
|
+
YUICompressor.compress_js(content, :munge => true)
|
26
59
|
else
|
27
|
-
|
60
|
+
content
|
28
61
|
end
|
29
62
|
end
|
30
63
|
|
31
|
-
def
|
32
|
-
|
64
|
+
def cache_headers(path)
|
65
|
+
duration = @config.perform_caching ? 31536000 : 0
|
66
|
+
{ "Cache-Control" => "public, max-age=#{duration.to_s}",
|
67
|
+
"ETag" => %("#{Digest::SHA1.hexdigest(path)}") }
|
33
68
|
end
|
34
69
|
end
|
35
70
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010 Michael Rykov
|
3
|
+
#++
|
4
|
+
|
5
|
+
module Stapler
|
6
|
+
module Rails
|
7
|
+
class << self
|
8
|
+
def activate!
|
9
|
+
::ActionView::Base.send(:include, RailsHelper)
|
10
|
+
end
|
11
|
+
|
12
|
+
def asset_host_proc(image_host = nil)
|
13
|
+
prefix = File.join('/', Config::PREFIX)
|
14
|
+
if image_host
|
15
|
+
Proc.new { |source|
|
16
|
+
host = image_host
|
17
|
+
host << prefix if Config.stapleable_path?(source)
|
18
|
+
host
|
19
|
+
}
|
20
|
+
else
|
21
|
+
Proc.new { |source, request|
|
22
|
+
host = request.host_with_port
|
23
|
+
host << prefix if Config.stapleable_path?(source)
|
24
|
+
host
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module RailsHelper
|
31
|
+
def javascript_include_tag(*sources)
|
32
|
+
options = sources.extract_options!.stringify_keys
|
33
|
+
|
34
|
+
if options.delete('cache') || options.delete('concat')
|
35
|
+
recursive = options.delete('recursive')
|
36
|
+
paths = compute_javascript_paths(sources, recursive)
|
37
|
+
javascript_src_tag(Utils.bundle_path(paths), options)
|
38
|
+
else
|
39
|
+
sources << options
|
40
|
+
super(*sources)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def stylesheet_link_tag(*sources)
|
45
|
+
options = sources.extract_options!.stringify_keys
|
46
|
+
|
47
|
+
if options.delete('cache') || options.delete('concat')
|
48
|
+
recursive = options.delete('recursive')
|
49
|
+
paths = compute_stylesheet_paths(sources, recursive)
|
50
|
+
stylesheet_tag(Utils.bundle_path(paths), options)
|
51
|
+
else
|
52
|
+
sources << options
|
53
|
+
super(*sources)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def compute_public_path(src, dir, ext = nil, include_host = true)
|
59
|
+
staple = include_host && src !~ %r{^[-a-z]+://} && Config.stapleable_dir?(dir)
|
60
|
+
path = super(src, dir, ext, include_host)
|
61
|
+
staple ? Config.staplize_url(path) : path
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) Michael Rykov
|
3
|
+
#
|
4
|
+
# Some methods copied from Dragonfly gem Serializer
|
5
|
+
#++
|
6
|
+
|
7
|
+
require 'base64'
|
8
|
+
require 'cgi'
|
9
|
+
require 'digest/sha1'
|
10
|
+
|
11
|
+
module Stapler
|
12
|
+
module Utils
|
13
|
+
# Exceptions
|
14
|
+
class BadString < RuntimeError; end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def response_body(response)
|
18
|
+
body = response[2]
|
19
|
+
body.is_a?(Rack::File) ? File.read(body.path) : body
|
20
|
+
end
|
21
|
+
|
22
|
+
#### Base64 encoding for URLS ####
|
23
|
+
def b64_encode(string)
|
24
|
+
Base64.encode64(string).tr("\n=",'')
|
25
|
+
end
|
26
|
+
|
27
|
+
def b64_decode(string)
|
28
|
+
padding_length = string.length % 4
|
29
|
+
Base64.decode64(string + '=' * padding_length)
|
30
|
+
end
|
31
|
+
|
32
|
+
def url_encode(object)
|
33
|
+
CGI.escape(b64_encode(Marshal.dump(object)))
|
34
|
+
end
|
35
|
+
|
36
|
+
def url_decode(string)
|
37
|
+
Marshal.load(b64_decode(CGI.unescape(string)))
|
38
|
+
rescue TypeError, ArgumentError => e
|
39
|
+
raise BadString, "couldn't decode #{string} - got #{e}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def groom_path(path)
|
43
|
+
# Remove leading slashes and query params
|
44
|
+
path.gsub(/^\//, '').gsub(/\?.*$/, '')
|
45
|
+
end
|
46
|
+
|
47
|
+
# Convert a list of assets into an URL
|
48
|
+
# Note: Rails helpers adds the appropriate extension
|
49
|
+
def bundle_path(assets)
|
50
|
+
File.join('/stapler/bundle/', Bundle::Key.to_key(assets))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
metadata
CHANGED
@@ -1,94 +1,71 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: stapler
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 0
|
10
|
-
version: 0.1.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.1
|
5
|
+
prerelease:
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Michael Rykov
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-12-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
22
15
|
name: yuicompressor
|
23
|
-
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &70096179375860 !ruby/object:Gem::Requirement
|
25
17
|
none: false
|
26
|
-
requirements:
|
18
|
+
requirements:
|
27
19
|
- - ~>
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
hash: 31
|
30
|
-
segments:
|
31
|
-
- 1
|
32
|
-
- 2
|
33
|
-
- 0
|
20
|
+
- !ruby/object:Gem::Version
|
34
21
|
version: 1.2.0
|
35
22
|
type: :runtime
|
36
|
-
|
37
|
-
|
38
|
-
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70096179375860
|
25
|
+
description: ! 'Dynamic asset compression for Rails using YUI Compressor
|
39
26
|
|
27
|
+
'
|
40
28
|
email: mrykov@gmail
|
41
29
|
executables: []
|
42
|
-
|
43
30
|
extensions: []
|
44
|
-
|
45
31
|
extra_rdoc_files: []
|
46
|
-
|
47
|
-
files:
|
32
|
+
files:
|
48
33
|
- README.md
|
49
34
|
- Rakefile
|
50
35
|
- LICENSE
|
51
|
-
- lib/stapler/
|
36
|
+
- lib/stapler/asset.rb
|
37
|
+
- lib/stapler/bundle/key.rb
|
38
|
+
- lib/stapler/bundle/serialized_key.rb
|
39
|
+
- lib/stapler/bundle.rb
|
52
40
|
- lib/stapler/config.rb
|
53
|
-
- lib/stapler/helper.rb
|
54
41
|
- lib/stapler/middleware.rb
|
55
|
-
- lib/stapler/
|
42
|
+
- lib/stapler/rails.rb
|
43
|
+
- lib/stapler/utils.rb
|
56
44
|
- lib/stapler.rb
|
57
45
|
- lib/tasks/stapler.rake
|
58
46
|
- lib/tasks/tasks.rb
|
59
|
-
has_rdoc: false
|
60
47
|
homepage: http://github.com/rykov/stapler
|
61
48
|
licenses: []
|
62
|
-
|
63
49
|
post_install_message:
|
64
50
|
rdoc_options: []
|
65
|
-
|
66
|
-
require_paths:
|
51
|
+
require_paths:
|
67
52
|
- lib
|
68
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
54
|
none: false
|
70
|
-
requirements:
|
71
|
-
- -
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
|
74
|
-
|
75
|
-
- 0
|
76
|
-
version: "0"
|
77
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
60
|
none: false
|
79
|
-
requirements:
|
80
|
-
- -
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
|
83
|
-
segments:
|
84
|
-
- 0
|
85
|
-
version: "0"
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
86
65
|
requirements: []
|
87
|
-
|
88
66
|
rubyforge_project:
|
89
|
-
rubygems_version: 1.
|
67
|
+
rubygems_version: 1.8.11
|
90
68
|
signing_key:
|
91
69
|
specification_version: 3
|
92
70
|
summary: Dynamic asset compression for Rails
|
93
71
|
test_files: []
|
94
|
-
|
data/lib/stapler/compressor.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2009 Michael Rykov
|
3
|
-
#++
|
4
|
-
|
5
|
-
module Stapler
|
6
|
-
class Compressor
|
7
|
-
def initialize(from, to)
|
8
|
-
@from_path = from
|
9
|
-
@to_path = to
|
10
|
-
end
|
11
|
-
|
12
|
-
def compress!
|
13
|
-
compress(@from_path, @to_path)
|
14
|
-
logger.info("[Stapler] Compressed #{@from_path}")
|
15
|
-
rescue => e
|
16
|
-
logger.warn("[Stapler] Compression failure for #{@from_path}: #{e}")
|
17
|
-
FileUtil.cp(@from_path, @to_path)
|
18
|
-
end
|
19
|
-
|
20
|
-
protected
|
21
|
-
def compress(from, to)
|
22
|
-
out = File.open(from) do |from_file|
|
23
|
-
if from =~ /\.css$/
|
24
|
-
YUICompressor.compress_css(from_file)
|
25
|
-
elsif from =~ /\.js$/
|
26
|
-
YUICompressor.compress_js(from_file, :munge => true)
|
27
|
-
else
|
28
|
-
raise StandardError.new("Unrecognized file type")
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
File.open(to, 'w') { |f| f.write(out) }
|
33
|
-
end
|
34
|
-
|
35
|
-
def logger
|
36
|
-
Rails.logger
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
data/lib/stapler/helper.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2009 Michael Rykov
|
3
|
-
#++
|
4
|
-
|
5
|
-
module Stapler
|
6
|
-
module Helper
|
7
|
-
StaplerRoot = "/stapler"
|
8
|
-
|
9
|
-
def self.included(base)
|
10
|
-
base.send :alias_method_chain, :rewrite_asset_path, :stapler
|
11
|
-
#base.send :alias_method_chain, :compute_asset_host, :stapler
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
def rewrite_asset_path_with_stapler(source)
|
16
|
-
if Config.stapleable?(source)
|
17
|
-
@@stapler ||= Stapler.new
|
18
|
-
stapled_source = "#{StaplerRoot}#{source}"
|
19
|
-
stapled_path = asset_file_path(stapled_source)
|
20
|
-
|
21
|
-
if @@stapler.ready?(stapled_path)
|
22
|
-
source = stapled_source
|
23
|
-
else
|
24
|
-
@@stapler.process(asset_file_path(source), stapled_path)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
rewrite_asset_path_without_stapler(source)
|
29
|
-
end
|
30
|
-
|
31
|
-
#def compute_asset_host_with_stapler(source)
|
32
|
-
# compute_asset_host_without_stapler(source)
|
33
|
-
#end
|
34
|
-
end
|
35
|
-
end
|
data/lib/stapler/stapler.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
#--
|
2
|
-
# Copyright (c) 2009 Michael Rykov
|
3
|
-
#++
|
4
|
-
|
5
|
-
module Stapler
|
6
|
-
class Stapler
|
7
|
-
|
8
|
-
def initialize
|
9
|
-
@in_progress = {}
|
10
|
-
@in_progress_guard = Mutex.new
|
11
|
-
end
|
12
|
-
|
13
|
-
def ready?(path)
|
14
|
-
!@in_progress[path] && File.exists?(path)
|
15
|
-
end
|
16
|
-
|
17
|
-
def process(from, to)
|
18
|
-
@in_progress_guard.synchronize do
|
19
|
-
return if @in_progress[to]
|
20
|
-
@in_progress[to] = true
|
21
|
-
end
|
22
|
-
|
23
|
-
Thread.new { self.compress(from, to) }
|
24
|
-
end
|
25
|
-
|
26
|
-
protected
|
27
|
-
def compress(from, to)
|
28
|
-
FileUtils.mkdir_p(File.dirname(to))
|
29
|
-
Compressor.new(from, to).compress!
|
30
|
-
@in_progress.delete(to)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|