Permalink
Browse files

Factory of Resources

  • Loading branch information...
1 parent 410fba9 commit d179ef0af3cda1fce6cc07d8d420075abc050a86 Roger Leite committed Apr 30, 2012
View
@@ -16,7 +16,6 @@ $ open doc/index.html
Improvements:
-* Centralize in one Place, Resource creation
* Add "events" before and after request. This could be
cool to make projects that extends Restfolia features.
View
@@ -8,6 +8,7 @@
require "restfolia/exceptions"
require "restfolia/http"
require "restfolia/entry_point"
+require "restfolia/resource_creator"
require "restfolia/resource"
# Public: Restfolia: a REST client to consume and interact with Hypermedia API.
@@ -54,7 +54,7 @@ def on_2xx(http_response)
http_body = http_response.body.to_s
unless http_body.empty?
json_parsed = parse_body(http_response)
- return Restfolia::Resource.new(json_parsed)
+ return Restfolia.create_resource(json_parsed)
end
if (location = http_response["location"])
View
@@ -1,38 +1,21 @@
module Restfolia
# Public: Resource is the representation of JSON response. It transforms
- # all JSON attributes in attributes and all JSON objects in Resources.
- # Resource provides a "links" method, to help with hypermedia navigation.
+ # all JSON attributes in attributes and provides a "links" method, to
+ # help with hypermedia navigation.
#
# Examples
#
# resource = Resource.new(:attr_test => "test")
# resource.attr_test # => "test"
# resource.links # => []
#
- # resource = Resource.new(:attr_test => {:nested => "nested"},
+ # resource = Resource.new(:attr_test => "test",
# :links => {:href => "http://service.com",
# :rel => "self",
# :type => "application/json"})
- # resource.attr_test # => #<Restfolia::Resource ...>
- # resource.links # => [#<Restfolia::EntryPoint ...>]
- #
- # resource = Resource.new(:attr_test => "test",
- # :attr_tags => ["tag1", "tag2"],
- # :attr_array_obj => [{:nested => "nested"}],
- # :links => [{:href => "http://service.com",
- # :rel => "contacts",
- # :type => "application/json"},
- # {:href => "http://another.com",
- # :rel => "relations",
- # :type => "application/json"}
- # ])
# resource.attr_test # => "test"
- # resource.attr_tags # => ["tag1", "tag2"]
- # resource.attr_array_obj # => [#<Restfolia::Resource ...>]
- # resource.links # => [#<Restfolia::EntryPoint ...>, #<Librarian::EntryPoint ...>]
- # resource.links("relations").get # => #<Restfolia::Resource ...>
- #
+ # resource.links # => [#<Restfolia::EntryPoint ...>]
#
# By default, "links" method, expects from JSON to be the following formats:
#
@@ -74,7 +57,6 @@ def initialize(json)
#http://blog.jayfields.com/2008/02/ruby-replace-methodmissing-with-dynamic.html
@_json.each do |method, value|
next if self.respond_to?(method) #avoid method already defined
- value = look_for_resource(value)
(class << self; self; end).class_eval do
define_method(method) do |*args|
@@ -122,25 +104,6 @@ def parse_links(json)
end
end
- # Internal: Check if value is eligible to become a Restfolia::Resource.
- # If value is Array object, looks inner contents, using rules below.
- # If value is Hash object, it becomes a Restfolia::Resource.
- # Else return itself.
- #
- # value - object to be checked.
- #
- # Returns value itself or Restfolia::Resource.
- def look_for_resource(value)
- if value.is_a?(Array)
- value = value.inject([]) do |resources, array_obj|
- resources << look_for_resource(array_obj)
- end
- elsif value.is_a?(Hash)
- value = Resource.new(value)
- end
- value
- end
-
end
end
@@ -0,0 +1,97 @@
+module Restfolia
+
+ # Public: Call a Factory of Resources. This is a good place to override and
+ # returns a custom Resource Factory. By default, Restfolia uses
+ # Restfolia::ResourceCreator.
+ #
+ # json - Hash parsed from Response body.
+ #
+ # Returns Resource instance, configured at ResourceCreator.
+ # Raises ArgumentError if json is not a Hash.
+ def self.create_resource(json)
+ @creator ||= Restfolia::ResourceCreator.new
+ @creator.create(json)
+ end
+
+ # Public: Factory of Resources. It transforms all JSON objects in Resources.
+ #
+ # Examples
+ #
+ # factory = Restfolia::ResourceCreator.new
+ # resource = factory.create(:attr_test => "test",
+ # :attr_tags => ["tag1", "tag2"],
+ # :attr_array_obj => [{:nested => "nested"}],
+ # :links => [{:href => "http://service.com",
+ # :rel => "contacts",
+ # :type => "application/json"},
+ # {:href => "http://another.com",
+ # :rel => "relations",
+ # :type => "application/json"}
+ # ])
+ # resource.attr_test # => "test"
+ # resource.attr_tags # => ["tag1", "tag2"]
+ # resource.attr_array_obj # => [#<Restfolia::Resource ...>]
+ #
+ class ResourceCreator
+
+ # Public: By default, returns Restfolia::Resource. You can use
+ # this method to override and returns a custom Resource. See examples.
+ #
+ # Examples
+ #
+ # # using a custom Resource
+ # class Restfolia::ResourceCreator
+ # def resource_class
+ # OpenStruct #dont forget to require 'ostruct'
+ # end
+ # end
+ #
+ # Returns class of Resource to be constructed.
+ def resource_class
+ Restfolia::Resource
+ end
+
+ # Public: creates Resource looking recursively for JSON
+ # objects and transforming in Resources. To create Resource,
+ # this method use #resource_class.new(json).
+ #
+ # json - Hash parsed from Response body.
+ #
+ # Returns Resource from #resource_class.
+ # Raises ArgumentError if json is not a Hash.
+ def create(json)
+ unless json.is_a?(Hash)
+ raise(ArgumentError, "JSON parameter have to be a Hash object", caller)
+ end
+
+ json_parsed = {}
+ json.each do |attr, value|
+ json_parsed[attr] = look_for_resource(value)
+ end
+ resource_class.new(json_parsed)
+ end
+
+ protected
+
+ # Internal: Check if value is eligible to become a Restfolia::Resource.
+ # If value is Array object, looks inner contents, using rules below.
+ # If value is Hash object, it becomes a Restfolia::Resource.
+ # Else return itself.
+ #
+ # value - object to be checked.
+ #
+ # Returns value itself or Resource.
+ def look_for_resource(value)
+ if value.is_a?(Array)
+ value = value.inject([]) do |resources, array_obj|
+ resources << look_for_resource(array_obj)
+ end
+ elsif value.is_a?(Hash)
+ value = resource_class.new(value)
+ end
+ value
+ end
+
+ end
+
+end
@@ -23,7 +23,7 @@ module Restfolia::HTTP::Behaviour
# Here we change 3xx behaviour to return a Resource
def on_3xx(http_response)
- Restfolia::Resource.new(:redirected => "I'm free! :D")
+ Restfolia.create_resource(:redirected => "I'm free! :D")
end
end
@@ -0,0 +1,25 @@
+
+# Run this sample from root project:
+# $ ruby samples/using_custom_factory.rb
+
+require "rubygems"
+$LOAD_PATH << "lib"
+require "restfolia"
+require "ostruct"
+
+SERVICE_URL = "http://localhost:9292/recursos/busca"
+
+resource = Restfolia.at(SERVICE_URL).get
+puts resource.inspect # => #<Restfolia::Resource ...>
+
+# Here you have the "pure" json from response body.
+# You can do anything.
+module Restfolia
+ def self.create_resource(json)
+ OpenStruct.new(json)
+ end
+end
+resource = Restfolia.at(SERVICE_URL).get
+puts resource.inspect # => #<OpenStruct ...>
+
+puts "Done!"
@@ -0,0 +1,25 @@
+
+# Run this sample from root project:
+# $ ruby samples/using_custom_resource.rb
+
+require "rubygems"
+$LOAD_PATH << "lib"
+require "restfolia"
+require "ostruct"
+
+SERVICE_URL = "http://localhost:9292/recursos/busca"
+
+resource = Restfolia.at(SERVICE_URL).get
+puts resource.inspect # => #<Restfolia::Resource ...>
+
+# Here you have the advantage to use a custom resource
+# and the same time you have the recursive lookup at hash
+class Restfolia::ResourceCreator
+ def resource_class
+ OpenStruct
+ end
+end
+resource = Restfolia.at(SERVICE_URL).get
+puts resource.inspect # => #<OpenStruct ...>
+
+puts "Done!"
@@ -0,0 +1,54 @@
+require "test_helper"
+require "ostruct"
+
+describe Restfolia::ResourceCreator do
+
+ let(:subject) do
+ creator = Restfolia::ResourceCreator.new
+ def creator.resource_class
+ OpenStruct
+ end
+ creator
+ end
+
+ describe ".create" do
+
+ it "accept only hash object as parameter" do
+ lambda { subject.create(nil) }.must_raise(ArgumentError)
+ end
+
+ it "should create Resource for simple hash" do
+ resource = subject.create(:attr_test => "test")
+ resource.must_be_instance_of(OpenStruct)
+ end
+
+ it "transforms nested hash in Resource" do
+ resource = subject.create(:attr_test => {:nested => "nested"})
+ resource.attr_test.must_be_instance_of(OpenStruct)
+ resource.attr_test.nested.must_equal("nested")
+ end
+
+ it "transforms nested hash from Arrays in Resource" do
+ resource = subject.create(:attr_test => [{:nested_array => "object"}],
+ :attr_test2 => ["not object"])
+
+ resource.attr_test.must_be_instance_of(Array)
+ resource.attr_test[0].must_be_instance_of(OpenStruct)
+ resource.attr_test[0].nested_array.must_equal("object")
+
+ resource.attr_test2[0].must_be_instance_of(String)
+ resource.attr_test2[0].must_equal("not object")
+ end
+
+ it "transforms nested hash from nested Array from Array in Resource" do
+ resource = subject.create(:attr_test => [[{:nested => "nested2"}]])
+
+ resource.attr_test.must_be_instance_of(Array)
+ resource.attr_test[0].must_be_instance_of(Array)
+ resource.attr_test[0][0].must_be_instance_of(OpenStruct)
+ resource.attr_test[0][0].nested.must_equal("nested2")
+ end
+
+ end
+
+end
@@ -21,34 +21,6 @@
resource.attr_test.must_equal("test")
end
- it "transforms nested hash in Resource" do
- resource = subject.new(:attr_test => {:nested => "nested"})
-
- resource.attr_test.must_be_instance_of(Restfolia::Resource)
- resource.attr_test.nested.must_equal("nested")
- end
-
- it "transforms nested hash from Arrays in Resource" do
- resource = subject.new(:attr_test => [{:nested_array => "object"}],
- :attr_test2 => ["not object"])
-
- resource.attr_test.must_be_instance_of(Array)
- resource.attr_test[0].must_be_instance_of(Restfolia::Resource)
- resource.attr_test[0].nested_array.must_equal("object")
-
- resource.attr_test2[0].must_be_instance_of(String)
- resource.attr_test2[0].must_equal("not object")
- end
-
- it "transforms nested hash from nested Array from Array in Resource" do
- resource = subject.new(:attr_test => [[{:nested => "nested2"}]])
-
- resource.attr_test.must_be_instance_of(Array)
- resource.attr_test[0].must_be_instance_of(Array)
- resource.attr_test[0][0].must_be_instance_of(Restfolia::Resource)
- resource.attr_test[0][0].nested.must_equal("nested2")
- end
-
end
describe "#links" do

0 comments on commit d179ef0

Please sign in to comment.