magic-paperclip 0.0.1

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,5 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ test/debug.log
5
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in paperclip-filemagic.gemspec
4
+ gemspec
@@ -0,0 +1,74 @@
1
+ # MagicPaperclip
2
+
3
+ [Paperclip] is a wonderful module by Thoughtbot that lets makes handling
4
+ attachments in Rails a breeze, except for one minor niggle - file types. It
5
+ relies on the content type header sent by the browser which is woefully
6
+ inconsistent. For example, when uploading a zip the possible values sent
7
+ for content type are:
8
+
9
+ + '`application/octet-stream`'
10
+ + '`application/x-zip-compressed`'
11
+ + '`application/zip`'
12
+ + '' (yes empty)
13
+
14
+ In short you can't rely on Content-Type from the browser to ever have a
15
+ sensible value.
16
+
17
+ Thus the purpose of this module: it uses the wonderful
18
+ [libmagic](http://www.darwinsys.com/file/) to work out the file type based
19
+ on the contents of the uploaded file without shelling out to `file` to do its
20
+ work.
21
+
22
+ # Requirements
23
+
24
+ The ruby-filemagic gem (which this gem uses) depends upon `libmagic` must be
25
+ installed to give us file type detection. On Linux this means installing the
26
+ relevant package:
27
+
28
+ sudo apt-get install libmagic-dev # Deb
29
+ sudo yum install file-devel # rpm
30
+ sudo emerge file # gentoo
31
+
32
+ On OSX ships with the `file` binary but not the `libmagic` shared library so I
33
+ recommend installing it via [homebrew]:
34
+
35
+ brew install libmagic
36
+ # Since this will be in a non-standard place we need to build ruby-filemagic specially
37
+ gem install ruby-filemagic -- --with-opt-dir=$(brew list libmagic | head -n1 | xargs dirname)
38
+
39
+ # Installation
40
+
41
+ Include the gem in your Gemfile:
42
+
43
+ gem 'magic-paperclip'
44
+
45
+ # Usage
46
+
47
+ Its all automatic - magic-paperclip does its trick by just being in the
48
+ Gemfile (via a Railtie).
49
+
50
+ When a Paperclip attachment is assigned to its content_type will be detected
51
+ and will overwrite what the browser sends.
52
+
53
+ # Caveats/Bugs
54
+
55
+ libmagic often returns charset info or similar for files (i.e. `text/plain;
56
+ charset=us-asci`) that this module attempts to remove to use just the base
57
+ type. Supposedly older versions of libmagic might return this in a
58
+ different format and thus not get removed. If you find an example of this
59
+ happening please let me know.
60
+
61
+ # Credits & License
62
+
63
+ ![digiresults](https://www.digiresults.com/stylesheets/images/logo_white.png)
64
+
65
+ This gem was developed for use at [DigiResults] and pulled out into a reusable gem.
66
+
67
+ Released under the [MIT License][MIT]
68
+
69
+ Copyright (c) 2011, Ash Berlin and DigiResults Ltd.
70
+
71
+ [Paperclip]: http://github.com/thoughtbot/paperclip
72
+ [homebrew]: http://mxcl.github.com/homebrew/
73
+ [MIT]: http://creativecommons.org/licenses/MIT/
74
+ [DigiResults]: http://www.digiresults.com/
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+ require 'rake/testtask'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ task :default => :test
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << 'lib' << 'test'
9
+ t.pattern = 'test/**/*_test.rb'
10
+ end
@@ -0,0 +1,48 @@
1
+ # Released under MIT License
2
+ # Copyright (c) 2011 Ash Berlin and DigiResults Ltd.
3
+
4
+ require 'filemagic'
5
+ require 'paperclip'
6
+
7
+ require 'magic-paperclip/railtie'
8
+
9
+ module Paperclip
10
+ def self.magic_content_type!
11
+ Attachment.send :include, MagicPaperclip
12
+ end
13
+ end
14
+
15
+ module MagicPaperclip
16
+ def self.included( base )
17
+ base.class_eval do
18
+ alias_method :assign_without_filemagic, :assign
19
+ alias_method :assign, :assign_with_filemagic
20
+ end
21
+ end
22
+
23
+ def assign_with_filemagic( uploaded_file )
24
+ # Call next method up the chain
25
+ val = assign_without_filemagic( uploaded_file )
26
+
27
+ return val if uploaded_file.is_a?( Paperclip::Attachment )
28
+
29
+ if uploaded_file
30
+ magic = FileMagic.new( FileMagic::MAGIC_MIME )
31
+
32
+ if defined?( StringIO ) && uploaded_file.is_a?( StringIO )
33
+ type = magic.buffer( uploaded_file.string )
34
+ else
35
+ type = magic.file( uploaded_file.path )
36
+ end
37
+
38
+ # Remove the '; charset=us-ascii' from the end if there is one
39
+ type.sub! /\s*;.*$/, ''
40
+
41
+ instance_write( :content_type, type )
42
+ end
43
+ val
44
+ ensure
45
+ magic.close if magic
46
+ end
47
+
48
+ end
@@ -0,0 +1,12 @@
1
+ require 'magic-paperclip'
2
+
3
+ module MagicPaperclip
4
+ if defined? Rails::Railtie
5
+ require 'rails'
6
+ class Railtie < Rails::Railtie
7
+ initializer 'magic-paperclip' do
8
+ Paperclip.magic_content_type!
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module MagicPaperclip
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "magic-paperclip/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "magic-paperclip"
7
+ s.version = MagicPaperclip::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ash Berlin"]
10
+ s.email = ["ash.berlin@gmail.com"]
11
+ s.homepage = "https://github.com/DigiResults/magic-paperclip"
12
+ s.summary = %q{Filemagic based mimetype detection for Paperclip}
13
+ s.description = %q{Adds better (a.k.a magic) file type detection support into Thoughtbot's Paperclip}
14
+
15
+ #s.rubyforge_project = "paperclip-filemagic"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency 'ruby-filemagic'
23
+ s.add_dependency 'paperclip'
24
+
25
+ s.add_development_dependency 'mocha'
26
+ s.add_development_dependency 'shoulda'
27
+ s.add_development_dependency 'sqlite3-ruby'
28
+ end
@@ -0,0 +1,39 @@
1
+ require 'helper'
2
+
3
+ class ContentTypeTest < Test::Unit::TestCase
4
+ context "Assigning a StringIO attachment" do
5
+ setup do
6
+ rebuild_model
7
+ @file = StringIO.new("abc")
8
+ @file.stubs(:original_filename).returns("5k.png\n\n")
9
+ @file.stubs(:content_type).returns("image/png\n\n")
10
+ @file.stubs(:to_tempfile).returns(@file)
11
+ @dummy = Dummy.new
12
+ @dummy.avatar = @file
13
+ end
14
+
15
+ should "set content_type based on file magic" do
16
+ assert_equal "text/plain", @dummy.avatar.content_type
17
+ assert_equal "text/plain", @dummy.avatar_content_type
18
+ end
19
+ end
20
+
21
+ context "Assigning a ZIP upfile attachment" do
22
+ setup do
23
+ rebuild_model
24
+ @file = File.new File.join( FIXTURES_DIR, 'zip_file_called.txt' )
25
+ class << @file
26
+ include Paperclip::Upfile
27
+ end
28
+
29
+ @file.stubs(:content_type).returns("") # Some versions of chrome do this
30
+ @dummy = Dummy.new
31
+ @dummy.avatar = @file
32
+ end
33
+
34
+ should "set content_type based on file magic" do
35
+ assert_equal "application/zip", @dummy.avatar.content_type
36
+ assert_equal "application/zip", @dummy.avatar_content_type
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: ":memory:"
@@ -0,0 +1,42 @@
1
+ # Copied from Paperclip's own test suite
2
+
3
+ require 'active_record'
4
+ require 'mocha'
5
+ require 'shoulda'
6
+ require 'test/unit'
7
+
8
+ require 'magic-paperclip'
9
+
10
+ Paperclip.magic_content_type!
11
+
12
+ FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
13
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
14
+ ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(File.dirname(__FILE__) + "/debug.log")
15
+ ActiveRecord::Base.establish_connection(config['test'])
16
+
17
+
18
+ class Dummy
19
+ end
20
+
21
+ def rebuild_model options = {}
22
+ ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
23
+ table.column :other, :string
24
+ table.column :avatar_file_name, :string
25
+ table.column :avatar_content_type, :string
26
+ table.column :avatar_file_size, :integer
27
+ table.column :avatar_updated_at, :datetime
28
+ table.column :avatar_fingerprint, :string
29
+ end
30
+ rebuild_class options
31
+ end
32
+
33
+ def rebuild_class options = {}
34
+ ActiveRecord::Base.send(:include, Paperclip::Glue)
35
+ Object.send(:remove_const, "Dummy") rescue nil
36
+ Object.const_set("Dummy", Class.new(ActiveRecord::Base))
37
+ Dummy.class_eval do
38
+ include Paperclip::Glue
39
+ has_attached_file :avatar, options
40
+ end
41
+ end
42
+
metadata ADDED
@@ -0,0 +1,125 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: magic-paperclip
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Ash Berlin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-08-01 00:00:00 +01:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: ruby-filemagic
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: paperclip
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: "0"
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: mocha
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: shoulda
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ type: :development
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: sqlite3-ruby
62
+ prerelease: false
63
+ requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ type: :development
70
+ version_requirements: *id005
71
+ description: Adds better (a.k.a magic) file type detection support into Thoughtbot's Paperclip
72
+ email:
73
+ - ash.berlin@gmail.com
74
+ executables: []
75
+
76
+ extensions: []
77
+
78
+ extra_rdoc_files: []
79
+
80
+ files:
81
+ - .gitignore
82
+ - Gemfile
83
+ - README.markdown
84
+ - Rakefile
85
+ - lib/magic-paperclip.rb
86
+ - lib/magic-paperclip/railtie.rb
87
+ - lib/magic-paperclip/version.rb
88
+ - magic-paperlcip.gemspec
89
+ - test/content_type_test.rb
90
+ - test/database.yml
91
+ - test/fixtures/zip_file_called.txt
92
+ - test/helper.rb
93
+ has_rdoc: true
94
+ homepage: https://github.com/DigiResults/magic-paperclip
95
+ licenses: []
96
+
97
+ post_install_message:
98
+ rdoc_options: []
99
+
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: "0"
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: "0"
114
+ requirements: []
115
+
116
+ rubyforge_project:
117
+ rubygems_version: 1.6.1
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: Filemagic based mimetype detection for Paperclip
121
+ test_files:
122
+ - test/content_type_test.rb
123
+ - test/database.yml
124
+ - test/fixtures/zip_file_called.txt
125
+ - test/helper.rb