Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Resource handling enhancements #2

Merged
merged 3 commits into from

1 participant

Wynn Netherland
Wynn Netherland
Owner

Some changes to support crazy, jacked up JSON keys like {"8": "eight", "@android": "android.xml"}.

  • Instead of ivars, it uses #attrs.
  • Also does not try to hydrate resources for Arrays of non-hashes.
pengwynn added some commits
Wynn Netherland pengwynn Handle arrays of strings 4e68e36
Wynn Netherland pengwynn Handle simplified HAL link hashes 6c8c5b2
Wynn Netherland pengwynn Switch from ivar to attrs for Resource fields
Some JSON is waacked. This change supports key
names like '8' => 'eight' and '@file' => 'file.xml'
via [] notation.
123da27
Wynn Netherland pengwynn merged commit 2e4865d into from
Wynn Netherland pengwynn deleted the branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 1, 2012
  1. Wynn Netherland

    Handle arrays of strings

    pengwynn authored
Commits on Nov 2, 2012
  1. Wynn Netherland
  2. Wynn Netherland

    Switch from ivar to attrs for Resource fields

    pengwynn authored
    Some JSON is waacked. This change supports key
    names like '8' => 'eight' and '@file' => 'file.xml'
    via [] notation.
This page is out of date. Refresh to see the latest.
7 lib/sawyer/relation.rb
View
@@ -82,7 +82,12 @@ def self.from_links(agent, index, rels = Map.new)
#
# Returns a Relation.
def self.from_link(agent, name, options)
- new agent, name, options[:href], options[:method]
+ case options
+ when Hash
+ new agent, name, options[:href], options[:method]
+ when String
+ new agent, name, options
+ end
end
# A Relation represents an available next action for a resource.
55 lib/sawyer/resource.rb
View
@@ -2,19 +2,22 @@ module Sawyer
class Resource
SPECIAL_METHODS = Set.new(%w(agent rels fields))
attr_reader :_agent, :_rels, :_fields
+ attr_reader :attrs
+ alias to_hash attrs
# Initializes a Resource with the given data.
#
# agent - The Sawyer::Agent that made the API request.
# data - Hash of key/value properties.
- def initialize(agent, data)
+ def initialize(agent, data = {})
@_agent = agent
@_rels = Relation.from_links(agent, data.delete(:_links))
@_fields = Set.new
@_metaclass = (class << self; self; end)
+ @attrs = {}
data.each do |key, value|
@_fields << key
- instance_variable_set "@#{key}", process_value(value)
+ @attrs[key.to_sym] = process_value(value)
end
@_metaclass.send(:attr_accessor, *data.keys)
end
@@ -42,6 +45,29 @@ def key?(key)
@_fields.include? key
end
+ # Allow fields to be retrieved via Hash notation
+ #
+ # method - key name
+ #
+ # Returns the value from attrs if exists
+ def [](method)
+ send(method.to_sym)
+ rescue NoMethodError
+ nil
+ end
+
+ # Allow fields to be set via Hash notation
+ #
+ # method - key name
+ # value - value to set for the attr key
+ #
+ # Returns - value
+ def []=(method, value)
+ send("#{method}=", value)
+ rescue NoMethodError
+ nil
+ end
+
ATTR_SETTER = '='.freeze
ATTR_PREDICATE = '?'.freeze
@@ -51,9 +77,9 @@ def method_missing(method, *args)
if suffix == ATTR_SETTER
@_metaclass.send(:attr_accessor, attr_name)
@_fields << attr_name.to_sym
- instance_variable_set("@#{attr_name}", args.first)
- elsif @_fields.include?(attr_name.to_sym)
- value = instance_variable_get("@#{attr_name}")
+ send(method, args.first)
+ elsif attr_name && @_fields.include?(attr_name.to_sym)
+ value = @attrs[attr_name.to_sym]
case suffix
when nil
@_metaclass.send(:attr_accessor, attr_name)
@@ -66,6 +92,25 @@ def method_missing(method, *args)
super
end
end
+
+ # Wire up accessor methods to pull from attrs
+ def self.attr_accessor(*attrs)
+ attrs.each do |attribute|
+ class_eval do
+ define_method attribute do
+ @attrs[attribute.to_sym]
+ end
+
+ define_method "#{attribute}=" do |value|
+ @attrs[attribute.to_sym] = value
+ end
+
+ define_method "#{attribute}?" do
+ !!@attrs[attribute.to_sym]
+ end
+ end
+ end
+ end
end
end
3  lib/sawyer/response.rb
View
@@ -29,8 +29,7 @@ def process_data(data)
when Hash then Resource.new(agent, data)
when Array then data.map { |hash| process_data(hash) }
when nil then nil
- else
- raise ArgumentError, "Unable to process #{data.inspect}. Want a Hash or Array"
+ else data
end
end
17 test/relation_test.rb
View
@@ -28,6 +28,23 @@ def test_builds_multiple_rels_from_multiple_methods
assert_kind_of URITemplate, rel.href_template
end
+ def test_builds_rels_from_hash
+ index = {
+ 'self' => '/users/1'
+ }
+
+ rels = Sawyer::Relation.from_links(nil, index)
+
+ assert_equal 1, rels.size
+ assert_equal [:self], rels.keys
+ assert rel = rels[:self]
+ assert_equal :self, rel.name
+ assert_equal '/users/1', rel.href
+ assert_equal :get, rel.method
+ assert_equal [:get], rel.available_methods.to_a
+ assert_kind_of URITemplate, rel.href_template
+ end
+
def test_builds_rels_from_hash_index
index = {
'self' => {:href => '/users/1'}
14 test/resource_test.rb
View
@@ -95,5 +95,19 @@ def test_dynamic_attribute_methods_from_setter
assert res.respond_to?(:b)
assert res.respond_to?(:b=)
end
+
+ def test_attrs
+ res = Resource.new :agent, :a => 1
+ hash = {:a => 1 }
+ assert_equal hash, res.attrs
+ end
+
+ def test_handle_hash_notation_with_string_key
+ res = Resource.new :agent, :a => 1
+ assert_equal 1, res['a']
+
+ res[:b] = 2
+ assert_equal 2, res.b
+ end
end
end
10 test/response_test.rb
View
@@ -16,6 +16,11 @@ def setup
}
)]
end
+
+ stub.get '/emails' do
+ emails = %w(rick@example.com technoweenie@example.com)
+ [200, {'Content-Type' => 'application/json'}, Sawyer::Agent.encode(emails)]
+ end
end
end
@@ -55,6 +60,11 @@ def test_makes_request_from_relation
assert_equal 201, res.status
assert_nil res.data
end
+
+ def test_handles_arrays_of_strings
+ res = @agent.call(:get, '/emails')
+ assert_equal 'rick@example.com', res.data.first
+ end
end
end
Something went wrong with that request. Please try again.