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.
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