moped-gridfs 1.0.0

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,29 @@
1
+ require "moped/gridfs/bucketable"
2
+ require "moped/gridfs/file"
3
+
4
+ module Moped
5
+ module GridFS
6
+ class Files
7
+ include Enumerable
8
+ include Bucketable
9
+
10
+ attr_reader :bucket
11
+
12
+ def initialize(bucket)
13
+ @bucket = bucket
14
+ end
15
+
16
+ def [](id)
17
+ bucket.open(id, 'r')
18
+ end
19
+
20
+ def count
21
+ files_collection.find.count
22
+ end
23
+
24
+ def each(&block)
25
+ files_collection.find.each { |document| yield(self[document['_id']]) }
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ module Moped
2
+ module GridFS
3
+ module Inspectable
4
+
5
+ private
6
+
7
+ def build_inspect_string(hash)
8
+ memaddr = (__send__(:object_id) << 1).to_s(16)
9
+ string = "#<#{self.class.name}:#{memaddr}"
10
+ hash.each { |k, v| string << " #{k}=#{v}" }
11
+ string << ">"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ module Moped
2
+ module GridFS
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,26 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'moped/gridfs/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "moped-gridfs"
7
+ spec.version = Moped::GridFS::VERSION
8
+ spec.authors = ["topac"]
9
+ spec.email = ["dani.m.mobile@gmail.com"]
10
+ spec.summary = %q{mongoDB GridFS implementation for Moped}
11
+ spec.description = %q{mongoDB GridFS implementation for Moped}
12
+ spec.homepage = "https://www.github.com/topac/moped-gridfs"
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency("moped")
21
+
22
+ spec.add_development_dependency("bundler", "~> 1.6")
23
+ spec.add_development_dependency("rake")
24
+ spec.add_development_dependency("rspec")
25
+ spec.add_development_dependency("pry")
26
+ end
data/perf/compare.rb ADDED
@@ -0,0 +1,143 @@
1
+ # Compare with mongo-ruby-driver
2
+ # $ gem install mongo
3
+ # $ gem install bson_ext
4
+
5
+ $INCLUDE_MONGO = true
6
+
7
+ require_relative 'perf_helper'
8
+
9
+ def reset
10
+ purge
11
+
12
+ @bucket = moped_session.bucket
13
+ @grid = Mongo::GridFileSystem.new(mongo_connection)
14
+ end
15
+
16
+ def content(size = 0.5) # 0.5 mb
17
+ "\xDF\x00\xAB\xFA" * (1024 * 1024 * size)
18
+ end
19
+
20
+ profile("Create an empty file", n: [1000, 5_000]) do |bm, n|
21
+ reset
22
+
23
+ bm.report do
24
+ n.times { |i| @bucket.open("file#{i}", 'w') }
25
+ end
26
+
27
+ reset
28
+
29
+ bm.report do
30
+ n.times { |i| @grid.open( "file#{i}", 'w').close }
31
+ end
32
+ end
33
+
34
+ profile("Create and write a file", n: [10, 100]) do |bm, n|
35
+ reset
36
+
37
+ bm.report do
38
+ n.times { |i| @bucket.open("file#{i}", 'w').write(content) }
39
+ end
40
+
41
+ reset
42
+
43
+ bm.report do
44
+ n.times do |i|
45
+ file = @grid.open("file", "w")
46
+ file.write(content)
47
+ file.close
48
+ end
49
+ end
50
+ end
51
+
52
+ profile("Sequentially write on a file", n: [1000, 5_000]) do |bm, n|
53
+ reset
54
+ file = @bucket.open("file", 'w')
55
+
56
+ bm.report do
57
+ n.times { |i| file.write("foobar") }
58
+ end
59
+
60
+ reset
61
+ file = @grid.open("file", "w")
62
+
63
+ bm.report do
64
+ (n-1).times { |i| file.write("foobar") }
65
+ file.close
66
+ end
67
+ end
68
+
69
+ profile("Open a file in r mode", n: [1000, 5_000]) do |bm, n|
70
+ reset
71
+ @bucket.open("file", 'w')
72
+
73
+ bm.report do
74
+ n.times { |i| @bucket.open("file", "r") }
75
+ end
76
+
77
+ reset
78
+ @grid.open("file", 'w').close
79
+
80
+ bm.report do
81
+ n.times { |i| @grid.open("file", "r") }
82
+ end
83
+ end
84
+
85
+ profile("Open a file in w mode", n: [1000, 5_000]) do |bm, n|
86
+ reset
87
+
88
+ bm.report do
89
+ n.times { |i| @bucket.open("file", "w") }
90
+ end
91
+
92
+ reset
93
+
94
+ bm.report do
95
+ n.times { |i| @grid.open("file", "w") }
96
+ end
97
+ end
98
+
99
+ def write_sample_file(klass)
100
+ file = klass.open("file", 'w')
101
+ file.write(content)
102
+ file.close if file.respond_to?(:close)
103
+
104
+ klass.open("file", "r")
105
+ end
106
+
107
+ profile("Read a whole file from the beginning", n: 100) do |bm, n|
108
+ reset
109
+ file = write_sample_file(@bucket)
110
+
111
+ bm.report do
112
+ n.times { |i| file.seek(0); file.read }
113
+ end
114
+
115
+ reset
116
+ file = write_sample_file(@grid)
117
+
118
+ bm.report do
119
+ n.times { |i| file.seek(0); file.read }
120
+ end
121
+ end
122
+
123
+ profile("Read 100 bytes a time till the end", n: [10, 100]) do |bm, n|
124
+ reset
125
+ file = write_sample_file(@bucket)
126
+
127
+ bm.report do
128
+ n.times do |i|
129
+ file.seek(0)
130
+ while !file.eof?; file.read(100); end
131
+ end
132
+ end
133
+
134
+ reset
135
+ file = write_sample_file(@grid)
136
+
137
+ bm.report do
138
+ n.times do |i|
139
+ file.seek(0)
140
+ while !file.eof?; file.read(100); end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,33 @@
1
+ require 'benchmark'
2
+ require_relative '../spec/spec_helper'
3
+
4
+ if $INCLUDE_MONGO
5
+ require 'mongo'
6
+
7
+ def mongo_connection
8
+ client = Mongo::MongoClient.new(ENV["MOPED-GRIDFS_SPEC_HOST"], ENV["MOPED-GRIDFS_SPEC_PORT"])
9
+ client[ENV["MOPED-GRIDFS_SPEC_DB"]]
10
+ end
11
+
12
+ module Mongo
13
+ class GridIO
14
+ def warn(*args); end
15
+ end
16
+ end
17
+ end
18
+
19
+ def purge
20
+ drop_all_collections
21
+ end
22
+
23
+ def profile(message, options = {})
24
+ ary = [options[:n] || 1].flatten
25
+
26
+ ary.each do |n|
27
+ puts message+" (#{n} times)"
28
+
29
+ Benchmark.bm do |bm|
30
+ yield(bm, n)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+ require 'moped/gridfs/bucket'
3
+
4
+ describe Moped::GridFS::Bucket do
5
+
6
+ let(:session) { moped_session }
7
+
8
+ describe '#initialize' do
9
+
10
+ context 'when the given name is empty' do
11
+
12
+ it 'raises an error' do
13
+ expect { described_class.new(session, '') }.to raise_error
14
+ end
15
+ end
16
+
17
+ context 'when the given name is nil' do
18
+
19
+ it 'raises an error' do
20
+ expect { described_class.new(session, nil) }.to raise_error
21
+ end
22
+ end
23
+
24
+ context 'when the given name is not empty nor nil' do
25
+
26
+ it 'does not raise any error' do
27
+ expect { described_class.new(session, 'foo') }.not_to raise_error
28
+ end
29
+ end
30
+ end
31
+
32
+ let(:subject) { described_class.new(session, 'bar') }
33
+
34
+ describe '#files' do
35
+
36
+ it 'returns an enumerable' do
37
+ expect(subject.files).to respond_to(:each)
38
+ end
39
+ end
40
+
41
+ describe '#drop' do
42
+
43
+ before do
44
+ subject.files_collection.insert(foo: 'bar')
45
+ subject.chunks_collection.insert(foo: 'bar')
46
+ end
47
+
48
+ it 'drops the two collections' do
49
+ subject.drop
50
+
51
+ expect(subject.files_collection.find.count).to eq(0)
52
+ expect(subject.chunks_collection.find.count).to eq(0)
53
+ end
54
+ end
55
+
56
+ describe '#delete' do
57
+
58
+ context 'when a file is missing' do
59
+
60
+ it 'returns nil' do
61
+ expect(subject.delete("file")).to be_nil
62
+ end
63
+ end
64
+
65
+ context 'when a file exists' do
66
+
67
+ before do
68
+ subject.open("file", "w").write("buffer")
69
+ end
70
+
71
+ it 'not to returns nil' do
72
+ expect(subject.delete("file")).not_to be_nil
73
+ end
74
+
75
+ it 'deletes the file' do
76
+ subject.delete("file")
77
+ expect { subject.open("foo", "r") }.to raise_error
78
+ end
79
+ end
80
+ end
81
+
82
+ describe '#open' do
83
+
84
+ context 'when the mode is w' do
85
+
86
+ it 'returns a writable file' do
87
+ expect(subject.open("foo", "w")).to be_writable
88
+ end
89
+ end
90
+
91
+ context 'when the mode is r' do
92
+
93
+ context 'and the file is missing' do
94
+
95
+ it 'raises an error' do
96
+ expect { subject.open("foo", "r") }.to raise_error
97
+ end
98
+ end
99
+
100
+ context 'and the file exists' do
101
+
102
+ before do
103
+ subject.open("bar", "w").write("buffer")
104
+ end
105
+
106
+ it 'returns a readable file' do
107
+ expect(subject.open("bar", "r")).to be_readable
108
+ end
109
+ end
110
+ end
111
+
112
+ context 'when the mode is a' do
113
+
114
+ it 'returns a writable file' do
115
+ expect(subject.open("foo", "a")).to be_writable
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+ require 'moped/gridfs/buckets'
3
+
4
+ describe Moped::GridFS::Buckets do
5
+
6
+ let(:session) { moped_session }
7
+
8
+ let(:subject) { described_class.new(session) }
9
+
10
+ before do
11
+ Moped::GridFS::Bucket.new(session, "bar").open("file", "w")
12
+ Moped::GridFS::Bucket.new(session, "foo").open("file", "w")
13
+ end
14
+
15
+ describe '#names' do
16
+
17
+ it 'returns the bucket names' do
18
+ expect(subject.names.sort).to eq(%w[bar foo])
19
+ end
20
+ end
21
+
22
+ describe '#count' do
23
+
24
+ it 'returns the buckets count' do
25
+ expect(subject.count).to eq(2)
26
+ end
27
+ end
28
+
29
+ describe '#[]' do
30
+
31
+ it 'returns a bucket with the given name' do
32
+ bucket = subject['test']
33
+ expect(bucket.name).to eq('test')
34
+ end
35
+ end
36
+
37
+ describe '#each' do
38
+
39
+ it 'iterates over the buckets' do
40
+ names = []
41
+ subject.each { |bucket| names << bucket.name }
42
+ expect(names.sort).to eq(%w[bar foo])
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+ require 'moped/gridfs/file'
3
+
4
+ require_relative 'write'
5
+ require_relative 'read'
6
+ require_relative 'getters'
7
+ require_relative 'setters'
8
+
9
+ describe Moped::GridFS::File do
10
+
11
+ $chunk_size = 5
12
+
13
+ before do
14
+ described_class.any_instance.stub(:default_chunk_size).and_return($chunk_size)
15
+ end
16
+
17
+ let(:session) { moped_session }
18
+
19
+ let(:bucket) { session.bucket }
20
+
21
+ context 'when mode is r' do
22
+
23
+ let(:access_mode) { 'r' }
24
+
25
+ include_examples :read, :getters
26
+
27
+ let(:file) do
28
+ bucket.open("file", "w").write("foobar")
29
+ bucket.open("file", access_mode)
30
+ end
31
+
32
+ it 'cannot be written' do
33
+ expect { file.write("foo") }.to raise_error
34
+ end
35
+
36
+ it 'does not have setters' do
37
+ %w[content_type metadata aliases filename upload_date].each do |name|
38
+ expect(file).not_to respond_to(:"#{name}=")
39
+ end
40
+ end
41
+ end
42
+
43
+ context 'when mode is r+' do
44
+
45
+ let(:access_mode) { 'r+' }
46
+
47
+ include_examples :read, :getters, :setters
48
+ end
49
+
50
+ context 'when mode is w' do
51
+
52
+ let(:access_mode) { 'w' }
53
+
54
+ include_examples :write, :getters, :setters
55
+
56
+ it 'cannot be readed' do
57
+ bucket.open("file", "w").write("foobar")
58
+ file = bucket.open("file", access_mode)
59
+ expect { file.read }.to raise_error
60
+ end
61
+ end
62
+
63
+ context 'when mode is w+' do
64
+
65
+ let(:access_mode) { 'w+' }
66
+
67
+ include_examples :write, :getters, :setters
68
+ end
69
+
70
+ context 'when mode is a' do
71
+
72
+ let(:access_mode) { 'a' }
73
+
74
+ include_examples :write, :getters, :setters
75
+ end
76
+
77
+ context 'when mode is a+' do
78
+
79
+ let(:access_mode) { 'a+' }
80
+
81
+ include_examples :write, :read, :getters, :setters
82
+ end
83
+ end