Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Resource handling enhancements #2

Merged
merged 3 commits into from

1 participant

@pengwynn
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
@pengwynn pengwynn Handle arrays of strings 4e68e36
@pengwynn pengwynn Handle simplified HAL link hashes 6c8c5b2
@pengwynn 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
@pengwynn pengwynn merged commit 2e4865d into master

1 check passed

Details default The Travis build passed
@pengwynn pengwynn deleted the resource-handling 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. @pengwynn

    Handle arrays of strings

    pengwynn authored
Commits on Nov 2, 2012
  1. @pengwynn
  2. @pengwynn

    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.
View
7 lib/sawyer/relation.rb
@@ -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.
View
55 lib/sawyer/resource.rb
@@ -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
View
3  lib/sawyer/response.rb
@@ -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
View
17 test/relation_test.rb
@@ -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'}
View
14 test/resource_test.rb
@@ -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
View
10 test/response_test.rb
@@ -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.