assets_booster 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +2 -0
- data/Rakefile +4 -0
- data/asset_booster.gemspec +6 -1
- data/lib/assets_booster/compiler/closure.rb +8 -6
- data/lib/assets_booster/compiler/dummy.rb +2 -5
- data/lib/assets_booster/compiler/jsmin.rb +138 -148
- data/lib/assets_booster/compiler/rainpress.rb +3 -3
- data/lib/assets_booster/compiler/uglify.rb +6 -4
- data/lib/assets_booster/merger/base.rb +26 -0
- data/lib/assets_booster/merger/css.rb +38 -43
- data/lib/assets_booster/merger/simple.rb +7 -11
- data/lib/assets_booster/package/base.rb +24 -14
- data/lib/assets_booster/package/javascript.rb +3 -7
- data/lib/assets_booster/package/stylesheet.rb +3 -7
- data/lib/assets_booster/packager.rb +102 -11
- data/lib/assets_booster/railtie.rb +5 -3
- data/lib/assets_booster/tasks/tasks.rake +9 -11
- data/lib/assets_booster/version.rb +1 -1
- data/lib/assets_booster/view_helper.rb +3 -6
- data/spec/compiler/base.rb +15 -0
- data/spec/compiler/closure_spec.rb +16 -0
- data/spec/compiler/dummy_spec.rb +16 -0
- data/spec/compiler/jsmin_spec.rb +16 -0
- data/spec/compiler/rainpress_spec.rb +16 -0
- data/spec/compiler/uglify_spec.rb +16 -0
- data/spec/merger/base.rb +31 -0
- data/spec/merger/css_spec.rb +138 -0
- data/spec/merger/simple_spec.rb +18 -0
- data/spec/package/base.rb +26 -0
- data/spec/package/javascript_spec.rb +16 -0
- data/spec/package/stylesheet_spec.rb +16 -0
- data/spec/packager_spec.rb +87 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/view_helper_spec.rb +12 -0
- metadata +69 -7
- data/lib/assets_booster/configuration.rb +0 -104
@@ -0,0 +1,26 @@
|
|
1
|
+
module AssetsBooster
|
2
|
+
module Merger
|
3
|
+
class Base
|
4
|
+
attr_accessor :assets
|
5
|
+
|
6
|
+
def initialize(sources)
|
7
|
+
self.assets = []
|
8
|
+
sources.each do |source|
|
9
|
+
load_source(source)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def mtime
|
14
|
+
assets.map{ |asset| File.mtime(asset[:source]) }.max
|
15
|
+
end
|
16
|
+
|
17
|
+
def load_source(source)
|
18
|
+
assets << {
|
19
|
+
:source => source,
|
20
|
+
:css => File.read(source),
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -1,40 +1,27 @@
|
|
1
|
+
require 'assets_booster/merger/base'
|
1
2
|
module AssetsBooster
|
2
3
|
module Merger
|
3
|
-
class CSS
|
4
|
-
|
5
|
-
|
6
|
-
def self.name
|
4
|
+
class CSS < Base
|
5
|
+
def name
|
7
6
|
"CSS Merger"
|
8
7
|
end
|
9
|
-
|
10
|
-
def
|
11
|
-
|
12
|
-
sources.each do |source|
|
13
|
-
load_source(source)
|
14
|
-
end
|
15
|
-
|
16
|
-
target_folder = File.dirname(target)
|
8
|
+
|
9
|
+
def merge(target)
|
10
|
+
target_folder = dirname(target)
|
17
11
|
assets.inject("") do |code, asset|
|
18
|
-
source_folder =
|
19
|
-
rewrite_urls
|
20
|
-
code << asset[:css]
|
12
|
+
source_folder = dirname(asset[:source])
|
13
|
+
asset[:css]= rewrite_urls(asset[:css], source_folder, target_folder)
|
14
|
+
code << asset[:css]
|
15
|
+
code << "\n"
|
21
16
|
end.strip
|
22
17
|
end
|
23
18
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def self.load_source(source)
|
35
|
-
css = File.read(source)
|
36
|
-
source_folder = File.dirname(source)
|
37
|
-
css.gsub!(/@import\s+([^;\n\s]+)/).each do |import|
|
19
|
+
def load_source(source)
|
20
|
+
super(source)
|
21
|
+
asset = assets.pop
|
22
|
+
source_folder = dirname(asset[:source])
|
23
|
+
source_folder << "/" unless source_folder == ""
|
24
|
+
asset[:css].gsub!(/@import\s+([^;\n\s]+)/).each do |import|
|
38
25
|
url = $1.gsub(/^url\((.+)\)/i, '\1')
|
39
26
|
url, quotes = extract_url(url.strip)
|
40
27
|
|
@@ -42,21 +29,17 @@ module AssetsBooster
|
|
42
29
|
next import if absolute_url?(url)
|
43
30
|
|
44
31
|
# recursively process the imported css
|
45
|
-
load_source(source_folder+
|
32
|
+
load_source(source_folder+url)
|
46
33
|
""
|
47
34
|
end
|
48
|
-
|
49
|
-
:source => source,
|
50
|
-
:css => css
|
51
|
-
}
|
35
|
+
assets << asset
|
52
36
|
end
|
53
|
-
|
54
|
-
def
|
55
|
-
|
56
|
-
url_prepend
|
57
|
-
return unless url_prepend
|
37
|
+
|
38
|
+
def rewrite_urls(css, source_folder, target_folder)
|
39
|
+
url_prepend = path_difference(source_folder, target_folder)
|
40
|
+
return css if url_prepend == ""
|
58
41
|
|
59
|
-
css.gsub
|
42
|
+
css.gsub(/url\(([^)]+)\)/i) do |match|
|
60
43
|
url, quotes = extract_url($1.strip)
|
61
44
|
|
62
45
|
# we don't want to change references to external assets
|
@@ -66,12 +49,24 @@ module AssetsBooster
|
|
66
49
|
end
|
67
50
|
end
|
68
51
|
|
69
|
-
def
|
52
|
+
def extract_url(quoted_url)
|
70
53
|
(quoted_url[0].chr =~ /["']/) ? [quoted_url.slice(1, quoted_url.length-2), quoted_url[0].chr] : [quoted_url, ""]
|
71
54
|
end
|
72
55
|
|
73
|
-
def
|
74
|
-
url
|
56
|
+
def absolute_url?(url)
|
57
|
+
!!(url =~ /^(\/|https?:\/\/)/i)
|
58
|
+
end
|
59
|
+
|
60
|
+
def dirname(path)
|
61
|
+
path.include?("/") ? File.dirname(path) : ""
|
62
|
+
end
|
63
|
+
|
64
|
+
def path_difference(source, target)
|
65
|
+
return source if target == ""
|
66
|
+
if source[0..target.length-1] != target
|
67
|
+
raise ArgumentError, "source and target to not share a common base path [#{source}, #{target}]"
|
68
|
+
end
|
69
|
+
source[target.length+1..-1] || ""
|
75
70
|
end
|
76
71
|
end
|
77
72
|
end
|
@@ -1,21 +1,17 @@
|
|
1
|
+
require 'assets_booster/merger/base'
|
1
2
|
module AssetsBooster
|
2
3
|
module Merger
|
3
|
-
class Simple
|
4
|
-
def
|
4
|
+
class Simple < Base
|
5
|
+
def name
|
5
6
|
"Simple Merger"
|
6
7
|
end
|
7
8
|
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
9
|
+
def merge(target)
|
10
|
+
assets.inject("") do |code, asset|
|
11
|
+
code << asset[:css]
|
12
|
+
code << "\n"
|
13
13
|
end.strip
|
14
14
|
end
|
15
|
-
|
16
|
-
def self.mtime(sources)
|
17
|
-
sources.map{ |source| File.mtime(source) }.max
|
18
|
-
end
|
19
15
|
end
|
20
16
|
end
|
21
17
|
end
|
@@ -1,27 +1,37 @@
|
|
1
|
+
require "assets_booster/packager"
|
1
2
|
module AssetsBooster
|
2
3
|
module Package
|
3
4
|
class Base
|
4
5
|
attr_accessor :name
|
5
|
-
attr_accessor :filename
|
6
6
|
attr_accessor :assets
|
7
|
-
attr_accessor :
|
7
|
+
attr_accessor :filename
|
8
|
+
attr_accessor :merger_class
|
9
|
+
attr_accessor :compiler_class
|
8
10
|
|
9
11
|
def initialize(name, assets)
|
10
12
|
self.name = name+"_packaged"
|
11
13
|
self.assets = assets
|
12
|
-
self.filename =
|
14
|
+
self.filename = asset_path(self.name)
|
13
15
|
end
|
14
16
|
|
15
17
|
def exists?
|
16
18
|
File.exists?(filename)
|
17
19
|
end
|
18
20
|
|
21
|
+
def merger
|
22
|
+
@merger ||= merger_class.new(sources)
|
23
|
+
end
|
24
|
+
|
25
|
+
def compiler
|
26
|
+
@compiler ||= compiler_class.new
|
27
|
+
end
|
28
|
+
|
19
29
|
def mtime
|
20
|
-
@mtime ||=
|
30
|
+
@mtime ||= merger.mtime
|
21
31
|
end
|
22
32
|
|
23
33
|
def sources
|
24
|
-
assets.each.map{ |asset|
|
34
|
+
@sources ||= assets.each.map{ |asset| asset_path(asset) }
|
25
35
|
end
|
26
36
|
|
27
37
|
def delete
|
@@ -29,20 +39,20 @@ module AssetsBooster
|
|
29
39
|
end
|
30
40
|
|
31
41
|
def merge
|
32
|
-
AssetsBooster.log("Merging assets using #{
|
33
|
-
save(
|
42
|
+
AssetsBooster.log("Merging assets using #{merger.name} to #{relative_filename}...")
|
43
|
+
save(merger.merge(filename))
|
34
44
|
end
|
35
45
|
|
36
46
|
def compile
|
37
|
-
|
38
|
-
AssetsBooster.log("Compiling #{relative_filename} using #{
|
39
|
-
code =
|
40
|
-
AssetsBooster.log("Compilation finished: %5.2f%% saved." % [(1-code.size.to_f/
|
47
|
+
merged_code = merge
|
48
|
+
AssetsBooster.log("Compiling #{relative_filename} using #{compiler.name}...")
|
49
|
+
code = compiler.compile(merged_code)
|
50
|
+
AssetsBooster.log("Compilation finished: %5.2f%% saved." % [(1-code.size.to_f/merged_code.size)*100])
|
41
51
|
save(code)
|
42
52
|
end
|
43
53
|
|
44
|
-
def view_helper
|
45
|
-
sources =
|
54
|
+
def view_helper(packager)
|
55
|
+
sources = packager.boosted_environment? ? [name] : assets
|
46
56
|
[view_helper_method, sources]
|
47
57
|
end
|
48
58
|
|
@@ -63,7 +73,7 @@ module AssetsBooster
|
|
63
73
|
end
|
64
74
|
|
65
75
|
def relative_filename
|
66
|
-
filename.sub(Rails.root, "
|
76
|
+
filename.sub("#{Rails.root}/", "")
|
67
77
|
end
|
68
78
|
end
|
69
79
|
end
|
@@ -1,17 +1,13 @@
|
|
1
1
|
module AssetsBooster
|
2
2
|
module Package
|
3
3
|
class Javascript < Base
|
4
|
-
def
|
5
|
-
AssetsBooster::Configuration.compiler_for_type(:javascript)
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.merger
|
4
|
+
def merger_class
|
9
5
|
require "assets_booster/merger/simple"
|
10
6
|
AssetsBooster::Merger::Simple
|
11
7
|
end
|
12
8
|
|
13
|
-
def
|
14
|
-
path = AssetsBooster::
|
9
|
+
def asset_path(name)
|
10
|
+
path = AssetsBooster::Packager.asset_path("javascripts")
|
15
11
|
path = File.join(path, name+".js") if name
|
16
12
|
end
|
17
13
|
|
@@ -1,17 +1,13 @@
|
|
1
1
|
module AssetsBooster
|
2
2
|
module Package
|
3
3
|
class Stylesheet < Base
|
4
|
-
def
|
5
|
-
AssetsBooster::Configuration.compiler_for_type(:stylesheet)
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.merger
|
4
|
+
def merger_class
|
9
5
|
require "assets_booster/merger/css"
|
10
6
|
AssetsBooster::Merger::CSS
|
11
7
|
end
|
12
8
|
|
13
|
-
def
|
14
|
-
path = AssetsBooster::
|
9
|
+
def asset_path(name)
|
10
|
+
path = AssetsBooster::Packager.asset_path("stylesheets")
|
15
11
|
path = File.join(path, name+".css") if name
|
16
12
|
end
|
17
13
|
|
@@ -1,33 +1,124 @@
|
|
1
|
+
require 'yaml'
|
1
2
|
module AssetsBooster
|
2
3
|
class Packager
|
3
|
-
|
4
|
+
attr_accessor :config
|
5
|
+
attr_accessor :configuration_filename
|
6
|
+
attr_accessor :packages
|
4
7
|
|
5
|
-
def self.
|
6
|
-
|
7
|
-
Configuration.load
|
8
|
+
def self.asset_path(file)
|
9
|
+
File.join(Rails.root, "public", file)
|
8
10
|
end
|
9
11
|
|
10
|
-
def
|
11
|
-
|
12
|
+
def initialize(config_filename = nil)
|
13
|
+
self.configuration_filename = config_filename || File.join(Rails.root, "config", "assets_booster.yml")
|
14
|
+
end
|
15
|
+
|
16
|
+
def config
|
17
|
+
@config ||= YAML.load_file(configuration_filename)
|
18
|
+
end
|
19
|
+
|
20
|
+
def packages
|
21
|
+
@packages ||= begin
|
22
|
+
packages = {}
|
23
|
+
config['packages'].each_pair do |type, type_packages|
|
24
|
+
type = type.to_sym
|
25
|
+
packages[type] = {}
|
26
|
+
type_packages.each_pair do |name, assets|
|
27
|
+
package = get_package_class(type).new(name, assets)
|
28
|
+
package.compiler_class = get_compiler_class_for_type(type)
|
29
|
+
packages[type][name] = package
|
30
|
+
end
|
31
|
+
end
|
32
|
+
packages
|
33
|
+
end
|
12
34
|
end
|
13
35
|
|
14
|
-
def
|
15
|
-
|
36
|
+
def boosted_environment?
|
37
|
+
@boosted_environment ||= config['options']['environments'].include?(Rails.env)
|
38
|
+
end
|
39
|
+
|
40
|
+
def merge_all
|
41
|
+
each_package{ |package| package.merge }
|
42
|
+
end
|
43
|
+
|
44
|
+
def compile_all
|
45
|
+
each_package{ |package| package.compile }
|
16
46
|
end
|
17
47
|
|
18
|
-
def
|
19
|
-
each_package
|
48
|
+
def delete_all
|
49
|
+
each_package{ |package| package.delete }
|
20
50
|
end
|
51
|
+
|
52
|
+
def create_configuration
|
53
|
+
if File.exists?(configuration_filename)
|
54
|
+
AssetsBooster.log("#{configuration_filename} already exists. Aborting task...")
|
55
|
+
return
|
56
|
+
end
|
21
57
|
|
58
|
+
config = {
|
59
|
+
'packages' => {
|
60
|
+
'javascript' => {
|
61
|
+
'base' => file_list("#{Rails.root}/public/javascripts", "js"),
|
62
|
+
},
|
63
|
+
'stylesheet' => {
|
64
|
+
'base' => file_list("#{Rails.root}/public/stylesheets", "css"),
|
65
|
+
},
|
66
|
+
},
|
67
|
+
'options' => {
|
68
|
+
'javascript' => {
|
69
|
+
'compiler' => "closure",
|
70
|
+
},
|
71
|
+
'stylesheet' => {
|
72
|
+
'compiler' => "rainpress",
|
73
|
+
},
|
74
|
+
'environments' => %w(staging production),
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
File.open(configuration_filename, "w") do |file|
|
79
|
+
YAML.dump(config, file)
|
80
|
+
end
|
81
|
+
|
82
|
+
AssetsBooster.log("Configuration file #{configuration_filename} created!")
|
83
|
+
AssetsBooster.log("Please check the generates packages so dependencies are loaded in correct order.")
|
84
|
+
end
|
85
|
+
|
22
86
|
private
|
87
|
+
|
88
|
+
def file_list(path, extension)
|
89
|
+
Dir[File.join(path, "*.#{extension}")].map do |file|
|
90
|
+
file[path.length+1..-1].chomp(".#{extension}")
|
91
|
+
end
|
92
|
+
end
|
23
93
|
|
24
|
-
def
|
94
|
+
def each_package(&block)
|
25
95
|
packages.each_value do |packages|
|
26
96
|
packages.each_value do |package|
|
27
97
|
block.call(package)
|
28
98
|
end
|
29
99
|
end
|
30
100
|
end
|
101
|
+
|
102
|
+
def get_package_class(type)
|
103
|
+
require "assets_booster/package/base"
|
104
|
+
require "assets_booster/package/#{type}"
|
105
|
+
klass = "AssetsBooster::Package::#{type.to_s.camelize}"
|
106
|
+
klass.constantize
|
107
|
+
rescue LoadError => e
|
108
|
+
raise "You've specified an invalid package type '#{type}'"
|
109
|
+
end
|
110
|
+
|
111
|
+
def get_compiler_class(name)
|
112
|
+
require "assets_booster/compiler/#{name}"
|
113
|
+
klass = "AssetsBooster::Compiler::#{name.to_s.camelize}"
|
114
|
+
klass.constantize
|
115
|
+
rescue LoadError => e
|
116
|
+
raise "You've specified an invalid compiler '#{name}'"
|
117
|
+
end
|
118
|
+
|
119
|
+
def get_compiler_class_for_type(type)
|
120
|
+
get_compiler_class(config['options'][type.to_s]['compiler'])
|
121
|
+
end
|
31
122
|
end
|
32
123
|
end
|
33
124
|
|
@@ -1,12 +1,14 @@
|
|
1
1
|
require 'rails'
|
2
|
+
require "assets_booster/packager"
|
3
|
+
require 'assets_booster/view_helper'
|
2
4
|
|
3
5
|
module AssetsBooster
|
4
6
|
class Railtie < Rails::Railtie
|
7
|
+
cattr_accessor :packager
|
8
|
+
|
5
9
|
config.after_initialize do
|
6
|
-
|
7
|
-
AssetsBooster::Packager.init
|
10
|
+
self.packager = AssetsBooster::Packager.new
|
8
11
|
ActiveSupport.on_load :action_view do
|
9
|
-
require 'assets_booster/view_helper'
|
10
12
|
ActionView::Base.send(:include, AssetsBooster::ViewHelper)
|
11
13
|
end
|
12
14
|
end
|