File: gzip.rb

package info (click to toggle)
ruby-sprockets 4.2.1-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,964 kB
  • sloc: ruby: 13,014; javascript: 157; makefile: 4
file content (99 lines) | stat: -rw-r--r-- 3,300 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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
98
99
# frozen_string_literal: true
module Sprockets
  module Utils
    class Gzip
      # Private: Generates a gzipped file based off of reference asset.
      #
      #     ZlibArchiver.call(file, source, mtime)
      #
      # Compresses a given `source` using stdlib Zlib algorithm
      # writes contents to the `file` passed in. Sets `mtime` of
      # written file to passed in `mtime`
      module ZlibArchiver
        def self.call(file, source, mtime)
          gz = Zlib::GzipWriter.new(file, Zlib::BEST_COMPRESSION)
          gz.mtime = mtime
          gz.write(source)
          gz.close

          File.utime(mtime, mtime, file.path)
        end
      end

      # Private: Generates a gzipped file based off of reference asset.
      #
      #     ZopfliArchiver.call(file, source, mtime)
      #
      # Compresses a given `source` using the zopfli gem
      # writes contents to the `file` passed in. Sets `mtime` of
      # written file to passed in `mtime`
      module ZopfliArchiver
        def self.call(file, source, mtime)
          compressed_source = Autoload::Zopfli.deflate(source, format: :gzip, mtime: mtime)
          file.write(compressed_source)
          file.close

          nil
        end
      end

      attr_reader :content_type, :source, :charset, :archiver

      # Private: Generates a gzipped file based off of reference file.
      def initialize(asset, archiver: ZlibArchiver)
        @content_type  = asset.content_type
        @source        = asset.source
        @charset       = asset.charset
        @archiver      = archiver
      end

      # What non-text mime types should we compress? This list comes from:
      # https://www.fastly.com/blog/new-gzip-settings-and-deciding-what-compress
      COMPRESSABLE_MIME_TYPES = {
        "application/vnd.ms-fontobject" => true,
        "application/x-font-opentype" => true,
        "application/x-font-ttf" => true,
        "image/x-icon" => true,
        "image/svg+xml" => true
      }

      # Private: Returns whether or not an asset can be compressed.
      #
      # We want to compress any file that is text based.
      # You do not want to compress binary
      # files as they may already be compressed and running them
      # through a compression algorithm would make them larger.
      #
      # Return Boolean.
      def can_compress?
        # The "charset" of a mime type is present if the value is
        # encoded text. We can check this value to see if the asset
        # can be compressed.
        #
        # We also check against our list of non-text compressible mime types
        @charset || COMPRESSABLE_MIME_TYPES.include?(@content_type)
      end

      # Private: Opposite of `can_compress?`.
      #
      # Returns Boolean.
      def cannot_compress?
        !can_compress?
      end

      # Private: Generates a gzipped file based off of reference asset.
      #
      # Compresses the target asset's contents and puts it into a file with
      # the same name plus a `.gz` extension in the same folder as the original.
      # Does not modify the target asset.
      #
      # Returns nothing.
      def compress(file, target)
        mtime = Sprockets::PathUtils.stat(target).mtime
        archiver.call(file, source, mtime)

        nil
      end
    end
  end
end