shared-mime-info 0.1 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d7bc9f651e0b3ff517d8c2ec1dfad3912d246449
4
+ data.tar.gz: 84771f2ad03cb8a8c176297d3f5ddbc9055cddf5
5
+ SHA512:
6
+ metadata.gz: c91043438e9e4d8da897b2bc944ac0953817cea3d1e28e3fe1e4256f431fb7efe3cf01eeb8ce33fdb2b7477218b4683e745265ac8dde5b0abdbcd29f25701f55
7
+ data.tar.gz: bbcb438545358fd618c5425a4acf045b6d0ce6f7aeb6cecd29a44c4323481b0172882b4fca3ae3a3cc9eb4713b94afa2967586efcbb1ccc7c9264520039b3825
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2006 Mael Clerambault <mael@clerambault.fr>
2
+
3
+ Permission to use, copy, modify, and distribute this software for any
4
+ purpose with or without fee is hereby granted, provided that the above
5
+ copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,25 @@
1
+ = shared-mime-info
2
+
3
+ shared-mime-info is a pure Ruby library for accessing the MIME info database provided by Freedesktop[http://freedesktop.org/] on {Standards/shared-mime-info-spec}[http://freedesktop.org/wiki/Specifications/shared-mime-info-spec].
4
+
5
+ = Project
6
+
7
+ The rubyforge project : http://rubyforge.org/projects/shared-mime
8
+
9
+ The github repository: http://github.com/hanklords/shared-mime-info/tree/master
10
+
11
+
12
+ = Usage
13
+
14
+ require 'shared-mime-info'
15
+
16
+ MIME.check 'sample.jpg' # => #<MIME::Type ..., @type="image/jpeg">
17
+
18
+ MIME['image/jpeg'].match_filename? 'sample.jpg' # => true
19
+
20
+ = Notes
21
+ * Ensure that shared-mime-info is installed on the system:
22
+ > brew install shared-mime-info
23
+ * You may need to update the mime database first:
24
+ > update-mime-database
25
+
@@ -0,0 +1,43 @@
1
+ require 'rdoc/task'
2
+ require 'rake/packagetask'
3
+ require 'rubygems/package_task'
4
+
5
+ require_relative 'lib/shared-mime-info/version'
6
+
7
+ PKG_FILES = FileList["lib/*.rb", "lib/shared-mime-info/*", "Rakefile", "LICENSE", "README.rdoc"]
8
+
9
+ spec = Gem::Specification.new do |s|
10
+ s.summary = "Library to guess the MIME type of a file with both filename lookup and magic file detection"
11
+ s.name = "shared-mime-info"
12
+ s.description = 'shared-mime-info is a pure Ruby library for accessing the MIME info database provided by Freedesktop'
13
+ s.author = "Mael Clerambault"
14
+ s.email = "mael@clerambault.fr"
15
+ s.license = 'Public Domain'
16
+ s.homepage = 'http://shared-mime.rubyforge.org/'
17
+ s.version = SharedMimeInfo::VERSION
18
+ s.files = PKG_FILES.to_a
19
+ end
20
+
21
+ RDoc::Task.new do |rd|
22
+ rd.rdoc_files.include "README.rdoc", "lib/*.rb"
23
+ rd.options << "--inline-source"
24
+ end
25
+
26
+ Gem::PackageTask.new(spec).define
27
+
28
+ desc 'Generate the magics parser'
29
+ file "lib/magics.rb" => "magics.rl" do |t|
30
+ sh "ragel -R -o #{t.name} #{t.prerequisites.join(' ')}"
31
+ end
32
+
33
+ desc 'Generate the gemspec'
34
+ task :spec do
35
+ open("#{spec.name}.gemspec", "w") {|g| g.puts spec.to_ruby }
36
+ end
37
+
38
+ desc "Open an pry session preloaded with this library"
39
+ task :console do
40
+ require 'pry' rescue nil
41
+ console = defined?(Pry) ? :pry : :irb
42
+ sh "#{console} -rubygems -I lib -r shared-mime-info.rb"
43
+ end
@@ -0,0 +1,364 @@
1
+
2
+ # line 1 "magics.rl"
3
+ module MIME
4
+ module Magic
5
+
6
+ # line 7 "lib/magics.rb"
7
+ class << self
8
+ attr_accessor :_magic_actions
9
+ private :_magic_actions, :_magic_actions=
10
+ end
11
+ self._magic_actions = [
12
+ 0, 1, 0, 1, 1, 1, 3, 1,
13
+ 5, 1, 12, 1, 13, 2, 0, 1,
14
+ 2, 2, 6, 2, 2, 7, 2, 2,
15
+ 9, 2, 11, 12, 3, 2, 8, 4,
16
+ 3, 2, 9, 13, 3, 2, 10, 13,
17
+ 3, 12, 0, 1, 4, 11, 12, 0,
18
+ 1
19
+ ]
20
+
21
+ class << self
22
+ attr_accessor :_magic_key_offsets
23
+ private :_magic_key_offsets, :_magic_key_offsets=
24
+ end
25
+ self._magic_key_offsets = [
26
+ 0, 0, 1, 2, 3, 4, 5, 6,
27
+ 7, 8, 9, 10, 11, 12, 14, 17,
28
+ 27, 36, 46, 57, 58, 61, 64, 66,
29
+ 69, 73, 76, 78, 81, 83, 87, 88
30
+ ]
31
+
32
+ class << self
33
+ attr_accessor :_magic_trans_keys
34
+ private :_magic_trans_keys, :_magic_trans_keys=
35
+ end
36
+ self._magic_trans_keys = [
37
+ 77, 73, 77, 69, 45, 77, 97, 103,
38
+ 105, 99, 0, 10, 48, 57, 58, 48,
39
+ 57, 43, 95, 45, 46, 48, 57, 65,
40
+ 90, 97, 122, 43, 47, 95, 45, 57,
41
+ 65, 90, 97, 122, 43, 95, 45, 46,
42
+ 48, 57, 65, 90, 97, 122, 43, 93,
43
+ 95, 45, 46, 48, 57, 65, 90, 97,
44
+ 122, 10, 62, 48, 57, 62, 48, 57,
45
+ 48, 57, 61, 48, 57, 10, 38, 43,
46
+ 126, 10, 43, 126, 48, 57, 10, 48,
47
+ 57, 48, 57, 10, 43, 48, 57, 91,
48
+ 62, 91, 48, 57, 0
49
+ ]
50
+
51
+ class << self
52
+ attr_accessor :_magic_single_lengths
53
+ private :_magic_single_lengths, :_magic_single_lengths=
54
+ end
55
+ self._magic_single_lengths = [
56
+ 0, 1, 1, 1, 1, 1, 1, 1,
57
+ 1, 1, 1, 1, 1, 0, 1, 2,
58
+ 3, 2, 3, 1, 1, 1, 0, 1,
59
+ 4, 3, 0, 1, 0, 2, 1, 2
60
+ ]
61
+
62
+ class << self
63
+ attr_accessor :_magic_range_lengths
64
+ private :_magic_range_lengths, :_magic_range_lengths=
65
+ end
66
+ self._magic_range_lengths = [
67
+ 0, 0, 0, 0, 0, 0, 0, 0,
68
+ 0, 0, 0, 0, 0, 1, 1, 4,
69
+ 3, 4, 4, 0, 1, 1, 1, 1,
70
+ 0, 0, 1, 1, 1, 1, 0, 1
71
+ ]
72
+
73
+ class << self
74
+ attr_accessor :_magic_index_offsets
75
+ private :_magic_index_offsets, :_magic_index_offsets=
76
+ end
77
+ self._magic_index_offsets = [
78
+ 0, 0, 2, 4, 6, 8, 10, 12,
79
+ 14, 16, 18, 20, 22, 24, 26, 29,
80
+ 36, 43, 50, 58, 60, 63, 66, 68,
81
+ 71, 76, 80, 82, 85, 87, 91, 93
82
+ ]
83
+
84
+ class << self
85
+ attr_accessor :_magic_indicies
86
+ private :_magic_indicies, :_magic_indicies=
87
+ end
88
+ self._magic_indicies = [
89
+ 0, 1, 2, 1, 3, 1, 4, 1,
90
+ 5, 1, 6, 1, 7, 1, 8, 1,
91
+ 9, 1, 10, 1, 11, 1, 12, 1,
92
+ 13, 1, 15, 14, 1, 16, 16, 16,
93
+ 16, 16, 16, 1, 17, 18, 17, 17,
94
+ 17, 17, 1, 19, 19, 19, 19, 19,
95
+ 19, 1, 19, 20, 19, 19, 19, 19,
96
+ 19, 1, 21, 1, 23, 22, 1, 25,
97
+ 24, 1, 26, 1, 28, 27, 1, 29,
98
+ 30, 31, 32, 1, 29, 31, 32, 1,
99
+ 33, 1, 34, 35, 1, 36, 1, 37,
100
+ 38, 39, 1, 40, 1, 42, 40, 41,
101
+ 1, 0
102
+ ]
103
+
104
+ class << self
105
+ attr_accessor :_magic_trans_targs
106
+ private :_magic_trans_targs, :_magic_trans_targs=
107
+ end
108
+ self._magic_trans_targs = [
109
+ 2, 0, 3, 4, 5, 6, 7, 8,
110
+ 9, 10, 11, 12, 30, 14, 14, 15,
111
+ 16, 16, 17, 18, 19, 20, 21, 22,
112
+ 21, 22, 23, 23, 24, 31, 25, 26,
113
+ 28, 27, 31, 27, 29, 31, 26, 29,
114
+ 13, 21, 22
115
+ ]
116
+
117
+ class << self
118
+ attr_accessor :_magic_trans_actions
119
+ private :_magic_trans_actions, :_magic_trans_actions=
120
+ end
121
+ self._magic_trans_actions = [
122
+ 0, 0, 0, 0, 0, 0, 0, 0,
123
+ 0, 0, 0, 0, 0, 13, 3, 16,
124
+ 1, 0, 0, 3, 5, 0, 44, 25,
125
+ 3, 19, 13, 3, 28, 11, 7, 0,
126
+ 0, 13, 36, 3, 13, 32, 22, 3,
127
+ 0, 40, 9
128
+ ]
129
+
130
+ class << self
131
+ attr_accessor :magic_start
132
+ end
133
+ self.magic_start = 1;
134
+ class << self
135
+ attr_accessor :magic_first_final
136
+ end
137
+ self.magic_first_final = 30;
138
+ class << self
139
+ attr_accessor :magic_error
140
+ end
141
+ self.magic_error = 0;
142
+
143
+ class << self
144
+ attr_accessor :magic_en_main
145
+ end
146
+ self.magic_en_main = 1;
147
+
148
+
149
+ # line 53 "magics.rl"
150
+
151
+
152
+ def self.parse_magic( data )
153
+ magics = []
154
+ data = data.unpack("c*")
155
+
156
+
157
+ # line 158 "lib/magics.rb"
158
+ begin
159
+ p ||= 0
160
+ pe ||= data.length
161
+ cs = magic_start
162
+ end
163
+
164
+ # line 60 "magics.rl"
165
+ eof = pe
166
+
167
+ # line 168 "lib/magics.rb"
168
+ begin
169
+ _klen, _trans, _keys, _acts, _nacts = nil
170
+ _goto_level = 0
171
+ _resume = 10
172
+ _eof_trans = 15
173
+ _again = 20
174
+ _test_eof = 30
175
+ _out = 40
176
+ while true
177
+ _trigger_goto = false
178
+ if _goto_level <= 0
179
+ if p == pe
180
+ _goto_level = _test_eof
181
+ next
182
+ end
183
+ if cs == 0
184
+ _goto_level = _out
185
+ next
186
+ end
187
+ end
188
+ if _goto_level <= _resume
189
+ _keys = _magic_key_offsets[cs]
190
+ _trans = _magic_index_offsets[cs]
191
+ _klen = _magic_single_lengths[cs]
192
+ _break_match = false
193
+
194
+ begin
195
+ if _klen > 0
196
+ _lower = _keys
197
+ _upper = _keys + _klen - 1
198
+
199
+ loop do
200
+ break if _upper < _lower
201
+ _mid = _lower + ( (_upper - _lower) >> 1 )
202
+
203
+ if data[p] < _magic_trans_keys[_mid]
204
+ _upper = _mid - 1
205
+ elsif data[p] > _magic_trans_keys[_mid]
206
+ _lower = _mid + 1
207
+ else
208
+ _trans += (_mid - _keys)
209
+ _break_match = true
210
+ break
211
+ end
212
+ end # loop
213
+ break if _break_match
214
+ _keys += _klen
215
+ _trans += _klen
216
+ end
217
+ _klen = _magic_range_lengths[cs]
218
+ if _klen > 0
219
+ _lower = _keys
220
+ _upper = _keys + (_klen << 1) - 2
221
+ loop do
222
+ break if _upper < _lower
223
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1)
224
+ if data[p] < _magic_trans_keys[_mid]
225
+ _upper = _mid - 2
226
+ elsif data[p] > _magic_trans_keys[_mid+1]
227
+ _lower = _mid + 2
228
+ else
229
+ _trans += ((_mid - _keys) >> 1)
230
+ _break_match = true
231
+ break
232
+ end
233
+ end # loop
234
+ break if _break_match
235
+ _trans += _klen
236
+ end
237
+ end while false
238
+ _trans = _magic_indicies[_trans]
239
+ cs = _magic_trans_targs[_trans]
240
+ if _magic_trans_actions[_trans] != 0
241
+ _acts = _magic_trans_actions[_trans]
242
+ _nacts = _magic_actions[_acts]
243
+ _acts += 1
244
+ while _nacts > 0
245
+ _nacts -= 1
246
+ _acts += 1
247
+ case _magic_actions[_acts - 1]
248
+ when 0 then
249
+ # line 6 "magics.rl"
250
+ begin
251
+ b = p end
252
+ # line 6 "magics.rl"
253
+ when 1 then
254
+ # line 7 "magics.rl"
255
+ begin
256
+ e = data[ b .. p] end
257
+ # line 7 "magics.rl"
258
+ when 2 then
259
+ # line 8 "magics.rl"
260
+ begin
261
+ n = e.pack("c*").to_i end
262
+ # line 8 "magics.rl"
263
+ when 3 then
264
+ # line 12 "magics.rl"
265
+ begin
266
+ type = e.pack("c*") end
267
+ # line 12 "magics.rl"
268
+ when 4 then
269
+ # line 17 "magics.rl"
270
+ begin
271
+
272
+ value_length = data[p+1, 2].pack("c*").unpack('n').first
273
+ p +=2
274
+ value = data[p+1, value_length]
275
+ mask = [0xff] * value_length
276
+ p += value_length
277
+ end
278
+ # line 17 "magics.rl"
279
+ when 5 then
280
+ # line 24 "magics.rl"
281
+ begin
282
+
283
+ mask = data[p+1, value_length]
284
+ p += value_length
285
+ end
286
+ # line 24 "magics.rl"
287
+ when 6 then
288
+ # line 28 "magics.rl"
289
+ begin
290
+ priority = n end
291
+ # line 28 "magics.rl"
292
+ when 7 then
293
+ # line 29 "magics.rl"
294
+ begin
295
+ indent = n end
296
+ # line 29 "magics.rl"
297
+ when 8 then
298
+ # line 30 "magics.rl"
299
+ begin
300
+ start_offset = n end
301
+ # line 30 "magics.rl"
302
+ when 9 then
303
+ # line 31 "magics.rl"
304
+ begin
305
+ word_size = n end
306
+ # line 31 "magics.rl"
307
+ when 10 then
308
+ # line 32 "magics.rl"
309
+ begin
310
+ range_length = n end
311
+ # line 32 "magics.rl"
312
+ when 11 then
313
+ # line 33 "magics.rl"
314
+ begin
315
+ magics << RootEntry.new(type, priority) end
316
+ # line 33 "magics.rl"
317
+ when 12 then
318
+ # line 34 "magics.rl"
319
+ begin
320
+ indent = 0; word_size = 0; range_length = 1 end
321
+ # line 34 "magics.rl"
322
+ when 13 then
323
+ # line 35 "magics.rl"
324
+ begin
325
+
326
+ magics.last.add_subentry Entry.new(indent, start_offset, value_length, value, mask, word_size, range_length)
327
+ end
328
+ # line 35 "magics.rl"
329
+ # line 330 "lib/magics.rb"
330
+ end # action switch
331
+ end
332
+ end
333
+ if _trigger_goto
334
+ next
335
+ end
336
+ end
337
+ if _goto_level <= _again
338
+ if cs == 0
339
+ _goto_level = _out
340
+ next
341
+ end
342
+ p += 1
343
+ if p != pe
344
+ _goto_level = _resume
345
+ next
346
+ end
347
+ end
348
+ if _goto_level <= _test_eof
349
+ end
350
+ if _goto_level <= _out
351
+ break
352
+ end
353
+ end
354
+ end
355
+
356
+ # line 62 "magics.rl"
357
+ if cs < magic_first_final
358
+ raise BadMagic
359
+ end
360
+
361
+ magics
362
+ end
363
+ end
364
+ end
@@ -1,377 +1,145 @@
1
- # Copyright (c) 2006 Hank Lords <hanklords@gmail.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining
4
- # a copy of this software and associated documentation files (the
5
- # "Software"), to deal in the Software without restriction, including
6
- # without limitation the rights to use, copy, modify, merge, publish,
7
- # distribute, sublicense, and/or sell copies of the Software, and to
8
- # permit persons to whom the Software is furnished to do so, subject to
9
- # the following conditions:
10
- #
11
- # The above copyright notice and this permission notice shall be included in all
12
- # copies or substantial portions of the Software.
13
- #
14
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
- # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
- # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
- # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
- # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
-
22
- require 'enumerator'
23
- require 'rexml/document'
24
-
25
- # shared-mime-info is a pure Ruby library for accessing the MIME info
26
- # database provided by Freedesktop[http://freedesktop.org/] on
27
- # {Standards/shared-mime-info-spec}[http://wiki.freedesktop.org/wiki/Standards_2fshared_2dmime_2dinfo_2dspec].
28
- #
29
- # This provides a way to guess the mime type of a file by doing both
30
- # filename lookups and _magic_ file checks. This implementation tries to
31
- # follow the version 0.13 of the
32
- # specification[http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-0.13.html].
33
- module MIME
34
- VERSION = '0.1'
35
-
36
- module Magic # :nodoc: all
37
- class BadMagic < StandardError; end
38
-
39
- class RootEntry
40
- def initialize
41
- @sub_entries = []
42
- @indent = -1
43
- end
44
-
45
- def add_subentry(entry)
46
- return unless entry.indent > @indent
47
- if entry.indent == @indent + 1
48
- @sub_entries << entry
49
- elsif entry.indent > @indent + 1
50
- if @sub_entries.last.respond_to? :add_subentry
51
- @sub_entries.last.add_subentry entry
52
- else
53
- raise BadMagic
54
- end
55
- else
56
- raise BadMagic
57
- end
58
- end
59
-
60
- def check_file(f)
61
- @sub_entries.empty? || @sub_entries.any? {|e| e.check_file f}
62
- end
63
- end
64
-
65
- class Entry < RootEntry
66
- attr_reader :indent
67
- def initialize(indent, start_offset, value_length, value, mask, word_size, range_length)
68
- super()
69
- @indent = indent
70
- @start_offset = start_offset
71
- @value_length = value_length
72
- @value = value.freeze
73
- @mask = mask.freeze
74
- @word_size = word_size
75
- @range_length = range_length
76
- end
77
-
78
- def check_file(f)
79
- check_entry(f) && super(f)
80
- end
81
-
82
- private
83
- def check_entry(f)
84
- f.pos = @start_offset
85
- f.read(@value_length) == @value
86
- end
87
- end
88
-
89
- def self.parse(magic)
90
- parsed = RootEntry.new
91
- entry = magic
92
-
93
- until entry.empty?
94
- entry = entry.sub /^(\d?)>(\d+)=/, ''
95
- indent = $1.to_i
96
- start_offset = $2.to_i
97
- value_length = entry.unpack('n').first
98
- value, entry = entry.unpack("x2a#{value_length}a*")
99
-
100
- if entry[/./m] == '&'
101
- mask, entry = entry.unpack("xa#{value_length}a*")
102
- end
103
-
104
- if entry[/./m] == '~'
105
- entry =~ /^~(\d+)(.*)/m
106
- word_size = $1
107
- entry = $2
108
- end
109
-
110
- if entry[/./m] == '+'
111
- entry =~ /^\+(\d+)(.*)/m
112
- range_length = $1
113
- entry = $2
114
- end
115
- entry = entry.sub /^[^\n]*\n/m, ''
116
-
117
- parsed.add_subentry Entry.new(indent, start_offset, value_length, value, mask, word_size, range_length)
118
- end
119
-
120
- parsed
121
- end
122
- end
123
-
124
- # Type represents a single mime type such as <b>text/html</b>.
125
- class Type
126
- attr_reader :magic_priority # :nodoc:
127
-
128
- # Returns the type of a mime type as a String, such as <b>text/html</b>.
129
- attr_reader :type
130
-
131
- # Returns the media part of the type of a mime type as a string,
132
- # such as <b>text</b> for a type of <b>text/html</b>.
133
- def media; @type.split('/', 2).first; end
134
-
135
- # Returns the subtype part of the type of a mime type as a string,
136
- # such as <b>html</b> for a type of <b>text/html</b>.
137
- def subtype; @type.split('/', 2).last; end
138
-
139
- # Synonym of type.
140
- def to_s; @type; end
141
-
142
- # Returns a Hash of the comments associated with a mime type in
143
- # different languages.
144
- #
145
- # MIME.types['text/html'].default
146
- # => "HTML page"
147
- #
148
- # MIME.types['text/html'].comment['fr']
149
- # => "page HTML"
150
- def comment
151
- file = ''
152
- MIME.mime_dirs.each { |dir|
153
- file = "#{dir}/#{@type}.xml"
154
- break if File.file? file
155
- }
156
-
157
- open(file) { |f|
158
- doc = REXML::Document.new f
159
- comments = {}
160
- REXML::XPath.match(doc, '*/comment').each { |c|
161
- if att = c.attributes['xml:lang']
162
- comments[att] = c.text
163
- else
164
- comments.default = c.text
165
- end
166
- }
167
- }
168
- comments
169
- end
170
-
171
- # Returns all the types this type is a subclass of.
172
- def parents
173
- file = ''
174
- MIME.mime_dirs.each { |dir|
175
- file = "#{dir}/#{@type}.xml"
176
- break if File.file? file
177
- }
178
-
179
- open(file) { |f|
180
- doc = REXML::Document.new f
181
- REXML::XPath.match(doc, '*/sub-class-of').collect { |c|
182
- MIME[c.attributes['type']]
183
- }
184
- }
185
- end
186
-
187
- # Equality test.
188
- #
189
- # MIME['text/html'] == 'text/html'
190
- # => true
191
- def ==(type)
192
- if type.is_a? Type
193
- @type == type.type
194
- elsif type.respond_to? :to_str
195
- @type == type
196
- else
197
- false
198
- end
199
- end
200
-
201
- # Check if _filename_ is of this particular type by comparing it to
202
- # some common extensions.
203
- #
204
- # MIME.types['text/html'].match_filename? 'index.html'
205
- # => true
206
- def match_filename?(filename)
207
- @glob_patterns.any? {|pattern| File.fnmatch pattern, filename}
208
- end
209
-
210
- # Check if _file_ is of this particular type by looking for precise
211
- # patterns (_magic_ numbers) in different locations of the file.
212
- #
213
- # _file_ must be an IO object opened with read permissions.
214
- def match_file?(file)
215
- if @magic.nil?
216
- false
217
- else
218
- @magic.check_file file
219
- end
220
- end
221
-
222
- def initialize(type) # :nodoc:
223
- @type = type.freeze
224
- @glob_patterns = []
225
- end
226
-
227
- def load_magic(magic, priority) # :nodoc:
228
- @magic_priority = priority
229
- @magic = Magic.parse magic
230
- end
231
-
232
- def add_glob(glob) # :nodoc:
233
- @glob_patterns << glob.freeze
234
- end
235
- end
236
-
237
- class << self
238
- attr_reader :mime_dirs # :nodoc:
239
-
240
- # Returns the MIME::Type object corresponding to _type_.
241
- def [](type)
242
- @types.fetch type, nil
243
- end
244
-
245
- # Look for the type of a file by doing successive checks on
246
- # the filename patterns.
247
- #
248
- # Returns a MIME::Type object or _nil_ if nothing matches.
249
- def check_globs(filename)
250
- enum = Enumerable::Enumerator.new(@globs, :each_key)
251
- found = enum.select { |pattern| File.fnmatch pattern, filename }
252
-
253
- if found.empty?
254
- downcase_filename = filename.downcase
255
- found = enum.select { |pattern|
256
- File.fnmatch pattern, downcase_filename
257
- }
258
- end
259
-
260
- @globs[found.max]
261
- end
262
-
263
- # Look for the type of a file by doing successive checks on
264
- # _magic_ numbers.
265
- #
266
- # Returns a MIME::Type object or _nil_ if nothing matches.
267
- def check_magics(file)
268
- if file.respond_to? :read
269
- check_magics_with_priority(file, 0)
270
- else
271
- open(file) {|f| check_magics_with_priority(f, 0) }
272
- end
273
- end
274
-
275
- # Look for the type of a file by doing successive checks with
276
- # the filename patterns or magic numbers. If none of the matches
277
- # are successful, returns a type of <b>application/octet-stream</b> if
278
- # the file contains control characters at its beginning, or <b>text/plain</b> otherwise.
279
- #
280
- # Returns a MIME::Type object.
281
- def check(filename)
282
- check_special(filename) ||
283
- open(filename) { |f|
284
- check_magics_with_priority(f, 80) ||
285
- check_globs(filename) ||
286
- check_magics_with_priority(f, 0) ||
287
- check_default(f)
288
- }
289
- end
290
-
291
- private
292
- def check_magics_with_priority(f, priority_threshold)
293
- @magics.find { |t|
294
- break if t.magic_priority < priority_threshold
295
- t.match_file? f
296
- }
297
- end
298
-
299
- def check_special(filename)
300
- case File.ftype(filename)
301
- when 'directory' then @types['inode/directory']
302
- when 'characterSpecial' then @types['inode/chardevice']
303
- when 'blockSpecial' then @types['inode/blockdevice']
304
- when 'fifo' then @types['inode/fifo']
305
- when 'socket' then @types['inode/socket']
306
- else
307
- nil
308
- end
309
- end
310
-
311
- def check_default(f)
312
- f.pos = 0
313
- firsts = f.read(32) || ''
314
- bytes = firsts.unpack('C*')
315
- if bytes.any? {|byte| byte < 32 && ![9, 10, 13].include?(byte) }
316
- @types['application/octet-stream']
317
- else
318
- @types['text/plain']
319
- end
320
- end
321
-
322
- def load_globs(file)
323
- open(file) { |f|
324
- f.each { |line|
325
- next if line =~ /^#/
326
- cline = line.chomp
327
- type, pattern = cline.split ':', 2
328
- @types[type].add_glob pattern
329
- @globs[pattern] = @types[type] unless @globs.has_key? pattern
330
- }
331
- }
332
- end
333
-
334
- def load_magic(file)
335
- open(file) { |f|
336
- raise 'Bad magic file' if f.readline != "MIME-Magic\0\n"
337
-
338
- f.gets =~ /^\[(\d\d):(.+)\]/
339
- priority = $1.to_i
340
- type = $2
341
- buf =''
342
-
343
- f.each { |line|
344
- if line =~ /^\[(\d\d):(.+)\]/
345
- @types[type].load_magic buf, priority
346
- @magics << @types[type]
347
-
348
- priority = $1.to_i
349
- type = $2
350
- buf = ''
351
- else
352
- buf << line
353
- end
354
- }
355
- }
356
- end
357
- end
358
-
359
- xdg_data_home = ENV['XDG_DATA_HOME'] || "#{ENV['HOME']}/.local/share"
360
- xdg_data_dirs = ENV['XDG_DATA_DIRS'] || "/usr/local/share/:/usr/share"
361
-
362
- @mime_dirs = (xdg_data_home + ':' + xdg_data_dirs).split(':').collect { |dir|
363
- "#{dir}/mime"
364
- }
365
-
366
- @types = Hash.new {|h,k| h[k] = Type.new(k)}
367
- @magics = []
368
- @globs = {}
369
-
370
- @mime_dirs.each {|dir|
371
- glob_file = "#{dir}/globs"
372
- load_globs glob_file if File.file? glob_file
373
-
374
- magic_file = "#{dir}/magic"
375
- load_magic magic_file if File.file? magic_file
376
- }
377
- end
1
+ # Copyright (c) 2006 Mael Clerambault <mael@clerambault.fr>
2
+ #
3
+ # Permission to use, copy, modify, and distribute this software for any
4
+ # purpose with or without fee is hereby granted, provided that the above
5
+ # copyright notice and this permission notice appear in all copies.
6
+ #
7
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
+
15
+ require 'shared-mime-info/magic'
16
+ require 'shared-mime-info/type'
17
+ require 'shared-mime-info/version'
18
+
19
+ # This provides a way to guess the mime type of a file by doing both
20
+ # filename lookups and _magic_ file checks. This implementation tries to
21
+ # follow the version 0.13 of the
22
+ # specification[http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-0.13.html].
23
+ module MIME
24
+ class << self
25
+ attr_reader :mime_dirs # :nodoc:
26
+
27
+ # Returns the MIME::Type object corresponding to _type_.
28
+ def [](type)
29
+ @types.fetch type, nil
30
+ end
31
+
32
+ # Look for the type of a file by doing successive checks on
33
+ # the filename patterns.
34
+ #
35
+ # Returns a MIME::Type object or _nil_ if nothing matches.
36
+ def check_globs(filename)
37
+ basename = File.basename(filename)
38
+ found = @globs.each_key.select { |pattern| File.fnmatch pattern, basename }
39
+
40
+ if found.empty?
41
+ downcase_basename = basename.downcase
42
+ found = @globs.each_key.select { |pattern|
43
+ File.fnmatch pattern, downcase_basename
44
+ }
45
+ end
46
+
47
+ @globs[found.max]
48
+ end
49
+
50
+ # Look for the type of a file by doing successive checks on
51
+ # _magic_ numbers.
52
+ #
53
+ # Returns a MIME::Type object or _nil_ if nothing matches.
54
+ def check_magics(file)
55
+ if file.respond_to? :read
56
+ check_magics_type(file, @magics)
57
+ else
58
+ open(file) {|f| check_magics_type(f, @magics) }
59
+ end
60
+ end
61
+
62
+ # Look for the type of a file by doing successive checks with
63
+ # the filename patterns or magic numbers. If none of the matches
64
+ # are successful, returns a type of <b>application/octet-stream</b> if
65
+ # the file contains control characters at its beginning, or <b>text/plain</b> otherwise.
66
+ #
67
+ # Returns a MIME::Type object.
68
+ def check(filename)
69
+ check_special(filename) ||
70
+ open(filename) { |f|
71
+ check_magics_gt80(f) ||
72
+ check_globs(filename) ||
73
+ check_magics_lt80(f) ||
74
+ check_default(f)
75
+ }
76
+ end
77
+
78
+ private
79
+ def check_magics_type(f, set); c = set.find {|m| m =~ f} and MIME[c.type] end
80
+ def check_magics_gt80(f); check_magics_type(f, @magics_gt80) end
81
+ def check_magics_lt80(f); check_magics_type(f, @magics_lt80) end
82
+
83
+ def check_special(filename)
84
+ case File.ftype(filename)
85
+ when 'directory' then @types['inode/directory']
86
+ when 'characterSpecial' then @types['inode/chardevice']
87
+ when 'blockSpecial' then @types['inode/blockdevice']
88
+ when 'fifo' then @types['inode/fifo']
89
+ when 'socket' then @types['inode/socket']
90
+ else
91
+ nil
92
+ end
93
+ end
94
+
95
+ def check_default(f)
96
+ f.pos = 0
97
+ firsts = f.read(32) || ''
98
+ bytes = firsts.unpack('C*')
99
+ if bytes.any? {|byte| byte < 32 && ![9, 10, 13].include?(byte) }
100
+ @types['application/octet-stream']
101
+ else
102
+ @types['text/plain']
103
+ end
104
+ end
105
+
106
+ def load_globs(file)
107
+ open(file) { |f|
108
+ f.each { |line|
109
+ next if line =~ /^#/
110
+ cline = line.chomp
111
+ type, pattern = cline.split ':', 2
112
+ @types[type].glob_patterns << pattern
113
+ @globs[pattern] = @types[type] unless @globs.has_key? pattern
114
+ }
115
+ }
116
+ end
117
+
118
+ def load_magic(file)
119
+ @magics.concat Magic.parse_magic(File.read(file))
120
+ end
121
+ end
122
+
123
+ xdg_data_home = ENV['XDG_DATA_HOME'] || "#{ENV['HOME']}/.local/share"
124
+ xdg_data_dirs = ENV['XDG_DATA_DIRS'] || "/usr/local/share:/usr/share"
125
+
126
+ @mime_dirs = (xdg_data_home + ':' + xdg_data_dirs).split(':').collect { |dir|
127
+ "#{dir}/mime"
128
+ }
129
+
130
+ @types = Hash.new {|h,k| h[k] = Type.new(k)}
131
+ @magics = []
132
+ @globs = {}
133
+
134
+ @mime_dirs.each {|dir|
135
+ glob_file = "#{dir}/globs"
136
+ load_globs glob_file if File.file? glob_file
137
+
138
+ magic_file = "#{dir}/magic"
139
+ load_magic magic_file if File.file? magic_file
140
+ }
141
+
142
+ @magics.sort! {|a,b| b.priority <=> a.priority}
143
+ @magics.each {|m| @types[m.type].magics << m}
144
+ @magics_gt80, @magics_lt80 = @magics.partition {|m| m.priority >= 80}
145
+ end
@@ -0,0 +1,79 @@
1
+ # Copyright (c) 2006 Mael Clerambault <mael@clerambault.fr>
2
+ #
3
+ # Permission to use, copy, modify, and distribute this software for any
4
+ # purpose with or without fee is hereby granted, provided that the above
5
+ # copyright notice and this permission notice appear in all copies.
6
+ #
7
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
+
15
+ require 'magics'
16
+
17
+ module MIME
18
+ module Magic # :nodoc: all
19
+ class BadMagic < StandardError; end
20
+
21
+ class Entry
22
+ attr_reader :indent
23
+ def initialize(indent, start_offset, value_length, value, mask, word_size, range_length)
24
+ @indent = indent
25
+ @start_offset = start_offset
26
+ @value_length = value_length
27
+ @value = value.freeze
28
+ @mask = mask.freeze
29
+ @word_size = word_size
30
+ @range_length = range_length
31
+ @sub_entries = []
32
+ end
33
+
34
+ def add_subentry(entry)
35
+ if entry.indent == @indent + 1
36
+ @sub_entries << entry
37
+ elsif entry.indent > @indent + 1
38
+ if not @sub_entries.empty?
39
+ @sub_entries.last.add_subentry entry
40
+ else
41
+ raise BadMagic
42
+ end
43
+ else
44
+ raise BadMagic
45
+ end
46
+ end
47
+
48
+ def =~(f)
49
+ check_file(f) and (@sub_entries.empty? || @sub_entries.any? {|e| e =~ f})
50
+ end
51
+
52
+ private
53
+ def check_file(f)
54
+ f.pos = @start_offset
55
+ r = (f.read(@value_length + @range_length -1)|| '').unpack("c*")
56
+ range_length = 0
57
+ found = false
58
+ while not found and range_length < r.size
59
+ found = @value.zip(@mask, r[range_length, @value_length]).all? {|vb, mb, rb| (rb & mb) == (vb & mb) }
60
+ range_length = range_length + 1
61
+ end
62
+ found
63
+ end
64
+ end
65
+
66
+ class RootEntry < Entry
67
+ attr_reader :priority, :type
68
+ def initialize(type, priority)
69
+ @indent = -1
70
+ @type = type
71
+ @priority = priority
72
+ @sub_entries = []
73
+ end
74
+
75
+ private
76
+ def check_file(*args) true end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,96 @@
1
+ # Copyright (c) 2006 Mael Clerambault <mael@clerambault.fr>
2
+ #
3
+ # Permission to use, copy, modify, and distribute this software for any
4
+ # purpose with or without fee is hereby granted, provided that the above
5
+ # copyright notice and this permission notice appear in all copies.
6
+ #
7
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
+
15
+ require 'rexml/document'
16
+ require 'mime/types'
17
+
18
+ module MIME
19
+ # Override the existing MIME::Type class
20
+ OriginalType = Type
21
+ MIME.send(:remove_const, :Type)
22
+
23
+ # Type represents a single mime type such as <b>text/html</b>.
24
+ class Type < OriginalType
25
+ attr_reader :magics, :glob_patterns
26
+
27
+ def initialize(content_type) # :nodoc:
28
+ @glob_patterns = []
29
+ @magics = []
30
+ super
31
+ end
32
+
33
+ # Returns a Hash of the comments associated with a mime type in
34
+ # different languages.
35
+ #
36
+ # MIME['text/html'].comment.default
37
+ # => "HTML page"
38
+ #
39
+ # MIME['text/html'].comment['fr']
40
+ # => "page HTML"
41
+ def comment
42
+ file = ''
43
+ MIME.mime_dirs.each { |dir|
44
+ file = "#{dir}/#{content_type}.xml"
45
+ break if File.file? file
46
+ }
47
+
48
+ comments = {}
49
+ open(file) { |f|
50
+ doc = REXML::Document.new f
51
+ REXML::XPath.match(doc, '*/comment').each { |c|
52
+ if att = c.attributes['xml:lang']
53
+ comments[att] = c.text
54
+ else
55
+ comments.default = c.text
56
+ end
57
+ }
58
+ }
59
+ comments
60
+ end
61
+
62
+ # Returns all the types this type is a subclass of.
63
+ def parents
64
+ file = ''
65
+ MIME.mime_dirs.each { |dir|
66
+ file = "#{dir}/#{content_type}.xml"
67
+ break if File.file? file
68
+ }
69
+
70
+ open(file) { |f|
71
+ doc = REXML::Document.new f
72
+ REXML::XPath.match(doc, '*/sub-class-of').collect { |c|
73
+ MIME[c.attributes['type']]
74
+ }
75
+ }
76
+ end
77
+
78
+ # Check if _filename_ is of this particular type by comparing it to
79
+ # some common extensions.
80
+ #
81
+ # MIME['text/html'].match_filename? 'index.html'
82
+ # => true
83
+ def matches_filename?(filename)
84
+ basename = File.basename(filename)
85
+ @glob_patterns.any? {|pattern| File.fnmatch pattern, basename.downcase}
86
+ end
87
+
88
+ # Check if _file_ is of this particular type by looking for precise
89
+ # patterns (_magic_ numbers) in different locations of the file.
90
+ #
91
+ # _file_ must be an IO object opened with read permissions.
92
+ def matches_file?(f)
93
+ @magics.any? {|m| m =~ f }
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,3 @@
1
+ module SharedMimeInfo
2
+ VERSION = "0.2.5"
3
+ end
metadata CHANGED
@@ -1,47 +1,53 @@
1
- --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.11
3
- specification_version: 1
1
+ --- !ruby/object:Gem::Specification
4
2
  name: shared-mime-info
5
- version: !ruby/object:Gem::Version
6
- version: "0.1"
7
- date: 2006-09-24 00:00:00 +02:00
8
- summary: Library to guess the MIME type of a file with both filename lookup and magic file detection
9
- require_paths:
10
- - lib
11
- email: hanklords@gmail.com
12
- homepage:
13
- rubyforge_project:
14
- description:
15
- autorequire: rake
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">"
22
- - !ruby/object:Gem::Version
23
- version: 0.0.0
24
- version:
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.5
25
5
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- authors:
29
- - Hank Lords
30
- files:
31
- - lib/shared-mime-info.rb
32
- - rakefile
33
- - copying.txt
34
- test_files: []
35
-
36
- rdoc_options: []
37
-
38
- extra_rdoc_files: []
39
-
6
+ authors:
7
+ - Mael Clerambault
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-02 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: shared-mime-info is a pure Ruby library for accessing the MIME info database
14
+ provided by Freedesktop
15
+ email: mael@clerambault.fr
40
16
  executables: []
41
-
42
17
  extensions: []
43
-
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/magics.rb
21
+ - lib/shared-mime-info.rb
22
+ - lib/shared-mime-info/magic.rb
23
+ - lib/shared-mime-info/type.rb
24
+ - lib/shared-mime-info/version.rb
25
+ - Rakefile
26
+ - LICENSE
27
+ - README.rdoc
28
+ homepage: http://shared-mime.rubyforge.org/
29
+ licenses:
30
+ - Public Domain
31
+ metadata: {}
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
44
46
  requirements: []
45
-
46
- dependencies: []
47
-
47
+ rubyforge_project:
48
+ rubygems_version: 2.0.3
49
+ signing_key:
50
+ specification_version: 4
51
+ summary: Library to guess the MIME type of a file with both filename lookup and magic
52
+ file detection
53
+ test_files: []
@@ -1,20 +0,0 @@
1
- Copyright (c) 2006 Hank Lords <hanklords@gmail.com>
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be included in all
12
- copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/rakefile DELETED
@@ -1,30 +0,0 @@
1
- require 'rake/rdoctask'
2
- require 'rake/packagetask'
3
- require 'rake/gempackagetask'
4
-
5
- require 'lib/shared-mime-info'
6
-
7
- PKG_FILES = FileList["lib/*.rb", "rakefile", "copying.txt"].to_a
8
-
9
- spec = Gem::Specification.new do |s|
10
- s.summary = "Library to guess the MIME type of a file with both filename lookup and magic file detection"
11
- s.name = "shared-mime-info"
12
- s.author = "Hank Lords"
13
- s.email = "hanklords@gmail.com"
14
- s.version = MIME::VERSION
15
- s.has_rdoc = true
16
- s.require_path = 'lib'
17
- s.autorequire = 'rake'
18
- s.files = PKG_FILES
19
- # s.description = ""
20
- end
21
-
22
- Rake::RDocTask.new do |rd|
23
- rd.rdoc_files.include "lib/*.rb"
24
- rd.options << "--inline-source"
25
- rd.main = "MIME"
26
- end
27
-
28
- Rake::GemPackageTask.new spec do |p|
29
- p.need_tar_gz = true
30
- end