require 'time' module RubyBox class Item @@has_many = [] @@has_many_paginated = [] def initialize( session, raw_item ) @session = session @raw_item = raw_item end def self.has_many(*keys) keys.each {|key| @@has_many << key.to_s} end def self.has_many_paginated(*keys) keys.each {|key| @@has_many_paginated << key.to_s} end def update reload_meta unless etag url = "#{RubyBox::API_URL}/#{resource_name}/#{id}" uri = URI.parse(url) request = Net::HTTP::Put.new(uri.path, { "if-match" => etag, "Content-Type" => 'application/json' }) request.body = JSON.dump(serialize) @raw_item = @session.request(uri, request) self end def delete url = "#{RubyBox::API_URL}/#{resource_name}/#{id}" resp = @session.delete( url ) end def reload_meta url = "#{RubyBox::API_URL}/#{resource_name}/#{@raw_item['id']}" @raw_item = @session.get( url ) self end def method_missing(method, *args, &block) key = method.to_s # Support has many and paginated has many relationships. return many(key) if @@has_many.include?(key) return paginated(key, args[0] || 100, args[1] || 0, args[2]) if @@has_many_paginated.include?(key) # update @raw_item hash if this appears to be a setter. setter = method.to_s.end_with?('=') key = key[0...-1] if setter @raw_item[key] = args[0] if setter and update_fields.include?(key) # we may have a mini version of the object loaded, fix this. reload_meta if @raw_item[key].nil? and has_mini_format? if @raw_item[key].kind_of?(Hash) return RubyBox::Item.factory(@session, @raw_item[key]) elsif RubyBox::ISO_8601_TEST.match(@raw_item[key].to_s) return Time.parse(@raw_item[key]) else return @raw_item[key] end end protected def self.factory(session, entry) type = entry['type'] ? entry['type'].capitalize.to_sym : nil if RubyBox.constants.include? type RubyBox.const_get(type).new(session, entry) else entry end end def has_mini_format? true end private def many(key) url = "#{RubyBox::API_URL}/#{resource_name}/#{id}/#{key}" resp = @session.get( url ) resp['entries'].map {|i| RubyBox::Item.factory(@session, i)} end def paginated(key, item_limit=100, offset=0, fields=nil) Enumerator.new do |yielder| while true url = "#{RubyBox::API_URL}/#{resource_name}/#{id}/#{key}?limit=#{item_limit}&offset=#{offset}" url = "#{url}&fields=#{fields.map(&:to_s).join(',')}" if fields resp = @session.get( url ) resp['entries'].each do |entry| yielder.yield(RubyBox::Item.factory(@session, entry)) end offset += resp['entries'].count break if resp['offset'].to_i + resp['limit'].to_i >= resp['total_count'].to_i end end end def serialize update_fields.inject({}) {|hash, field| hash[field] = @raw_item[field]; hash} end end end