rstacruz/sinatra-assetpack

View on GitHub
lib/sinatra/assetpack/package.rb

Summary

Maintainability
A
1 hr
Test Coverage
module Sinatra
  module AssetPack
    # A package.
    #
    # == Common usage
    #
    #     package = assets.packages['application.css']
    #
    #     package.files   # List of local files
    #     package.paths   # List of URI paths
    #
    #     package.type    # :css or :js
    #     package.css?
    #     package.js?
    #
    #     package.path    # '/css/application.css' => where to serve the compressed file
    #
    #     package.to_development_html
    #     package.to_production_html
    #
    class Package
      include HtmlHelpers
      include BusterHelpers

      def initialize(assets, name, type, path, filespecs)
        @assets      = assets     # Options instance
        @name        = name       # "application"
        @type        = type       # :js or :css
        @path        = path       # '/js/app.js' -- where to served the compressed file
        @filespecs   = filespecs  # [ '/js/*.js' ]
      end

      attr_reader :type
      attr_reader :path
      attr_reader :filespecs
      attr_reader :name

      # Returns a list of URIs
      def paths_and_files
        list = @assets.glob(@filespecs)
        list.reject! { |path, file| @assets.ignored?(path) }
        list
      end

      def files
        paths_and_files.values.compact
      end

      def paths
        paths_and_files.keys
      end

      def mtime
        BusterHelpers.mtime_for(files)
      end

      # Returns the regex for the route, including cache buster.
      def route_regex
        re = @path.gsub(/(.[^.]+)$/) { |ext| "(?:\.[a-f0-9]{32})?#{ext}" }
        /^#{re}$/
      end

      def to_development_html(path_prefix, options={})
        paths_and_files.map { |path, file|
          path = add_cache_buster(path, file)
          path = add_path_prefix(path, path_prefix)
          link_tag(path, options)
        }.join("\n")
      end

      # The URI path of the minified file (with cache buster, but not a path prefix)
      def production_path
        add_cache_buster @path, *files
      end

      def to_production_html(path_prefix, options={})
        path = production_path
        path = add_path_prefix(path, path_prefix)
        link_tag path, options
      end

      def add_path_prefix(path, path_prefix)
        if path_prefix == '/'
          path
        else
          "#{path_prefix}#{path}"
        end
      end

      def minify
        engine  = @assets.send(:"#{@type}_compression")
        options = @assets.send(:"#{@type}_compression_options")

        Compressor.compress combined, @type, engine, options
      end

      # The cache hash.
      def hash
        if @assets.app.development?
          "#{name}.#{type}/#{mtime}"
        else
          "#{name}.#{type}"
        end
      end

      def combined
        session = Rack::Test::Session.new(@assets.app)
        paths.map { |path|
          result = session.get(path)
          if result.body.respond_to?(:force_encoding)
            response_encoding = result.content_type.split(/\;\s*charset\s*=\s*/).last.upcase rescue 'ASCII-8BIT'
            result.body.force_encoding(response_encoding).encode(Encoding.default_external || 'ASCII-8BIT')  if result.status == 200
          else
            result.body  if result.status == 200
          end
        }.join("\n")
      end

      def js?()  @type == :js; end
      def css?() @type == :css; end

    private
      def link_tag(file, options={})
        file_path = HtmlHelpers.get_file_uri(file, @assets)

        if js?
          "<script src='#{e(file_path)}'#{kv(options)}></script>"
        elsif css?
          "<link rel='stylesheet' href='#{e(file_path)}'#{kv(options)} />"
        end
      end
    end
  end
end