assets_booster 0.0.1 → 0.0.2
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/.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
|