mongoid-grid_fs 2.0.0 → 2.1.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.
@@ -1,2 +1,2 @@
1
- require 'mongoid-grid_fs.rb' unless defined?(Mongoid::GridFS)
2
- Mongoid::GridFS
1
+ require 'mongoid/grid_fs' unless defined?(Mongoid::GridFs)
2
+ Mongoid::GridFs
@@ -1,2 +1,2 @@
1
- require 'mongoid-grid_fs.rb' unless defined?(Mongoid::GridFS::Fs::Chunk)
2
- Mongoid::GridFS::Fs::Chunk
1
+ require 'mongoid/grid_fs' unless defined?(Mongoid::GridFs::Fs::Chunk)
2
+ Mongoid::GridFs::Fs::Chunk
@@ -1,2 +1,2 @@
1
- require 'mongoid-grid_fs.rb' unless defined?(Mongoid::GridFS::Fs::File)
2
- Mongoid::GridFS::Fs::File
1
+ require 'mongoid/grid_fs' unless defined?(Mongoid::GridFs::Fs::File)
2
+ Mongoid::GridFs::Fs::File
@@ -1,644 +1 @@
1
- ##
2
- #
3
- module Mongoid
4
- class GridFS
5
- const_set :Version, '2.0.0'
6
-
7
- class << GridFS
8
- def version
9
- const_get :Version
10
- end
11
-
12
- def dependencies
13
- {
14
- 'mongoid' => [ 'mongoid' , '>= 3.0', '< 5.0' ] ,
15
- 'mime/types' => [ 'mime-types' , '>= 1.0', '< 3.0'] ,
16
- }
17
- end
18
-
19
- def libdir(*args, &block)
20
- @libdir ||= File.expand_path(__FILE__).sub(/\.rb$/,'')
21
- args.empty? ? @libdir : File.join(@libdir, *args)
22
- ensure
23
- if block
24
- begin
25
- $LOAD_PATH.unshift(@libdir)
26
- block.call()
27
- ensure
28
- $LOAD_PATH.shift()
29
- end
30
- end
31
- end
32
-
33
- def load(*libs)
34
- libs = libs.join(' ').scan(/[^\s+]+/)
35
- libdir{ libs.each{|lib| Kernel.load(lib) } }
36
- end
37
- end
38
-
39
- begin
40
- require 'rubygems'
41
- rescue LoadError
42
- nil
43
- end
44
-
45
- if defined?(gem)
46
- dependencies.each do |lib, dependency|
47
- gem(*dependency)
48
- require(lib)
49
- end
50
- end
51
-
52
- require "digest/md5"
53
- require "cgi"
54
- end
55
- end
56
-
57
- ##
58
- #
59
- module Mongoid
60
- class GridFS
61
- class << GridFS
62
- attr_accessor :namespace
63
- attr_accessor :file_model
64
- attr_accessor :chunk_model
65
-
66
- def init!
67
- GridFS.build_namespace_for(:Fs)
68
-
69
- GridFS.namespace = Fs
70
- GridFS.file_model = Fs.file_model
71
- GridFS.chunk_model = Fs.chunk_model
72
-
73
- const_set(:File, Fs.file_model)
74
- const_set(:Chunk, Fs.chunk_model)
75
-
76
- to_delegate = %w(
77
- put
78
- get
79
- delete
80
- find
81
- []
82
- []=
83
- clear
84
- )
85
-
86
- to_delegate.each do |method|
87
- class_eval <<-__
88
- def self.#{ method }(*args, &block)
89
- ::Mongoid::GridFS::Fs::#{ method }(*args, &block)
90
- end
91
- __
92
- end
93
- end
94
- end
95
-
96
- ##
97
- #
98
- def GridFS.namespace_for(prefix)
99
- prefix = prefix.to_s.downcase
100
- const = "::GridFS::#{ prefix.to_s.camelize }"
101
- namespace = const.split(/::/).last
102
- const_defined?(namespace) ? const_get(namespace) : build_namespace_for(namespace)
103
- end
104
-
105
- ##
106
- #
107
- def GridFS.build_namespace_for(prefix)
108
- prefix = prefix.to_s.downcase
109
- const = prefix.camelize
110
-
111
- namespace =
112
- Module.new do
113
- module_eval(&NamespaceMixin)
114
- self
115
- end
116
-
117
- const_set(const, namespace)
118
-
119
- file_model = build_file_model_for(namespace)
120
- chunk_model = build_chunk_model_for(namespace)
121
-
122
- file_model.namespace = namespace
123
- chunk_model.namespace = namespace
124
-
125
- file_model.chunk_model = chunk_model
126
- chunk_model.file_model = file_model
127
-
128
- namespace.prefix = prefix
129
- namespace.file_model = file_model
130
- namespace.chunk_model = chunk_model
131
-
132
- namespace.send(:const_set, :File, file_model)
133
- namespace.send(:const_set, :Chunk, chunk_model)
134
-
135
- #at_exit{ file_model.create_indexes rescue nil }
136
- #at_exit{ chunk_model.create_indexes rescue nil }
137
-
138
- const_get(const)
139
- end
140
-
141
- NamespaceMixin = proc do
142
- class << self
143
- attr_accessor :prefix
144
- attr_accessor :file_model
145
- attr_accessor :chunk_model
146
-
147
- def to_s
148
- prefix
149
- end
150
-
151
- def namespace
152
- prefix
153
- end
154
-
155
- def put(readable, attributes = {})
156
- chunks = []
157
- file = file_model.new
158
- attributes.to_options!
159
-
160
- if attributes.has_key?(:id)
161
- file.id = attributes.delete(:id)
162
- end
163
-
164
- if attributes.has_key?(:_id)
165
- file.id = attributes.delete(:_id)
166
- end
167
-
168
- if attributes.has_key?(:content_type)
169
- attributes[:contentType] = attributes.delete(:content_type)
170
- end
171
-
172
- if attributes.has_key?(:upload_date)
173
- attributes[:uploadDate] = attributes.delete(:upload_date)
174
- end
175
-
176
- if attributes.has_key?(:meta_data)
177
- attributes[:metadata] = attributes.delete(:meta_data)
178
- end
179
-
180
- if attributes.has_key?(:aliases)
181
- attributes[:aliases] = Array(attributes.delete(:aliases)).flatten.compact.map{|a| "#{ a }"}
182
- end
183
-
184
- md5 = Digest::MD5.new
185
- length = 0
186
- chunkSize = file.chunkSize
187
- n = 0
188
-
189
- GridFS.reading(readable) do |io|
190
- unless attributes.has_key?(:filename)
191
- attributes[:filename] =
192
- [file.id.to_s, GridFS.extract_basename(io)].join('/').squeeze('/')
193
- end
194
-
195
- unless attributes.has_key?(:contentType)
196
- attributes[:contentType] =
197
- GridFS.extract_content_type(attributes[:filename]) || file.contentType
198
- end
199
-
200
- GridFS.chunking(io, chunkSize) do |buf|
201
- md5 << buf
202
- length += buf.size
203
- chunk = file.chunks.build
204
- chunk.data = binary_for(buf)
205
- chunk.n = n
206
- n += 1
207
- chunk.save!
208
- chunks.push(chunk)
209
- end
210
- end
211
-
212
- attributes[:length] ||= length
213
- attributes[:uploadDate] ||= Time.now.utc
214
- attributes[:md5] ||= md5.hexdigest
215
-
216
- file.update_attributes(attributes)
217
-
218
- file.save!
219
- file
220
- rescue
221
- chunks.each{|chunk| chunk.destroy rescue nil}
222
- raise
223
- end
224
-
225
- def binary_for(*buf)
226
- if defined?(Moped::BSON)
227
- Moped::BSON::Binary.new(:generic, buf.join)
228
- else
229
- BSON::Binary.new(buf.join, :generic)
230
- end
231
- end
232
-
233
- def get(id)
234
- file_model.find(id)
235
- end
236
-
237
- def delete(id)
238
- file_model.find(id).destroy
239
- rescue
240
- nil
241
- end
242
-
243
- def where(conditions = {})
244
- case conditions
245
- when String
246
- file_model.where(:filename => conditions)
247
- else
248
- file_model.where(conditions)
249
- end
250
- end
251
-
252
- def find(*args)
253
- where(*args).first
254
- end
255
-
256
- def [](filename)
257
- file_model.
258
- where(:filename => filename.to_s).
259
- order_by(:uploadDate => :desc).
260
- limit(1).
261
- first
262
- end
263
-
264
- def []=(filename, readable)
265
- put(readable, :filename => filename.to_s)
266
- end
267
-
268
- def clear
269
- file_model.destroy_all
270
- end
271
-
272
- # TODO - opening with a mode = 'w' should return a GridIO::IOProxy
273
- # implementing a StringIO-like interface
274
- #
275
- def open(filename, mode = 'r', &block)
276
- raise NotImplementedError
277
- end
278
- end
279
- end
280
-
281
- ##
282
- #
283
- class Defaults < ::Hash
284
- def method_missing(method, *args, &block)
285
- case method.to_s
286
- when /(.*)=/
287
- key = $1
288
- val = args.first
289
- update(key => val)
290
- else
291
- key = method.to_s
292
- super unless has_key?(key)
293
- fetch(key)
294
- end
295
- end
296
- end
297
-
298
- ##
299
- #
300
- def GridFS.build_file_model_for(namespace)
301
- prefix = namespace.name.split(/::/).last.downcase
302
- file_model_name = "#{ namespace.name }::File"
303
- chunk_model_name = "#{ namespace.name }::Chunk"
304
-
305
- Class.new do
306
- include Mongoid::Document
307
- include Mongoid::Attributes::Dynamic if Mongoid::VERSION.to_i >= 4
308
-
309
- singleton_class = class << self; self; end
310
-
311
- singleton_class.instance_eval do
312
- define_method(:name){ file_model_name }
313
- attr_accessor :namespace
314
- attr_accessor :chunk_model
315
- attr_accessor :defaults
316
- end
317
-
318
- self.store_in :collection => "#{ prefix }.files"
319
-
320
- self.defaults = Defaults.new
321
-
322
- self.defaults.chunkSize = 4 * (mb = 2**20)
323
- self.defaults.contentType = 'application/octet-stream'
324
-
325
- field(:length, :type => Integer, :default => 0)
326
- field(:chunkSize, :type => Integer, :default => defaults.chunkSize)
327
- field(:uploadDate, :type => Time, :default => Time.now.utc)
328
- field(:md5, :type => String, :default => Digest::MD5.hexdigest(''))
329
-
330
- field(:filename, :type => String)
331
- field(:contentType, :type => String, :default => defaults.contentType)
332
- field(:aliases, :type => Array)
333
- field(:metadata) rescue nil
334
-
335
- required = %w( length chunkSize uploadDate md5 )
336
-
337
- required.each do |f|
338
- validates_presence_of(f)
339
- end
340
-
341
- index({:filename => 1})
342
- index({:aliases => 1})
343
- index({:uploadDate => 1})
344
- index({:md5 => 1})
345
-
346
- has_many(:chunks, :class_name => chunk_model_name, :inverse_of => :files, :dependent => :destroy, :order => [:n, :asc])
347
-
348
- def path
349
- filename
350
- end
351
-
352
- def basename
353
- ::File.basename(filename) if filename
354
- end
355
-
356
- def attachment_filename(*paths)
357
- return basename if basename
358
-
359
- if paths.empty?
360
- paths.push('attachment')
361
- paths.push(id.to_s)
362
- paths.push(updateDate.iso8601)
363
- end
364
-
365
- path = paths.join('--')
366
- base = ::File.basename(path).split('.', 2).first
367
- ext = GridFS.extract_extension(contentType)
368
-
369
- "#{ base }.#{ ext }"
370
- end
371
-
372
- def prefix
373
- self.class.namespace.prefix
374
- end
375
-
376
- def each(&block)
377
- fetched, limit = 0, 7
378
-
379
- while fetched < chunks.size
380
- chunks.where(:n.lt => fetched+limit, :n.gte => fetched).
381
- order_by([:n, :asc]).each do |chunk|
382
- block.call(chunk.to_s)
383
- end
384
-
385
- fetched += limit
386
- end
387
- end
388
-
389
- def slice(*args)
390
- case args.first
391
- when Range
392
- range = args.first
393
- first_chunk = (range.min / chunkSize).floor
394
- last_chunk = (range.max / chunkSize).floor
395
- offset = range.min % chunkSize
396
- length = range.max - range.min + 1
397
- when Fixnum
398
- start = args.first
399
- start = self.length + start if start < 0
400
- length = args.size == 2 ? args.last : 1
401
- first_chunk = (start / chunkSize).floor
402
- last_chunk = ((start + length) / chunkSize).floor
403
- offset = start % chunkSize
404
- end
405
-
406
- data = ''
407
-
408
- chunks.where(:n => (first_chunk..last_chunk)).order_by(n: 'asc').each do |chunk|
409
- data << chunk
410
- end
411
-
412
- data[offset, length]
413
- end
414
-
415
- def data
416
- data = ''
417
- each{|chunk| data << chunk}
418
- data
419
- end
420
-
421
- def base64
422
- Array(to_s).pack('m')
423
- end
424
-
425
- def data_uri(options = {})
426
- data = base64.chomp
427
- "data:#{ content_type };base64,".concat(data)
428
- end
429
-
430
- def bytes(&block)
431
- if block
432
- each{|data| block.call(data)}
433
- length
434
- else
435
- bytes = []
436
- each{|data| bytes.push(*data)}
437
- bytes
438
- end
439
- end
440
-
441
- def close
442
- self
443
- end
444
-
445
- def content_type
446
- contentType
447
- end
448
-
449
- def update_date
450
- updateDate
451
- end
452
-
453
- def created_at
454
- updateDate
455
- end
456
-
457
- def namespace
458
- self.class.namespace
459
- end
460
- end
461
- end
462
-
463
- ##
464
- #
465
- def GridFS.build_chunk_model_for(namespace)
466
- prefix = namespace.name.split(/::/).last.downcase
467
- file_model_name = "#{ namespace.name }::File"
468
- chunk_model_name = "#{ namespace.name }::Chunk"
469
-
470
- Class.new do
471
- include Mongoid::Document
472
-
473
- singleton_class = class << self; self; end
474
-
475
- singleton_class.instance_eval do
476
- define_method(:name){ chunk_model_name }
477
- attr_accessor :file_model
478
- attr_accessor :namespace
479
- end
480
-
481
- self.store_in :collection => "#{ prefix }.chunks"
482
-
483
- field(:n, :type => Integer, :default => 0)
484
- field(:data, :type => (defined?(Moped::BSON) ? Moped::BSON::Binary : BSON::Binary))
485
-
486
- belongs_to(:file, :foreign_key => :files_id, :class_name => file_model_name)
487
-
488
- index({:files_id => 1, :n => -1}, :unique => true)
489
-
490
- def namespace
491
- self.class.namespace
492
- end
493
-
494
- def to_s
495
- data.data
496
- end
497
-
498
- alias_method 'to_str', 'to_s'
499
- end
500
- end
501
-
502
- ##
503
- #
504
- def GridFS.reading(arg, &block)
505
- if arg.respond_to?(:read)
506
- rewind(arg) do |io|
507
- block.call(io)
508
- end
509
- else
510
- open(arg.to_s) do |io|
511
- block.call(io)
512
- end
513
- end
514
- end
515
-
516
- def GridFS.chunking(io, chunk_size, &block)
517
- if io.method(:read).arity == 0
518
- data = io.read
519
- i = 0
520
- loop do
521
- offset = i * chunk_size
522
- length = i + chunk_size < data.size ? chunk_size : data.size - offset
523
-
524
- break if offset >= data.size
525
-
526
- buf = data[offset, length]
527
- block.call(buf)
528
- i += 1
529
- end
530
- else
531
- while((buf = io.read(chunk_size)))
532
- block.call(buf)
533
- end
534
- end
535
- end
536
-
537
- def GridFS.rewind(io, &block)
538
- begin
539
- pos = io.pos
540
- io.flush
541
- io.rewind
542
- rescue
543
- nil
544
- end
545
-
546
- begin
547
- block.call(io)
548
- ensure
549
- begin
550
- io.pos = pos
551
- rescue
552
- nil
553
- end
554
- end
555
- end
556
-
557
- def GridFS.extract_basename(object)
558
- filename = nil
559
-
560
- [:original_path, :original_filename, :path, :filename, :pathname].each do |msg|
561
- if object.respond_to?(msg)
562
- filename = object.send(msg)
563
- break
564
- end
565
- end
566
-
567
- filename ? cleanname(filename) : nil
568
- end
569
-
570
- MIME_TYPES = {
571
- 'md' => 'text/x-markdown; charset=UTF-8'
572
- }
573
-
574
- def GridFS.mime_types
575
- MIME_TYPES
576
- end
577
-
578
- def GridFS.extract_content_type(filename, options = {})
579
- options.to_options!
580
-
581
- basename = ::File.basename(filename.to_s)
582
- parts = basename.split('.')
583
- parts.shift
584
- ext = parts.pop
585
-
586
- default =
587
- case
588
- when options[:default]==false
589
- nil
590
- when options[:default]==true
591
- "application/octet-stream"
592
- else
593
- (options[:default] || "application/octet-stream").to_s
594
- end
595
-
596
- content_type = mime_types[ext] || MIME::Types.type_for(::File.basename(filename.to_s)).first
597
-
598
- if content_type
599
- content_type.to_s
600
- else
601
- default
602
- end
603
- end
604
-
605
- def GridFS.extract_extension(content_type)
606
- list = MIME::Types[content_type.to_s]
607
- type = list.first
608
- if type
609
- type.extensions.first
610
- end
611
- end
612
-
613
- def GridFS.cleanname(pathname)
614
- basename = ::File.basename(pathname.to_s)
615
- CGI.unescape(basename).gsub(%r/[^0-9a-zA-Z_@)(~.-]/, '_').gsub(%r/_+/,'_')
616
- end
617
- end
618
-
619
- GridFs = GridFS
620
- GridFS.init!
621
- end
622
-
623
- ##
624
- #
625
- if defined?(Rails)
626
- class Mongoid::GridFS::Engine < Rails::Engine
627
- paths['app/models'] = File.dirname(__FILE__)
628
- end
629
-
630
- module Mongoid::GridFSHelper
631
- def grid_fs_render(grid_fs_file, options = {})
632
- options.to_options!
633
-
634
- if options[:inline] == false or options[:attachment] == true
635
- headers['Content-Disposition'] = "attachment; filename=#{ grid_fs_file.attachment_filename }"
636
- end
637
-
638
- self.content_type = grid_fs_file.content_type
639
- self.response_body = grid_fs_file
640
- end
641
- end
642
-
643
- Mongoid::GridFS::Helper = Mongoid::GridFSHelper
644
- end
1
+ require "mongoid/grid_fs"