Class: Moped::GridFS::File

Inherits:
Object
  • Object
show all
Includes:
AccessModes, Bucketable, Inspectable
Defined in:
lib/moped/gridfs/file.rb

Constant Summary collapse

EMPTINESS =
''.force_encoding('BINARY')
DEFAULT_CHUNK_SIZE =
255 * 1024

Constants included from AccessModes

AccessModes::ACCESS_MODES

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from AccessModes

#append?, #read_only?, #read_write?, #readable?, #writable?, #write_only?

Methods included from Bucketable

#chunks_collection, #files_collection

Constructor Details

#initialize(bucket, mode, selector) ⇒ File

Returns a new instance of File.

Raises:

  • (ArgumentError)


14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/moped/gridfs/file.rb', line 14

def initialize(bucket, mode, selector)
  selector = parse_selector(selector)
  @mode = mode
  @bucket = bucket
  @cached_chunk = nil
  @pos = 0

  raise ArgumentError.new("Invalid access mode #{mode}") unless ACCESS_MODES.include?(mode)

  document = files_collection.find(selector).first

  raise "No such file" if need_file? and !document

  if document and truncate?
    chunks_collection.find(files_id: document['_id']).remove_all
    files_collection.find(_id: document['_id']).remove_all

    @attributes = normalize_attributes(selector)
  else
    @attributes = normalize_attributes(document || selector)
    @attributes.freeze if read_only?
  end

  define_dynamic_accessors

  file_query.upsert(attributes) if writable?

  @pos = length if append_only?
end

Instance Attribute Details

#attributesObject (readonly)

Returns the value of attribute attributes.



12
13
14
# File 'lib/moped/gridfs/file.rb', line 12

def attributes
  @attributes
end

#bucketObject (readonly)

Returns the value of attribute bucket.



12
13
14
# File 'lib/moped/gridfs/file.rb', line 12

def bucket
  @bucket
end

#modeObject (readonly)

Returns the value of attribute mode.



12
13
14
# File 'lib/moped/gridfs/file.rb', line 12

def mode
  @mode
end

#posObject Also known as: tell

Returns the value of attribute pos.



12
13
14
# File 'lib/moped/gridfs/file.rb', line 12

def pos
  @pos
end

Instance Method Details

#default_chunk_sizeObject



139
140
141
# File 'lib/moped/gridfs/file.rb', line 139

def default_chunk_size
  DEFAULT_CHUNK_SIZE
end

#eof?Boolean

Returns:

  • (Boolean)


58
59
60
61
62
# File 'lib/moped/gridfs/file.rb', line 58

def eof?
  raise "Not opened for reading" if write_only?

  pos >= length
end

#inspectObject



143
144
145
# File 'lib/moped/gridfs/file.rb', line 143

def inspect
  build_inspect_string(bucket: bucket.name, _id: _id, mode: mode, filename: filename, length: length)
end

#read(size = length) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/moped/gridfs/file.rb', line 66

def read(size = length)
  raise "Not opened for reading" if write_only?

  check_negative_value(size)

  chunk_number = pos / chunk_size
  chunk_offset = pos % chunk_size

  data = EMPTINESS

  loop do
    break if data.size >= size
    break unless read_chunk(chunk_number)
    buffer = @cached_chunk[:data][chunk_offset..-1]
    data.empty? ? (data = buffer) : (data << buffer)
    chunk_number += 1
    chunk_offset = 0
  end

  data = data[0..size - 1]
  @pos += data.size
  data
end

#rewindObject



54
55
56
# File 'lib/moped/gridfs/file.rb', line 54

def rewind
  self.pos = 0
end

#write(data) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/moped/gridfs/file.rb', line 90

def write(data)
  raise "Not opened for writing" if read_only?

  data.force_encoding('BINARY') if data.respond_to?(:force_encoding)

  @pos = length if @pos > length
  @pos = length if append?

  chunk_number = pos / chunk_size
  chunk_offset = pos % chunk_size
  written = data.size
  new_length = 0

  loop do
    if buffer = read_chunk(chunk_number)
      data = (chunk_offset.zero? ? EMPTINESS : buffer[0..chunk_offset - 1]) + data + (buffer[chunk_offset + data.size..-1] || EMPTINESS)
    end

    to_write = data[0..chunk_size - 1] || EMPTINESS

    break if to_write.empty?

    new_length = chunk_number * chunk_size + write_chunk(chunk_number, to_write)

    data = data[chunk_size..-1] || EMPTINESS

    break if data.empty?

    chunk_number += 1
    chunk_offset = 0
  end

  # Update internal position
  @pos += written

  # Calculate new md5 (if needed)
  md5 = bucket.md5(@attributes[:_id]) if written > 0

  # Update if something changed
  updates = {}
  updates[:md5] = md5 if md5
  updates[:length] = new_length if new_length > length
  change_attributes(updates) if updates.any?

  written
end