mime-types 1.25.1 → 2.0

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 (61) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.autotest +5 -0
  5. data/.minitest.rb +2 -0
  6. data/.travis.yml +0 -4
  7. data/Contributing.rdoc +13 -14
  8. data/Gemfile +1 -0
  9. data/History.rdoc +100 -7
  10. data/Licence.rdoc +1 -1
  11. data/Manifest.txt +17 -24
  12. data/README.rdoc +26 -47
  13. data/Rakefile +42 -185
  14. data/data/mime-types.json +1 -0
  15. data/docs/COPYING.txt +339 -339
  16. data/docs/artistic.txt +127 -127
  17. data/lib/mime.rb +50 -0
  18. data/lib/mime/type.rb +634 -0
  19. data/lib/mime/types.rb +254 -912
  20. data/lib/mime/types/cache.rb +73 -0
  21. data/lib/mime/types/loader.rb +248 -0
  22. data/lib/mime/types/loader_path.rb +16 -0
  23. data/support/benchmarker.rb +55 -0
  24. data/support/convert.rb +130 -0
  25. data/support/iana_downloader.rb +201 -0
  26. data/test/fixture/json.json +1 -0
  27. data/test/fixture/old-data +9 -0
  28. data/test/fixture/yaml.yaml +75 -0
  29. data/test/minitest_helper.rb +22 -0
  30. data/test/test_mime_type.rb +337 -143
  31. data/test/test_mime_types.rb +75 -84
  32. data/test/test_mime_types_cache.rb +30 -29
  33. data/test/test_mime_types_class.rb +135 -0
  34. data/test/test_mime_types_lazy.rb +3 -2
  35. data/test/test_mime_types_loader.rb +42 -0
  36. metadata +61 -90
  37. metadata.gz.sig +0 -0
  38. data/lib/mime/types/application +0 -1010
  39. data/lib/mime/types/application.mac +0 -3
  40. data/lib/mime/types/application.nonstandard +0 -132
  41. data/lib/mime/types/application.obsolete +0 -41
  42. data/lib/mime/types/audio +0 -138
  43. data/lib/mime/types/audio.nonstandard +0 -11
  44. data/lib/mime/types/audio.obsolete +0 -1
  45. data/lib/mime/types/image +0 -46
  46. data/lib/mime/types/image.nonstandard +0 -20
  47. data/lib/mime/types/image.obsolete +0 -5
  48. data/lib/mime/types/message +0 -18
  49. data/lib/mime/types/message.obsolete +0 -2
  50. data/lib/mime/types/model +0 -15
  51. data/lib/mime/types/multipart +0 -14
  52. data/lib/mime/types/multipart.nonstandard +0 -1
  53. data/lib/mime/types/multipart.obsolete +0 -7
  54. data/lib/mime/types/other.nonstandard +0 -8
  55. data/lib/mime/types/text +0 -61
  56. data/lib/mime/types/text.nonstandard +0 -7
  57. data/lib/mime/types/text.obsolete +0 -8
  58. data/lib/mime/types/text.vms +0 -1
  59. data/lib/mime/types/video +0 -75
  60. data/lib/mime/types/video.nonstandard +0 -16
  61. data/lib/mime/types/video.obsolete +0 -3
@@ -0,0 +1,73 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ class MIME::Types
4
+ # Caching of MIME::Types registries is advisable if you will be loading
5
+ # the default registry relatively frequently. With the class methods on
6
+ # MIME::Types::Cache, any MIME::Types registry can be marshaled quickly
7
+ # and easily.
8
+ #
9
+ # The cache is invalidated on a per-version basis; a cache file for
10
+ # version 2.0 will not be reused with version 2.0.1.
11
+ Cache = Struct.new(:version, :data)
12
+
13
+ class << Cache
14
+ # Attempts to load the cache from the file provided as a parameter or in
15
+ # the environment variable +RUBY_MIME_TYPES_CACHE+. Returns +nil+ if the
16
+ # file does not exist, if the file cannot be loaded, or if the data in
17
+ # the cache version is different than this version.
18
+ def load(cache_file = nil)
19
+ cache_file = cache_file || ENV['RUBY_MIME_TYPES_CACHE']
20
+ return nil unless cache_file and File.exists?(cache_file)
21
+
22
+ cache = Marshal.load(File.binread(cache_file))
23
+ if cache.version == MIME::Types::VERSION
24
+ Marshal.load(cache.data)
25
+ else
26
+ warn "Could not load MIME::Types cache: invalid version"
27
+ nil
28
+ end
29
+ rescue => e
30
+ warn "Could not load MIME::Types cache: #{e}"
31
+ return nil
32
+ end
33
+
34
+ # Attempts to save the types provided to the cache file provided.
35
+ #
36
+ # If +types+ is not provided or is +nil+, the cache will contain the
37
+ # current MIME::Types default registry.
38
+ #
39
+ # If +cache_file+ is not provided or is +nil+, the cache will be written
40
+ # to the file specified in the environment variable
41
+ # +RUBY_MIME_TYPES_CACHE+. If there is no cache file specified either
42
+ # directly or through the environment, this method will return +nil+
43
+ def save(types = nil, cache_file = nil)
44
+ cache_file = cache_file || ENV['RUBY_MIME_TYPES_CACHE']
45
+ return nil unless cache_file
46
+
47
+ types = types || MIME::Types.send(:__types__)
48
+
49
+ File.open(cache_file, 'wb') do |f|
50
+ f.write(Marshal.dump(new(types.data_version, Marshal.dump(types))))
51
+ end
52
+ end
53
+ end
54
+
55
+ # MIME::Types requires a container Hash with a default values for keys
56
+ # resulting in an empty array (<tt>[]</tt>), but this cannot be dumped
57
+ # through Marshal because of the presence of that default Proc. This class
58
+ # exists solely to satisfy that need.
59
+ class Container < Hash # :nodoc:
60
+ def initialize
61
+ super
62
+ self.default_proc = ->(h, k) { h[k] = [] }
63
+ end
64
+
65
+ def marshal_dump
66
+ {}.merge(self)
67
+ end
68
+
69
+ def marshal_load(hash)
70
+ self.merge!(hash)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,248 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ require 'mime/types/loader_path'
4
+
5
+ # This class is responsible for initializing the MIME::Types registry from
6
+ # the data files supplied with the mime-types library.
7
+ #
8
+ # The Loader will use one of the following paths:
9
+ # 1. The +path+ provided in its constructor argument;
10
+ # 2. The value of ENV['RUBY_MIME_TYPES_DATA']; or
11
+ # 3. The value of MIME::Types::Loader::PATH.
12
+ #
13
+ # When #load is called, the +path+ will be searched recursively for all YAML
14
+ # (.yml or .yaml) files. By convention, there is one file for each media type
15
+ # (application.yml, audio.yml, etc.), but this is not required.
16
+ #
17
+ #
18
+ class MIME::Types::Loader
19
+ # The path that will be read for the MIME::Types files.
20
+ attr_reader :path
21
+ # The MIME::Types container instance that will be loaded. If not provided
22
+ # at initialization, a new MIME::Types instance will be constructed.
23
+ attr_reader :container
24
+
25
+ # Creates a Loader object that can be used to load MIME::Types registries
26
+ # into memory, using YAML, JSON, or v1 registry format loaders.
27
+ def initialize(path = nil, container = nil)
28
+ path = path || ENV['RUBY_MIME_TYPES_DATA'] ||
29
+ MIME::Types::Loader::PATH
30
+ @path = File.expand_path(File.join(path, '**'))
31
+ @container = container || MIME::Types.new
32
+ end
33
+
34
+ # Loads a MIME::Types registry from YAML files (<tt>*.yml</tt> or
35
+ # <tt>*.yaml</tt>) recursively found in +path+.
36
+ #
37
+ # It is expected that the YAML objects contained within the registry array
38
+ # will be tagged as <tt>!ruby/object:MIME::Type</tt>.
39
+ #
40
+ # Note that the YAML format is about 2½ times *slower* than either the v1
41
+ # format or the JSON format.
42
+ #
43
+ # NOTE: The purpose of this format is purely for maintenance reasons.
44
+ def load_yaml
45
+ Dir[yaml_path].sort.each do |f|
46
+ container.add(*self.class.load_from_yaml(f), :silent)
47
+ end
48
+ container
49
+ end
50
+
51
+ # Loads a MIME::Types registry from JSON files (<tt>*.json</tt>)
52
+ # recursively found in +path+.
53
+ #
54
+ # It is expected that the JSON objects will be an array of hash objects.
55
+ # The JSON format is the registry format for the MIME types registry
56
+ # shipped with the mime-types library.
57
+ #
58
+ # This method is aliased to #load.
59
+ def load_json
60
+ Dir[json_path].sort.each do |f|
61
+ types = self.class.load_from_json(f).map { |type|
62
+ MIME::Type.new(type)
63
+ }
64
+ container.add(*types, :silent)
65
+ end
66
+ container
67
+ end
68
+ alias_method :load, :load_json
69
+
70
+ # Loads a MIME::Types registry from files found in +path+ that are in the
71
+ # v1 data format. The file search for this will exclude both JSON
72
+ # (<tt>*.json</tt>) and YAML (<tt>*.yml</tt> or <tt>*.yaml</tt>) files.
73
+ #
74
+ # This method has been deprecated.
75
+ def load_v1
76
+ MIME.deprecated(self.class, __method__)
77
+ Dir[v1_path].sort.each do |f|
78
+ next if f =~ /\.ya?ml$|\.json$/
79
+ container.add(self.class.load_from_v1(f), true)
80
+ end
81
+ container
82
+ end
83
+
84
+ class << self
85
+ # Loads the default MIME::Type registry.
86
+ def load
87
+ new.load
88
+ end
89
+
90
+ # Build the type list from a file in the format:
91
+ #
92
+ # [*][!][os:]mt/st[<ws>@ext][<ws>:enc][<ws>'url-list][<ws>=docs]
93
+ #
94
+ # == *
95
+ # An unofficial MIME type. This should be used if and only if the MIME type
96
+ # is not properly specified (that is, not under either x-type or
97
+ # vnd.name.type).
98
+ #
99
+ # == !
100
+ # An obsolete MIME type. May be used with an unofficial MIME type.
101
+ #
102
+ # == os:
103
+ # Platform-specific MIME type definition.
104
+ #
105
+ # == mt
106
+ # The media type.
107
+ #
108
+ # == st
109
+ # The media subtype.
110
+ #
111
+ # == <ws>@ext
112
+ # The list of comma-separated extensions.
113
+ #
114
+ # == <ws>:enc
115
+ # The encoding.
116
+ #
117
+ # == <ws>'url-list
118
+ # The list of comma-separated URLs.
119
+ #
120
+ # == <ws>=docs
121
+ # The documentation string.
122
+ #
123
+ # That is, everything except the media type and the subtype is optional. The
124
+ # more information that's available, though, the richer the values that can
125
+ # be provided.
126
+ def load_from_v1(filename)
127
+ data = read_file(filename).split($/)
128
+ mime = MIME::Types.new
129
+ data.each_with_index { |line, index|
130
+ item = line.chomp.strip
131
+ next if item.empty?
132
+
133
+ begin
134
+ m = MIME::Types::Loader::V1_FORMAT.match(item).captures
135
+ rescue Exception
136
+ warn <<-EOS
137
+ #{filename}:#{index}: Parsing error in v1 MIME type definition.
138
+ => #{line}
139
+ EOS
140
+ raise
141
+ end
142
+
143
+ unregistered, obsolete, platform, mediatype, subtype, extensions,
144
+ encoding, urls, docs, comment = *m
145
+
146
+ if mediatype.nil?
147
+ if comment.nil?
148
+ warn <<-EOS
149
+ #{filename}:#{index}: Parsing error in v1 MIME type definition (no media type).
150
+ => #{line}
151
+ EOS
152
+ raise
153
+ end
154
+
155
+ next
156
+ end
157
+
158
+ extensions &&= extensions.split(/,/)
159
+ urls &&= urls.split(/,/)
160
+
161
+ if docs.nil?
162
+ use_instead = nil
163
+ else
164
+ use_instead = docs.scan(%r{use-instead:(\S+)}).flatten
165
+ docs = docs.gsub(%r{use-instead:\S+}, "").squeeze(" \t")
166
+ end
167
+
168
+ mime_type = MIME::Type.new("#{mediatype}/#{subtype}") do |t|
169
+ t.extensions = extensions
170
+ t.encoding = encoding
171
+ t.system = platform
172
+ t.obsolete = obsolete
173
+ t.registered = false if unregistered
174
+ t.use_instead = use_instead
175
+ t.docs = docs
176
+ t.references = urls
177
+ end
178
+
179
+ mime.add_type(mime_type, true)
180
+ }
181
+ mime
182
+ end
183
+
184
+ # Loads MIME::Types from a single YAML file.
185
+ #
186
+ # It is expected that the YAML objects contained within the registry
187
+ # array will be tagged as <tt>!ruby/object:MIME::Type</tt>.
188
+ #
189
+ # Note that the YAML format is about 2½ times *slower* than either the v1
190
+ # format or the JSON format.
191
+ #
192
+ # NOTE: The purpose of this format is purely for maintenance reasons.
193
+ def load_from_yaml(filename)
194
+ begin
195
+ require 'psych'
196
+ rescue LoadError
197
+ nil
198
+ end
199
+ require 'yaml'
200
+ YAML.load(read_file(filename))
201
+ end
202
+
203
+ # Loads MIME::Types from a single JSON file.
204
+ #
205
+ # It is expected that the JSON objects will be an array of hash objects.
206
+ # The JSON format is the registry format for the MIME types registry
207
+ # shipped with the mime-types library.
208
+ def load_from_json(filename)
209
+ require 'json'
210
+ JSON.load(read_file(filename)).map { |type| MIME::Type.new(type) }
211
+ end
212
+
213
+ private
214
+ def read_file(filename)
215
+ File.open(filename, 'r:UTF-8:-') { |f| f.read }
216
+ end
217
+ end
218
+
219
+ private
220
+ def yaml_path
221
+ File.join(path, '*.y{,a}ml')
222
+ end
223
+
224
+ def json_path
225
+ File.join(path, '*.json')
226
+ end
227
+
228
+ def v1_path
229
+ File.join(path, '*')
230
+ end
231
+
232
+ # The regular expression used to match a v1-format file-based MIME type
233
+ # definition.
234
+ MIME::Types::Loader::V1_FORMAT = # :nodoc:
235
+ %r{\A\s*
236
+ ([*])? # 0: Unregistered?
237
+ (!)? # 1: Obsolete?
238
+ (?:(\w+):)? # 2: Platform marker
239
+ #{MIME::Type::MEDIA_TYPE_RE}? # 3,4: Media type
240
+ (?:\s+@(\S+))? # 5: Extensions
241
+ (?:\s+:(base64|7bit|8bit|quoted\-printable))? # 6: Encoding
242
+ (?:\s+'(\S+))? # 7: URL list
243
+ (?:\s+=(.+))? # 8: Documentation
244
+ (?:\s*([#].*)?)?
245
+ \s*
246
+ \z
247
+ }x
248
+ end
@@ -0,0 +1,16 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ class MIME::Types::Loader
4
+ # The path that will be used for loading the MIME::Types data. The default
5
+ # location is __FILE__/../../../../data, which is where the data lives
6
+ # in the gem installation of the mime-types library.
7
+ #
8
+ # The MIME::Types::Loader will load all YAML files contained in this path.
9
+ # By convention, there is one file for each media type (e.g.,
10
+ # application.yml, audio.yml, etc.).
11
+ #
12
+ # System repackagers note: this is the constant that you would change if
13
+ # you repackage mime-types for your system. It is recommended that the
14
+ # path be something like /usr/share/ruby/mime-types/.
15
+ PATH = File.expand_path('../../../../data', __FILE__)
16
+ end
@@ -0,0 +1,55 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
+ require 'benchmark'
5
+
6
+ class Benchmarker
7
+ def self.benchmark(repeats)
8
+ new(repeats.to_i).benchmark
9
+ end
10
+
11
+ def initialize(repeats = nil)
12
+ @cache_file = File.expand_path('../cache.mtc', __FILE__)
13
+ @repeats = repeats.to_i
14
+ @repeats = 50 if repeats.zero?
15
+ end
16
+
17
+ def reload_mime_types(repeats = 1, force_load = false)
18
+ path = File.expand_path('../../lib', __FILE__)
19
+
20
+ repeats.times {
21
+ Object.send(:remove_const, :MIME) if defined? MIME
22
+ $LOADED_FEATURES.delete_if { |n| n =~ /#{path}/ }
23
+ require 'mime/types'
24
+ MIME::Types.send(:__types__) if force_load
25
+ }
26
+ end
27
+
28
+ def benchmark
29
+ remove_cache
30
+
31
+ Benchmark.bm(17) do |mark|
32
+ mark.report("Normal:") { reload_mime_types(@repeats) }
33
+
34
+ ENV['RUBY_MIME_TYPES_LAZY_LOAD'] = 'yes'
35
+ mark.report("Lazy:") { reload_mime_types(@repeats) }
36
+ mark.report("Lazy+Load:") { reload_mime_types(@repeats, true) }
37
+
38
+ ENV.delete('RUBY_MIME_TYPES_LAZY_LOAD')
39
+
40
+ ENV['RUBY_MIME_TYPES_CACHE'] = @cache_file
41
+ reload_mime_types
42
+
43
+ mark.report("Cached:") { reload_mime_types(@repeats) }
44
+ ENV['RUBY_MIME_TYPES_LAZY_LOAD'] = 'yes'
45
+ mark.report("Lazy Cached:") { reload_mime_types(@repeats) }
46
+ mark.report("Lazy Cached Load:") { reload_mime_types(@repeats, true) }
47
+ end
48
+ ensure
49
+ remove_cache
50
+ end
51
+
52
+ def remove_cache
53
+ File.unlink(@cache_file) if File.exist?(@cache_file)
54
+ end
55
+ end
@@ -0,0 +1,130 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
+ require 'mime/types'
5
+ require 'fileutils'
6
+
7
+ class Convert
8
+ class << self
9
+ def from_yaml(path = nil)
10
+ new(path: path, from: :yaml)
11
+ end
12
+
13
+ def from_json(path = nil)
14
+ new(path: path, from: :json)
15
+ end
16
+
17
+ def from_v1(path = nil)
18
+ new(path: path, from: :v1)
19
+ end
20
+
21
+ def from_yaml_to_json(args)
22
+ from_yaml(yaml_path(args.source)).
23
+ to_json(destination: json_path(args.destination),
24
+ multiple_files: multiple_files(args.multiple_files))
25
+ end
26
+
27
+ def from_json_to_yaml(args)
28
+ from_json(json_path(args.source)).
29
+ to_yaml(destination: yaml_path(args.destination),
30
+ multiple_files: multiple_files(args.multiple_files))
31
+ end
32
+
33
+ private :new
34
+
35
+ private
36
+ def yaml_path(path)
37
+ if path.nil? or path.empty?
38
+ 'type-lists'
39
+ else
40
+ path
41
+ end
42
+ end
43
+
44
+ def json_path(path)
45
+ if path.nil? or path.empty?
46
+ 'data'
47
+ else
48
+ path
49
+ end
50
+ end
51
+
52
+ def multiple_files(flag)
53
+ case flag
54
+ when "true", "yes"
55
+ true
56
+ else
57
+ false
58
+ end
59
+ end
60
+ end
61
+
62
+ def initialize(options = {})
63
+ if options[:path].nil? or options[:path].empty?
64
+ raise ArgumentError, ':path is required'
65
+ end
66
+ if options[:from].nil? or options[:from].empty?
67
+ raise ArgumentError, ':from is required'
68
+ end
69
+
70
+ path = options[:path]
71
+
72
+ @loader = MIME::Types::Loader.new(options[:path])
73
+ load_from(options[:from])
74
+ end
75
+
76
+ def to_json(options = {})
77
+ raise ArgumentError, 'destination is required' unless options[:destination]
78
+ write_types(options.merge(format: :json))
79
+ end
80
+
81
+ def to_yaml(options = {})
82
+ raise ArgumentError, 'destination is required' unless options[:destination]
83
+ write_types(options.merge(format: :yaml))
84
+ end
85
+
86
+ private
87
+ def load_from(source_type)
88
+ method = :"load_#{source_type}"
89
+ @loader.send(method)
90
+ end
91
+
92
+ def write_types(options)
93
+ if options[:multiple_files]
94
+ write_multiple_files(options)
95
+ else
96
+ write_one_file(options)
97
+ end
98
+ end
99
+
100
+ def write_one_file(options)
101
+ d = options[:destination]
102
+ d = File.join(d, "mime-types.#{options[:format]}") if File.directory?(d)
103
+
104
+ File.open(d, 'wb') { |f|
105
+ f.puts convert(@loader.container.map.sort, options[:format])
106
+ }
107
+ end
108
+
109
+ def write_multiple_files(options)
110
+ d = options[:destination]
111
+ if File.exist?(d) and not File.directory?(d)
112
+ raise ArgumentError, 'Cannot write multiple files to a file.'
113
+ end
114
+
115
+ FileUtils.mkdir_p d unless File.exist?(d)
116
+
117
+ media_types = MIME::Types.map(&:media_type).uniq
118
+ media_types.each { |media_type|
119
+ n = File.join(d, "#{media_type}.#{options[:format]}")
120
+ t = @loader.container.select { |e| e.media_type == media_type }
121
+ File.open(n, 'wb') { |f|
122
+ f.puts convert(t.sort, options[:format])
123
+ }
124
+ }
125
+ end
126
+
127
+ def convert(data, format)
128
+ data.send(:"to_#{format}")
129
+ end
130
+ end