diff --git a/lib/fog/rackspace/models/storage/directories.rb b/lib/fog/rackspace/models/storage/directories.rb index 295f92dc7..f36ebca3d 100644 --- a/lib/fog/rackspace/models/storage/directories.rb +++ b/lib/fog/rackspace/models/storage/directories.rb @@ -27,7 +27,7 @@ module Fog end end - directory.metadata = Metadata.from_headers(data.headers) + directory.metadata = Metadata.from_headers(directory, data.headers) directory.files.merge_attributes(options) directory.files.instance_variable_set(:@loaded, true) diff --git a/lib/fog/rackspace/models/storage/directory.rb b/lib/fog/rackspace/models/storage/directory.rb index 57dcd5085..b64a2ca35 100644 --- a/lib/fog/rackspace/models/storage/directory.rb +++ b/lib/fog/rackspace/models/storage/directory.rb @@ -16,19 +16,19 @@ module Fog def metadata=(hash) if hash.is_a? Fog::Storage::Rackspace::Metadata - @metadata = hash + attributes[:metadata] = hash else - @metadata = Fog::Storage::Rackspace::Metadata.new(hash) + attributes[:metadata] = Fog::Storage::Rackspace::Metadata.new(self, hash) end - @metadata + attributes[:metadata] end def metadata - unless @metadata + unless attributes[:metadata] response = service.head_container(key) - @metadata = Fog::Storage::Rackspace::Metadata.from_headers(response.headers) + attributes[:metadata] = Fog::Storage::Rackspace::Metadata.from_headers(self, response.headers) end - @metadata + attributes[:metadata] end def destroy diff --git a/lib/fog/rackspace/models/storage/file.rb b/lib/fog/rackspace/models/storage/file.rb index 34132b9f3..c01ff8904 100644 --- a/lib/fog/rackspace/models/storage/file.rb +++ b/lib/fog/rackspace/models/storage/file.rb @@ -15,6 +15,9 @@ module Fog attribute :access_control_allow_origin, :aliases => ['Access-Control-Allow-Origin'] attribute :origin, :aliases => ['Origin'] + attr_accessor :directory + attr_writer :public + def body attributes[:body] ||= if last_modified collection.get(identity).body @@ -27,10 +30,6 @@ module Fog attributes[:body] = new_body end - def directory - @directory - end - def copy(target_directory_key, target_file_key, options={}) requires :directory, :key options['Content-Type'] ||= content_type if content_type @@ -47,10 +46,19 @@ module Fog true end - def metadata - @metadata ||= headers_to_metadata + def metadata=(hash) + if hash.is_a? Fog::Storage::Rackspace::Metadata + attributes[:metadata] = hash + else + attributes[:metadata] = Fog::Storage::Rackspace::Metadata.new(self, hash) + end + attributes[:metadata] end - + + def metadata + attributes[:metadata] ||= Fog::Storage::Rackspace::Metadata.new(self) + end + def owner=(new_owner) if new_owner attributes[:owner] = { @@ -60,10 +68,6 @@ module Fog end end - def public=(new_public) - new_public - end - def public? directory.public? end @@ -86,72 +90,19 @@ module Fog options['Content-Type'] = content_type if content_type options['Access-Control-Allow-Origin'] = access_control_allow_origin if access_control_allow_origin options['Origin'] = origin if origin - options.merge!(metadata_to_headers) + options.merge!(metadata.to_headers) data = service.put_object(directory.key, key, body, options) update_attributes_from(data) - refresh_metadata - + self.content_length = Fog::Storage.get_body_size(body) self.content_type ||= Fog::Storage.get_content_type(body) true end + private - def directory=(new_directory) - @directory = new_directory - end - - def refresh_metadata - metadata.reject! {|k, v| v.nil? } - end - - def headers_to_metadata - key_map = key_mapping - Hash[metadata_attributes.map {|k, v| [key_map[k], v] }] - end - - def key_mapping - key_map = metadata_attributes - key_map.each_pair {|k, v| key_map[k] = header_to_key(k)} - end - - def header_to_key(opt) - opt.gsub(metadata_prefix, '').split('-').map {|k| k[0, 1].downcase + k[1..-1]}.join('_').to_sym - end - - def metadata_to_headers - hash = {} - metadata.each_pair do |k,v| - key = metakey(k,v) - hash[key] = v - end - hash - end - - def metakey(key, value) - prefix = value.nil? ? "X-Remove-Object-Meta-" : "X-Object-Meta-" - prefix + key.to_s.split(/[-_]/).map(&:capitalize).join('-') - end - - def metadata_attributes - if last_modified - headers = service.head_object(directory.key, self.key).headers - headers.reject! {|k, v| !metadata_attribute?(k)} - else - {} - end - end - - def metadata_attribute?(key) - key.to_s =~ /^#{metadata_prefix}/ - end - - def metadata_prefix - "X-Object-Meta-" - end - def update_attributes_from(data) merge_attributes(data.headers.reject {|key, value| ['Content-Length', 'Content-Type'].include?(key)}) end diff --git a/lib/fog/rackspace/models/storage/files.rb b/lib/fog/rackspace/models/storage/files.rb index f79e3c13f..3184c0e86 100644 --- a/lib/fog/rackspace/models/storage/files.rb +++ b/lib/fog/rackspace/models/storage/files.rb @@ -55,10 +55,13 @@ module Fog def get(key, &block) requires :directory data = service.get_object(directory.key, key, &block) + metadata = Metadata.from_headers(data.headers) file_data = data.headers.merge({ :body => data.body, - :key => key + :key => key, + :metadata => metadata }) + new(file_data) rescue Fog::Storage::Rackspace::NotFound nil diff --git a/lib/fog/rackspace/models/storage/metadata.rb b/lib/fog/rackspace/models/storage/metadata.rb index d586e964b..7de5925d9 100644 --- a/lib/fog/rackspace/models/storage/metadata.rb +++ b/lib/fog/rackspace/models/storage/metadata.rb @@ -4,21 +4,24 @@ module Fog class Metadata - # META_PREFIX = "X-Object-Meta-" - # REMOVE_META_PREFIX = "X-Remove-Object-Meta-" - META_PREFIX = "X-Container-Meta-" - REMOVE_META_PREFIX = "X-Remove-Container-Meta-" + OBJECT_META_PREFIX = "X-Object-Meta-" + OBJECT_REMOVE_META_PREFIX = "X-Remove-Object-Meta-" + CONTAINER_META_PREFIX = "X-Container-Meta-" + CONTAINER_REMOVE_META_PREFIX = "X-Remove-Container-Meta-" # Cloud Files will ignore headers without a value DUMMY_VALUE = 1 - KEY_REGEX = /^#{META_PREFIX}(.*)/ + CONTAINER_KEY_REGEX = /^#{CONTAINER_META_PREFIX}(.*)/ + OBJECT_KEY_REGEX = /^#{OBJECT_META_PREFIX}(.*)/ - attr_reader :data - def initialize(hash={}) + attr_reader :data, :parent + + def initialize(parent, hash={}) @data = hash || {} @deleted_hash = {} + @parent = parent end def delete(key) @@ -37,10 +40,10 @@ module Fog headers end - def self.from_headers(headers) - metadata = Metadata.new + def self.from_headers(parent, headers) + metadata = Metadata.new(parent) headers.each_pair do |k, v| - key = Metadata.to_key(k) + key = metadata.send(:to_key, k) next unless key metadata.data[key] = Fog::JSON.decode(v) end @@ -57,8 +60,38 @@ module Fog private - def self.to_key(key) - m = key.match KEY_REGEX + def meta_prefix + if parent.is_a? Fog::Storage::Rackspace::Directory + CONTAINER_META_PREFIX + elsif parent.is_a? Fog::Storage::Rackspace::File + OBJECT_META_PREFIX + else + raise "Metadata prefix is unknown for #{parent.class}" + end + end + + def remove_meta_prefix + if parent.is_a? Fog::Storage::Rackspace::Directory + CONTAINER_REMOVE_META_PREFIX + elsif parent.is_a? Fog::Storage::Rackspace::File + OBJECT_REMOVE_META_PREFIX + else + raise "Remove Metadata prefix is unknown for #{parent.class}" + end + end + + def meta_prefix_regex + if parent.is_a? Fog::Storage::Rackspace::Directory + CONTAINER_KEY_REGEX + elsif parent.is_a? Fog::Storage::Rackspace::File + OBJECT_KEY_REGEX + else + raise "Metadata prefix is unknown for #{parent.class}" + end + end + + def to_key(key) + m = key.match meta_prefix_regex return nil unless m && m[1] a = m[1].split('-') @@ -68,7 +101,7 @@ module Fog end def to_header_key(key, value) - prefix = value.nil? ? REMOVE_META_PREFIX : META_PREFIX + prefix = value.nil? ? remove_meta_prefix : meta_prefix prefix + key.to_s.split(/[-_]/).collect(&:capitalize).join('-') end diff --git a/tests/rackspace/models/storage/directory_tests.rb b/tests/rackspace/models/storage/directory_tests.rb index 851795bd8..afd2bc8df 100644 --- a/tests/rackspace/models/storage/directory_tests.rb +++ b/tests/rackspace/models/storage/directory_tests.rb @@ -50,6 +50,12 @@ Shindo.tests('Fog::Rackspace::Storage | directory', ['rackspace']) do returns(true) { dir.metadata[:list_test] } end + tests("should reload metadata after calling reload").returns("42") do + @service.put_container @instance.key, "X-Container-Meta-Answer" => 42 + @instance.reload + @instance.metadata[:answer] + end + end end diff --git a/tests/rackspace/models/storage/file_tests.rb b/tests/rackspace/models/storage/file_tests.rb index 42190d3e1..ae43ed813 100644 --- a/tests/rackspace/models/storage/file_tests.rb +++ b/tests/rackspace/models/storage/file_tests.rb @@ -35,7 +35,7 @@ Shindo.tests('Fog::Rackspace::Storage | file', ['rackspace']) do model_tests(@directory.files, file_attributes, Fog.mocking?) do tests("#metadata should load empty metadata").returns({}) do - @instance.metadata + @instance.metadata.data end tests('#save') do