joint 0.6.0 → 0.6.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/.gitignore +1 -0
- data/Gemfile +1 -0
- data/joint.gemspec +1 -1
- data/lib/joint/class_methods.rb +3 -2
- data/lib/joint/instance_methods.rb +10 -12
- data/lib/joint/version.rb +1 -1
- data/test/helper.rb +12 -1
- data/test/test_joint.rb +193 -6
- metadata +18 -18
- data/Gemfile.lock +0 -52
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/joint.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
|
|
12
12
|
|
13
13
|
s.add_dependency 'wand', '~> 0.4'
|
14
14
|
s.add_dependency 'mime-types'
|
15
|
-
s.add_dependency 'mongo_mapper', '~> 0.9
|
15
|
+
s.add_dependency 'mongo_mapper', '~> 0.9'
|
16
16
|
|
17
17
|
s.files = `git ls-files`.split("\n")
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/lib/joint/class_methods.rb
CHANGED
@@ -11,6 +11,7 @@ module Joint
|
|
11
11
|
self.attachment_names = attachment_names.dup.add(name)
|
12
12
|
|
13
13
|
after_save :save_attachments
|
14
|
+
before_save :nullify_nil_attachments_attributes
|
14
15
|
after_save :destroy_nil_attachments
|
15
16
|
before_destroy :destroy_all_attachments
|
16
17
|
|
@@ -27,12 +28,12 @@ module Joint
|
|
27
28
|
end
|
28
29
|
|
29
30
|
def #{name}?
|
30
|
-
!nil_attachments.
|
31
|
+
!nil_attachments.has_key?(:#{name}) && send(:#{name}_id?)
|
31
32
|
end
|
32
33
|
|
33
34
|
def #{name}=(file)
|
34
35
|
if file.nil?
|
35
|
-
nil_attachments
|
36
|
+
nil_attachments[:#{name}] = send("#{name}_id")
|
36
37
|
assigned_attachments.delete(:#{name})
|
37
38
|
else
|
38
39
|
send("#{name}_id=", BSON::ObjectId.new) if send("#{name}_id").nil?
|
@@ -10,7 +10,7 @@ module Joint
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def nil_attachments
|
13
|
-
@nil_attachments ||=
|
13
|
+
@nil_attachments ||= {}
|
14
14
|
end
|
15
15
|
|
16
16
|
# IO must respond to read and rewind
|
@@ -27,21 +27,19 @@ module Joint
|
|
27
27
|
end
|
28
28
|
assigned_attachments.clear
|
29
29
|
end
|
30
|
-
|
31
|
-
def
|
32
|
-
|
33
|
-
nil_attachments.each do |name|
|
34
|
-
grid.delete(send(name).id)
|
30
|
+
|
31
|
+
def nullify_nil_attachments_attributes
|
32
|
+
nil_attachments.each_key do |name|
|
35
33
|
send(:"#{name}_id=", nil)
|
36
34
|
send(:"#{name}_size=", nil)
|
37
35
|
send(:"#{name}_type=", nil)
|
38
36
|
send(:"#{name}_name=", nil)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def destroy_nil_attachments
|
41
|
+
nil_attachments.each_value do |id|
|
42
|
+
grid.delete(id)
|
45
43
|
end
|
46
44
|
|
47
45
|
nil_attachments.clear
|
data/lib/joint/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -25,7 +25,8 @@ class Test::Unit::TestCase
|
|
25
25
|
exps.each_with_index do |e, i|
|
26
26
|
error = "#{e.inspect} didn't change by #{difference}"
|
27
27
|
error = "#{message}.\n#{error}" if message
|
28
|
-
|
28
|
+
after = eval(e, b)
|
29
|
+
assert_equal(before[i] + difference, after, error)
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
@@ -46,6 +47,16 @@ class Asset
|
|
46
47
|
include MongoMapper::Document
|
47
48
|
plugin Joint
|
48
49
|
|
50
|
+
key :title, String
|
51
|
+
attachment :image
|
52
|
+
attachment :file
|
53
|
+
has_many :embedded_assets
|
54
|
+
end
|
55
|
+
|
56
|
+
class EmbeddedAsset
|
57
|
+
include MongoMapper::EmbeddedDocument
|
58
|
+
plugin Joint
|
59
|
+
|
49
60
|
key :title, String
|
50
61
|
attachment :image
|
51
62
|
attachment :file
|
data/test/test_joint.rb
CHANGED
@@ -56,17 +56,21 @@ class JointTest < Test::Unit::TestCase
|
|
56
56
|
context "Using Joint plugin" do
|
57
57
|
should "add each attachment to attachment_names" do
|
58
58
|
Asset.attachment_names.should == Set.new([:image, :file])
|
59
|
+
EmbeddedAsset.attachment_names.should == Set.new([:image, :file])
|
59
60
|
end
|
60
61
|
|
61
62
|
should "add keys for each attachment" do
|
62
63
|
key_names.each do |key|
|
63
64
|
Asset.keys.should include("image_#{key}")
|
64
65
|
Asset.keys.should include("file_#{key}")
|
66
|
+
EmbeddedAsset.keys.should include("image_#{key}")
|
67
|
+
EmbeddedAsset.keys.should include("file_#{key}")
|
65
68
|
end
|
66
69
|
end
|
67
70
|
|
68
71
|
should "add memoized accessors module" do
|
69
72
|
Asset.attachment_accessor_module.should be_instance_of(Module)
|
73
|
+
EmbeddedAsset.attachment_accessor_module.should be_instance_of(Module)
|
70
74
|
end
|
71
75
|
|
72
76
|
context "with inheritance" do
|
@@ -153,9 +157,79 @@ class JointTest < Test::Unit::TestCase
|
|
153
157
|
subject.file?.should be(true)
|
154
158
|
end
|
155
159
|
|
156
|
-
should "respond with false when asked if the attachment is
|
157
|
-
subject.image.
|
158
|
-
subject.file.
|
160
|
+
should "respond with false when asked if the attachment is blank?" do
|
161
|
+
subject.image.blank?.should be(false)
|
162
|
+
subject.file.blank?.should be(false)
|
163
|
+
end
|
164
|
+
|
165
|
+
should "clear assigned attachments so they don't get uploaded twice" do
|
166
|
+
Mongo::Grid.any_instance.expects(:put).never
|
167
|
+
subject.save
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context "Assigning new attachments to embedded document" do
|
172
|
+
setup do
|
173
|
+
@asset = Asset.new
|
174
|
+
@doc = @asset.embedded_assets.build(:image => @image, :file => @file)
|
175
|
+
@asset.save!
|
176
|
+
rewind_files
|
177
|
+
end
|
178
|
+
subject { @doc }
|
179
|
+
|
180
|
+
should "assign GridFS content_type" do
|
181
|
+
grid.get(subject.image_id).content_type.should == 'image/jpeg'
|
182
|
+
grid.get(subject.file_id).content_type.should == 'application/pdf'
|
183
|
+
end
|
184
|
+
|
185
|
+
should "assign joint keys" do
|
186
|
+
subject.image_size.should == 13661
|
187
|
+
subject.file_size.should == 68926
|
188
|
+
|
189
|
+
subject.image_type.should == "image/jpeg"
|
190
|
+
subject.file_type.should == "application/pdf"
|
191
|
+
|
192
|
+
subject.image_id.should_not be_nil
|
193
|
+
subject.file_id.should_not be_nil
|
194
|
+
|
195
|
+
subject.image_id.should be_instance_of(BSON::ObjectId)
|
196
|
+
subject.file_id.should be_instance_of(BSON::ObjectId)
|
197
|
+
end
|
198
|
+
|
199
|
+
should "allow accessing keys through attachment proxy" do
|
200
|
+
subject.image.size.should == 13661
|
201
|
+
subject.file.size.should == 68926
|
202
|
+
|
203
|
+
subject.image.type.should == "image/jpeg"
|
204
|
+
subject.file.type.should == "application/pdf"
|
205
|
+
|
206
|
+
subject.image.id.should_not be_nil
|
207
|
+
subject.file.id.should_not be_nil
|
208
|
+
|
209
|
+
subject.image.id.should be_instance_of(BSON::ObjectId)
|
210
|
+
subject.file.id.should be_instance_of(BSON::ObjectId)
|
211
|
+
end
|
212
|
+
|
213
|
+
should "proxy unknown methods to GridIO object" do
|
214
|
+
subject.image.files_id.should == subject.image_id
|
215
|
+
subject.image.content_type.should == 'image/jpeg'
|
216
|
+
subject.image.filename.should == 'mr_t.jpg'
|
217
|
+
subject.image.file_length.should == 13661
|
218
|
+
end
|
219
|
+
|
220
|
+
should "assign file name from path if original file name not available" do
|
221
|
+
subject.image_name.should == 'mr_t.jpg'
|
222
|
+
subject.file_name.should == 'unixref.pdf'
|
223
|
+
end
|
224
|
+
|
225
|
+
should "save attachment contents correctly" do
|
226
|
+
subject.file.read.should == @file.read
|
227
|
+
subject.image.read.should == @image.read
|
228
|
+
end
|
229
|
+
|
230
|
+
should "know that attachment exists" do
|
231
|
+
subject.image?.should be(true)
|
232
|
+
subject.file?.should be(true)
|
159
233
|
end
|
160
234
|
|
161
235
|
should "respond with false when asked if the attachment is blank?" do
|
@@ -198,6 +272,33 @@ class JointTest < Test::Unit::TestCase
|
|
198
272
|
end
|
199
273
|
end
|
200
274
|
|
275
|
+
context "Updating existing attachment in embedded document" do
|
276
|
+
setup do
|
277
|
+
@asset = Asset.new
|
278
|
+
@doc = @asset.embedded_assets.build(:file => @test1)
|
279
|
+
@asset.save!
|
280
|
+
assert_no_grid_difference do
|
281
|
+
@doc.file = @test2
|
282
|
+
@doc.save!
|
283
|
+
end
|
284
|
+
rewind_files
|
285
|
+
end
|
286
|
+
subject { @doc }
|
287
|
+
|
288
|
+
should "update keys" do
|
289
|
+
subject.file_name.should == 'test2.txt'
|
290
|
+
subject.file_type.should == "text/plain"
|
291
|
+
subject.file_size.should == 5
|
292
|
+
end
|
293
|
+
|
294
|
+
should "update GridFS" do
|
295
|
+
grid.get(subject.file_id).filename.should == 'test2.txt'
|
296
|
+
grid.get(subject.file_id).content_type.should == 'text/plain'
|
297
|
+
grid.get(subject.file_id).file_length.should == 5
|
298
|
+
grid.get(subject.file_id).read.should == @test2.read
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
201
302
|
context "Updating document but not attachments" do
|
202
303
|
setup do
|
203
304
|
@doc = Asset.create(:image => @image)
|
@@ -216,6 +317,26 @@ class JointTest < Test::Unit::TestCase
|
|
216
317
|
end
|
217
318
|
end
|
218
319
|
|
320
|
+
context "Updating embedded document but not attachments" do
|
321
|
+
setup do
|
322
|
+
@asset = Asset.new
|
323
|
+
@doc = @asset.embedded_assets.build(:image => @image)
|
324
|
+
@doc.update_attributes(:title => 'Updated')
|
325
|
+
@asset.reload
|
326
|
+
@doc = @asset.embedded_assets.first
|
327
|
+
rewind_files
|
328
|
+
end
|
329
|
+
subject { @doc }
|
330
|
+
|
331
|
+
should "not affect attachment" do
|
332
|
+
subject.image.read.should == @image.read
|
333
|
+
end
|
334
|
+
|
335
|
+
should "update document attributes" do
|
336
|
+
subject.title.should == 'Updated'
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
219
340
|
context "Assigning file where file pointer is not at beginning" do
|
220
341
|
setup do
|
221
342
|
@image.read
|
@@ -278,7 +399,58 @@ class JointTest < Test::Unit::TestCase
|
|
278
399
|
assert_nil subject.image_type
|
279
400
|
assert_nil subject.image_size
|
280
401
|
end
|
402
|
+
end
|
403
|
+
|
404
|
+
context "Setting attachment to nil on embedded document" do
|
405
|
+
setup do
|
406
|
+
@asset = Asset.new
|
407
|
+
@doc = @asset.embedded_assets.build(:image => @image)
|
408
|
+
@asset.save!
|
409
|
+
rewind_files
|
410
|
+
end
|
411
|
+
subject { @doc }
|
412
|
+
|
413
|
+
should "delete attachment after save" do
|
414
|
+
assert_no_grid_difference { subject.image = nil }
|
415
|
+
assert_grid_difference(-1) { subject.save }
|
416
|
+
end
|
281
417
|
|
418
|
+
should "know that the attachment has been nullified" do
|
419
|
+
subject.image = nil
|
420
|
+
subject.image?.should be(false)
|
421
|
+
end
|
422
|
+
|
423
|
+
should "respond with true when asked if the attachment is nil?" do
|
424
|
+
subject.image = nil
|
425
|
+
subject.image.nil?.should be(true)
|
426
|
+
end
|
427
|
+
|
428
|
+
should "respond with true when asked if the attachment is blank?" do
|
429
|
+
subject.image = nil
|
430
|
+
subject.image.blank?.should be(true)
|
431
|
+
end
|
432
|
+
|
433
|
+
should "clear nil attachments after save and not attempt to delete again" do
|
434
|
+
Mongo::Grid.any_instance.expects(:delete).once
|
435
|
+
subject.image = nil
|
436
|
+
subject.save
|
437
|
+
Mongo::Grid.any_instance.expects(:delete).never
|
438
|
+
subject.save
|
439
|
+
end
|
440
|
+
|
441
|
+
should "clear id, name, type, size" do
|
442
|
+
subject.image = nil
|
443
|
+
subject.save
|
444
|
+
assert_nil subject.image_id
|
445
|
+
assert_nil subject.image_name
|
446
|
+
assert_nil subject.image_type
|
447
|
+
assert_nil subject.image_size
|
448
|
+
s = subject._root_document.reload.embedded_assets.first
|
449
|
+
assert_nil s.image_id
|
450
|
+
assert_nil s.image_name
|
451
|
+
assert_nil s.image_type
|
452
|
+
assert_nil s.image_size
|
453
|
+
end
|
282
454
|
end
|
283
455
|
|
284
456
|
context "Retrieving attachment that does not exist" do
|
@@ -313,6 +485,22 @@ class JointTest < Test::Unit::TestCase
|
|
313
485
|
end
|
314
486
|
end
|
315
487
|
|
488
|
+
context "Destroying an embedded document's _root_document" do
|
489
|
+
setup do
|
490
|
+
@asset = Asset.new
|
491
|
+
@doc = @asset.embedded_assets.build(:image => @image)
|
492
|
+
@doc.save!
|
493
|
+
rewind_files
|
494
|
+
end
|
495
|
+
subject { @doc }
|
496
|
+
|
497
|
+
should "remove files from grid fs as well" do
|
498
|
+
assert_grid_difference(-1) { subject._root_document.destroy }
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
# What about when an embedded document is removed?
|
503
|
+
|
316
504
|
context "Assigning file name" do
|
317
505
|
should "default to path" do
|
318
506
|
Asset.create(:image => @image).image.name.should == 'mr_t.jpg'
|
@@ -358,15 +546,14 @@ class JointTest < Test::Unit::TestCase
|
|
358
546
|
io = Joint::IO.new({
|
359
547
|
:name => 'foo.txt',
|
360
548
|
:type => 'plain/text',
|
361
|
-
:content => 'This is my stuff'
|
362
|
-
:size => 19,
|
549
|
+
:content => 'This is my stuff'
|
363
550
|
})
|
364
551
|
@asset = Asset.create(:file => io)
|
365
552
|
end
|
366
553
|
|
367
554
|
should "work" do
|
368
555
|
@asset.file_name.should == 'foo.txt'
|
369
|
-
@asset.file_size.should ==
|
556
|
+
@asset.file_size.should == 16
|
370
557
|
@asset.file_type.should == 'plain/text'
|
371
558
|
@asset.file.read.should == 'This is my stuff'
|
372
559
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: joint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 6
|
9
|
-
-
|
10
|
-
version: 0.6.
|
9
|
+
- 1
|
10
|
+
version: 0.6.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- John Nunemaker
|
@@ -15,12 +15,14 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-12-14 00:00:00 -05:00
|
19
|
+
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
22
|
+
type: :runtime
|
21
23
|
name: wand
|
22
24
|
prerelease: false
|
23
|
-
|
25
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
24
26
|
none: false
|
25
27
|
requirements:
|
26
28
|
- - ~>
|
@@ -30,12 +32,12 @@ dependencies:
|
|
30
32
|
- 0
|
31
33
|
- 4
|
32
34
|
version: "0.4"
|
33
|
-
|
34
|
-
version_requirements: *id001
|
35
|
+
requirement: *id001
|
35
36
|
- !ruby/object:Gem::Dependency
|
37
|
+
type: :runtime
|
36
38
|
name: mime-types
|
37
39
|
prerelease: false
|
38
|
-
|
40
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
39
41
|
none: false
|
40
42
|
requirements:
|
41
43
|
- - ">="
|
@@ -44,24 +46,22 @@ dependencies:
|
|
44
46
|
segments:
|
45
47
|
- 0
|
46
48
|
version: "0"
|
47
|
-
|
48
|
-
version_requirements: *id002
|
49
|
+
requirement: *id002
|
49
50
|
- !ruby/object:Gem::Dependency
|
51
|
+
type: :runtime
|
50
52
|
name: mongo_mapper
|
51
53
|
prerelease: false
|
52
|
-
|
54
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
53
55
|
none: false
|
54
56
|
requirements:
|
55
57
|
- - ~>
|
56
58
|
- !ruby/object:Gem::Version
|
57
|
-
hash:
|
59
|
+
hash: 25
|
58
60
|
segments:
|
59
61
|
- 0
|
60
62
|
- 9
|
61
|
-
|
62
|
-
|
63
|
-
type: :runtime
|
64
|
-
version_requirements: *id003
|
63
|
+
version: "0.9"
|
64
|
+
requirement: *id003
|
65
65
|
description: MongoMapper and GridFS joined in file upload love.
|
66
66
|
email: nunemaker@gmail.com
|
67
67
|
executables: []
|
@@ -73,7 +73,6 @@ extra_rdoc_files: []
|
|
73
73
|
files:
|
74
74
|
- .gitignore
|
75
75
|
- Gemfile
|
76
|
-
- Gemfile.lock
|
77
76
|
- LICENSE
|
78
77
|
- README.rdoc
|
79
78
|
- Rakefile
|
@@ -95,6 +94,7 @@ files:
|
|
95
94
|
- test/helper.rb
|
96
95
|
- test/joint/test_io.rb
|
97
96
|
- test/test_joint.rb
|
97
|
+
has_rdoc: true
|
98
98
|
homepage: http://github.com/jnunemaker/joint
|
99
99
|
licenses: []
|
100
100
|
|
@@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
124
|
requirements: []
|
125
125
|
|
126
126
|
rubyforge_project:
|
127
|
-
rubygems_version: 1.
|
127
|
+
rubygems_version: 1.6.1
|
128
128
|
signing_key:
|
129
129
|
specification_version: 3
|
130
130
|
summary: MongoMapper and GridFS joined in file upload love.
|
data/Gemfile.lock
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
joint (0.6.0)
|
5
|
-
mime-types
|
6
|
-
mongo_mapper (~> 0.9.0)
|
7
|
-
wand (~> 0.4)
|
8
|
-
|
9
|
-
GEM
|
10
|
-
remote: http://rubygems.org/
|
11
|
-
specs:
|
12
|
-
activemodel (3.1.0)
|
13
|
-
activesupport (= 3.1.0)
|
14
|
-
bcrypt-ruby (~> 3.0.0)
|
15
|
-
builder (~> 3.0.0)
|
16
|
-
i18n (~> 0.6)
|
17
|
-
activesupport (3.1.0)
|
18
|
-
multi_json (~> 1.0)
|
19
|
-
bcrypt-ruby (3.0.1)
|
20
|
-
bson (1.3.1)
|
21
|
-
bson_ext (1.3.1)
|
22
|
-
builder (3.0.0)
|
23
|
-
i18n (0.6.0)
|
24
|
-
jnunemaker-matchy (0.4.0)
|
25
|
-
mime-types (1.16)
|
26
|
-
mocha (0.9.10)
|
27
|
-
rake
|
28
|
-
mongo (1.3.1)
|
29
|
-
bson (>= 1.3.1)
|
30
|
-
mongo_mapper (0.9.2)
|
31
|
-
activemodel (~> 3.0)
|
32
|
-
activesupport (~> 3.0)
|
33
|
-
plucky (~> 0.3.8)
|
34
|
-
multi_json (1.0.2)
|
35
|
-
plucky (0.3.8)
|
36
|
-
mongo (~> 1.3)
|
37
|
-
rake (0.8.7)
|
38
|
-
safe_shell (1.0.0)
|
39
|
-
shoulda (2.11.3)
|
40
|
-
wand (0.4)
|
41
|
-
mime-types
|
42
|
-
safe_shell (~> 1.0.0)
|
43
|
-
|
44
|
-
PLATFORMS
|
45
|
-
ruby
|
46
|
-
|
47
|
-
DEPENDENCIES
|
48
|
-
bson_ext
|
49
|
-
jnunemaker-matchy
|
50
|
-
joint!
|
51
|
-
mocha
|
52
|
-
shoulda
|