content_type 1.1.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.
@@ -0,0 +1,38 @@
1
+ require 'rake'
2
+ require 'spec'
3
+ require 'spec/rake/spectask'
4
+
5
+ require 'vendor/gems/environment'
6
+
7
+ task :default => [:clean, :make, :spec]
8
+
9
+ task :make do
10
+ Dir.chdir 'ext' do
11
+ puts `ruby extconf.rb`
12
+ puts `make`
13
+ end
14
+ end
15
+
16
+ Spec::Rake::SpecTask.new(:spec) do |t|
17
+ t.spec_opts = %w(-fs -c)
18
+ t.spec_files = FileList['spec/*_spec.rb']
19
+ end
20
+
21
+ task :clean do
22
+ `rm -r *.o *.so *.bundle conftest.dSYM 2>/dev/null`
23
+ end
24
+
25
+ require 'jeweler'
26
+ Jeweler::Tasks.new do |s|
27
+ s.name = 'content_type'
28
+ s.summary = 'libmagic bindings to quickly determine content type of files'
29
+ s.email = 'dsturnbull@me.com'
30
+ s.homepage = 'http://github.com/dsturnbull/content_type'
31
+ s.description =<<-eod
32
+ Provides ContentType#content_type, File#content_type and
33
+ File::content_type methods to determine mime type
34
+ eod
35
+ s.executables = []
36
+ s.authors = ['David Turnbull']
37
+ s.files = ['Rakefile', 'ext/content_type.c', 'ext/extconf.rb']
38
+ end
@@ -0,0 +1,117 @@
1
+ #include "ruby.h"
2
+ #include <magic.h>
3
+ #include <stdio.h>
4
+ #include <sys/stat.h>
5
+
6
+ #define MAGIC_OPTIONS MAGIC_SYMLINK | MAGIC_MIME_TYPE | MAGIC_PRESERVE_ATIME
7
+
8
+ VALUE content_type = Qnil;
9
+ VALUE content_type_initialize(VALUE self, VALUE path);
10
+ VALUE content_type_content_type(VALUE self);
11
+
12
+ VALUE file_content_type_wrap(VALUE self, VALUE path);
13
+ VALUE file_content_type(VALUE self);
14
+ VALUE file_singleton_content_type(VALUE self, VALUE path);
15
+
16
+ void magic_fail(const char *error);
17
+
18
+ void
19
+ Init_content_type()
20
+ {
21
+ // class definition
22
+ content_type = rb_define_class("ContentType", rb_cObject);
23
+
24
+ // instance methods
25
+ rb_define_method(content_type, "initialize", content_type_initialize, 1);
26
+ rb_define_method(content_type, "content_type", content_type_content_type, 0);
27
+
28
+ // instance attributes
29
+ rb_define_attr(content_type, "filepath", 1, 0);
30
+ rb_define_attr(content_type, "processed", 1, 0);
31
+
32
+ // hax on File
33
+ rb_define_method(rb_cFile,
34
+ "content_type", file_content_type, 0);
35
+ rb_define_singleton_method(rb_cFile,
36
+ "content_type", file_singleton_content_type, 1);
37
+ }
38
+
39
+ VALUE
40
+ content_type_initialize(VALUE self, VALUE path)
41
+ {
42
+ struct stat st;
43
+
44
+ SafeStringValue(path);
45
+
46
+ if ((stat(RSTRING_PTR(path), &st)) != 0)
47
+ rb_raise(rb_const_get(rb_cObject, rb_intern("ArgumentError")),
48
+ "invalid file");
49
+
50
+ rb_iv_set(self, "@content_type", rb_str_new("", 0));
51
+ rb_iv_set(self, "@filepath", path);
52
+ rb_iv_set(self, "@processed", Qfalse);
53
+
54
+ return self;
55
+ }
56
+
57
+ VALUE
58
+ content_type_content_type(VALUE self)
59
+ {
60
+ VALUE ct;
61
+ struct magic_set *mh;
62
+ const char *mime;
63
+
64
+ if (rb_iv_get(self, "@processed"))
65
+ return rb_iv_get(self, "@content_type");
66
+
67
+ if (!(mh = magic_open(MAGIC_OPTIONS)))
68
+ magic_fail("open");
69
+
70
+ if ((magic_load(mh, NULL)) != 0)
71
+ magic_fail("load");
72
+
73
+ if (!(mime = magic_file(mh, RSTRING_PTR(rb_iv_get(self, "@filepath")))))
74
+ magic_fail("file");
75
+
76
+ ct = rb_str_new(mime, strlen(mime));
77
+ rb_iv_set(self, "@content_type", ct);
78
+ rb_iv_set(self, "@processed", Qtrue);
79
+ magic_close(mh);
80
+
81
+ return ct;
82
+ }
83
+
84
+ VALUE
85
+ file_content_type_wrap(VALUE self, VALUE path)
86
+ {
87
+ VALUE ct, mime, args[1];
88
+
89
+ SafeStringValue(path);
90
+ args[0] = path;
91
+ ct = rb_class_new_instance(1, args, content_type);
92
+
93
+ return rb_funcall(ct, rb_intern("content_type"), 0);
94
+ }
95
+
96
+ VALUE
97
+ file_content_type(VALUE self)
98
+ {
99
+ return file_content_type_wrap(self, rb_funcall(self, rb_intern("path"), 0));
100
+ }
101
+
102
+ VALUE
103
+ file_singleton_content_type(VALUE self, VALUE path)
104
+ {
105
+ return file_content_type_wrap(self, path);
106
+ }
107
+
108
+ void
109
+ magic_fail(const char *error)
110
+ {
111
+ const char *format = "magic_%s() error";
112
+ char *error_message;
113
+
114
+ error_message = malloc(sizeof(char *) * (strlen(format) + strlen(error)));
115
+ sprintf((char *)error_message, format, error);
116
+ rb_raise(rb_const_get(rb_cObject, rb_intern("RuntimeError")), error_message);
117
+ }
@@ -0,0 +1,8 @@
1
+ require 'mkmf'
2
+ extension_name = 'content_type'
3
+ dir_config(extension_name)
4
+
5
+ find_header('magic.h', '/opt/local/include')
6
+ find_library('magic', 'magic_open', '/opt/local/lib')
7
+
8
+ create_makefile(extension_name)
@@ -0,0 +1,83 @@
1
+ require 'rubygems'
2
+ require 'should_be_faster'
3
+ require 'tempfile'
4
+ require 'ext/content_type'
5
+
6
+ describe ContentType do
7
+ before do
8
+ @img = 'spec/fixtures/grindewald.jpg'
9
+ @pdf = 'spec/fixtures/pdftest.pdf'
10
+ @lzm = 'spec/fixtures/compressed.jpg.lz'
11
+ end
12
+
13
+ context 'initialising' do
14
+ it 'should take a file path' do
15
+ path = @img
16
+ ct = ContentType.new(path)
17
+ ct.filepath.should == path
18
+ end
19
+
20
+ it 'should check that the file exists' do
21
+ lambda {
22
+ ct = ContentType.new('poopstain')
23
+ }.should raise_error ArgumentError
24
+ end
25
+
26
+ it 'should memoize the content type' do
27
+ ct = ContentType.new(@img)
28
+ lambda {
29
+ ct.content_type.should == 'image/jpeg'
30
+ }.should change(ct, :processed).to(true)
31
+ end
32
+ end
33
+
34
+ context 'detecting mime type' do
35
+ it 'should detect images' do
36
+ ct = ContentType.new(@img)
37
+ ct.content_type.should == 'image/jpeg'
38
+ end
39
+
40
+ it 'should detect pdfs' do
41
+ ct = ContentType.new(@pdf)
42
+ ct.content_type.should == 'application/pdf'
43
+ end
44
+
45
+ it 'should detect lzma files' do
46
+ ct = ContentType.new(@lzm)
47
+ ct.content_type.should == 'application/x-lzip'
48
+ end
49
+ end
50
+
51
+ context 'comparing with shelling out' do
52
+ it 'should be much faster' do
53
+ shell = lambda { `file -i #{@img}` }
54
+ ext = lambda { ContentType.new(@img).content_type }
55
+ ext.should be_at_least(5).times.faster_than(shell)
56
+ end
57
+
58
+ it 'should slower to reinstantiate' do
59
+ @ct = ContentType.new(@img)
60
+ memo = lambda { @ct.content_type }
61
+ kgo = lambda { ContentType.new(@img).content_type }
62
+ kgo.should be_at_least(5).times.slower_than(memo, :iterations => 1000)
63
+ end
64
+ end
65
+
66
+ context 'when using the file class methods' do
67
+ it 'should have File.content_type(path)' do
68
+ File.content_type(@img).should == 'image/jpeg'
69
+ end
70
+
71
+ it 'should have File#content_type' do
72
+ File.open(@img).content_type.should == 'image/jpeg'
73
+ end
74
+
75
+ it 'should make it into tempfile' do
76
+ t = Tempfile.new('hi')
77
+ t.content_type.should == 'application/x-empty'
78
+ t << File.read(@img)
79
+ t.content_type.should == 'image/jpeg'
80
+ File.unlink(t.path)
81
+ end
82
+ end
83
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: content_type
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 1
8
+ - 0
9
+ version: 1.1.0
10
+ platform: ruby
11
+ authors:
12
+ - David Turnbull
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-16 00:00:00 +11:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: " Provides ContentType#content_type, File#content_type and\n File::content_type methods to determine mime type\n"
22
+ email: dsturnbull@me.com
23
+ executables: []
24
+
25
+ extensions:
26
+ - ext/extconf.rb
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - Rakefile
31
+ - ext/content_type.c
32
+ - ext/extconf.rb
33
+ has_rdoc: true
34
+ homepage: http://github.com/dsturnbull/content_type
35
+ licenses: []
36
+
37
+ post_install_message:
38
+ rdoc_options:
39
+ - --charset=UTF-8
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ requirements: []
57
+
58
+ rubyforge_project:
59
+ rubygems_version: 1.3.6
60
+ signing_key:
61
+ specification_version: 3
62
+ summary: libmagic bindings to quickly determine content type of files
63
+ test_files:
64
+ - spec/content_type_spec.rb