Class: Juicer::CssCacheBuster

Inherits:
Object
  • Object
show all
Includes:
Chainable
Defined in:
lib/juicer/css_cache_buster.rb

Overview

The CssCacheBuster is a tool that can parse a CSS file and substitute all referenced URLs by a URL appended with a timestamp denoting it’s last change. This causes the URLs to be unique every time they’ve been modified, thus facilitating using a far future expires header on your web server.

See Juicer::CacheBuster for more information on how the cache buster URLs work.

When dealing with CSS files that reference absolute URLs like /images/1.png you must specify the :web_root option that these URLs should be resolved against.

When dealing with full URLs (ie including hosts) you can optionally specify an array of hosts to recognize as “local”, meaning they serve assets from the :web_root directory. This way even asset host cycling can benefit from cache busters.

Instance Method Summary collapse

Methods included from Chainable

included, #next_in_chain, #next_in_chain=

Constructor Details

#initialize(options = {}) ⇒ CssCacheBuster

Returns a new instance of CssCacheBuster.



26
27
28
29
30
31
32
# File 'lib/juicer/css_cache_buster.rb', line 26

def initialize(options = {})
  @web_root = options[:web_root]
  @web_root.sub!(%r{/?$}, "") if @web_root # Remove trailing slash
  @type = options[:type] || :soft
  @hosts = (options[:hosts] || []).collect { |h| h.sub!(%r{/?$}, "") } # Remove trailing slashes
  @contents = nil
end

Instance Method Details

#resolve(target, from) ⇒ Object

Resolve full path from URL



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/juicer/css_cache_buster.rb', line 70

def resolve(target, from)
  # If URL is external, check known hosts to see if URL can be treated
  # like a local one (ie so we can add cache buster)
  catch(:continue) do
    if target =~ %r{^[a-z]+\://}
      # This could've been a one-liner, but I prefer to be
      # able to read my own code ;)
      @hosts.each do |host|
        if target =~ /^#{host}/
          target.sub!(/^#{host}/, "")
          throw :continue
        end
      end

      # No known hosts matched, return
      return target
    end
  end

  # Simply add web root to absolute URLs
  if target =~ %r{^/}
    raise FileNotFoundError.new("Unable to resolve absolute path #{target} without :web_root option") unless @web_root
    return File.expand_path(File.join(@web_root, target))
  end

  # Resolve relative URLs to full paths
  File.expand_path(File.join(File.dirname(File.expand_path(from)), target))
end

#save(file, output = nil) ⇒ Object

Update file. If no output is provided, the input file is overwritten



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/juicer/css_cache_buster.rb', line 37

def save(file, output = nil)
  @contents = File.read(file)

  urls(file).each do |url|
    path = resolve(url, file)

    if path != url
      basename = File.basename(Juicer::CacheBuster.path(path))
      @contents.sub!(url, File.join(File.dirname(url), basename))
    end
  end

  File.open(output || file, "w") { |f| f.puts @contents }
  @contents = nil
end

#urls(file) ⇒ Object

Returns all referenced URLs in file. Returned paths are absolute (ie, they’re resolved relative to the file path.



59
60
61
62
63
64
65
# File 'lib/juicer/css_cache_buster.rb', line 59

def urls(file)
  @contents = File.read(file) unless @contents

  @contents.scan(/url\(([^\)]*)\)/m).collect do |match|
    match.first
  end
end