moviepilot-restful 0.2.18
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.markdown +40 -0
- data/LICENSE.markdown +22 -0
- data/README.markdown +126 -0
- data/Rakefile +22 -0
- data/TODO.markdown +10 -0
- data/init.rb +1 -0
- data/lib/restful/apimodel/attribute.rb +17 -0
- data/lib/restful/apimodel/collection.rb +22 -0
- data/lib/restful/apimodel/link.rb +21 -0
- data/lib/restful/apimodel/map.rb +41 -0
- data/lib/restful/apimodel/resource.rb +23 -0
- data/lib/restful/converters/active_record.rb +159 -0
- data/lib/restful/rails/action_controller.rb +14 -0
- data/lib/restful/rails/active_record/configuration.rb +219 -0
- data/lib/restful/rails/active_record/metadata_tools.rb +102 -0
- data/lib/restful/rails.rb +22 -0
- data/lib/restful/serializers/atom_like_serializer.rb +51 -0
- data/lib/restful/serializers/base.rb +58 -0
- data/lib/restful/serializers/hash_serializer.rb +46 -0
- data/lib/restful/serializers/json_serializer.rb +18 -0
- data/lib/restful/serializers/params_serializer.rb +46 -0
- data/lib/restful/serializers/xml_serializer.rb +161 -0
- data/lib/restful.rb +65 -0
- data/rails/init.rb +1 -0
- data/restful.gemspec +17 -0
- data/test/converters/active_record_converter_test.rb +147 -0
- data/test/converters/basic_types_converter_test.rb +99 -0
- data/test/fixtures/models/paginated_collection.rb +3 -0
- data/test/fixtures/models/person.rb +29 -0
- data/test/fixtures/models/pet.rb +5 -0
- data/test/fixtures/models/wallet.rb +5 -0
- data/test/fixtures/people.json.yaml +107 -0
- data/test/fixtures/people.xml.yaml +117 -0
- data/test/fixtures/pets.json.yaml +20 -0
- data/test/fixtures/pets.xml.yaml +31 -0
- data/test/rails/active_record_metadata_test.rb +23 -0
- data/test/rails/configuration_test.rb +47 -0
- data/test/rails/restful_publish_test.rb +54 -0
- data/test/serializers/atom_serializer_test.rb +33 -0
- data/test/serializers/json_serializer_test.rb +90 -0
- data/test/serializers/params_serializer_test.rb +76 -0
- data/test/serializers/xml_serializer_test.rb +51 -0
- data/test/test_helper.rb +154 -0
- 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,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,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
|
+
}
|