joint 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.
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