require 'rid/attachments' require 'rid/makros' require 'uri' module Rid class DesignDocument # Files that should have a .js extension JAVASCRIPT_FILES = %w[ validate_doc_update lists/* shows/* updates/* views/*/* ] # Files that should not be included in document EXCLUDE_FILES = %w[ README ] include Attachments include Makros attr_accessor :hash def initialize @hash = {} end # Read document from a filesystem. # # Takes a filename, # many filenames, # or an array of filenames # and assign the return value of a yielded block to the hash. # # Nested hashes # like { "hash" => { "key" => "value" } } # can be constructed if the filename contains a slash (/), # eg "hash/key". # def read(*filenames, &block) filenames.flatten.uniq.each do |filename| # skip exclude files next if EXCLUDE_FILES.include?(filename) key = filename.dup # strip extname from javascript files key.sub!(/\.js$/, '') if filename =~ /#{JAVASCRIPT_FILES.join('|')}/ set_hash_at key, block.call(filename) end map_attachments! inject_makros! end # Write document to a filesystem # # Takes a directoy as startpoint (default is nil), # a document hash (default is the design documents hash) # and recursively yields all keys and values to the given block. # # Nested hashes # like { "hash" => { "key" => "value" } } # will result in the yielded filename # "hash/key". # # The key "_attachments" has a special meaning: # the value holds base64 encoded data as well as other metadata. # This data will gets decoded and used as value for the key. # def write(directory = nil, doc = nil, &block) reduce_attachments! reject_makros! doc ||= hash doc.each do |key, value| filename = directory ? File.join(directory, key) : key.dup if value.is_a?(Hash) write(filename, value, &block) else # append extname to javascript files filename << '.js' if filename =~ /#{JAVASCRIPT_FILES.join('|')}/ block.call(filename, value) end end end # Returns a JSON string representation of the documents hash # def json hash.to_json end # Build the documents hash from a JSON string # def json=(json) self.hash = JSON.parse(json) end # Accessor for id def id hash["_id"] || Rid.id end # Accessor for rev def rev hash["_rev"] || Rid.rev end # Updates rev in documents hash def rev=(new_rev) hash["_rev"] = new_rev end # Accessor for rid database def database @database ||= Rid.database end # Base URL for document def base_url @base_url ||= File.join(database, id) end # URL for accessing design document # # Takes an optional options hash # which gets converted to url encoded options # and appended to the documents base url # def url(options = {}) base_url + build_options_string(options) end private def hash_at(path) current_hash = hash parts = path.split('/') key = parts.pop parts.each do |part| current_hash[part] ||= {} current_hash = current_hash[part] end current_hash[key] end def set_hash_at(path, value) current_hash = hash parts = path.split('/') key = parts.pop parts.each do |part| current_hash[part] ||= {} current_hash = current_hash[part] end current_hash[key] = value end def build_options_string(options) return '' if options.empty? options_array = [] options.each do |key, value| options_array << URI.escape([key, value].join('=')) end '?' + options_array.join("&") end end end