moviepilot-restful 0.2.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/CHANGES.markdown +40 -0
  2. data/LICENSE.markdown +22 -0
  3. data/README.markdown +126 -0
  4. data/Rakefile +22 -0
  5. data/TODO.markdown +10 -0
  6. data/init.rb +1 -0
  7. data/lib/restful/apimodel/attribute.rb +17 -0
  8. data/lib/restful/apimodel/collection.rb +22 -0
  9. data/lib/restful/apimodel/link.rb +21 -0
  10. data/lib/restful/apimodel/map.rb +41 -0
  11. data/lib/restful/apimodel/resource.rb +23 -0
  12. data/lib/restful/converters/active_record.rb +159 -0
  13. data/lib/restful/rails/action_controller.rb +14 -0
  14. data/lib/restful/rails/active_record/configuration.rb +219 -0
  15. data/lib/restful/rails/active_record/metadata_tools.rb +102 -0
  16. data/lib/restful/rails.rb +22 -0
  17. data/lib/restful/serializers/atom_like_serializer.rb +51 -0
  18. data/lib/restful/serializers/base.rb +58 -0
  19. data/lib/restful/serializers/hash_serializer.rb +46 -0
  20. data/lib/restful/serializers/json_serializer.rb +18 -0
  21. data/lib/restful/serializers/params_serializer.rb +46 -0
  22. data/lib/restful/serializers/xml_serializer.rb +161 -0
  23. data/lib/restful.rb +65 -0
  24. data/rails/init.rb +1 -0
  25. data/restful.gemspec +17 -0
  26. data/test/converters/active_record_converter_test.rb +147 -0
  27. data/test/converters/basic_types_converter_test.rb +99 -0
  28. data/test/fixtures/models/paginated_collection.rb +3 -0
  29. data/test/fixtures/models/person.rb +29 -0
  30. data/test/fixtures/models/pet.rb +5 -0
  31. data/test/fixtures/models/wallet.rb +5 -0
  32. data/test/fixtures/people.json.yaml +107 -0
  33. data/test/fixtures/people.xml.yaml +117 -0
  34. data/test/fixtures/pets.json.yaml +20 -0
  35. data/test/fixtures/pets.xml.yaml +31 -0
  36. data/test/rails/active_record_metadata_test.rb +23 -0
  37. data/test/rails/configuration_test.rb +47 -0
  38. data/test/rails/restful_publish_test.rb +54 -0
  39. data/test/serializers/atom_serializer_test.rb +33 -0
  40. data/test/serializers/json_serializer_test.rb +90 -0
  41. data/test/serializers/params_serializer_test.rb +76 -0
  42. data/test/serializers/xml_serializer_test.rb +51 -0
  43. data/test/test_helper.rb +154 -0
  44. metadata +97 -0
@@ -0,0 +1,161 @@
1
+ require 'restful/serializers/base'
2
+ require "rexml/document"
3
+ require 'builder'
4
+ require 'ruby-debug'
5
+
6
+ #
7
+ # Converts an APIModel to and from XML.
8
+ #
9
+ module Restful
10
+ module Serializers
11
+ class XMLSerializer < Base
12
+
13
+ serializer_name :xml
14
+
15
+ def serialize(resource, options = {})
16
+
17
+ xml = options[:builder] || Builder::XmlMarkup.new(:indent => 2)
18
+ xml.instruct! unless options[:instruct].is_a?(FalseClass)
19
+
20
+ raise NotImplementedError.new("xml serialization of maps has not been implemented. ") if resource.class == Restful::ApiModel::Map
21
+
22
+ if resource.is_a?(Restful::ApiModel::Collection)
23
+ add_collection(resource, xml, show_as_array = false)
24
+ else
25
+ xml.tag!(*root_element(resource)) do
26
+ add_link_to(resource, xml, :self => true)
27
+
28
+ resource.values.each do |value|
29
+ if value.type == :collection # serialize the stuffs
30
+ add_collection(value, xml)
31
+ elsif value.type == :link
32
+ add_link_to(value, xml)
33
+ elsif value.type == :resource
34
+ serialize(value, {:instruct => false, :builder => xml})
35
+ else # plain ole
36
+ add_tag(xml, value)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ # returns a resource, or collection of resources.
44
+ def deserialize(xml, options = {})
45
+ build_resource(REXML::Document.new(xml).root)
46
+ end
47
+
48
+ protected
49
+
50
+ def add_collection(value, xml, show_as_array = true)
51
+ resources = value.value
52
+ if first_resource = resources.first
53
+ xml.tag!(first_resource.name.pluralize, (show_as_array ? collections_decorations : {})) do
54
+ resources.each do |resource|
55
+ serialize(resource, { :instruct => false, :builder => xml })
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ def add_link_to(resource, builder, options = {})
62
+ is_self = !!options[:self]
63
+
64
+ attributes = {:type => "link"}
65
+ attributes.merge!(:nil => "true") if resource.full_url.blank?
66
+ builder.tag!((is_self ? "restful-url" : transform_link_name(resource.name)), resource.full_url, attributes)
67
+ end
68
+
69
+ def add_tag(builder, value)
70
+
71
+ if value.extended_type == :hash
72
+ build_hash(builder, value)
73
+ else
74
+ builder.tag!(value.name.to_s.dasherize, serialize_attribute(value), decorations(value))
75
+ end
76
+ end
77
+
78
+ def build_hash(builder, value)
79
+ builder.tag!(value.name.to_s.dasherize) do
80
+ value.value.each do |k, v|
81
+ builder.tag! k.to_s.dasherize, v
82
+ end
83
+ end
84
+ end
85
+
86
+ def decorations(value)
87
+ decorations = {}
88
+
89
+ if value.extended_type == :binary
90
+ decorations[:encoding] = 'base64'
91
+ end
92
+
93
+ if value.extended_type != :string and value.extended_type != :notype
94
+ decorations[:type] = value.extended_type
95
+ end
96
+
97
+ if value.extended_type == :datetime
98
+ decorations[:type] = :datetime
99
+ end
100
+
101
+ if value.value.nil?
102
+ decorations[:nil] = true
103
+ end
104
+
105
+ if value.value.is_a?(FalseClass) || value.value.is_a?(TrueClass)
106
+ decorations[:type] = :boolean
107
+ end
108
+
109
+ decorations
110
+ end
111
+
112
+ def collections_decorations
113
+ { :type => "array" }
114
+ end
115
+
116
+ def root_element(resource, options = {})
117
+ [resource.name]
118
+ end
119
+
120
+ # turns a rexml node into a Resource
121
+ def build_resource(node)
122
+ resource = root_resource(node)
123
+
124
+ node.elements.each do |el|
125
+ type = calculate_node_type(el)
126
+ resource.values << case type
127
+
128
+ when :link : build_link(el, type)
129
+ when :datetime
130
+ Restful.attr(el.name, DateTime.parse(el.text), type)
131
+ when :resource
132
+ build_resource(el)
133
+ when :array
134
+ Restful.collection(el.name, el.elements.map { |child| build_resource(child) }, type)
135
+ else
136
+ Restful.attr(el.name, el.text, type)
137
+ end
138
+ end
139
+
140
+ resource
141
+ end
142
+
143
+ def calculate_node_type(el)
144
+ if el.children.size > 1 && el.attributes["type"].blank?
145
+ return :resource
146
+ else
147
+ (el.attributes["type"] || "string").to_sym
148
+ end
149
+ end
150
+
151
+ def build_link(el, type)
152
+ Restful.link(revert_link_name(el.name), nil, el.text, type)
153
+ end
154
+
155
+ def root_resource(node)
156
+ url = node.delete_element("restful-url").try(:text)
157
+ Restful.resource(node.name, :url => url)
158
+ end
159
+ end
160
+ end
161
+ end
data/lib/restful.rb ADDED
@@ -0,0 +1,65 @@
1
+ require 'restful/rails'
2
+ require 'restful/rails/active_record/configuration'
3
+ require 'restful/rails/active_record/metadata_tools'
4
+ require 'restful/rails/action_controller'
5
+ require 'restful/converters/active_record'
6
+ require 'restful/apimodel/map'
7
+ require 'restful/apimodel/resource'
8
+ require 'restful/apimodel/attribute'
9
+ require 'restful/apimodel/collection'
10
+ require 'restful/apimodel/link'
11
+ require 'restful/serializers/xml_serializer'
12
+ require 'restful/serializers/json_serializer'
13
+ require 'restful/serializers/atom_like_serializer'
14
+ require 'restful/serializers/params_serializer'
15
+ require 'restful/serializers/hash_serializer'
16
+
17
+ module Restful
18
+
19
+ MAJOR = 0
20
+ MINOR = 1
21
+ REVISION = 2
22
+ VERSION = [MAJOR, MINOR, REVISION].join(".")
23
+
24
+ #
25
+ # Restful.from_xml, #from_atom_like. Methods correspond with
26
+ # resgistered serializers.
27
+ #
28
+ def self.method_missing(method, *args, &block)
29
+ if method.to_s.match(/^from_(.*)$/)
30
+ if serializer_clazz = Restful::Serializers::Base.serializers[type = $1.to_sym]
31
+ s = serializer_clazz.new
32
+ s.deserialize(args.first)
33
+ else
34
+ super
35
+ end
36
+ else
37
+ super
38
+ end
39
+ end
40
+
41
+ #
42
+ # Shortcuts past the namespaces
43
+ #
44
+
45
+ def self.cfg(*options)
46
+ Restful::Rails::ActiveRecord::Configuration::Config.new(*options)
47
+ end
48
+
49
+ def self.attr(*options)
50
+ Restful::ApiModel::Attribute.new(*options)
51
+ end
52
+
53
+ def self.link(*options)
54
+ Restful::ApiModel::Link.new(*options)
55
+ end
56
+
57
+ def self.collection(*options)
58
+ Restful::ApiModel::Collection.new(*options)
59
+ end
60
+
61
+ def self.resource(*options)
62
+ Restful::ApiModel::Resource.new(*options)
63
+ end
64
+
65
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'restful'
data/restful.gemspec ADDED
@@ -0,0 +1,17 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "restful"
3
+ s.version = "0.2.18"
4
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
5
+ s.authors = ["Daniel Bornkessel", "Rany Keddo"]
6
+ s.date = "2009-08-11"
7
+ s.email = "M4SSIVE@m4ssive.com"
8
+ s.extra_rdoc_files = %w{ README.markdown }
9
+ s.files = %w{ CHANGES.markdown init.rb lib/restful/apimodel/attribute.rb lib/restful/apimodel/collection.rb lib/restful/apimodel/link.rb lib/restful/apimodel/map.rb lib/restful/apimodel/resource.rb lib/restful/converters/active_record.rb lib/restful/rails/action_controller.rb lib/restful/rails/active_record/configuration.rb lib/restful/rails/active_record/metadata_tools.rb lib/restful/rails.rb lib/restful/serializers/atom_like_serializer.rb lib/restful/serializers/base.rb lib/restful/serializers/hash_serializer.rb lib/restful/serializers/json_serializer.rb lib/restful/serializers/params_serializer.rb lib/restful/serializers/xml_serializer.rb lib/restful.rb LICENSE.markdown rails/init.rb Rakefile README.markdown restful.gemspec test/converters/active_record_converter_test.rb test/converters/basic_types_converter_test.rb test/fixtures/models/paginated_collection.rb test/fixtures/models/person.rb test/fixtures/models/pet.rb test/fixtures/models/wallet.rb test/fixtures/people.json.yaml test/fixtures/people.xml.yaml test/fixtures/pets.json.yaml test/fixtures/pets.xml.yaml test/rails/active_record_metadata_test.rb test/rails/configuration_test.rb test/rails/restful_publish_test.rb test/serializers/atom_serializer_test.rb test/serializers/json_serializer_test.rb test/serializers/params_serializer_test.rb test/serializers/xml_serializer_test.rb test/test_helper.rb TODO.markdown }
10
+ s.has_rdoc = true
11
+ s.rdoc_options = ["--line-numbers", "--inline-source"]
12
+ s.homepage = "http://github.com/M4SSIVE/restful"
13
+ s.require_paths = %w{ lib }
14
+ s.requirements = %w{ brianmario-yajl-ruby }
15
+ s.rubygems_version = "1.3.1"
16
+ s.summary = "api niceness. "
17
+ end
@@ -0,0 +1,147 @@
1
+ require File.dirname(__FILE__) + '/../test_helper.rb'
2
+
3
+ #
4
+ # FIXME: remove xml serialzation here and test resource directly.
5
+ #
6
+ context "active record converter" do
7
+ setup do
8
+ Person.restful_publish(:name, :wallet, :current_location, :pets => [:name, :species])
9
+ Pet.restful_publish(:person_id, :name) # person_id gets converted to a link automagically.
10
+
11
+ @person = Person.create(:name => "Joe Bloggs", :current_location => "Under a tree", :birthday => "1976-04-03")
12
+ @wallet = @person.wallet = Wallet.create!(:contents => "something in the wallet")
13
+ @pet = @person.pets.create(:name => "Mietze", :species => "cat")
14
+ end
15
+
16
+ teardown do
17
+ reset_config
18
+ end
19
+
20
+ specify "should publish link and not resource when :oldest_pet_restful_url, where oldest_pet is a defined method" do
21
+ Person.restful_publish(:oldest_pet_restful_url)
22
+ @person.to_restful.links.size.should.== 1
23
+ @person.to_restful.links.first.name.should.== "oldest-pet-restful-url"
24
+ end
25
+
26
+ specify "should publish link and not a nested resource with :wallet_restful_url" do
27
+ Person.restful_publish(:wallet_restful_url)
28
+ @person.to_restful.links.size.should.== 1
29
+ @person.to_restful.links.first.name.should.== "wallet-restful-url"
30
+ @person.to_restful.links.first.value.should.== @wallet.restful_url
31
+ end
32
+
33
+ specify "should be able to force expansion. force expanded attributes can never be collapsed. " do
34
+ Wallet.restful_publish(:contents)
35
+ Person.restful_publish(:name, :wallet, :current_location, { :pets => [:name, :species], :restful_options => { :force_expand => :wallet } })
36
+ Pet.restful_publish(:owner, :name)
37
+
38
+ @pet.to_restful
39
+ end
40
+
41
+ specify "should return link attributes from a model" do
42
+ @pet.to_restful.links.map { |node| node.name }.sort.should.equal [:person_id]
43
+ end
44
+
45
+ specify "should convert a NULL inner association such as person.wallet to a link with a null value" do
46
+ @person.wallet = nil
47
+
48
+ wallet = @person.to_restful(:restful_options => { :expansion => :collapsed }).links.select { |link| link.name == "wallet-restful-url" }.first
49
+ wallet.should.not.== nil
50
+ wallet.value.should.== nil
51
+ end
52
+
53
+ specify "should return plain attributes from a model" do
54
+ @pet.to_restful.simple_attributes.map { |node| node.name }.should.equal [:name]
55
+ end
56
+
57
+ specify "should return collections attributes from a model" do
58
+ restful = @person.to_restful
59
+ restful.collections.map { |node| node.name }.sort.should.equal [:pets]
60
+ end
61
+
62
+ specify "should set correct type for date" do
63
+ restful = @person.to_restful :birthday
64
+ restful.simple_attributes.detect { |node| node.name == :birthday }.extended_type.should.== :date
65
+ end
66
+
67
+ specify "should be able to convert themselves to an apimodel containing all and only the attributes exposed by Model.publish_api" do
68
+ resource = @person.to_restful
69
+
70
+ resource.simple_attributes.select { |node| node.name == :name }.should.not.blank
71
+ resource.simple_attributes.select { |node| node.name == :biography }.should.blank
72
+
73
+ mietze = @person.to_restful.collections .select { |node| node.name == :pets }.first.value.first
74
+ mietze.simple_attributes.size.should.== 2
75
+ mietze.simple_attributes.select { |node| node.name == :name }.should.not.blank
76
+ mietze.simple_attributes.select { |node| node.name == :species }.should.not.blank
77
+ end
78
+
79
+ specify "should be able to convert themselves to an apimodel containing all and only the attributes exposed by Model.publish_api. this holds true if to_restful is called with some configuration options. " do
80
+ resource = @person.to_restful(:restful_options => { :nested => false })
81
+ resource.simple_attributes.select { |node| node.name == :name }.should.not.blank
82
+ resource.simple_attributes.select { |node| node.name == :biography }.should.blank
83
+
84
+ mietze = resource.collections .select { |node| node.name == :pets }.first.value.first
85
+ mietze.simple_attributes.size.should.== 2
86
+ mietze.simple_attributes.select { |node| node.name == :name }.should.not.blank
87
+ mietze.simple_attributes.select { |node| node.name == :species }.should.not.blank
88
+ end
89
+
90
+ specify "should be able to override to_restful published fields by passing them into the method" do
91
+ api = @person.to_restful(:pets)
92
+
93
+ api.simple_attributes.should.blank?
94
+ api.collections.map { |node| node.name }.sort.should.equal [:pets]
95
+ end
96
+
97
+ specify "should be able to handle relations that are nil/null" do
98
+ @person.wallet = nil
99
+ @person.save!
100
+ @person.reload
101
+
102
+ assert_nothing_raised do
103
+ @person.to_restful
104
+ end
105
+ end
106
+
107
+ specify "should be able to expand a :belongs_to relationship" do
108
+ xml_should_eql_fixture(@pet.to_restful_xml(:owner), "pets", :nameless_pet)
109
+ end
110
+
111
+ specify "should return collapsed resources by default when :expansion => :collapsed is passed" do
112
+ Person.restful_publish(:name, :wallet, :restful_options => { :expansion => :collapsed })
113
+ xml_should_eql_fixture(@person.to_restful_xml, "people", :joe_bloggs)
114
+ end
115
+
116
+ specify "should be able to export content generated by methods that return strings" do
117
+ xml_should_eql_fixture(@person.to_restful_xml(:location_sentence), "people", :no_wallet)
118
+ end
119
+
120
+ specify "should be able to export content generated by methods (not attributes) and compute the correct style" do
121
+ xml_should_eql_fixture(@person.to_restful_xml(:oldest_pet), "people", :with_oldest_pet)
122
+ end
123
+
124
+ specify "should be able to export content generated by methods (not attributes) while filtering with a nested configuration" do
125
+ xml_should_eql_fixture(@person.to_restful_xml(:oldest_pet => [:species]), "people", :with_oldest_pet_species)
126
+ end
127
+
128
+ specify "should create element with nil='true' attribute if no relation is set" do
129
+ @person.wallet = nil
130
+ @person.save
131
+
132
+ xml_should_eql_fixture(@person.to_restful_xml(:wallet), "people", :joe_with_zwiebelleder)
133
+ end
134
+
135
+ specify "should include attributes when include parameter is passed to to_restful" do
136
+ Person.restful_publish(:name)
137
+ Pet.restful_publish(:name)
138
+
139
+ @person = Person.create
140
+ @pet = @person.pets.create(:name => "Mietze")
141
+
142
+ @pet.to_restful(:include => :owner).values.map(&:name).should.include :owner
143
+ Pet.restful_config.whitelisted.include?(:owner).should.equal false
144
+ end
145
+
146
+ end
147
+
@@ -0,0 +1,99 @@
1
+ require File.dirname(__FILE__) + '/../test_helper.rb'
2
+
3
+ context "basic types converter" do
4
+
5
+ teardown { reset_config }
6
+
7
+ specify "should be able to convert a hash to a resource map" do
8
+ Person.restful_publish(:name)
9
+ resource = { "zeperson" => @person = Person.create(:name => "fuddzle") }.to_restful
10
+ resource.should.is_a?(Restful::ApiModel::Map)
11
+
12
+ attrs = resource.simple_attributes
13
+ attrs.size.should.== 1
14
+ attrs.first.name.should.== "zeperson"
15
+
16
+ attrs.first.value.values.first.value.== "fuddzle"
17
+ end
18
+
19
+ specify "should raise exception if not all array contents respond to .to_restful" do
20
+ Person.restful_publish(:name)
21
+
22
+ should.raise(TypeError) do
23
+ [""].to_restful
24
+ end
25
+ end
26
+
27
+ specify "should convert an empty array to a restful collection" do
28
+ collection = [].to_restful
29
+ collection.name.should.== "nil-classes"
30
+ end
31
+
32
+ specify "should infer array name from first element class" do
33
+ collection = [Pet.new].to_restful
34
+ collection.name.should.== "pets"
35
+ end
36
+
37
+ specify "should infer array name from first element base_class if it is an active_record object" do
38
+ collection = [Emu.new, Pet.new].to_restful
39
+ collection.name.should.== "pets"
40
+ end
41
+
42
+ specify "should convert an array to a restful collection" do
43
+ Person.restful_publish(:name)
44
+
45
+ collection = [Person.create(:name => "Joe Bloggs")].to_restful
46
+ collection.name.should.== "people"
47
+ collection.value.size.should.== 1
48
+ collection.value.first.simple_attributes.first.value.should.== "Joe Bloggs"
49
+ end
50
+
51
+ specify "should set total_entries on the restful collection if the array responds to this" do
52
+ Person.restful_publish(:name)
53
+ people = PaginatedCollection.new([Person.create(:name => "Joe Bloggs")])
54
+ people.total_entries = 1001
55
+
56
+ collection = people.to_restful
57
+ collection.total_entries.should.== 1001
58
+ end
59
+
60
+ specify "should set name on collection if array responds to .name and has this set" do
61
+ Person.restful_publish(:name)
62
+ people = PaginatedCollection.new()
63
+ people.total_entries = 0
64
+ people.name = "people"
65
+
66
+ collection = people.to_restful
67
+ collection.name.should.== "people"
68
+ end
69
+ end
70
+
71
+ context "basic types converter :includes" do
72
+
73
+ specify "should include extra attributes for hashes" do
74
+ Person.restful_publish(:name)
75
+ Pet.restful_publish(:name)
76
+
77
+ @person = Person.create
78
+ @pet = @person.pets.create(:name => "Mietze")
79
+
80
+ map = { :pet => @pet }.to_restful(:include => :owner)
81
+ map.values.first.name.should.== :pet
82
+ map.values.first.value.values.map(&:name).should.include :owner
83
+
84
+ Pet.restful_config.whitelisted.include?(:owner).should.equal false
85
+ end
86
+
87
+ specify "should include extra attributes for arrays" do
88
+ Person.restful_publish(:name)
89
+ Pet.restful_publish(:name)
90
+
91
+ @person = Person.create
92
+ @pet = @person.pets.create(:name => "Mietze")
93
+
94
+ collection = [@pet].to_restful(:include => :owner)
95
+ collection.value.first.values.map(&:name).should.include :owner
96
+
97
+ Pet.restful_config.whitelisted.include?(:owner).should.equal false
98
+ end
99
+ end
@@ -0,0 +1,3 @@
1
+ class PaginatedCollection < Array
2
+ attr_accessor :total_entries, :name
3
+ end
@@ -0,0 +1,29 @@
1
+ class Person < ActiveRecord::Base
2
+ has_many :pets
3
+ has_one :wallet
4
+
5
+ accepts_nested_attributes_for :pets
6
+ accepts_nested_attributes_for :wallet
7
+
8
+ def oldest_pet
9
+ pets.first :order => "age DESC"
10
+ end
11
+
12
+ def location_sentence
13
+ "Hi. I'm currently in #{ current_location }"
14
+ end
15
+
16
+ def has_pets
17
+ pets.size > 0
18
+ end
19
+
20
+ def pets_ages_hash
21
+ returning pets_hash = {} do
22
+ pets.each do |pet|
23
+ pets_hash[pet.name] = pet.age
24
+ end
25
+ end
26
+ end
27
+
28
+ apiable
29
+ end
@@ -0,0 +1,5 @@
1
+ class Pet < ActiveRecord::Base
2
+ belongs_to :owner, :class_name => "Person", :foreign_key => "person_id"
3
+
4
+ apiable
5
+ end
@@ -0,0 +1,5 @@
1
+ class Wallet < ActiveRecord::Base
2
+ belongs_to :person
3
+
4
+ apiable
5
+ end
@@ -0,0 +1,107 @@
1
+ bloggs:
2
+ |
3
+ {
4
+ "restful_url": "http://example.com:3000/people/<%= @person.to_param %>",
5
+ "wallet": {
6
+ "restful_url": "http://example.com:3000/wallets/<%= @person.wallet.to_param %>",
7
+ "contents": "an old photo, 5 euros in coins"
8
+ },
9
+ "current_location": "Under a tree",
10
+ "name": "Joe Bloggs",
11
+ "pets": [ {
12
+ "restful_url": "http://example.com:3000/pets/<%= @person.pets.first.to_param %>",
13
+ "name": "mietze"
14
+ }],
15
+ "created_at": "<%= @person.created_at.xmlschema %>"
16
+ }
17
+
18
+ bloggs_with_oldest_pet:
19
+ |
20
+ {
21
+ "restful_url": "http://example.com:3000/people/<%= @person.to_param %>",
22
+ "oldest_pet": {
23
+ "restful_url": "http://example.com:3000/pets/<%= @person.pets.first.to_param %>",
24
+ "name": "mietze"
25
+ }
26
+ }
27
+
28
+ bloggs_with_birthday:
29
+ |
30
+ {
31
+ "restful_url": "http://example.com:3000/people/<%= @person.to_param %>",
32
+ "birthday": "<%= @person.birthday.to_s(:db) %>"
33
+ }
34
+
35
+ bloggs_with_pets_ages_hash:
36
+ |
37
+ {
38
+ "restful_url": "http://example.com:3000/people/<%= @person.to_param %>",
39
+ "pets_ages_hash": {
40
+ "mietze": 200,
41
+ "motze": 100
42
+ }
43
+ }
44
+ bloggs_with_has_pets:
45
+ |
46
+ {
47
+ "restful_url": "http://example.com:3000/people/<%= @person.to_param %>",
48
+ "has_pets": true
49
+ }
50
+ bloggs_with_hasno_pets:
51
+ |
52
+ {
53
+ "restful_url": "http://example.com:3000/people/<%= @person.to_param %>",
54
+ "has_pets": false
55
+ }
56
+
57
+
58
+ bloggs_da_pet_hater:
59
+ |
60
+ {
61
+ "restful_url": "http://example.com:3000/people/<%= @person.to_param %>",
62
+ "wallet": {
63
+ "restful_url": "http://example.com:3000/wallets/<%= @person.wallet.to_param %>",
64
+ "contents": "an old photo, 5 euros in coins"
65
+ },
66
+ "current_location": "Under a tree",
67
+ "name": "Joe Bloggs",
68
+ "pets": [],
69
+ "created_at": "<%= @person.created_at.xmlschema %>"
70
+ }
71
+
72
+ hash_with_person:
73
+ |
74
+ {
75
+ "total_hits": 1,
76
+ "a_person": {
77
+ "restful_url": "http://example.com:3000/people/<%= @person.to_param %>",
78
+ "name": "Joe Bloggs"
79
+ }
80
+ }
81
+
82
+ hash_with_people:
83
+ |
84
+ {
85
+ "total_hits": 2,
86
+ "people": [{
87
+ "restful_url": "http://example.com:3000/people/<%= @person.to_param %>",
88
+ "name": "Joe Bloggs"
89
+ },
90
+ {
91
+ "restful_url": "http://example.com:3000/people/<%= @person.to_param %>",
92
+ "name": "Joe Bloggs"
93
+ }]
94
+ }
95
+
96
+ hash_with_rich_person:
97
+ |
98
+ {
99
+ "person": {
100
+ "restful_url": "http://example.com:3000/people/<%= @person.to_param %>",
101
+ "name": "Joe Bloggs",
102
+ "wallet": {
103
+ "restful_url": "http://example.com:3000/wallets/<%= @person.wallet.to_param %>",
104
+ "contents": "<%= @person.wallet.contents %>"
105
+ }
106
+ }
107
+ }