lib/survey_gizmo/resource.rb in survey-gizmo-ruby-0.5.0 vs lib/survey_gizmo/resource.rb in survey-gizmo-ruby-0.6.0
- old
+ new
@@ -9,74 +9,79 @@
instance_variable_set('@paths', {})
instance_variable_set('@collections', {})
SurveyGizmo::Resource.descendants << self
end
+ # @return [Set] Every class that includes SurveyGizmo::Resource
def self.descendants
@descendants ||= Set.new
end
+ # These are methods that every API resource has to access resources
+ # in Survey Gizmo
module ClassMethods
# Get a list of resources
# @param [Hash] conditions
- # @return [SurveGizmo::Collection, false]
+ # @return [SurveyGizmo::Collection, Array]
def all(conditions = {})
- response = SurveyGizmo.get(handle_route(:create, conditions))
- if response.parsed_response['result_ok']
- collection = SurveyGizmo::Collection.new(self, nil, response.parsed_response['data'])
- collection.send(:options=, {:target => self, :parent => self})
- collection
+ response = Response.new SurveyGizmo.get(handle_route(:create, conditions))
+ if response.ok?
+ _collection = SurveyGizmo::Collection.new(self, nil, response.data)
+ _collection.send(:options=, {:target => self, :parent => self})
+ _collection
else
- # do something
- # e = response.parsed_response['message']
- false
+ []
end
end
# Get the first resource
# @param [Hash] conditions
- # @return [Object, false]
+ # @return [Object, nil]
def first(conditions)
- response = SurveyGizmo.get(handle_route(:get, conditions))
- if response.parsed_response['result_ok']
- resource = new(conditions.merge(response.parsed_response['data']))
- resource.__send__(:clean!)
- resource
- else
- # do something
- # e = response.parsed_response['message']
- false
- end
+ response = Response.new SurveyGizmo.get(handle_route(:get, conditions))
+ response.ok? ? load(conditions.merge(response.data)) : nil
end
# Create a new resource
# @param [Hash] attributes
- # @return [Object]
+ # @return [Resource]
+ # The newly created Resource instance
def create(attributes = {})
resource = new(attributes)
resource.__send__(:_create)
resource
end
# Define the path where a resource is located
- # @param [String] path the path in Survey Gizmo for the resource
- # @param [Hash] options must include `:via` which is `:get`, `:create`, `:update`, `:delete`, or `:any`
+ # @param [String] path
+ # the path in Survey Gizmo for the resource
+ # @param [Hash] options
+ # @option options [Array] :via
+ # which is `:get`, `:create`, `:update`, `:delete`, or `:any`
+ # @scope class
def route(path, options)
methods = options[:via]
methods = [:get, :create, :update, :delete] if methods == :any
methods.is_a?(Array) ? methods.each{|m| @paths[m] = path } : (@paths[methods] = path)
nil
end
-
+ # @api private
def load(attributes = {})
resource = new(attributes)
resource.__send__(:clean!)
resource
end
+ # Defines a new collection. These are child objects of the resource.
+ # @macro [new] collection
+ # @param [Symbol] resource_name the name of the collection, pluralized
+ # @param [Class] model and optional class name if the class name does not match the resource_name
+ # @return [Collection]
+ # the $1 collection
+ # @scope instance
def collection(resource_name, model = nil)
@collections[resource_name] = {:parent => self, :target => (model ? model : resource_name)} # workaround for weird bug with passing a class to Collection
class_eval(<<-EOS)
def #{resource_name}
@#{resource_name} ||= []
@@ -86,115 +91,178 @@
@#{resource_name} = SurveyGizmo::Collection.new(#{self}, :#{resource_name}, array)
end
EOS
end
+ # @api private
def collections
- @collections
+ @collections.dup.freeze
end
+ # @api private
def handle_route(key, *interp)
path = @paths[key]
raise "No routes defined for `#{key}` in #{self.name}" unless path
options = interp.last.is_a?(Hash) ? interp.pop : path.scan(/:(\w+)/).inject({}){|hash, k| hash.merge(k.to_sym => interp.shift) }
path.gsub(/:(\w+)/){|m| options[$1.to_sym] }
end
end
-
+
+ # Updates attributes and saves this Resource instance
+ #
+ # @param [Hash] attributes
+ # attributes to be updated
+ #
+ # @return [Boolean]
+ # true if resource is saved
def update(attributes = {})
self.attributes = attributes
self.save
end
+ # Save the instance to Survey Gizmo
+ #
+ # @return [Boolean]
+ # true if Resource instance is saved
def save
- response = SurveyGizmo.post(handle_route(:update), :query => self.attributes_without_blanks)
- _result = response.parsed_response['result_ok']
- saved! if _result
- _result
+ if new?
+ _create
+ else
+ handle_response SurveyGizmo.post(handle_route(:update), :query => self.attributes_without_blanks), do
+ _response.ok? ? saved! : false
+ end
+ end
end
# fetch resource from SurveyGizmo and reload the attributes
+ # @return [self, false]
+ # Returns the object, if saved. Otherwise returns false.
def reload
- response = SurveyGizmo.get(handle_route(:get))
- if response.parsed_response['result_ok']
- self.attributes = response.parsed_response['data']
- clean!
- self
- else
- # do something
- # e = response.parsed_response['message']
- false
+ handle_response SurveyGizmo.get(handle_route(:get)), do
+ if _response.ok?
+ self.attributes = _response.data
+ clean!
+ else
+ false
+ end
end
end
+ # Deleted the Resource from Survey Gizmo
+ # @return [Boolean]
def destroy
- return false if new?
- response = SurveyGizmo.delete(handle_route(:delete))
- _result = response.parsed_response['result_ok']
- destroyed! if _result
- _result
+ return false if new? || destroyed?
+ handle_response SurveyGizmo.delete(handle_route(:delete)), do
+ _response.ok? ? destroyed! : false
+ end
end
+ # The state of the current Resource
+ # @api private
def new?
@_state.nil?
end
# @todo This seemed like a good way to prevent accidently trying to perform an action
- # on a record at a point when it would fail. Not sure if it's really necessary though.
+ # on a record at a point when it would fail. Not sure if it's really necessary though.
[:clean, # stored and not dirty
:saved, # stored and not modified
:destroyed, # duh!
:zombie # needs to be stored
].each do |state|
+ # Change the method state to $1
define_method("#{state}!") do
@_state = state
+ true
end
+ # Inquire about the method state if $1
define_method("#{state}?") do
@_state == state
end
private "#{state}!"
end
# Sets the hash that will be used to interpolate values in routes. It needs to be defined per model.
- # @return [Hash] a hash of the values needed in routing. ie. {:id => self.id}
+ # @return [Hash] a hash of the values needed in routing
def to_param_options
raise "Define #to_param_options in #{self.class.name}"
end
+ # Any errors returned by Survey Gizmo
+ # @return [Array]
+ def errors
+ @errors ||= []
+ end
+
+ # @visibility private
def inspect
attrs = self.class.attributes.map do |attrib|
value = attrib.get!(self).inspect
"#{attrib.instance_variable_name}=#{value}"
end
"#<#{self.class.name}:#{self.object_id} #{attrs.join(' ')}>"
end
-
+
+ # This class normalizes the response returned by Survey Gizmo
+ class Response
+ def ok?
+ @response['result_ok']
+ end
+
+ # The parsed JSON data of the response
+ def data
+ @_data ||= (@response['data'] || {})
+ end
+
+ # The error message if there is one
+ def message
+ @_message ||= @response['message']
+ end
+
+ private
+ def initialize(response)
+ @response = response.parsed_response
+ end
+ end
+
protected
+ def attributes_without_blanks
+ self.attributes.reject{|k,v| v.blank? }
+ end
+
+ private
+ attr_reader :_response
+
+ def set_response(http)
+ @_response = Response.new(http)
+ end
+
def handle_route(key)
self.class.handle_route(key, to_param_options)
end
- # @private
- def _create(attributes = {})
- response = SurveyGizmo.put(handle_route(:create), :query => self.attributes_without_blanks)
- if response.parsed_response['result_ok']
- self.attributes = response.parsed_response['data']
- saved!
- else
- # do something
- # e = response.parsed_response['message']
- false
- end
+ def handle_response(resp, &block)
+ set_response(resp)
+ (self.errors << _response.message) unless _response.ok?
+ self.errors.clear if !self.errors.empty? && _response.ok?
+ instance_eval(&block)
end
- # @private
- def attributes_without_blanks
- self.attributes.reject{|k,v| v.blank? }
+ def _create(attributes = {})
+ http = SurveyGizmo.put(handle_route(:create), :query => self.attributes_without_blanks)
+ handle_response http, do
+ if _response.ok?
+ self.attributes = _response.data
+ saved!
+ else
+ false
+ end
+ end
end
end
end
\ No newline at end of file