mime-types 2.99.3 → 3.2.2

Sign up to get free protection for your applications and to get access to all the features.
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'