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.
Files changed (36) hide show
  1. data/.rspec +2 -0
  2. data/Rakefile +4 -0
  3. data/asset_booster.gemspec +6 -1
  4. data/lib/assets_booster/compiler/closure.rb +8 -6
  5. data/lib/assets_booster/compiler/dummy.rb +2 -5
  6. data/lib/assets_booster/compiler/jsmin.rb +138 -148
  7. data/lib/assets_booster/compiler/rainpress.rb +3 -3
  8. data/lib/assets_booster/compiler/uglify.rb +6 -4
  9. data/lib/assets_booster/merger/base.rb +26 -0
  10. data/lib/assets_booster/merger/css.rb +38 -43
  11. data/lib/assets_booster/merger/simple.rb +7 -11
  12. data/lib/assets_booster/package/base.rb +24 -14
  13. data/lib/assets_booster/package/javascript.rb +3 -7
  14. data/lib/assets_booster/package/stylesheet.rb +3 -7
  15. data/lib/assets_booster/packager.rb +102 -11
  16. data/lib/assets_booster/railtie.rb +5 -3
  17. data/lib/assets_booster/tasks/tasks.rake +9 -11
  18. data/lib/assets_booster/version.rb +1 -1
  19. data/lib/assets_booster/view_helper.rb +3 -6
  20. data/spec/compiler/base.rb +15 -0
  21. data/spec/compiler/closure_spec.rb +16 -0
  22. data/spec/compiler/dummy_spec.rb +16 -0
  23. data/spec/compiler/jsmin_spec.rb +16 -0
  24. data/spec/compiler/rainpress_spec.rb +16 -0
  25. data/spec/compiler/uglify_spec.rb +16 -0
  26. data/spec/merger/base.rb +31 -0
  27. data/spec/merger/css_spec.rb +138 -0
  28. data/spec/merger/simple_spec.rb +18 -0
  29. data/spec/package/base.rb +26 -0
  30. data/spec/package/javascript_spec.rb +16 -0
  31. data/spec/package/stylesheet_spec.rb +16 -0
  32. data/spec/packager_spec.rb +87 -0
  33. data/spec/spec_helper.rb +9 -0
  34. data/spec/view_helper_spec.rb +12 -0
  35. metadata +69 -7
  36. 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
- cattr_accessor :assets
5
-
6
- def self.name
4
+ class CSS < Base
5
+ def name
7
6
  "CSS Merger"
8
7
  end
9
-
10
- def self.merge(sources, target)
11
- self.assets = []
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 = File.dirname(asset[:source])
19
- rewrite_urls!(asset[:css], source_folder, target_folder)
20
- code << asset[:css]+"\n"
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 self.mtime(sources)
25
- self.assets = []
26
- sources.each do |source|
27
- load_source(source)
28
- end
29
- assets.map{ |asset| File.mtime(asset[:source]) }.max
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+"/"+url)
32
+ load_source(source_folder+url)
46
33
  ""
47
34
  end
48
- self.assets << {
49
- :source => source,
50
- :css => css
51
- }
35
+ assets << asset
52
36
  end
53
-
54
- def self.rewrite_urls!(css, source_folder, target_folder)
55
- # difference between the source and target location
56
- url_prepend = source_folder[target_folder.length+1..-1]
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!(/url\(([^)]+)\)/i) do |match|
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 self.extract_url(quoted_url)
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 self.absolute_url?(url)
74
- url[0].chr =~ /^(\/|https?:\/\/)/i
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 self.name
4
+ class Simple < Base
5
+ def name
5
6
  "Simple Merger"
6
7
  end
7
8
 
8
- def self.merge(sources, target)
9
- sources.inject("") do |code, source|
10
- File.open(source, "r") do |file|
11
- code << file.read.strip+"\n"
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 :mtime
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 = self.class.asset_path(self.name)
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 ||= self.class.merger.mtime(sources)
30
+ @mtime ||= merger.mtime
21
31
  end
22
32
 
23
33
  def sources
24
- assets.each.map{ |asset| self.class.asset_path(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 #{self.class.merger.name} to #{relative_filename}...")
33
- save(self.class.merger.merge(sources, filename))
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
- merged = merge
38
- AssetsBooster.log("Compiling #{relative_filename} using #{self.class.compiler.name}...")
39
- code = self.class.compiler.compile(merged)
40
- AssetsBooster.log("Compilation finished: %5.2f%% saved." % [(1-code.size.to_f/merged.size)*100])
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 = AssetsBooster::Configuration.boosted_environment? ? [name] : assets
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 self.compiler
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 self.asset_path(name)
14
- path = AssetsBooster::Configuration.asset_path("javascripts")
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 self.compiler
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 self.asset_path(name)
14
- path = AssetsBooster::Configuration.asset_path("stylesheets")
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
- cattr_accessor :packages
4
+ attr_accessor :config
5
+ attr_accessor :configuration_filename
6
+ attr_accessor :packages
4
7
 
5
- def self.init
6
- require "assets_booster/configuration"
7
- Configuration.load
8
+ def self.asset_path(file)
9
+ File.join(Rails.root, "public", file)
8
10
  end
9
11
 
10
- def self.merge_all
11
- each_package { |package| package.merge }
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 self.compile_all
15
- each_package { |package| package.compile }
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 self.delete_all
19
- each_package { |package| package.delete }
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 self.each_package(&block)
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
- require "assets_booster/packager"
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