mime-types 2.99.3 → 3.2.2

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 (52) hide show
  1. checksums.yaml +5 -5
  2. data/{Code-of-Conduct.rdoc → Code-of-Conduct.md} +19 -20
  3. data/Contributing.md +139 -0
  4. data/History.md +208 -0
  5. data/{Licence.rdoc → Licence.md} +4 -18
  6. data/Manifest.txt +8 -25
  7. data/README.rdoc +63 -67
  8. data/Rakefile +144 -55
  9. data/lib/mime/type/columnar.rb +29 -62
  10. data/lib/mime/type.rb +192 -417
  11. data/lib/mime/types/_columnar.rb +137 -0
  12. data/lib/mime/types/cache.rb +51 -73
  13. data/lib/mime/types/columnar.rb +2 -147
  14. data/lib/mime/types/container.rb +94 -0
  15. data/lib/mime/types/deprecations.rb +5 -24
  16. data/lib/mime/types/full.rb +19 -0
  17. data/lib/mime/types/loader.rb +12 -141
  18. data/lib/mime/types/logger.rb +4 -0
  19. data/lib/mime/types/registry.rb +90 -0
  20. data/lib/mime/types.rb +43 -139
  21. data/lib/mime-types.rb +1 -1
  22. data/test/minitest_helper.rb +6 -12
  23. data/test/test_mime_type.rb +473 -455
  24. data/test/test_mime_types.rb +136 -86
  25. data/test/test_mime_types_cache.rb +83 -53
  26. data/test/test_mime_types_class.rb +119 -97
  27. data/test/test_mime_types_lazy.rb +27 -23
  28. data/test/test_mime_types_loader.rb +7 -32
  29. metadata +102 -62
  30. data/Contributing.rdoc +0 -170
  31. data/History-Types.rdoc +0 -454
  32. data/History.rdoc +0 -590
  33. data/data/mime-types.json +0 -1
  34. data/data/mime.content_type.column +0 -1980
  35. data/data/mime.docs.column +0 -1980
  36. data/data/mime.encoding.column +0 -1980
  37. data/data/mime.friendly.column +0 -1980
  38. data/data/mime.obsolete.column +0 -1980
  39. data/data/mime.registered.column +0 -1980
  40. data/data/mime.signature.column +0 -1980
  41. data/data/mime.use_instead.column +0 -1980
  42. data/data/mime.xrefs.column +0 -1980
  43. data/docs/COPYING.txt +0 -339
  44. data/docs/artistic.txt +0 -127
  45. data/lib/mime/types/loader_path.rb +0 -15
  46. data/support/apache_mime_types.rb +0 -108
  47. data/support/benchmarks/load.rb +0 -64
  48. data/support/benchmarks/load_allocations.rb +0 -83
  49. data/support/benchmarks/object_counts.rb +0 -41
  50. data/support/convert/columnar.rb +0 -88
  51. data/support/convert.rb +0 -158
  52. data/support/iana_registry.rb +0 -172
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mime/type/columnar'
4
+
5
+ # MIME::Types::Columnar is used to extend a MIME::Types container to load data
6
+ # by columns instead of from JSON or YAML. Column loads of MIME types loaded
7
+ # through the columnar store are synchronized with a Mutex.
8
+ #
9
+ # MIME::Types::Columnar is not intended to be used directly, but will be added
10
+ # to an instance of MIME::Types when it is loaded with
11
+ # MIME::Types::Loader#load_columnar.
12
+ module MIME::Types::Columnar
13
+ LOAD_MUTEX = Mutex.new # :nodoc:
14
+
15
+ def self.extended(obj) # :nodoc:
16
+ super
17
+ obj.instance_variable_set(:@__mime_data__, [])
18
+ obj.instance_variable_set(:@__files__, Set.new)
19
+ end
20
+
21
+ # Load the first column data file (type and extensions).
22
+ def load_base_data(path) #:nodoc:
23
+ @__root__ = path
24
+
25
+ each_file_line('content_type', false) do |line|
26
+ line = line.split
27
+ content_type = line.shift
28
+ extensions = line
29
+ # content_type, *extensions = line.split
30
+
31
+ type = MIME::Type::Columnar.new(self, content_type, extensions)
32
+ @__mime_data__ << type
33
+ add(type)
34
+ end
35
+
36
+ self
37
+ end
38
+
39
+ private
40
+
41
+ def each_file_line(name, lookup = true)
42
+ LOAD_MUTEX.synchronize do
43
+ next if @__files__.include?(name)
44
+
45
+ i = -1
46
+ column = File.join(@__root__, "mime.#{name}.column")
47
+
48
+ IO.readlines(column, encoding: 'UTF-8'.freeze).each do |line|
49
+ line.chomp!
50
+
51
+ if lookup
52
+ type = @__mime_data__[i += 1] or next
53
+ yield type, line
54
+ else
55
+ yield line
56
+ end
57
+ end
58
+
59
+ @__files__ << name
60
+ end
61
+ end
62
+
63
+ def load_encoding
64
+ each_file_line('encoding') do |type, line|
65
+ pool ||= {}
66
+ line.freeze
67
+ type.instance_variable_set(:@encoding, (pool[line] ||= line))
68
+ end
69
+ end
70
+
71
+ def load_docs
72
+ each_file_line('docs') do |type, line|
73
+ type.instance_variable_set(:@docs, opt(line))
74
+ end
75
+ end
76
+
77
+ def load_preferred_extension
78
+ each_file_line('pext') do |type, line|
79
+ type.instance_variable_set(:@preferred_extension, opt(line))
80
+ end
81
+ end
82
+
83
+ def load_flags
84
+ each_file_line('flags') do |type, line|
85
+ line = line.split
86
+ type.instance_variable_set(:@obsolete, flag(line.shift))
87
+ type.instance_variable_set(:@registered, flag(line.shift))
88
+ type.instance_variable_set(:@signature, flag(line.shift))
89
+ end
90
+ end
91
+
92
+ def load_xrefs
93
+ each_file_line('xrefs') { |type, line|
94
+ type.instance_variable_set(:@xrefs, dict(line, array: true))
95
+ }
96
+ end
97
+
98
+ def load_friendly
99
+ each_file_line('friendly') { |type, line|
100
+ type.instance_variable_set(:@friendly, dict(line))
101
+ }
102
+ end
103
+
104
+ def load_use_instead
105
+ each_file_line('use_instead') do |type, line|
106
+ type.instance_variable_set(:@use_instead, opt(line))
107
+ end
108
+ end
109
+
110
+ def dict(line, array: false)
111
+ if line == '-'.freeze
112
+ {}
113
+ else
114
+ line.split('|'.freeze).each_with_object({}) { |l, h|
115
+ k, v = l.split('^'.freeze)
116
+ v = nil if v.empty?
117
+ h[k] = array ? Array(v) : v
118
+ }
119
+ end
120
+ end
121
+
122
+ def arr(line)
123
+ if line == '-'.freeze
124
+ []
125
+ else
126
+ line.split('|'.freeze).flatten.compact.uniq
127
+ end
128
+ end
129
+
130
+ def opt(line)
131
+ line unless line == '-'.freeze
132
+ end
133
+
134
+ def flag(line)
135
+ line == '1'.freeze ? true : false
136
+ end
137
+ end
@@ -1,80 +1,58 @@
1
- # -*- ruby encoding: utf-8 -*-
2
-
3
- class MIME::Types
4
- Cache = Struct.new(:version, :data) # :nodoc:
5
-
6
- # Caching of MIME::Types registries is advisable if you will be loading
7
- # the default registry relatively frequently. With the class methods on
8
- # MIME::Types::Cache, any MIME::Types registry can be marshaled quickly
9
- # and easily.
10
- #
11
- # The cache is invalidated on a per-version basis; a cache file for
12
- # version 2.0 will not be reused with version 2.0.1.
13
- class Cache
14
- class << self
15
- # Attempts to load the cache from the file provided as a parameter or in
16
- # the environment variable +RUBY_MIME_TYPES_CACHE+. Returns +nil+ if the
17
- # file does not exist, if the file cannot be loaded, or if the data in
18
- # the cache version is different than this version.
19
- def load(cache_file = nil)
20
- cache_file ||= ENV['RUBY_MIME_TYPES_CACHE']
21
- return nil unless cache_file and File.exist?(cache_file)
22
-
23
- cache = Marshal.load(File.binread(cache_file))
24
- if cache.version == MIME::Types::VERSION
25
- Marshal.load(cache.data)
26
- else
27
- MIME::Types.logger.warn <<-warning.chomp
1
+ # frozen_string_literal: true
2
+
3
+ MIME::Types::Cache = Struct.new(:version, :data) # :nodoc:
4
+
5
+ # Caching of MIME::Types registries is advisable if you will be loading
6
+ # the default registry relatively frequently. With the class methods on
7
+ # MIME::Types::Cache, any MIME::Types registry can be marshaled quickly
8
+ # and easily.
9
+ #
10
+ # The cache is invalidated on a per-data-version basis; a cache file for
11
+ # version 3.2015.1118 will not be reused with version 3.2015.1201.
12
+ class << MIME::Types::Cache
13
+ # Attempts to load the cache from the file provided as a parameter or in
14
+ # the environment variable +RUBY_MIME_TYPES_CACHE+. Returns +nil+ if the
15
+ # file does not exist, if the file cannot be loaded, or if the data in
16
+ # the cache version is different than this version.
17
+ def load(cache_file = nil)
18
+ cache_file ||= ENV['RUBY_MIME_TYPES_CACHE']
19
+ return nil unless cache_file and File.exist?(cache_file)
20
+
21
+ cache = Marshal.load(File.binread(cache_file))
22
+ if cache.version == MIME::Types::Data::VERSION
23
+ Marshal.load(cache.data)
24
+ else
25
+ MIME::Types.logger.warn <<-warning.chomp
28
26
  Could not load MIME::Types cache: invalid version
29
- warning
30
- nil
31
- end
32
- rescue => e
33
- MIME::Types.logger.warn <<-warning.chomp
34
- Could not load MIME::Types cache: #{e}
35
- warning
36
- return nil
37
- end
38
-
39
- # Attempts to save the types provided to the cache file provided.
40
- #
41
- # If +types+ is not provided or is +nil+, the cache will contain the
42
- # current MIME::Types default registry.
43
- #
44
- # If +cache_file+ is not provided or is +nil+, the cache will be written
45
- # to the file specified in the environment variable
46
- # +RUBY_MIME_TYPES_CACHE+. If there is no cache file specified either
47
- # directly or through the environment, this method will return +nil+
48
- def save(types = nil, cache_file = nil)
49
- cache_file ||= ENV['RUBY_MIME_TYPES_CACHE']
50
- return nil unless cache_file
51
-
52
- types ||= MIME::Types.send(:__types__)
53
-
54
- File.open(cache_file, 'wb') do |f|
55
- f.write(Marshal.dump(new(types.data_version, Marshal.dump(types))))
56
- end
57
- end
27
+ warning
28
+ nil
58
29
  end
30
+ rescue => e
31
+ MIME::Types.logger.warn <<-warning.chomp
32
+ Could not load MIME::Types cache: #{e}
33
+ warning
34
+ return nil
59
35
  end
60
36
 
61
- # MIME::Types requires a container Hash with a default values for keys
62
- # resulting in an empty array (<tt>[]</tt>), but this cannot be dumped
63
- # through Marshal because of the presence of that default Proc. This class
64
- # exists solely to satisfy that need.
65
- class Container < Hash # :nodoc:
66
- def initialize
67
- super
68
- self.default_proc = ->(h, k) { h[k] = [] }
69
- end
70
-
71
- def marshal_dump
72
- {}.merge(self)
73
- end
74
-
75
- def marshal_load(hash)
76
- self.default_proc = ->(h, k) { h[k] = [] }
77
- self.merge!(hash)
37
+ # Attempts to save the types provided to the cache file provided.
38
+ #
39
+ # If +types+ is not provided or is +nil+, the cache will contain the
40
+ # current MIME::Types default registry.
41
+ #
42
+ # If +cache_file+ is not provided or is +nil+, the cache will be written
43
+ # to the file specified in the environment variable
44
+ # +RUBY_MIME_TYPES_CACHE+. If there is no cache file specified either
45
+ # directly or through the environment, this method will return +nil+
46
+ def save(types = nil, cache_file = nil)
47
+ cache_file ||= ENV['RUBY_MIME_TYPES_CACHE']
48
+ return nil unless cache_file
49
+
50
+ types ||= MIME::Types.send(:__types__)
51
+
52
+ File.open(cache_file, 'wb') do |f|
53
+ f.write(
54
+ Marshal.dump(new(MIME::Types::Data::VERSION, Marshal.dump(types)))
55
+ )
78
56
  end
79
57
  end
80
58
  end
@@ -1,148 +1,3 @@
1
- module MIME
2
- class Types
3
- end
4
- end
1
+ # frozen_string_literal: true
5
2
 
6
- require 'mime/type/columnar'
7
-
8
- # MIME::Types::Columnar is used to extend a MIME::Types container to load data
9
- # by columns instead of from JSON or YAML. Column loads of MIME types loaded
10
- # through the columnar store are synchronized with a Mutex.
11
- #
12
- # MIME::Types::Columnar is not intended to be used directly, but will be added
13
- # to an instance of MIME::Types when it is loaded with
14
- # MIME::Types::Loader#load_columnar.
15
- module MIME::Types::Columnar
16
- LOAD_MUTEX = Mutex.new # :nodoc:
17
-
18
- def self.extended(obj) # :nodoc:
19
- super
20
- obj.instance_variable_set(:@__mime_data__, [])
21
- obj.instance_variable_set(:@__attributes__, [])
22
- end
23
-
24
- # Load the first column data file (type and extensions).
25
- def load_base_data(path) #:nodoc:
26
- @__root__ = path
27
-
28
- each_file_line('content_type', false) do |line|
29
- content_type, *extensions = line.split
30
-
31
- type = MIME::Type::Columnar.new(self, content_type, extensions)
32
- @__mime_data__ << type
33
- add(type)
34
- end
35
-
36
- self
37
- end
38
-
39
- private
40
-
41
- def each_file_line(name, lookup = true)
42
- LOAD_MUTEX.synchronize do
43
- next if @__attributes__.include?(name)
44
-
45
- File.open(File.join(@__root__, "mime.#{name}.column"), 'r:UTF-8') do |f|
46
- i = -1
47
-
48
- f.each_line do |line|
49
- line.chomp!
50
-
51
- if lookup
52
- type = @__mime_data__[i += 1] or next
53
- yield type, line
54
- else
55
- yield line
56
- end
57
- end
58
- end
59
-
60
- @__attributes__ << name
61
- end
62
- end
63
-
64
- def load_encoding
65
- pool = {}
66
- each_file_line('encoding') do |type, line|
67
- line.freeze
68
- type.encoding = (pool[line] ||= line)
69
- end
70
- end
71
-
72
- def load_docs
73
- each_file_line('docs') do |type, line|
74
- type.docs = arr(line)
75
- end
76
- end
77
-
78
- def load_obsolete
79
- each_file_line('obsolete') do |type, line|
80
- type.obsolete = bool(line)
81
- end
82
- end
83
-
84
- def load_registered
85
- each_file_line('registered') do |type, line|
86
- type.registered = bool(line)
87
- end
88
- end
89
-
90
- def load_signature
91
- each_file_line('signature') do |type, line|
92
- type.signature = bool(line)
93
- end
94
- end
95
-
96
- def load_xrefs
97
- each_file_line('xrefs') { |type, line| type.xrefs = dict(line) }
98
- end
99
-
100
- def load_friendly
101
- each_file_line('friendly') { |type, line|
102
- v = dict(line)
103
- type.friendly = v.empty? ? nil : v
104
- }
105
- end
106
-
107
- def load_use_instead
108
- each_file_line('use_instead') do |type, line|
109
- type.use_instead = (line unless line == '-'.freeze)
110
- end
111
- end
112
-
113
- def dict(line)
114
- if line == '-'.freeze
115
- {}
116
- else
117
- line.split('|'.freeze).each_with_object({}) { |l, h|
118
- k, v = l.split('^'.freeze)
119
- v = [ nil ] if v.empty?
120
- h[k] = v
121
- }
122
- end
123
- end
124
-
125
- def arr(line)
126
- if line == '-'.freeze
127
- []
128
- else
129
- line.split('|'.freeze).flatten.compact.uniq
130
- end
131
- end
132
-
133
- def bool(line)
134
- line == '1'.freeze ? true : false
135
- end
136
- end
137
-
138
- unless MIME::Types.private_method_defined?(:load_mode)
139
- class << MIME::Types
140
- private
141
-
142
- def load_mode
143
- { columnar: true }
144
- end
145
- end
146
-
147
- require 'mime/types'
148
- end
3
+ require 'mime/types'
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+ require 'forwardable'
5
+
6
+ # MIME::Types requires a serializable keyed container that returns an empty Set
7
+ # on a key miss. Hash#default_value cannot be used because, while it traverses
8
+ # the Marshal format correctly, it won't survive any other serialization
9
+ # format (plus, a default of a mutable object resuls in a shared mess).
10
+ # Hash#default_proc cannot be used without a wrapper because it prevents
11
+ # Marshal serialization (and doesn't survive the round-trip).
12
+ class MIME::Types::Container #:nodoc:
13
+ extend Forwardable
14
+
15
+ def initialize(hash = {})
16
+ @container = {}
17
+ merge!(hash)
18
+ end
19
+
20
+ def [](key)
21
+ container[key] || EMPTY_SET
22
+ end
23
+
24
+ def []=(key, value)
25
+ case value
26
+ when Set
27
+ container[key] = value
28
+ else
29
+ container[key] = Set[*value]
30
+ end
31
+ end
32
+
33
+ def merge(other)
34
+ self.class.new(other)
35
+ end
36
+
37
+ def merge!(other)
38
+ tap {
39
+ other = other.kind_of?(MIME::Types::Container) ? other.container : other
40
+ self.container.merge!(other)
41
+ normalize
42
+ }
43
+ end
44
+
45
+ def to_hash
46
+ container
47
+ end
48
+
49
+ def_delegators :@container,
50
+ :==,
51
+ :count,
52
+ :each,
53
+ :each_value,
54
+ :empty?,
55
+ :flat_map,
56
+ :keys,
57
+ :select,
58
+ :values
59
+
60
+ def add(key, value)
61
+ (container[key] ||= Set.new).add(value)
62
+ end
63
+
64
+ def marshal_dump
65
+ {}.merge(container)
66
+ end
67
+
68
+ def marshal_load(hash)
69
+ @container = hash
70
+ end
71
+
72
+ def encode_with(coder)
73
+ container.each { |k, v| coder[k] = v.to_a }
74
+ end
75
+
76
+ def init_with(coder)
77
+ @container = {}
78
+ coder.map.each { |k, v| container[k] = Set[*v] }
79
+ end
80
+
81
+ protected
82
+
83
+ attr_accessor :container
84
+
85
+ def normalize
86
+ container.each do |k, v|
87
+ next if v.kind_of?(Set)
88
+ container[k] = Set[*v]
89
+ end
90
+ end
91
+
92
+ EMPTY_SET = Set.new.freeze
93
+ private_constant :EMPTY_SET
94
+ end
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # -*- ruby encoding: utf-8 -*-
2
4
 
3
5
  require 'mime/types/logger'
4
6
 
5
7
  # The namespace for MIME applications, tools, and libraries.
6
8
  module MIME
9
+ ##
7
10
  class Types
8
11
  # Used to mark a method as deprecated in the mime-types interface.
9
12
  def self.deprecated(klass, sym, message = nil, &block) # :nodoc:
@@ -22,32 +25,10 @@ module MIME
22
25
  else
23
26
  message
24
27
  end
25
- MIME::Types.logger.warn <<-warning.chomp
28
+ MIME::Types.logger.warn <<-WARNING.chomp
26
29
  #{caller[1]}: #{klass}#{level}#{sym} is deprecated #{message}.
27
- warning
30
+ WARNING
28
31
  block.call if block
29
32
  end
30
33
  end
31
-
32
- class << self
33
- # MIME::InvalidContentType was moved to MIME::Type::InvalidContentType.
34
- # Provide a single warning about this fact in the interim.
35
- def const_missing(name) # :nodoc:
36
- case name.to_s
37
- when 'InvalidContentType'
38
- warn_about_moved_constants(name)
39
- MIME::Type.const_get(name.to_sym)
40
- else
41
- super
42
- end
43
- end
44
-
45
- private
46
-
47
- def warn_about_moved_constants(name)
48
- MIME::Types.logger.warn <<-warning.chomp
49
- #{caller[1]}: MIME::#{name} is deprecated. Use MIME::Type::#{name} instead.
50
- warning
51
- end
52
- end
53
34
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ module MIME
5
+ ##
6
+ class Types
7
+ unless private_method_defined?(:load_mode)
8
+ class << self
9
+ private
10
+
11
+ def load_mode
12
+ { columnar: false }
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ require 'mime/types'