Class: Aqua::Store::CouchDB::Attachments
- Defined in:
- lib/aqua/store/couch_db/attachments.rb
Overview
Attachments is a Hash-like container with keys that are attacment names and values that are file-type objects. Initializing and adding to the collection assures the types of both keys and values. The collection implements a lazy-loading scheme, such that when an attachment is requested and not found, it will try to load it from CouchDB.
Instance Attribute Summary collapse
-
#document ⇒ Object
readonly
Returns the value of attribute document.
-
#stubs ⇒ Object
readonly
Returns the value of attribute stubs.
Class Method Summary collapse
-
.validate_hash(hash) ⇒ Object
private
Validates and throws an error on a hash, insisting that the key is a string or symbol, and the value is a file.
Instance Method Summary collapse
-
#add(name, file) ⇒ Object
Adds an attachment to the collection, checking for type.
-
#add!(name, file) ⇒ Object
Adds an attachment to the collection and to the database.
-
#delete!(name) ⇒ File?
Deletes an attachment from the collection, and from the database.
-
#get(name, stream = false) ⇒ File?
Gets an attachment from the collection first.
-
#get!(name, stream = false) ⇒ File?
Gets an attachment from the database.
-
#initialize(doc, hash = {}) ⇒ Attachments
constructor
Creates a new attachment collection with keys that are attachment names and values that are file-type objects.
-
#pack ⇒ Object
Creates a hash for the CouchDB _attachments key.
-
#update_doc_rev(response) ⇒ Object
private
Goes into the document and updates it’s rev to match the returned rev.
-
#uri_for(name, include_rev = true) ⇒ Object
private
Constructs the standalone attachment uri for PUT and DELETE actions.
Constructor Details
#initialize(doc, hash = {}) ⇒ Attachments
Creates a new attachment collection with keys that are attachment names and values that are file-type objects. The collection manages both the key and the value types.
19 20 21 22 23 24 |
# File 'lib/aqua/store/couch_db/attachments.rb', line 19 def initialize( doc, hash={} ) raise ArgumentError, "must be initialized with a document" unless doc.respond_to?( :retrieve ) @document = doc self.class.validate_hash( hash ) unless hash.empty? super( hash ) end |
Instance Attribute Details
#document ⇒ Object (readonly)
Returns the value of attribute document.
9 10 11 |
# File 'lib/aqua/store/couch_db/attachments.rb', line 9 def document @document end |
#stubs ⇒ Object (readonly)
Returns the value of attribute stubs.
10 11 12 |
# File 'lib/aqua/store/couch_db/attachments.rb', line 10 def stubs @stubs end |
Class Method Details
.validate_hash(hash) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Validates and throws an error on a hash, insisting that the key is a string or symbol, and the value is a file.
131 132 133 134 135 136 |
# File 'lib/aqua/store/couch_db/attachments.rb', line 131 def self.validate_hash( hash ) hash.each do |name, file| raise ArgumentError, "Attachment name, #{name.inspect}, must be a Symbol or a String" unless [Symbol, String ].include?( name.class ) raise ArgumentError, "Attachment file, #{file.inspect}, must be a File-like object" unless file.respond_to?( :read ) end end |
Instance Method Details
#add(name, file) ⇒ Object
Adds an attachment to the collection, checking for type. Does not add directly to the database.
32 33 34 35 |
# File 'lib/aqua/store/couch_db/attachments.rb', line 32 def add( name, file ) self.class.validate_hash( name => file ) self[name] = file end |
#add!(name, file) ⇒ Object
Adds an attachment to the collection and to the database. Document doesn’t have to be saved, but it does need to have an id.
44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/aqua/store/couch_db/attachments.rb', line 44 def add!( name, file ) add( name, file ) content_type = MIME::Types.type_for(file.path).first content_type = content_type.nil? ? "text\/plain" : content_type.simplified data = { 'content_type' => content_type, 'data' => Base64.encode64( file.read ).gsub(/\s/,'') } file.rewind response = CouchDB.put( uri_for( name ), data ) update_doc_rev( response ) file end |
#delete!(name) ⇒ File?
Deletes an attachment from the collection, and from the database. Use #delete (from Hash) to just delete the attachment from the collection.
65 66 67 68 69 70 71 72 73 |
# File 'lib/aqua/store/couch_db/attachments.rb', line 65 def delete!( name ) if self[name] file = delete( name ) unless document.new? CouchDB.delete( uri_for( name ) ) end file end end |
#get(name, stream = false) ⇒ File?
Gets an attachment from the collection first. If not found, it will be requested from the database.
81 82 83 84 85 86 87 88 |
# File 'lib/aqua/store/couch_db/attachments.rb', line 81 def get( name, stream=false ) file = self[name] unless file file = get!( name, stream ) end file.rewind if file # just in case of previous streaming file end |
#get!(name, stream = false) ⇒ File?
make this more memory favorable, maybe streaming/saving in a max number of bytes
Gets an attachment from the database. Stores it in the hash.
100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/aqua/store/couch_db/attachments.rb', line 100 def get!( name, stream=false ) file = nil response = CouchDB.get( uri_for( name, false ), true ) rescue nil data = response && response.respond_to?(:keys) ? Base64.decode64( response['data'] ) : nil if data || response file = Tempfile.new( CGI.escape( name.to_s ) ) file.binmode if file.respond_to?( :binmode ) data ? file.write( data ) : file.write( response ) file.rewind self[name] = file end stream ? file.read : file end |
#pack ⇒ Object
Creates a hash for the CouchDB _attachments key.
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/aqua/store/couch_db/attachments.rb', line 164 def pack pack_hash = {} self.keys.each do |key| file = self[key] content_type = MIME::Types.type_for(file.path).first content_type = content_type.nil? ? "text\/plain" : content_type.simplified data = { 'content_type' => content_type, 'data' => Base64.encode64( file.read ).gsub(/\s/,'') } file.rewind pack_hash[key.to_s] = data end pack_hash end |
#update_doc_rev(response) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Goes into the document and updates it’s rev to match the returned rev. That way #new? will return false when an attachment is created before the document is saved. It also means that future attempts to save the doc won’t fail with a conflict.
144 145 146 |
# File 'lib/aqua/store/couch_db/attachments.rb', line 144 def update_doc_rev( response ) document[:_rev] = response['rev'] end |
#uri_for(name, include_rev = true) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Constructs the standalone attachment uri for PUT and DELETE actions.
119 120 121 122 |
# File 'lib/aqua/store/couch_db/attachments.rb', line 119 def uri_for( name, include_rev = true ) raise ArgumentError, 'Document must have id in order to save an attachment' if document.id.nil? || document.id.empty? document.uri + "/#{CGI.escape( name.to_s )}" + ( document.rev && include_rev ? "?rev=#{document.rev}" : "" ) end |