joint 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,36 @@
1
+ = Joint
2
+
3
+ MongoMapper and GridFS united in file upload love.
4
+
5
+ == Usage
6
+
7
+ Declare the plugin and use the attachment method to make attachments.
8
+
9
+ class Foo
10
+ include MongoMapper::Document
11
+ plugin Joint
12
+
13
+ attachment :image
14
+ attachment :pdf
15
+ end
16
+
17
+ This gives you #image, #image=, #pdf, and #pdf=. The = methods take any IO that responds to read (File, Tempfile, etc). The image and pdf methods return a GridIO instance (can be found in the ruby driver).
18
+
19
+ == Dependencies
20
+
21
+ * MongoMapper 0.7.2 - gem install mongo_mapper
22
+ * Wand >= 0.2.1 - gem install wand
23
+
24
+ == Note on Patches/Pull Requests
25
+
26
+ * Fork the project.
27
+ * Make your feature addition or bug fix.
28
+ * Add tests for it. This is important so I don't break it in a
29
+ future version unintentionally.
30
+ * Commit, do not mess with rakefile, version, or history.
31
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
32
+ * Send me a pull request. Bonus points for topic branches.
33
+
34
+ == Copyright
35
+
36
+ Copyright (c) 2010 John Nunemaker. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'yard'
4
+ require 'jeweler'
5
+ require 'rake/testtask'
6
+
7
+ require File.join(File.dirname(__FILE__), 'lib', 'joint', 'version')
8
+
9
+ Jeweler::Tasks.new do |gem|
10
+ gem.name = "joint"
11
+ gem.summary = %Q{MongoMapper and GridFS united in file upload love.}
12
+ gem.description = %Q{MongoMapper and GridFS united in file upload love.}
13
+ gem.email = "nunemaker@gmail.com"
14
+ gem.homepage = "http://github.com/jnunemaker/joint"
15
+ gem.authors = ["John Nunemaker"]
16
+ gem.version = Joint::Version
17
+ gem.files = FileList['lib/**/*.rb', 'bin/*', '[A-Z]*', 'test/**/*'].to_a
18
+ gem.test_files = FileList['test/**/*'].to_a
19
+
20
+ gem.add_dependency 'wand', '>= 0.2.1'
21
+ gem.add_dependency 'mime-types'
22
+
23
+ gem.add_development_dependency 'jeweler'
24
+ gem.add_development_dependency 'mongo_mapper'
25
+ end
26
+ Jeweler::GemcutterTasks.new
27
+
28
+ Rake::TestTask.new(:test) do |test|
29
+ test.libs << 'lib' << 'test'
30
+ test.ruby_opts << '-rubygems'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ task :test => :check_dependencies
36
+ task :default => :test
data/lib/joint.rb ADDED
@@ -0,0 +1,102 @@
1
+ require 'mime/types'
2
+ require 'wand'
3
+
4
+ module Joint
5
+ autoload :Version, 'joint/version'
6
+
7
+ def self.file_name(file)
8
+ file.respond_to?(:original_filename) ? file.original_filename : File.basename(file.path)
9
+ end
10
+
11
+ module ClassMethods
12
+ def attachment(name)
13
+ self.class.class_inheritable_accessor :attachment_names
14
+ self.class.attachment_names ||= []
15
+ self.class.attachment_names << name
16
+
17
+ after_save :save_attachments
18
+ before_destroy :destroy_attached_files
19
+
20
+ key "#{name}_id".to_sym, ObjectId
21
+ key "#{name}_name".to_sym, String
22
+ key "#{name}_size".to_sym, Integer
23
+ key "#{name}_type".to_sym, String
24
+
25
+ define_method(name) do
26
+ AttachmentProxy.new(self, name)
27
+ end
28
+
29
+ define_method("#{name}=") do |file|
30
+ self["#{name}_id"] = Mongo::ObjectID.new
31
+ self["#{name}_size"] = File.size(file)
32
+ self["#{name}_type"] = Wand.wave(file.path)
33
+ self["#{name}_name"] = Joint.file_name(file)
34
+ attachment_assignments[name] = file
35
+ end
36
+ end
37
+
38
+ def grid
39
+ @grid ||= Mongo::Grid.new(database)
40
+ end
41
+ end
42
+
43
+ module InstanceMethods
44
+ def attachment_assignments
45
+ @attachment_assignments ||= {}
46
+ end
47
+
48
+ def grid
49
+ self.class.grid
50
+ end
51
+
52
+ private
53
+ def save_attachments
54
+ attachment_assignments.each do |attachment|
55
+ name, file = attachment
56
+ content_type = self["#{name}_type"]
57
+
58
+ if file.respond_to?(:read)
59
+ grid.put(file.read, self["#{name}_name"], :content_type => content_type, :_id => self["#{name}_id"])
60
+ end
61
+ end
62
+
63
+ @attachment_assignments.clear
64
+ end
65
+
66
+ def destroy_attached_files
67
+ self.class.attachment_names.each do |name|
68
+ grid.delete(self["#{name}_id"])
69
+ end
70
+ end
71
+ end
72
+
73
+ class AttachmentProxy
74
+ def initialize(instance, name)
75
+ @instance, @name = instance, name
76
+ end
77
+
78
+ def id
79
+ @instance.send("#{@name}_id")
80
+ end
81
+
82
+ def name
83
+ @instance.send("#{@name}_name")
84
+ end
85
+
86
+ def size
87
+ @instance.send("#{@name}_size")
88
+ end
89
+
90
+ def type
91
+ @instance.send("#{@name}_type")
92
+ end
93
+
94
+ def grid_io
95
+ @grid_io ||= @instance.grid.get(id)
96
+ end
97
+
98
+ def method_missing(method, *args, &block)
99
+ grid_io.send(method, *args, &block)
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,3 @@
1
+ module Joint
2
+ Version = '0.1'
3
+ end
Binary file
Binary file
data/test/helper.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'test/unit'
2
+ require 'tempfile'
3
+ require 'pp'
4
+ require 'mongo_mapper'
5
+
6
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/joint')
7
+
8
+ MongoMapper.database = "testing"
9
+
10
+ class Test::Unit::TestCase
11
+ def self.test(name, &block)
12
+ test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
13
+ defined = instance_method(test_name) rescue false
14
+ raise "#{test_name} is already defined in #{self}" if defined
15
+ if block_given?
16
+ define_method(test_name, &block)
17
+ else
18
+ define_method(test_name) do
19
+ flunk "No implementation provided for #{name}"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,108 @@
1
+ require 'helper'
2
+
3
+ class Foo
4
+ include MongoMapper::Document
5
+ plugin Joint
6
+
7
+ attachment :image
8
+ attachment :pdf
9
+ end
10
+
11
+ class JointTest < Test::Unit::TestCase
12
+ def setup
13
+ MongoMapper.database.collections.each(&:remove)
14
+ @grid = Mongo::Grid.new(MongoMapper.database)
15
+
16
+ dir = File.dirname(__FILE__) + '/fixtures'
17
+ @pdf = File.open("#{dir}/unixref.pdf", 'r')
18
+ @image = File.open("#{dir}/mr_t.jpg", 'r')
19
+
20
+ @pdf_contents = File.read("#{dir}/unixref.pdf")
21
+ @image_contents = File.read("#{dir}/mr_t.jpg")
22
+
23
+ @doc = Foo.create(:image => @image, :pdf => @pdf)
24
+ @doc.reload
25
+ end
26
+
27
+ def teardown
28
+ @pdf.close
29
+ @image.close
30
+ end
31
+
32
+ test "assigns grid fs content type correctly" do
33
+ assert_equal "image/jpeg", @grid.get(@doc.image_id).content_type
34
+ assert_equal "application/pdf", @grid.get(@doc.pdf_id).content_type
35
+ end
36
+
37
+ test "assigns keys correctly" do
38
+ assert_equal 13661, @doc.image_size
39
+ assert_equal 68926, @doc.pdf_size
40
+
41
+ assert_equal "image/jpeg", @doc.image_type
42
+ assert_equal "application/pdf", @doc.pdf_type
43
+
44
+ assert_not_nil @doc.image_id
45
+ assert_not_nil @doc.pdf_id
46
+
47
+ assert_kind_of Mongo::ObjectID, @doc.image_id
48
+ assert_kind_of Mongo::ObjectID, @doc.pdf_id
49
+ end
50
+
51
+ test "accessing keys through attachment proxy" do
52
+ assert_equal 13661, @doc.image.size
53
+ assert_equal 68926, @doc.pdf.size
54
+
55
+ assert_equal "image/jpeg", @doc.image.type
56
+ assert_equal "application/pdf", @doc.pdf.type
57
+
58
+ assert_not_nil @doc.image.id
59
+ assert_not_nil @doc.pdf.id
60
+
61
+ assert_kind_of Mongo::ObjectID, @doc.image.id
62
+ assert_kind_of Mongo::ObjectID, @doc.pdf.id
63
+ end
64
+
65
+ test "sends unknown proxy methods to grid io object" do
66
+ assert_equal 13661, @doc.image.file_length
67
+ assert_equal 'image/jpeg', @doc.image.content_type
68
+ assert_equal 'mr_t.jpg', @doc.image.filename
69
+ assert_equal @doc.image_id, @doc.image.files_id
70
+ end
71
+
72
+ test "assigns file name from path if original file name not available" do
73
+ assert_equal 'mr_t.jpg', @doc.image_name
74
+ assert_equal 'unixref.pdf', @doc.pdf_name
75
+ end
76
+
77
+ test "assigns file name from original filename if available" do
78
+ begin
79
+ file = Tempfile.new('testing.txt')
80
+ def file.original_filename
81
+ 'testing.txt'
82
+ end
83
+ doc = Foo.create(:image => file)
84
+ assert_equal 'testing.txt', doc.image_name
85
+ ensure
86
+ file.close
87
+ end
88
+ end
89
+
90
+ test "responds to keys" do
91
+ [ :pdf_size, :pdf_id, :pdf_name, :pdf_type,
92
+ :image_size, :image_id, :image_name, :image_type
93
+ ].each do |method|
94
+ assert @doc.respond_to?(method)
95
+ end
96
+ end
97
+
98
+ test "saves attachments correctly" do
99
+ assert_equal @pdf_contents, @doc.pdf.read
100
+ assert_equal @image_contents, @doc.image.read
101
+ end
102
+
103
+ test "cleans up attachments on destroy" do
104
+ @doc.destroy
105
+ assert_raises(Mongo::GridError) { @grid.get(@doc.image_id) }
106
+ assert_raises(Mongo::GridError) { @grid.get(@doc.pdf_id) }
107
+ end
108
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: joint
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - John Nunemaker
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2010-03-26 00:00:00 -04:00
17
+ default_executable:
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: wand
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ segments:
27
+ - 0
28
+ - 2
29
+ - 1
30
+ version: 0.2.1
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: mime-types
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ version: "0"
43
+ type: :runtime
44
+ version_requirements: *id002
45
+ - !ruby/object:Gem::Dependency
46
+ name: jeweler
47
+ prerelease: false
48
+ requirement: &id003 !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ type: :development
56
+ version_requirements: *id003
57
+ - !ruby/object:Gem::Dependency
58
+ name: mongo_mapper
59
+ prerelease: false
60
+ requirement: &id004 !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ type: :development
68
+ version_requirements: *id004
69
+ description: MongoMapper and GridFS united in file upload love.
70
+ email: nunemaker@gmail.com
71
+ executables: []
72
+
73
+ extensions: []
74
+
75
+ extra_rdoc_files:
76
+ - README.rdoc
77
+ files:
78
+ - README.rdoc
79
+ - Rakefile
80
+ - lib/joint.rb
81
+ - lib/joint/version.rb
82
+ - test/fixtures/mr_t.jpg
83
+ - test/fixtures/unixref.pdf
84
+ - test/helper.rb
85
+ - test/test_joint.rb
86
+ has_rdoc: true
87
+ homepage: http://github.com/jnunemaker/joint
88
+ licenses: []
89
+
90
+ post_install_message:
91
+ rdoc_options:
92
+ - --charset=UTF-8
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ requirements: []
110
+
111
+ rubyforge_project:
112
+ rubygems_version: 1.3.6
113
+ signing_key:
114
+ specification_version: 3
115
+ summary: MongoMapper and GridFS united in file upload love.
116
+ test_files:
117
+ - test/fixtures/mr_t.jpg
118
+ - test/fixtures/unixref.pdf
119
+ - test/helper.rb
120
+ - test/test_joint.rb