juicer 0.2.6 → 1.0.0

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 (122) hide show
  1. data/History.txt +28 -0
  2. data/Rakefile +84 -36
  3. data/Readme.rdoc +192 -23
  4. data/VERSION +1 -0
  5. data/bin/juicer +2 -4
  6. data/lib/juicer.rb +9 -10
  7. data/lib/juicer/asset/path.rb +275 -0
  8. data/lib/juicer/asset/path_resolver.rb +79 -0
  9. data/lib/juicer/binary.rb +3 -5
  10. data/lib/juicer/cache_buster.rb +112 -27
  11. data/lib/juicer/command/install.rb +4 -2
  12. data/lib/juicer/command/list.rb +16 -9
  13. data/lib/juicer/command/merge.rb +30 -14
  14. data/lib/juicer/command/verify.rb +1 -1
  15. data/lib/juicer/css_cache_buster.rb +31 -47
  16. data/lib/juicer/datafy/datafy.rb +20 -0
  17. data/lib/juicer/dependency_resolver/css_dependency_resolver.rb +29 -0
  18. data/lib/juicer/dependency_resolver/dependency_resolver.rb +101 -0
  19. data/lib/juicer/dependency_resolver/javascript_dependency_resolver.rb +23 -0
  20. data/lib/juicer/ext/logger.rb +5 -0
  21. data/lib/juicer/ext/string.rb +47 -0
  22. data/lib/juicer/ext/symbol.rb +15 -0
  23. data/lib/juicer/image_embed.rb +129 -0
  24. data/lib/juicer/install/base.rb +2 -2
  25. data/lib/juicer/install/closure_compiler_installer.rb +69 -0
  26. data/lib/juicer/install/jslint_installer.rb +3 -3
  27. data/lib/juicer/install/rhino_installer.rb +3 -2
  28. data/lib/juicer/install/yui_compressor_installer.rb +3 -2
  29. data/lib/juicer/jslint.rb +1 -1
  30. data/lib/juicer/merger/base.rb +1 -1
  31. data/lib/juicer/merger/javascript_merger.rb +3 -4
  32. data/lib/juicer/merger/stylesheet_merger.rb +13 -15
  33. data/lib/juicer/minifyer/closure_compiler.rb +90 -0
  34. data/lib/juicer/minifyer/java_base.rb +77 -0
  35. data/lib/juicer/minifyer/yui_compressor.rb +15 -48
  36. data/test/bin/jslint-1.0.js +523 -0
  37. data/test/bin/jslint.js +523 -0
  38. data/test/bin/rhino1_7R1.zip +0 -0
  39. data/test/bin/rhino1_7R2-RC1.jar +0 -0
  40. data/test/bin/rhino1_7R2-RC1.zip +0 -0
  41. data/test/bin/yuicompressor +0 -0
  42. data/test/bin/yuicompressor-2.3.5.zip +0 -0
  43. data/test/bin/yuicompressor-2.4.2.jar +0 -0
  44. data/test/bin/yuicompressor-2.4.2.zip +0 -0
  45. data/test/data/Changelog.txt +10 -0
  46. data/test/data/a.css +3 -0
  47. data/test/data/a.js +5 -0
  48. data/test/data/a1.css +5 -0
  49. data/test/data/b.css +1 -0
  50. data/test/data/b.js +5 -0
  51. data/test/data/b1.css +5 -0
  52. data/test/data/c1.css +3 -0
  53. data/test/data/css/2.gif +1 -0
  54. data/test/data/css/test.css +11 -0
  55. data/test/data/css/test2.css +1 -0
  56. data/test/data/d1.css +3 -0
  57. data/test/data/images/1.png +1 -0
  58. data/test/data/my_app.js +2 -0
  59. data/test/data/not-ok.js +2 -0
  60. data/test/data/ok.js +3 -0
  61. data/test/data/path_test.css +5 -0
  62. data/test/data/path_test2.css +14 -0
  63. data/test/data/pkg/module/moda.js +2 -0
  64. data/test/data/pkg/module/modb.js +3 -0
  65. data/test/data/pkg/pkg.js +1 -0
  66. data/test/fixtures/yui-download.html +425 -0
  67. data/test/test_helper.rb +36 -7
  68. data/test/unit/juicer/asset/path_resolver_test.rb +76 -0
  69. data/test/unit/juicer/asset/path_test.rb +370 -0
  70. data/test/unit/juicer/cache_buster_test.rb +104 -0
  71. data/test/{juicer/test_chainable.rb → unit/juicer/chainable_test.rb} +1 -1
  72. data/test/unit/juicer/command/install_test.rb +58 -0
  73. data/test/{juicer/command/test_list.rb → unit/juicer/command/list_test.rb} +26 -14
  74. data/test/unit/juicer/command/merge_test.rb +162 -0
  75. data/test/{juicer/command/test_util.rb → unit/juicer/command/util_test.rb} +10 -6
  76. data/test/unit/juicer/command/verify_test.rb +48 -0
  77. data/test/{juicer/test_css_cache_buster.rb → unit/juicer/css_cache_buster_test.rb} +10 -30
  78. data/test/unit/juicer/datafy_test.rb +37 -0
  79. data/test/{juicer/merger/test_css_dependency_resolver.rb → unit/juicer/dependency_resolver/css_dependency_resolver_test.rb} +2 -2
  80. data/test/{juicer/merger/test_javascript_dependency_resolver.rb → unit/juicer/dependency_resolver/javascript_dependency_resolver_test.rb} +13 -2
  81. data/test/unit/juicer/ext/{#string_test.rb# → string_test.rb} +0 -7
  82. data/test/unit/juicer/ext/symbol_test.rb +27 -0
  83. data/test/unit/juicer/image_embed_test.rb +271 -0
  84. data/test/unit/juicer/install/installer_base_test.rb +214 -0
  85. data/test/{juicer/install/test_jslint_installer.rb → unit/juicer/install/jslint_installer_test.rb} +1 -1
  86. data/test/{juicer/install/test_rhino_installer.rb → unit/juicer/install/rhino_installer_test.rb} +1 -1
  87. data/test/{juicer/install/test_yui_compressor_installer.rb → unit/juicer/install/yui_compressor_test.rb} +16 -16
  88. data/test/unit/juicer/jslint_test.rb +60 -0
  89. data/test/{juicer/merger/test_base.rb → unit/juicer/merger/base_test.rb} +1 -1
  90. data/test/{juicer/merger/test_javascript_merger.rb → unit/juicer/merger/javascript_merger_test.rb} +2 -2
  91. data/test/{juicer/merger/test_stylesheet_merger.rb → unit/juicer/merger/stylesheet_merger_test.rb} +15 -13
  92. data/test/unit/juicer/minifyer/closure_compressor_test.rb +107 -0
  93. data/test/{integration → unit}/juicer/minifyer/yui_compressor_test.rb +30 -47
  94. data/test/unit/juicer_test.rb +1 -0
  95. metadata +207 -113
  96. data/lib/juicer/core.rb +0 -61
  97. data/lib/juicer/merger/css_dependency_resolver.rb +0 -25
  98. data/lib/juicer/merger/dependency_resolver.rb +0 -82
  99. data/lib/juicer/merger/javascript_dependency_resolver.rb +0 -21
  100. data/tasks/ann.rake +0 -80
  101. data/tasks/bones.rake +0 -20
  102. data/tasks/gem.rake +0 -201
  103. data/tasks/git.rake +0 -40
  104. data/tasks/notes.rake +0 -27
  105. data/tasks/post_load.rake +0 -34
  106. data/tasks/rdoc.rake +0 -51
  107. data/tasks/rubyforge.rake +0 -55
  108. data/tasks/setup.rb +0 -292
  109. data/tasks/spec.rake +0 -54
  110. data/tasks/svn.rake +0 -47
  111. data/tasks/test.rake +0 -40
  112. data/tasks/test/setup.rake +0 -35
  113. data/tasks/zentest.rake +0 -36
  114. data/test/juicer/command/test_install.rb +0 -53
  115. data/test/juicer/command/test_merge.rb +0 -160
  116. data/test/juicer/command/test_verify.rb +0 -33
  117. data/test/juicer/install/test_installer_base.rb +0 -195
  118. data/test/juicer/minifyer/test_yui_compressor.rb +0 -159
  119. data/test/juicer/test_cache_buster.rb +0 -58
  120. data/test/juicer/test_core.rb +0 -47
  121. data/test/juicer/test_jslint.rb +0 -33
  122. data/test/test_juicer.rb +0 -4
@@ -0,0 +1,23 @@
1
+ require "juicer/dependency_resolver/dependency_resolver"
2
+
3
+ module Juicer
4
+ # Resolves @depends and @depend statements in comments in JavaScript files.
5
+ # Only the first comment in a JavaScript file is parsed
6
+ #
7
+ class JavaScriptDependencyResolver < DependencyResolver
8
+ @@depends_pattern = /\@depends?\s+([^\s\'\"\;]+)/
9
+
10
+ private
11
+ def parse(line, imported_file = nil)
12
+ return $1 if line =~ @@depends_pattern
13
+
14
+ # If we have already skimmed through some @depend/@depends or a
15
+ # closing comment we're done.
16
+ throw :done unless imported_file.nil? || !(line =~ /\*\//)
17
+ end
18
+
19
+ def extension
20
+ ".js"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ class Logger
2
+ def format_message(severity, datetime, progname, msg)
3
+ "#{msg}\n"
4
+ end
5
+ end
@@ -0,0 +1,47 @@
1
+ #
2
+ # Additions to core Ruby objects
3
+ #
4
+
5
+ class String
6
+
7
+ unless String.method_defined?(:camel_case)
8
+ #
9
+ # Turn an underscored string into camel case, ie this_becomes -> ThisBecomes
10
+ #
11
+ def camel_case
12
+ self.split("_").inject("") { |str, piece| str + piece.capitalize }
13
+ end
14
+ end
15
+
16
+ unless String.method_defined?(:to_class)
17
+ #
18
+ # Treat a string as a class name and return the class. Optionally provide a
19
+ # module to look up the class in.
20
+ #
21
+ def to_class(mod = nil)
22
+ res = "#{mod}::#{self}".sub(/^::/, "").split("::").inject(Object) do |mod, obj|
23
+ raise "No such class/module" unless mod.const_defined?(obj)
24
+ mod = mod.const_get(obj)
25
+ end
26
+ end
27
+ end
28
+
29
+ unless String.method_defined?(:classify)
30
+ #
31
+ # Turn a string in either underscore or camel case form into a class directly
32
+ #
33
+ def classify(mod = nil)
34
+ self.camel_case.to_class(mod)
35
+ end
36
+ end
37
+
38
+ unless String.method_defined?(:underscore)
39
+ #
40
+ # Turn a camelcase string into underscore string
41
+ #
42
+ def underscore
43
+ self.split(/([A-Z][^A-Z]*)/).find_all { |str| str != "" }.join("_").downcase
44
+ end
45
+ end
46
+ end
47
+
@@ -0,0 +1,15 @@
1
+ class Symbol
2
+ #
3
+ # Converts symbol to string and calls String#camel_case
4
+ #
5
+ def camel_case
6
+ self.to_s.camel_case
7
+ end
8
+
9
+ #
10
+ # Converts symbol to string and calls String#classify
11
+ #
12
+ def classify(mod = nil)
13
+ self.to_s.classify(mod)
14
+ end
15
+ end
@@ -0,0 +1,129 @@
1
+ require "juicer/chainable"
2
+ require "juicer/cache_buster"
3
+ require "juicer/asset/path_resolver"
4
+
5
+ module Juicer
6
+ #
7
+ # The ImageEmbed is a tool that can parse a CSS file and substitute all
8
+ # referenced URLs by a data uri
9
+ #
10
+ # - data uri (http://en.wikipedia.org/wiki/Data_URI_scheme)
11
+ #
12
+ # Only local resources will be processed this way, external resources referenced
13
+ # by absolute urls will be left alone
14
+ #
15
+ class ImageEmbed
16
+ include Juicer::Chainable
17
+
18
+ # The maximum supported limit for modern browsers, See the Readme.rdoc for details
19
+ SIZE_LIMIT = 32768
20
+
21
+ #
22
+ # Returns the size limit
23
+ #
24
+ def size_limit
25
+ SIZE_LIMIT
26
+ end
27
+
28
+ def initialize(options = {})
29
+ @document_root = options[:document_root]
30
+ @document_root.sub!(%r{/?$}, "") if @document_root # Remove trailing slash
31
+ @type = options[:type] || :none
32
+ @contents = nil
33
+ @hosts = options[:hosts]
34
+ @path_resolver = Juicer::Asset::PathResolver.new(:document_root => options[:document_root],
35
+ :hosts => options[:hosts])
36
+ end
37
+
38
+ #
39
+ # Update file. If no +output+ is provided, the input file is overwritten
40
+ #
41
+ def save(file, output = nil)
42
+ return unless @type == :data_uri
43
+
44
+ output_file = output || file
45
+ @contents = File.read(file)
46
+ used = []
47
+
48
+ @path_resolver = Juicer::Asset::PathResolver.new(:document_root => @document_root,
49
+ :hosts => @hosts,
50
+ :base => File.dirname(file))
51
+
52
+ assets = urls(file)
53
+
54
+ # TODO: Remove "?embed=true" from duplicate urls
55
+ duplicates = duplicate_urls(assets)
56
+
57
+ if duplicates.length > 0
58
+ Juicer::LOGGER.warn("Duplicate image urls detected, these images will not be embedded: #{duplicates.collect { |v| v.gsub('?embed=true', '') }.inspect}")
59
+ end
60
+
61
+ assets.each do |asset|
62
+ begin
63
+ next if used.include?(asset) || duplicates.include?(asset.path)
64
+ used << asset
65
+
66
+ # make sure we do not exceed SIZE_LIMIT
67
+ new_path = embed_data_uri(asset.filename)
68
+
69
+ if new_path.length < SIZE_LIMIT
70
+ # replace the url in the css file with the data uri
71
+ @contents.gsub!(asset.path, embed_data_uri(asset.path))
72
+ else
73
+ Juicer::LOGGER.warn("The final data uri for the image located at #{asset.path.gsub('?embed=true', '')} exceeds #{SIZE_LIMIT} and will not be embedded to maintain compatability.")
74
+ end
75
+ rescue Errno::ENOENT
76
+ puts "Unable to locate file #{asset.path}, skipping image embedding"
77
+ end
78
+ end
79
+
80
+ File.open(output || file, "w") { |f| f.puts @contents }
81
+ @contents = nil
82
+ end
83
+
84
+ chain_method :save
85
+
86
+ def embed_data_uri( path )
87
+ new_path = path
88
+
89
+ if path.match( /\?embed=true$/ )
90
+ supported_file_matches = path.match( /(?:\.)(png|gif|jpg|jpeg)(?:\?embed=true)$/i )
91
+ filetype = supported_file_matches[1] if supported_file_matches
92
+
93
+ if ( filetype )
94
+ filename = path.gsub('?embed=true','')
95
+
96
+ # check if file exists, throw an error if it doesn't exist
97
+ if File.exist?( filename )
98
+
99
+ # read contents of file into memory
100
+ content = File.read( filename )
101
+ content_type = "image/#{filetype}"
102
+
103
+ # encode the url
104
+ new_path = Datafy::make_data_uri( content, content_type )
105
+ else
106
+ puts "Unable to locate file #{filename} on local file system, skipping image embedding"
107
+ end
108
+ end
109
+ end
110
+ return new_path
111
+ end
112
+
113
+ #
114
+ # Returns all referenced URLs in +file+.
115
+ #
116
+ def urls(file)
117
+ @contents = File.read(file) unless @contents
118
+
119
+ @contents.scan(/url\([\s"']*([^\)"'\s]*)[\s"']*\)/m).collect do |match|
120
+ @path_resolver.resolve(match.first)
121
+ end
122
+ end
123
+
124
+ private
125
+ def duplicate_urls(urls)
126
+ urls.inject({}) { |h,v| h[v.path] = h[v.path].to_i+1; h }.reject{ |k,v| v == 1 }.keys
127
+ end
128
+ end
129
+ end
@@ -1,7 +1,7 @@
1
- require 'hpricot'
1
+ require 'nokogiri'
2
2
  require 'open-uri'
3
3
  require 'fileutils'
4
- require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. juicer])) unless defined?(Juicer)
4
+ require "juicer"
5
5
 
6
6
  module Juicer
7
7
  module Install
@@ -0,0 +1,69 @@
1
+ require "juicer"
2
+ require "juicer/install/base"
3
+ require "zip/zip"
4
+
5
+ module Juicer
6
+ module Install
7
+ #
8
+ # Install and uninstall routines for the Google Closure Compiler.
9
+ # Installation downloads the Closure Compiler distribution, unzips it and
10
+ # storesthe jar file on disk along with the README.
11
+ #
12
+ class ClosureCompilerInstaller < Base
13
+ def initialize(install_dir = Juicer.home)
14
+ super(install_dir)
15
+ @latest = nil
16
+ @website = "http://code.google.com/p/closure-compiler/downloads/list"
17
+ @download_link = "http://closure-compiler.googlecode.com/files/compiler-%s.zip"
18
+ end
19
+
20
+ #
21
+ # Install the Closure Compiler. Downloads the distribution and keeps the jar
22
+ # file inside PATH/closure_compiler/bin and the README in
23
+ # PATH/closere_compiler/yyyymmdd/ where yyyymmdd is the version, most recent if
24
+ # not specified otherwise.
25
+ #
26
+ # Path defaults to environment variable $JUICER_HOME or default Juicer
27
+ # home
28
+ #
29
+ def install(version = nil)
30
+ version = super(version)
31
+ base = "closure-compiler-#{version}"
32
+ filename = download(@download_link % version)
33
+ target = File.join(@install_dir, path)
34
+
35
+ Zip::ZipFile.open(filename) do |file|
36
+ file.extract("README", File.join(target, version, "README"))
37
+ file.extract("compiler.jar", File.join(target, "bin", "#{base}.jar"))
38
+ end
39
+ end
40
+
41
+ #
42
+ # Uninstalls the given version of Closure Compiler. If no location is
43
+ # provided the environment variable $JUICER_HOME or Juicers default home
44
+ # directory is used.
45
+ #
46
+ # If no version is provided the most recent version is assumed.
47
+ #
48
+ # If there are no more files left in INSTALLATION_PATH/closure_compiler, the
49
+ # whole directory is removed.
50
+ #
51
+ def uninstall(version = nil)
52
+ super(version) do |dir, version|
53
+ File.delete(File.join(dir, "bin/closure-compiler-#{version}.jar"))
54
+ end
55
+ end
56
+
57
+ #
58
+ # Check which version is the most recent
59
+ #
60
+ def latest
61
+ return @latest if @latest
62
+ webpage = Nokogiri::HTML(open(@website))
63
+ @latest = (webpage / "//table[@id='resultstable']//td/a[contains(@href, 'compiler')]").map{|link|
64
+ link.get_attribute('href')[/\d{8}/].to_i
65
+ }.sort.last.to_s
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,5 +1,5 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. juicer])) unless defined?(Juicer)
2
- require File.expand_path(File.join(File.dirname(__FILE__), "base"))
1
+ require "juicer"
2
+ require "juicer/install/base"
3
3
  require "zip/zip"
4
4
 
5
5
  module Juicer
@@ -28,7 +28,7 @@ module Juicer
28
28
  def install(version = nil)
29
29
  version = super(version)
30
30
  filename = download(File.join(@website, "rhino/jslint.js"))
31
- File.copy(filename, File.join(@install_dir, path, "bin", "jslint-#{version}.js"))
31
+ FileUtils.copy(filename, File.join(@install_dir, path, "bin", "jslint-#{version}.js"))
32
32
  end
33
33
 
34
34
  #
@@ -1,4 +1,5 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. juicer])) unless defined?(Juicer)
1
+ require "juicer"
2
+ require "juicer/install/base"
2
3
  require "zip/zip"
3
4
 
4
5
  module Juicer
@@ -12,7 +13,7 @@ module Juicer
12
13
  def initialize(install_dir = Juicer.home)
13
14
  super(install_dir)
14
15
  @latest = "1_7R2-RC1"
15
- @website = "ftp://ftp.mozilla.org/pub/mozilla.org/js/"
16
+ @website = "http://ftp.mozilla.org/pub/mozilla.org/js/"
16
17
  end
17
18
 
18
19
  #
@@ -1,4 +1,5 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. juicer])) unless defined?(Juicer)
1
+ require "juicer"
2
+ require "juicer/install/base"
2
3
  require "zip/zip"
3
4
 
4
5
  module Juicer
@@ -58,7 +59,7 @@ module Juicer
58
59
  #
59
60
  def latest
60
61
  return @latest if @latest
61
- webpage = Hpricot(open(@website))
62
+ webpage = Nokogiri::HTML(open(@website))
62
63
  @latest = (webpage / "//h2[@id='yuicompressor']/../../../..//a")[0].get_attribute("href").match(/(\d\.\d\.\d)/)[1]
63
64
  end
64
65
  end
data/lib/juicer/jslint.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "binary"))
1
+ require "juicer/binary"
2
2
 
3
3
  module Juicer
4
4
  #
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "..", "chainable"))
1
+ require "juicer/chainable"
2
2
 
3
3
  # Merge several files into one single output file
4
4
  module Juicer
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
- ['base', 'javascript_dependency_resolver'].each do |lib|
3
- require File.expand_path(File.join(File.dirname(__FILE__), lib))
4
- end
2
+ require "juicer/merger/base"
3
+ require "juicer/dependency_resolver/javascript_dependency_resolver"
5
4
 
6
5
  module Juicer
7
6
  module Merger
@@ -22,7 +21,7 @@ end
22
21
  # or similar.
23
22
  #
24
23
  if $0 == __FILE__
25
- return puts("Usage: javascript_merger.rb file[...] output") if $*.length < 2
24
+ puts("Usage: javascript_merger.rb file[...] output") and exit if $*.length < 2
26
25
 
27
26
  fm = JavaScriptMerger.new()
28
27
  fm << $*[0..-2]
@@ -1,8 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
- ['base', 'css_dependency_resolver'].each do |lib|
3
- require File.expand_path(File.join(File.dirname(__FILE__), lib))
4
- end
5
-
2
+ require "juicer/merger/base"
3
+ require "juicer/dependency_resolver/css_dependency_resolver"
6
4
  require 'pathname'
7
5
 
8
6
  module Juicer
@@ -15,7 +13,7 @@ module Juicer
15
13
  # Constructor
16
14
  #
17
15
  # Options:
18
- # * <tt>:web_root</tt> - Path to web root if there is any @import statements
16
+ # * <tt>:document_root</tt> - Path to web root if there is any @import statements
19
17
  # using absolute URLs
20
18
  #
21
19
  def initialize(files = [], options = {})
@@ -25,8 +23,8 @@ module Juicer
25
23
  @host_num = 0
26
24
  @use_absolute = options.key?(:absolute_urls) ? options[:absolute_urls] : false
27
25
  @use_relative = options.key?(:relative_urls) ? options[:relative_urls] : false
28
- @web_root = options[:web_root]
29
- @web_root = File.expand_path(@web_root).sub(/\/?$/, "") if @web_root # Make sure path doesn't end in a /
26
+ @document_root = options[:document_root]
27
+ @document_root = File.expand_path(@document_root).sub(/\/?$/, "") if @document_root # Make sure path doesn't end in a /
30
28
  end
31
29
 
32
30
  private
@@ -42,10 +40,10 @@ module Juicer
42
40
  # The options hash decides how Juicer recalculates referenced URLs:
43
41
  #
44
42
  # options[:absolute_urls] When true, all paths are converted to absolute
45
- # URLs. Requires options[:web_root] to define
43
+ # URLs. Requires options[:document_root] to define
46
44
  # root directory to resolve absolute URLs from.
47
45
  # options[:relative_urls] When true, all paths are converted to relative
48
- # paths. Requires options[:web_root] to define
46
+ # paths. Requires options[:document_root] to define
49
47
  # root directory to resolve absolute URLs from.
50
48
  #
51
49
  # If none if these are set then relative URLs are recalculated to match
@@ -55,7 +53,7 @@ module Juicer
55
53
  # for all absolute URLs regardless of absolute/relative URL strategy.
56
54
  #
57
55
  def merge(file)
58
- content = super.gsub(/^\s*\@import\s("|')(.*)("|')\;?/, '')
56
+ content = super.gsub(/^\s*@import(?:\surl\(|\s)(['"]?)([^\?'"\)\s]+)(\?(?:[^'"\)]+)?)?\1\)?(?:[^?;]+)?;?/i, "")
59
57
  dir = File.expand_path(File.dirname(file))
60
58
 
61
59
  content.scan(/url\([\s"']*([^\)"'\s]*)[\s"']*\)/m).uniq.collect do |url|
@@ -75,15 +73,15 @@ module Juicer
75
73
 
76
74
  # Absolute URLs
77
75
  if url =~ %r{^/} && @use_relative
78
- raise ArgumentError.new("Unable to handle absolute URLs without :web_root option") if !@web_root
79
- path = Pathname.new(File.join(@web_root, url)).relative_path_from(@root).to_s
76
+ raise ArgumentError.new("Unable to handle absolute URLs without :document_root option") if !@document_root
77
+ path = Pathname.new(File.join(@document_root, url)).relative_path_from(@root).to_s
80
78
  end
81
79
 
82
80
  # All URLs that don't start with a protocol
83
81
  if url !~ %r{^/} && url !~ %r{^[a-z]+://}
84
82
  if @use_absolute
85
- raise ArgumentError.new("Unable to handle absolute URLs without :web_root option") if !@web_root
86
- path = File.expand_path(File.join(dir, url)).sub(@web_root, "") # Make absolute
83
+ raise ArgumentError.new("Unable to handle absolute URLs without :document_root option") if !@document_root
84
+ path = File.expand_path(File.join(dir, url)).sub(@document_root, "") # Make absolute
87
85
  else
88
86
  path = Pathname.new(File.join(dir, url)).relative_path_from(@root).to_s # ...or redefine relative ref
89
87
  end
@@ -104,7 +102,7 @@ end
104
102
  # Run file from command line
105
103
  #
106
104
  if $0 == __FILE__
107
- return puts("Usage: stylesheet_merger.rb file[...] output") if $*.length < 2
105
+ puts("Usage: stylesheet_merger.rb file[...] output") and exit if $*.length < 2
108
106
 
109
107
  fm = Juicer::Merger::StylesheetMerger.new()
110
108
  fm << $*[0..-2]