plexus/asset_packer

View on GitHub
lib/asset_packer/processor/local.rb

Summary

Maintainability
A
45 mins
Test Coverage
module AssetPacker
  class Processor
    class Local < self

      def call(doc)
        Chain.new([Image, Script, Stylesheet].map {|klz|
          klz.new(source_uri, asset_dir, destination)
        }).(doc)
      end

      def save_asset(uri, extension)
        return uri if uri =~ /^data:/
        asset_dir.mkdir unless asset_dir.directory?
        content = retrieve_asset(uri)
        content = yield(content) if block_given?
        digest  = Digest::MD5.hexdigest(content)
        target  = asset_dir.join(extension ? digest + '.' + extension : digest)
        File.write(target, content) unless target.exist?
        target.relative_path_from(destination.dirname)
      end

      class Image < self
        def call(doc)
          doc.replace('img') do |img|
            uri = img[:src]
            extension = File.extname(uri).sub(/^\./, '')
            img.attr(:src, save_asset(uri, extension))
          end
        end
      end

      class Script < self
        def call(doc)
          doc.replace('script[src]') do |script|
            script.attr(:src, save_asset(script[:src], 'js'))
          end
        end
      end

      class Stylesheet < self
        def call(doc)
          doc.replace('link[rel=stylesheet]') do |link|
            link.attr(:href, save_asset(link[:href], 'css', &extract_references(link[:href])))
          end
        end

        def extract_references(base_url)
          ->(content) do
            content = extract_imports(base_url)[content]
            extract_css_links(base_url)[content]
          end
        end

        def extract_imports(base_url)
          ->(content) do
            content.gsub(/@import\s+['"]([^'"]+)['"]\s*(\w*);/) {
              path, type = $1, $2
              uri = URI.join(full_source_uri, base_url, path)
              block = extract_references(uri)
              "@import '../#{ save_asset(uri, 'css', &block) }' #{type};"
            }
          end
        end

        def extract_css_links(base_url)
          ->(content) do
            content.gsub(/url\(['"]?([^\)'"]*)['"]?\)/) {
              uri = URI.join(full_source_uri, base_url, $1)
              ext = File.extname($1)[1..-1]
              # TODO check for media type, not URL
              # using regex instead of checking ext because
              # google font files don't work otherwise
              block = extract_references(uri) if uri.to_s =~ /css/
              "url(../#{ save_asset(uri, ext, &block) })"
            }
          end
        end
      end
    end
  end
end