jamieorc-joint 0.5.6
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 +7 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +49 -0
- data/LICENSE +20 -0
- data/README.rdoc +37 -0
- data/Rakefile +12 -0
- data/joint.gemspec +25 -0
- data/lib/joint/attachment_proxy.rb +35 -0
- data/lib/joint/class_methods.rb +50 -0
- data/lib/joint/instance_methods.rb +52 -0
- data/lib/joint/io.rb +14 -0
- data/lib/joint/version.rb +3 -0
- data/lib/joint.rb +42 -0
- data/specs.watchr +38 -0
- data/test/fixtures/example.m4r +0 -0
- data/test/fixtures/font.eot +0 -0
- data/test/fixtures/harmony.png +0 -0
- data/test/fixtures/mr_t.jpg +0 -0
- data/test/fixtures/test1.txt +1 -0
- data/test/fixtures/test2.txt +1 -0
- data/test/fixtures/unixref.pdf +0 -0
- data/test/helper.rb +91 -0
- data/test/joint/test_io.rb +28 -0
- data/test/test_joint.rb +585 -0
- metadata +186 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
joint (0.5.6)
|
5
|
+
mime-types
|
6
|
+
mongo_mapper (~> 0.8.6)
|
7
|
+
wand (~> 0.4)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activesupport (3.0.3)
|
13
|
+
bson (1.3.1)
|
14
|
+
bson_ext (1.3.1)
|
15
|
+
i18n (0.4.2)
|
16
|
+
jnunemaker-matchy (0.4.0)
|
17
|
+
jnunemaker-validatable (1.8.4)
|
18
|
+
activesupport (>= 2.3.4)
|
19
|
+
mime-types (1.16)
|
20
|
+
mocha (0.9.10)
|
21
|
+
rake
|
22
|
+
mongo (1.3.1)
|
23
|
+
bson (>= 1.3.1)
|
24
|
+
mongo_mapper (0.8.6)
|
25
|
+
activesupport (>= 2.3.4)
|
26
|
+
jnunemaker-validatable (~> 1.8.4)
|
27
|
+
plucky (~> 0.3.6)
|
28
|
+
plucky (0.3.6)
|
29
|
+
mongo (~> 1.1)
|
30
|
+
rake (0.8.7)
|
31
|
+
safe_shell (1.0.0)
|
32
|
+
shoulda (2.11.3)
|
33
|
+
wand (0.4)
|
34
|
+
mime-types
|
35
|
+
safe_shell (~> 1.0.0)
|
36
|
+
|
37
|
+
PLATFORMS
|
38
|
+
ruby
|
39
|
+
|
40
|
+
DEPENDENCIES
|
41
|
+
bson_ext (~> 1.3)
|
42
|
+
i18n (= 0.4.2)
|
43
|
+
jnunemaker-matchy
|
44
|
+
joint!
|
45
|
+
mime-types
|
46
|
+
mocha
|
47
|
+
mongo_mapper (~> 0.8.6)
|
48
|
+
shoulda
|
49
|
+
wand (~> 0.4)
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 John Nunemaker
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
= Joint
|
2
|
+
|
3
|
+
MongoMapper and GridFS joined 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
|
+
Also, #image and #pdf are proxies so you can do stuff like:
|
20
|
+
|
21
|
+
doc.image.id, doc.image.size, doc.image.type, doc.image.name
|
22
|
+
|
23
|
+
If you call a method other than those in the proxy it calls it on the GridIO instance so you can still get at all the GridIO instance methods.
|
24
|
+
|
25
|
+
== Note on Patches/Pull Requests
|
26
|
+
|
27
|
+
* Fork the project.
|
28
|
+
* Make your feature addition or bug fix.
|
29
|
+
* Add tests for it. This is important so I don't break it in a
|
30
|
+
future version unintentionally.
|
31
|
+
* Commit, do not mess with rakefile, version, or history.
|
32
|
+
(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)
|
33
|
+
* Send me a pull request. Bonus points for topic branches.
|
34
|
+
|
35
|
+
== Copyright
|
36
|
+
|
37
|
+
Copyright (c) 2010 John Nunemaker. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rake/testtask'
|
5
|
+
Rake::TestTask.new do |test|
|
6
|
+
test.libs << 'lib' << 'test'
|
7
|
+
test.pattern = 'test/**/test_*.rb'
|
8
|
+
test.ruby_opts = ['-rubygems']
|
9
|
+
test.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
task :default => :test
|
data/joint.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require File.expand_path('../lib/joint/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "jamieorc-joint"
|
6
|
+
s.summary = %Q{MongoMapper and GridFS joined in file upload love.}
|
7
|
+
s.description = %Q{MongoMapper and GridFS joined in file upload love.}
|
8
|
+
s.email = "jamieorc@gmail.com"
|
9
|
+
s.homepage = "http://github.com/jamieorc/joint"
|
10
|
+
s.authors = ["John Nunemaker", "Jamie Orchard-Hays"]
|
11
|
+
s.version = Joint::Version
|
12
|
+
|
13
|
+
s.add_dependency 'wand', '~> 0.4'
|
14
|
+
s.add_dependency 'mime-types'
|
15
|
+
s.add_dependency 'mongo_mapper', '~> 0.8.6'
|
16
|
+
|
17
|
+
s.add_development_dependency 'shoulda'
|
18
|
+
s.add_development_dependency 'mocha'
|
19
|
+
s.add_development_dependency 'jnunemaker-matchy'
|
20
|
+
|
21
|
+
s.files = `git ls-files`.split("\n")
|
22
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
|
+
s.require_paths = ["lib"]
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Joint
|
2
|
+
class AttachmentProxy
|
3
|
+
def initialize(instance, name)
|
4
|
+
@instance, @name = instance, name
|
5
|
+
end
|
6
|
+
|
7
|
+
def id
|
8
|
+
@instance.send("#{@name}_id")
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
@instance.send("#{@name}_name")
|
13
|
+
end
|
14
|
+
|
15
|
+
def size
|
16
|
+
@instance.send("#{@name}_size")
|
17
|
+
end
|
18
|
+
|
19
|
+
def type
|
20
|
+
@instance.send("#{@name}_type")
|
21
|
+
end
|
22
|
+
|
23
|
+
def nil?
|
24
|
+
!@instance.send("#{@name}?")
|
25
|
+
end
|
26
|
+
|
27
|
+
def grid_io
|
28
|
+
@grid_io ||= @instance.grid.get(id)
|
29
|
+
end
|
30
|
+
|
31
|
+
def method_missing(method, *args, &block)
|
32
|
+
grid_io.send(method, *args, &block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Joint
|
2
|
+
module ClassMethods
|
3
|
+
def attachment_accessor_module
|
4
|
+
@attachment_accessor_module ||= Module.new
|
5
|
+
end
|
6
|
+
|
7
|
+
def attachment(name, options = {})
|
8
|
+
options.symbolize_keys!
|
9
|
+
name = name.to_sym
|
10
|
+
|
11
|
+
self.attachment_names << name
|
12
|
+
|
13
|
+
after_save :save_attachments
|
14
|
+
before_save :nullify_nil_attachments_attributes
|
15
|
+
after_save :destroy_nil_attachments
|
16
|
+
before_destroy :destroy_all_attachments
|
17
|
+
|
18
|
+
key :"#{name}_id", ObjectId
|
19
|
+
key :"#{name}_name", String
|
20
|
+
key :"#{name}_size", Integer
|
21
|
+
key :"#{name}_type", String
|
22
|
+
|
23
|
+
validates_presence_of(name) if options[:required]
|
24
|
+
|
25
|
+
attachment_accessor_module.module_eval <<-EOC
|
26
|
+
def #{name}
|
27
|
+
@#{name} ||= AttachmentProxy.new(self, :#{name})
|
28
|
+
end
|
29
|
+
|
30
|
+
def #{name}?
|
31
|
+
!nil_attachments.has_key?(:#{name}) && send(:#{name}_id?)
|
32
|
+
end
|
33
|
+
|
34
|
+
def #{name}=(file)
|
35
|
+
if file.nil?
|
36
|
+
nil_attachments[:#{name}] = send("#{name}_id")
|
37
|
+
assigned_attachments.delete(:#{name})
|
38
|
+
else
|
39
|
+
send("#{name}_id=", BSON::ObjectId.new) if send("#{name}_id").nil?
|
40
|
+
send("#{name}_name=", Joint.name(file))
|
41
|
+
send("#{name}_size=", Joint.size(file))
|
42
|
+
send("#{name}_type=", Joint.type(file))
|
43
|
+
assigned_attachments[:#{name}] = file
|
44
|
+
nil_attachments.delete(:#{name})
|
45
|
+
end
|
46
|
+
end
|
47
|
+
EOC
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Joint
|
2
|
+
module InstanceMethods
|
3
|
+
def grid
|
4
|
+
@grid ||= Mongo::Grid.new(database)
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
def assigned_attachments
|
9
|
+
@assigned_attachments ||= {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def nil_attachments
|
13
|
+
@nil_attachments ||= {}
|
14
|
+
end
|
15
|
+
|
16
|
+
# IO must respond to read and rewind
|
17
|
+
def save_attachments
|
18
|
+
assigned_attachments.each_pair do |name, io|
|
19
|
+
next unless io.respond_to?(:read)
|
20
|
+
io.rewind if io.respond_to?(:rewind)
|
21
|
+
grid.delete(send(name).id)
|
22
|
+
grid.put(io.read, {
|
23
|
+
:_id => send(name).id,
|
24
|
+
:filename => send(name).name,
|
25
|
+
:content_type => send(name).type,
|
26
|
+
})
|
27
|
+
end
|
28
|
+
assigned_attachments.clear
|
29
|
+
end
|
30
|
+
|
31
|
+
def nullify_nil_attachments_attributes
|
32
|
+
nil_attachments.each_key do |name|
|
33
|
+
send(:"#{name}_id=", nil)
|
34
|
+
send(:"#{name}_size=", nil)
|
35
|
+
send(:"#{name}_type=", nil)
|
36
|
+
send(:"#{name}_name=", nil)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def destroy_nil_attachments
|
41
|
+
nil_attachments.each_value do |id|
|
42
|
+
grid.delete(id)
|
43
|
+
end
|
44
|
+
|
45
|
+
nil_attachments.clear
|
46
|
+
end
|
47
|
+
|
48
|
+
def destroy_all_attachments
|
49
|
+
self.class.attachment_names.map { |name| grid.delete(send(name).id) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/joint/io.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Joint
|
2
|
+
class IO
|
3
|
+
attr_accessor :name, :content, :type, :size
|
4
|
+
|
5
|
+
def initialize(attrs={})
|
6
|
+
attrs.each { |key, value| send("#{key}=", value) }
|
7
|
+
@type ||= 'plain/text'
|
8
|
+
@size ||= @content.size unless @content.nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
alias path name
|
12
|
+
alias read content
|
13
|
+
end
|
14
|
+
end
|
data/lib/joint.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'mime/types'
|
3
|
+
require 'wand'
|
4
|
+
|
5
|
+
module Joint
|
6
|
+
def self.configure(model)
|
7
|
+
model.class_inheritable_accessor :attachment_names
|
8
|
+
model.attachment_names = Set.new
|
9
|
+
model.send(:include, model.attachment_accessor_module)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.name(file)
|
13
|
+
if file.respond_to?(:original_filename)
|
14
|
+
file.original_filename
|
15
|
+
else
|
16
|
+
File.basename(file.path)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.size(file)
|
21
|
+
if file.respond_to?(:size)
|
22
|
+
file.size
|
23
|
+
else
|
24
|
+
File.size(file)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.type(file)
|
29
|
+
return file.type if file.is_a?(Joint::IO)
|
30
|
+
Wand.wave(file.path, :original_filename => Joint.name(file))
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def self.blank?(str)
|
35
|
+
str.nil? || str !~ /\S/
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'joint/class_methods'
|
40
|
+
require 'joint/instance_methods'
|
41
|
+
require 'joint/attachment_proxy'
|
42
|
+
require 'joint/io'
|
data/specs.watchr
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
def run(cmd)
|
2
|
+
puts(cmd)
|
3
|
+
output = ""
|
4
|
+
IO.popen(cmd) do |com|
|
5
|
+
com.each_char do |c|
|
6
|
+
print c
|
7
|
+
output << c
|
8
|
+
$stdout.flush
|
9
|
+
end
|
10
|
+
end
|
11
|
+
output
|
12
|
+
end
|
13
|
+
|
14
|
+
def run_test_file(file)
|
15
|
+
run %Q(ruby -I"lib:test" -rubygems #{file})
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_all_tests
|
19
|
+
run "rake test"
|
20
|
+
end
|
21
|
+
|
22
|
+
def related_test_files(path)
|
23
|
+
Dir['test/**/*.rb'].select { |file| file =~ /test_#{File.basename(path)}/ }
|
24
|
+
end
|
25
|
+
|
26
|
+
watch('test/test_helper\.rb') { system('clear'); run_all_tests }
|
27
|
+
watch('test/.*test_.*\.rb') { |m| system('clear'); run_test_file(m[0]) }
|
28
|
+
watch('lib/.*') { |m| related_test_files(m[0]).each { |file| run_test_file(file) } }
|
29
|
+
|
30
|
+
# Ctrl-\
|
31
|
+
Signal.trap('QUIT') do
|
32
|
+
puts " --- Running all tests ---\n\n"
|
33
|
+
run_all_tests
|
34
|
+
end
|
35
|
+
|
36
|
+
# Ctrl-C
|
37
|
+
Signal.trap('INT') { abort("\n") }
|
38
|
+
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
test1
|
@@ -0,0 +1 @@
|
|
1
|
+
test2
|
Binary file
|
data/test/helper.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require 'pp'
|
3
|
+
require 'shoulda'
|
4
|
+
require 'matchy'
|
5
|
+
require 'mocha'
|
6
|
+
require 'mongo_mapper'
|
7
|
+
|
8
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/joint')
|
9
|
+
|
10
|
+
MongoMapper.database = "testing"
|
11
|
+
|
12
|
+
class Test::Unit::TestCase
|
13
|
+
def setup
|
14
|
+
MongoMapper.database.collections.each(&:remove)
|
15
|
+
end
|
16
|
+
|
17
|
+
def assert_difference(expression, difference = 1, message = nil, &block)
|
18
|
+
b = block.send(:binding)
|
19
|
+
exps = Array.wrap(expression)
|
20
|
+
before = exps.map { |e| eval(e, b) }
|
21
|
+
yield
|
22
|
+
exps.each_with_index do |e, i|
|
23
|
+
error = "#{e.inspect} didn't change by #{difference}"
|
24
|
+
error = "#{message}.\n#{error}" if message
|
25
|
+
after = eval(e, b)
|
26
|
+
assert_equal(before[i] + difference, after, error)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def assert_no_difference(expression, message = nil, &block)
|
31
|
+
assert_difference(expression, 0, message, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def assert_grid_difference(difference=1, &block)
|
35
|
+
assert_difference("MongoMapper.database['fs.files'].find().count", difference, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def assert_no_grid_difference(&block)
|
39
|
+
assert_grid_difference(0, &block)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Asset
|
44
|
+
include MongoMapper::Document
|
45
|
+
plugin Joint
|
46
|
+
|
47
|
+
key :title, String
|
48
|
+
attachment :image
|
49
|
+
attachment :file
|
50
|
+
has_many :embedded_assets
|
51
|
+
end
|
52
|
+
|
53
|
+
class EmbeddedAsset
|
54
|
+
include MongoMapper::EmbeddedDocument
|
55
|
+
plugin Joint
|
56
|
+
|
57
|
+
key :title, String
|
58
|
+
attachment :image
|
59
|
+
attachment :file
|
60
|
+
end
|
61
|
+
|
62
|
+
class BaseModel
|
63
|
+
include MongoMapper::Document
|
64
|
+
plugin Joint
|
65
|
+
attachment :file
|
66
|
+
end
|
67
|
+
|
68
|
+
class Image < BaseModel; attachment :image end
|
69
|
+
class Video < BaseModel; attachment :video end
|
70
|
+
|
71
|
+
module JointTestHelpers
|
72
|
+
def all_files
|
73
|
+
[@file, @image, @image2, @test1, @test2]
|
74
|
+
end
|
75
|
+
|
76
|
+
def rewind_files
|
77
|
+
all_files.each { |file| file.rewind }
|
78
|
+
end
|
79
|
+
|
80
|
+
def open_file(name)
|
81
|
+
File.open(File.join(File.dirname(__FILE__), 'fixtures', name), 'r')
|
82
|
+
end
|
83
|
+
|
84
|
+
def grid
|
85
|
+
@grid ||= Mongo::Grid.new(MongoMapper.database)
|
86
|
+
end
|
87
|
+
|
88
|
+
def key_names
|
89
|
+
[:id, :name, :type, :size]
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class IOTest < Test::Unit::TestCase
|
4
|
+
context "#initialize" do
|
5
|
+
should "set attributes from hash" do
|
6
|
+
Joint::IO.new(:name => 'foo').name.should == 'foo'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
should "default type to plain text" do
|
11
|
+
Joint::IO.new.type.should == 'plain/text'
|
12
|
+
end
|
13
|
+
|
14
|
+
should "default size to content size" do
|
15
|
+
content = 'This is my content'
|
16
|
+
Joint::IO.new(:content => content).size.should == content.size
|
17
|
+
end
|
18
|
+
|
19
|
+
should "alias path to name" do
|
20
|
+
Joint::IO.new(:name => 'foo').path.should == 'foo'
|
21
|
+
end
|
22
|
+
|
23
|
+
context "#read" do
|
24
|
+
should "return content" do
|
25
|
+
Joint::IO.new(:content => 'Testing').read.should == 'Testing'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/test/test_joint.rb
ADDED
@@ -0,0 +1,585 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class JointTest < Test::Unit::TestCase
|
4
|
+
include JointTestHelpers
|
5
|
+
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
@file = open_file('unixref.pdf')
|
9
|
+
@image = open_file('mr_t.jpg')
|
10
|
+
@image2 = open_file('harmony.png')
|
11
|
+
@test1 = open_file('test1.txt')
|
12
|
+
@test2 = open_file('test2.txt')
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
all_files.each { |file| file.close }
|
17
|
+
end
|
18
|
+
|
19
|
+
context ".name" do
|
20
|
+
should "return original_filename" do
|
21
|
+
def @image.original_filename
|
22
|
+
'frank.jpg'
|
23
|
+
end
|
24
|
+
Joint.name(@image).should == 'frank.jpg'
|
25
|
+
end
|
26
|
+
|
27
|
+
should "fall back to File.basename" do
|
28
|
+
Joint.name(@image).should == 'mr_t.jpg'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context ".size" do
|
33
|
+
should "return size" do
|
34
|
+
def @image.size
|
35
|
+
25
|
36
|
+
end
|
37
|
+
Joint.size(@image).should == 25
|
38
|
+
end
|
39
|
+
|
40
|
+
should "fall back to File.size" do
|
41
|
+
Joint.size(@image).should == 13661
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context ".type" do
|
46
|
+
should "return type if Joint::Io instance" do
|
47
|
+
file = Joint::IO.new(:type => 'image/jpeg')
|
48
|
+
Joint.type(@image).should == 'image/jpeg'
|
49
|
+
end
|
50
|
+
|
51
|
+
should "fall back to Wand" do
|
52
|
+
Joint.type(@image).should == 'image/jpeg'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "Using Joint plugin" do
|
57
|
+
should "add each attachment to attachment_names" do
|
58
|
+
Asset.attachment_names.should == Set.new([:image, :file])
|
59
|
+
EmbeddedAsset.attachment_names.should == Set.new([:image, :file])
|
60
|
+
end
|
61
|
+
|
62
|
+
should "add keys for each attachment" do
|
63
|
+
key_names.each do |key|
|
64
|
+
Asset.keys.should include("image_#{key}")
|
65
|
+
Asset.keys.should include("file_#{key}")
|
66
|
+
EmbeddedAsset.keys.should include("image_#{key}")
|
67
|
+
EmbeddedAsset.keys.should include("file_#{key}")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
should "add memoized accessors module" do
|
72
|
+
Asset.attachment_accessor_module.should be_instance_of(Module)
|
73
|
+
EmbeddedAsset.attachment_accessor_module.should be_instance_of(Module)
|
74
|
+
end
|
75
|
+
|
76
|
+
context "with inheritance" do
|
77
|
+
should "add attachment to attachment_names" do
|
78
|
+
BaseModel.attachment_names.should == Set.new([:file])
|
79
|
+
end
|
80
|
+
|
81
|
+
should "inherit attachments from superclass, but not share other inherited class attachments" do
|
82
|
+
Image.attachment_names.should == Set.new([:file, :image])
|
83
|
+
Video.attachment_names.should == Set.new([:file, :video])
|
84
|
+
end
|
85
|
+
|
86
|
+
should "add inherit keys from superclass" do
|
87
|
+
key_names.each do |key|
|
88
|
+
BaseModel.keys.should include("file_#{key}")
|
89
|
+
Image.keys.should include("file_#{key}")
|
90
|
+
Image.keys.should include("image_#{key}")
|
91
|
+
Video.keys.should include("file_#{key}")
|
92
|
+
Video.keys.should include("video_#{key}")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "Assigning new attachments to document" do
|
99
|
+
setup do
|
100
|
+
@doc = Asset.create(:image => @image, :file => @file)
|
101
|
+
rewind_files
|
102
|
+
end
|
103
|
+
subject { @doc }
|
104
|
+
|
105
|
+
should "assign GridFS content_type" do
|
106
|
+
grid.get(subject.image_id).content_type.should == 'image/jpeg'
|
107
|
+
grid.get(subject.file_id).content_type.should == 'application/pdf'
|
108
|
+
end
|
109
|
+
|
110
|
+
should "assign joint keys" do
|
111
|
+
subject.image_size.should == 13661
|
112
|
+
subject.file_size.should == 68926
|
113
|
+
|
114
|
+
subject.image_type.should == "image/jpeg"
|
115
|
+
subject.file_type.should == "application/pdf"
|
116
|
+
|
117
|
+
subject.image_id.should_not be_nil
|
118
|
+
subject.file_id.should_not be_nil
|
119
|
+
|
120
|
+
subject.image_id.should be_instance_of(BSON::ObjectId)
|
121
|
+
subject.file_id.should be_instance_of(BSON::ObjectId)
|
122
|
+
end
|
123
|
+
|
124
|
+
should "allow accessing keys through attachment proxy" do
|
125
|
+
subject.image.size.should == 13661
|
126
|
+
subject.file.size.should == 68926
|
127
|
+
|
128
|
+
subject.image.type.should == "image/jpeg"
|
129
|
+
subject.file.type.should == "application/pdf"
|
130
|
+
|
131
|
+
subject.image.id.should_not be_nil
|
132
|
+
subject.file.id.should_not be_nil
|
133
|
+
|
134
|
+
subject.image.id.should be_instance_of(BSON::ObjectId)
|
135
|
+
subject.file.id.should be_instance_of(BSON::ObjectId)
|
136
|
+
end
|
137
|
+
|
138
|
+
should "proxy unknown methods to GridIO object" do
|
139
|
+
subject.image.files_id.should == subject.image_id
|
140
|
+
subject.image.content_type.should == 'image/jpeg'
|
141
|
+
subject.image.filename.should == 'mr_t.jpg'
|
142
|
+
subject.image.file_length.should == 13661
|
143
|
+
end
|
144
|
+
|
145
|
+
should "assign file name from path if original file name not available" do
|
146
|
+
subject.image_name.should == 'mr_t.jpg'
|
147
|
+
subject.file_name.should == 'unixref.pdf'
|
148
|
+
end
|
149
|
+
|
150
|
+
should "save attachment contents correctly" do
|
151
|
+
subject.file.read.should == @file.read
|
152
|
+
subject.image.read.should == @image.read
|
153
|
+
end
|
154
|
+
|
155
|
+
should "know that attachment exists" do
|
156
|
+
subject.image?.should be(true)
|
157
|
+
subject.file?.should be(true)
|
158
|
+
end
|
159
|
+
|
160
|
+
should "respond with false when asked if the attachment is nil?" do
|
161
|
+
subject.image.nil?.should be(false)
|
162
|
+
subject.file.nil?.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)
|
233
|
+
end
|
234
|
+
|
235
|
+
should "respond with false when asked if the attachment is nil?" do
|
236
|
+
subject.image.nil?.should be(false)
|
237
|
+
subject.file.nil?.should be(false)
|
238
|
+
end
|
239
|
+
|
240
|
+
should "clear assigned attachments so they don't get uploaded twice" do
|
241
|
+
Mongo::Grid.any_instance.expects(:put).never
|
242
|
+
subject.save
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
|
247
|
+
context "Updating existing attachment" do
|
248
|
+
setup do
|
249
|
+
@doc = Asset.create(:file => @test1)
|
250
|
+
assert_no_grid_difference do
|
251
|
+
@doc.file = @test2
|
252
|
+
@doc.save!
|
253
|
+
end
|
254
|
+
rewind_files
|
255
|
+
end
|
256
|
+
subject { @doc }
|
257
|
+
|
258
|
+
should "not change attachment id" do
|
259
|
+
subject.file_id_changed?.should be(false)
|
260
|
+
end
|
261
|
+
|
262
|
+
should "update keys" do
|
263
|
+
subject.file_name.should == 'test2.txt'
|
264
|
+
subject.file_type.should == "text/plain"
|
265
|
+
subject.file_size.should == 5
|
266
|
+
end
|
267
|
+
|
268
|
+
should "update GridFS" do
|
269
|
+
grid.get(subject.file_id).filename.should == 'test2.txt'
|
270
|
+
grid.get(subject.file_id).content_type.should == 'text/plain'
|
271
|
+
grid.get(subject.file_id).file_length.should == 5
|
272
|
+
grid.get(subject.file_id).read.should == @test2.read
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
context "Updating existing attachment in embedded document" do
|
277
|
+
setup do
|
278
|
+
@asset = Asset.new
|
279
|
+
@doc = @asset.embedded_assets.build(:file => @test1)
|
280
|
+
@asset.save!
|
281
|
+
assert_no_grid_difference do
|
282
|
+
@doc.file = @test2
|
283
|
+
@doc.save!
|
284
|
+
end
|
285
|
+
rewind_files
|
286
|
+
end
|
287
|
+
subject { @doc }
|
288
|
+
|
289
|
+
# should "not change attachment id" do
|
290
|
+
# subject.file_id_changed?.should be(false)
|
291
|
+
# end
|
292
|
+
|
293
|
+
should "update keys" do
|
294
|
+
subject.file_name.should == 'test2.txt'
|
295
|
+
subject.file_type.should == "text/plain"
|
296
|
+
subject.file_size.should == 5
|
297
|
+
end
|
298
|
+
|
299
|
+
should "update GridFS" do
|
300
|
+
grid.get(subject.file_id).filename.should == 'test2.txt'
|
301
|
+
grid.get(subject.file_id).content_type.should == 'text/plain'
|
302
|
+
grid.get(subject.file_id).file_length.should == 5
|
303
|
+
grid.get(subject.file_id).read.should == @test2.read
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
context "Updating document but not attachments" do
|
308
|
+
setup do
|
309
|
+
@doc = Asset.create(:image => @image)
|
310
|
+
@doc.update_attributes(:title => 'Updated')
|
311
|
+
@doc.reload
|
312
|
+
rewind_files
|
313
|
+
end
|
314
|
+
subject { @doc }
|
315
|
+
|
316
|
+
should "not affect attachment" do
|
317
|
+
subject.image.read.should == @image.read
|
318
|
+
end
|
319
|
+
|
320
|
+
should "update document attributes" do
|
321
|
+
subject.title.should == 'Updated'
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
context "Updating embedded document but not attachments" do
|
326
|
+
setup do
|
327
|
+
@asset = Asset.new
|
328
|
+
@doc = @asset.embedded_assets.build(:image => @image)
|
329
|
+
@doc.update_attributes(:title => 'Updated')
|
330
|
+
@asset.reload
|
331
|
+
@doc = @asset.embedded_assets.first
|
332
|
+
rewind_files
|
333
|
+
end
|
334
|
+
subject { @doc }
|
335
|
+
|
336
|
+
should "not affect attachment" do
|
337
|
+
subject.image.read.should == @image.read
|
338
|
+
end
|
339
|
+
|
340
|
+
should "update document attributes" do
|
341
|
+
subject.title.should == 'Updated'
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
context "Assigning file where file pointer is not at beginning" do
|
346
|
+
setup do
|
347
|
+
@image.read
|
348
|
+
@doc = Asset.create(:image => @image)
|
349
|
+
@doc.reload
|
350
|
+
rewind_files
|
351
|
+
end
|
352
|
+
subject { @doc }
|
353
|
+
|
354
|
+
should "rewind and correctly store contents" do
|
355
|
+
subject.image.read.should == @image.read
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
context "Setting attachment to nil" do
|
360
|
+
setup do
|
361
|
+
@doc = Asset.create(:image => @image)
|
362
|
+
rewind_files
|
363
|
+
end
|
364
|
+
subject { @doc }
|
365
|
+
|
366
|
+
should "delete attachment after save" do
|
367
|
+
assert_no_grid_difference { subject.image = nil }
|
368
|
+
assert_grid_difference(-1) { subject.save }
|
369
|
+
end
|
370
|
+
|
371
|
+
should "know that the attachment has been nullified" do
|
372
|
+
subject.image = nil
|
373
|
+
subject.image?.should be(false)
|
374
|
+
end
|
375
|
+
|
376
|
+
should "respond with true when asked if the attachment is nil?" do
|
377
|
+
subject.image = nil
|
378
|
+
subject.image.nil?.should be(true)
|
379
|
+
end
|
380
|
+
|
381
|
+
should "clear nil attachments after save and not attempt to delete again" do
|
382
|
+
Mongo::Grid.any_instance.expects(:delete).once
|
383
|
+
subject.image = nil
|
384
|
+
subject.save
|
385
|
+
Mongo::Grid.any_instance.expects(:delete).never
|
386
|
+
subject.save
|
387
|
+
end
|
388
|
+
|
389
|
+
should "clear id, name, type, size" do
|
390
|
+
subject.image = nil
|
391
|
+
subject.save
|
392
|
+
assert_nil subject.image_id
|
393
|
+
assert_nil subject.image_name
|
394
|
+
assert_nil subject.image_type
|
395
|
+
assert_nil subject.image_size
|
396
|
+
subject.reload
|
397
|
+
assert_nil subject.image_id
|
398
|
+
assert_nil subject.image_name
|
399
|
+
assert_nil subject.image_type
|
400
|
+
assert_nil subject.image_size
|
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
|
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 "clear nil attachments after save and not attempt to delete again" do
|
429
|
+
Mongo::Grid.any_instance.expects(:delete).once
|
430
|
+
subject.image = nil
|
431
|
+
subject.save
|
432
|
+
Mongo::Grid.any_instance.expects(:delete).never
|
433
|
+
subject.save
|
434
|
+
end
|
435
|
+
|
436
|
+
should "clear id, name, type, size" do
|
437
|
+
subject.image = nil
|
438
|
+
subject.save
|
439
|
+
assert_nil subject.image_id
|
440
|
+
assert_nil subject.image_name
|
441
|
+
assert_nil subject.image_type
|
442
|
+
assert_nil subject.image_size
|
443
|
+
s = subject._root_document.reload.embedded_assets.first
|
444
|
+
assert_nil s.image_id
|
445
|
+
assert_nil s.image_name
|
446
|
+
assert_nil s.image_type
|
447
|
+
assert_nil s.image_size
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
context "Retrieving attachment that does not exist" do
|
452
|
+
setup do
|
453
|
+
@doc = Asset.create
|
454
|
+
rewind_files
|
455
|
+
end
|
456
|
+
subject { @doc }
|
457
|
+
|
458
|
+
should "know that the attachment is not present" do
|
459
|
+
subject.image?.should be(false)
|
460
|
+
end
|
461
|
+
|
462
|
+
should "respond with true when asked if the attachment is nil?" do
|
463
|
+
subject.image.nil?.should be(true)
|
464
|
+
end
|
465
|
+
|
466
|
+
should "raise Mongo::GridFileNotFound" do
|
467
|
+
assert_raises(Mongo::GridFileNotFound) { subject.image.read }
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
context "Destroying a document" do
|
472
|
+
setup do
|
473
|
+
@doc = Asset.create(:image => @image)
|
474
|
+
rewind_files
|
475
|
+
end
|
476
|
+
subject { @doc }
|
477
|
+
|
478
|
+
should "remove files from grid fs as well" do
|
479
|
+
assert_grid_difference(-1) { subject.destroy }
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
context "Destroying an embedded document's _root_document" do
|
484
|
+
setup do
|
485
|
+
@asset = Asset.new
|
486
|
+
@doc = @asset.embedded_assets.build(:image => @image)
|
487
|
+
@doc.save!
|
488
|
+
rewind_files
|
489
|
+
end
|
490
|
+
subject { @doc }
|
491
|
+
|
492
|
+
should "remove files from grid fs as well" do
|
493
|
+
assert_grid_difference(-1) { subject._root_document.destroy }
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
# What about when an embedded document is removed?
|
498
|
+
|
499
|
+
context "Assigning file name" do
|
500
|
+
should "default to path" do
|
501
|
+
Asset.create(:image => @image).image.name.should == 'mr_t.jpg'
|
502
|
+
end
|
503
|
+
|
504
|
+
should "use original_filename if available" do
|
505
|
+
def @image.original_filename
|
506
|
+
'testing.txt'
|
507
|
+
end
|
508
|
+
doc = Asset.create(:image => @image)
|
509
|
+
assert_equal 'testing.txt', doc.image_name
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
context "Validating attachment presence" do
|
514
|
+
setup do
|
515
|
+
@model_class = Class.new do
|
516
|
+
include MongoMapper::Document
|
517
|
+
plugin Joint
|
518
|
+
attachment :file, :required => true
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
should "work" do
|
523
|
+
model = @model_class.new
|
524
|
+
model.should_not be_valid
|
525
|
+
|
526
|
+
model.file = @file
|
527
|
+
model.should be_valid
|
528
|
+
|
529
|
+
model.file = nil
|
530
|
+
model.should_not be_valid
|
531
|
+
|
532
|
+
model.file = @image
|
533
|
+
model.should be_valid
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
context "Assigning joint io instance" do
|
538
|
+
setup do
|
539
|
+
io = Joint::IO.new({
|
540
|
+
:name => 'foo.txt',
|
541
|
+
:type => 'plain/text',
|
542
|
+
:content => 'This is my stuff',
|
543
|
+
:size => 19,
|
544
|
+
})
|
545
|
+
@asset = Asset.create(:file => io)
|
546
|
+
end
|
547
|
+
|
548
|
+
should "work" do
|
549
|
+
@asset.file_name.should == 'foo.txt'
|
550
|
+
@asset.file_size.should == 19
|
551
|
+
@asset.file_type.should == 'plain/text'
|
552
|
+
@asset.file.read.should == 'This is my stuff'
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
context "A font file" do
|
557
|
+
setup do
|
558
|
+
@file = open_file('font.eot')
|
559
|
+
@doc = Asset.create(:file => @file)
|
560
|
+
end
|
561
|
+
subject { @doc }
|
562
|
+
|
563
|
+
should "assign joint keys" do
|
564
|
+
subject.file_size.should == 17610
|
565
|
+
subject.file_type.should == "application/octet-stream"
|
566
|
+
subject.file_id.should_not be_nil
|
567
|
+
subject.file_id.should be_instance_of(BSON::ObjectId)
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
context "A music file" do
|
572
|
+
setup do
|
573
|
+
@file = open_file('example.m4r')
|
574
|
+
@doc = Asset.create(:file => @file)
|
575
|
+
end
|
576
|
+
subject { @doc }
|
577
|
+
|
578
|
+
should "assign joint keys" do
|
579
|
+
subject.file_size.should == 50790
|
580
|
+
subject.file_type.should == "audio/mp4"
|
581
|
+
subject.file_id.should_not be_nil
|
582
|
+
subject.file_id.should be_instance_of(BSON::ObjectId)
|
583
|
+
end
|
584
|
+
end
|
585
|
+
end
|
metadata
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jamieorc-joint
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 7
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 5
|
9
|
+
- 6
|
10
|
+
version: 0.5.6
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- John Nunemaker
|
14
|
+
- Jamie Orchard-Hays
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-11-23 00:00:00 -05:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: wand
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 3
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
- 4
|
34
|
+
version: "0.4"
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: mime-types
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
type: :runtime
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: mongo_mapper
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 51
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
- 8
|
63
|
+
- 6
|
64
|
+
version: 0.8.6
|
65
|
+
type: :runtime
|
66
|
+
version_requirements: *id003
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: shoulda
|
69
|
+
prerelease: false
|
70
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 3
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
version: "0"
|
79
|
+
type: :development
|
80
|
+
version_requirements: *id004
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: mocha
|
83
|
+
prerelease: false
|
84
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
hash: 3
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
type: :development
|
94
|
+
version_requirements: *id005
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: jnunemaker-matchy
|
97
|
+
prerelease: false
|
98
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
hash: 3
|
104
|
+
segments:
|
105
|
+
- 0
|
106
|
+
version: "0"
|
107
|
+
type: :development
|
108
|
+
version_requirements: *id006
|
109
|
+
description: MongoMapper and GridFS joined in file upload love.
|
110
|
+
email: jamieorc@gmail.com
|
111
|
+
executables: []
|
112
|
+
|
113
|
+
extensions: []
|
114
|
+
|
115
|
+
extra_rdoc_files: []
|
116
|
+
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- Gemfile
|
120
|
+
- Gemfile.lock
|
121
|
+
- LICENSE
|
122
|
+
- README.rdoc
|
123
|
+
- Rakefile
|
124
|
+
- joint.gemspec
|
125
|
+
- lib/joint.rb
|
126
|
+
- lib/joint/attachment_proxy.rb
|
127
|
+
- lib/joint/class_methods.rb
|
128
|
+
- lib/joint/instance_methods.rb
|
129
|
+
- lib/joint/io.rb
|
130
|
+
- lib/joint/version.rb
|
131
|
+
- specs.watchr
|
132
|
+
- test/fixtures/example.m4r
|
133
|
+
- test/fixtures/font.eot
|
134
|
+
- test/fixtures/harmony.png
|
135
|
+
- test/fixtures/mr_t.jpg
|
136
|
+
- test/fixtures/test1.txt
|
137
|
+
- test/fixtures/test2.txt
|
138
|
+
- test/fixtures/unixref.pdf
|
139
|
+
- test/helper.rb
|
140
|
+
- test/joint/test_io.rb
|
141
|
+
- test/test_joint.rb
|
142
|
+
has_rdoc: true
|
143
|
+
homepage: http://github.com/jamieorc/joint
|
144
|
+
licenses: []
|
145
|
+
|
146
|
+
post_install_message:
|
147
|
+
rdoc_options: []
|
148
|
+
|
149
|
+
require_paths:
|
150
|
+
- lib
|
151
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
152
|
+
none: false
|
153
|
+
requirements:
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
hash: 3
|
157
|
+
segments:
|
158
|
+
- 0
|
159
|
+
version: "0"
|
160
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ">="
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
hash: 3
|
166
|
+
segments:
|
167
|
+
- 0
|
168
|
+
version: "0"
|
169
|
+
requirements: []
|
170
|
+
|
171
|
+
rubyforge_project:
|
172
|
+
rubygems_version: 1.5.2
|
173
|
+
signing_key:
|
174
|
+
specification_version: 3
|
175
|
+
summary: MongoMapper and GridFS joined in file upload love.
|
176
|
+
test_files:
|
177
|
+
- test/fixtures/example.m4r
|
178
|
+
- test/fixtures/font.eot
|
179
|
+
- test/fixtures/harmony.png
|
180
|
+
- test/fixtures/mr_t.jpg
|
181
|
+
- test/fixtures/test1.txt
|
182
|
+
- test/fixtures/test2.txt
|
183
|
+
- test/fixtures/unixref.pdf
|
184
|
+
- test/helper.rb
|
185
|
+
- test/joint/test_io.rb
|
186
|
+
- test/test_joint.rb
|