purzelrakete-restful 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE.markdown +22 -0
- data/README.markdown +108 -0
- data/Rakefile +22 -0
- data/TODO.markdown +7 -0
- data/init.rb +1 -0
- data/lib/restful/apimodel/attribute.rb +17 -0
- data/lib/restful/apimodel/collection.rb +14 -0
- data/lib/restful/apimodel/link.rb +21 -0
- data/lib/restful/apimodel/resource.rb +47 -0
- data/lib/restful/converters/active_record.rb +128 -0
- data/lib/restful/rails/action_controller.rb +14 -0
- data/lib/restful/rails/active_record/configuration.rb +114 -0
- data/lib/restful/rails/active_record/metadata_tools.rb +106 -0
- data/lib/restful/rails.rb +22 -0
- data/lib/restful/serializers/atom_like_serializer.rb +51 -0
- data/lib/restful/serializers/base.rb +41 -0
- data/lib/restful/serializers/hash_serializer.rb +45 -0
- data/lib/restful/serializers/json_serializer.rb +20 -0
- data/lib/restful/serializers/params_serializer.rb +40 -0
- data/lib/restful/serializers/xml_serializer.rb +146 -0
- data/lib/restful.rb +64 -0
- data/rails/init.rb +1 -0
- data/restful.gemspec +17 -0
- data/test/converters/active_record_converter_test.rb +108 -0
- data/test/fixtures/models/person.rb +17 -0
- data/test/fixtures/models/pet.rb +5 -0
- data/test/fixtures/models/wallet.rb +5 -0
- data/test/fixtures/people.json.yaml +16 -0
- data/test/fixtures/people.xml.yaml +105 -0
- data/test/fixtures/pets.xml.yaml +21 -0
- data/test/rails/active_record_metadata_test.rb +23 -0
- data/test/rails/configuration_test.rb +45 -0
- data/test/rails/restful_publish_test.rb +41 -0
- data/test/serializers/atom_serializer_test.rb +33 -0
- data/test/serializers/json_serializer_test.rb +21 -0
- data/test/serializers/params_serializer_test.rb +44 -0
- data/test/serializers/xml_serializer_test.rb +38 -0
- data/test/test_helper.rb +129 -0
- metadata +93 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'restful/serializers/base'
|
2
|
+
require 'builder'
|
3
|
+
|
4
|
+
#
|
5
|
+
# Converts an APIModel to and from XML.
|
6
|
+
#
|
7
|
+
module Restful
|
8
|
+
module Serializers
|
9
|
+
class AtomLikeSerializer < XMLSerializer
|
10
|
+
|
11
|
+
serializer_name :atom_like
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def root_resource(node)
|
16
|
+
url_base = node.attribute(:base, :xml)
|
17
|
+
me_node = node.delete_element("link[@rel='self']")
|
18
|
+
own_url = me_node.attribute(:href)
|
19
|
+
Restful.resource(node.name, :path => own_url, :base => url_base)
|
20
|
+
end
|
21
|
+
|
22
|
+
def build_link(el, type)
|
23
|
+
Restful.link(revert_link_name(el.attribute('rel')), nil, el.attribute('href'), type)
|
24
|
+
end
|
25
|
+
|
26
|
+
def calculate_node_type(el)
|
27
|
+
return :link if el.name.downcase == "link"
|
28
|
+
(el.attributes["type"] || "string").to_sym
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_link_to(resource, builder, options = {})
|
32
|
+
is_self = !!options[:self]
|
33
|
+
builder.tag!("link", { :href => resource.path, :rel => (is_self ? "self" : resource.name) })
|
34
|
+
end
|
35
|
+
|
36
|
+
def root_element(resource)
|
37
|
+
decorations = {}
|
38
|
+
|
39
|
+
unless @nested_root
|
40
|
+
decorations = { :"xml:base" => Restful::Rails.api_hostname } unless Restful::Rails.api_hostname.blank?
|
41
|
+
@nested_root = true
|
42
|
+
end
|
43
|
+
|
44
|
+
[resource.name, decorations]
|
45
|
+
end
|
46
|
+
|
47
|
+
def decorations(value); {}; end
|
48
|
+
def collections_decorations; {}; end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#
|
2
|
+
# Converts an APIModel to and from a given format.
|
3
|
+
#
|
4
|
+
module Restful
|
5
|
+
module Serializers
|
6
|
+
class Base
|
7
|
+
cattr_accessor :serializers
|
8
|
+
|
9
|
+
def serialize(resource, options = {}) # implement me.
|
10
|
+
raise NotImplementedError.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def deserialize(resource, options = {}) # implement me.
|
14
|
+
raise NotImplementedError.new
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# Grabs a serializer, given...
|
19
|
+
#
|
20
|
+
# .serialize(:xml, Resource.new(:animal => "cow"))
|
21
|
+
#
|
22
|
+
def self.serializer(type)
|
23
|
+
serializers[type].new
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.serializer_name(key)
|
27
|
+
self.serializers ||= {}
|
28
|
+
self.serializers[key] = self
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
def transform_link_name(name)
|
33
|
+
name.to_s.gsub /_id$/, "-restful-url"
|
34
|
+
end
|
35
|
+
|
36
|
+
def revert_link_name(name)
|
37
|
+
name.to_s.gsub /-restful-url$/, "_id"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'restful/serializers/base'
|
2
|
+
|
3
|
+
#
|
4
|
+
# AR params hash.
|
5
|
+
#
|
6
|
+
module Restful
|
7
|
+
module Serializers
|
8
|
+
class HashSerializer < Base
|
9
|
+
|
10
|
+
serializer_name :hash
|
11
|
+
|
12
|
+
def serialize(resource, options = {})
|
13
|
+
params = {}
|
14
|
+
|
15
|
+
resource.values.each do |value|
|
16
|
+
if value.type == :collection # serialize the stuffs
|
17
|
+
resources = value.value
|
18
|
+
name = resources.first.name.pluralize
|
19
|
+
|
20
|
+
array = []
|
21
|
+
resources.each { |r| array << serialize(r) }
|
22
|
+
|
23
|
+
params["#{value.name}".to_sym] = array
|
24
|
+
elsif value.type == :link
|
25
|
+
params[value.name] = Restful::Rails.tools.dereference(value.value)
|
26
|
+
elsif value.type == :resource
|
27
|
+
params["#{value.name}".to_sym] = serialize(value)
|
28
|
+
else # plain ole
|
29
|
+
string_value = case value.extended_type
|
30
|
+
when :datetime
|
31
|
+
value.value.xmlschema
|
32
|
+
else
|
33
|
+
value.value
|
34
|
+
end
|
35
|
+
|
36
|
+
params[value.name] = string_value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
params["restful_url"] = resource.full_url
|
41
|
+
params
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'restful/serializers/base'
|
2
|
+
require 'yajl'
|
3
|
+
|
4
|
+
#
|
5
|
+
# AR params hash.
|
6
|
+
#
|
7
|
+
module Restful
|
8
|
+
module Serializers
|
9
|
+
class JsonSerializer < Base
|
10
|
+
|
11
|
+
serializer_name :json
|
12
|
+
|
13
|
+
def serialize(resource, options = {})
|
14
|
+
hasher = Restful::Serializers::HashSerializer.new
|
15
|
+
hash = hasher.serialize(resource, options)
|
16
|
+
Yajl::Encoder.encode(hash)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'restful/serializers/base'
|
2
|
+
require 'builder'
|
3
|
+
|
4
|
+
#
|
5
|
+
# AR params hash.
|
6
|
+
#
|
7
|
+
module Restful
|
8
|
+
module Serializers
|
9
|
+
class ParamsSerializer < Base
|
10
|
+
|
11
|
+
serializer_name :params
|
12
|
+
|
13
|
+
def serialize(resource, options = {})
|
14
|
+
params = {}
|
15
|
+
|
16
|
+
resource.values.each do |value|
|
17
|
+
if value.type == :collection # serialize the stuffs
|
18
|
+
resources = value.value
|
19
|
+
name = resources.first.name.pluralize
|
20
|
+
|
21
|
+
array = []
|
22
|
+
resources.each do |resource|
|
23
|
+
array << serialize(resource)
|
24
|
+
end
|
25
|
+
|
26
|
+
params["#{value.name.to_sym}_attributes".to_sym] = array
|
27
|
+
elsif value.type == :link
|
28
|
+
params[value.name] = Restful::Rails.tools.dereference(value.value)
|
29
|
+
elsif value.type == :resource
|
30
|
+
params["#{value.name.to_sym}_attributes".to_sym] = serialize(value)
|
31
|
+
else # plain ole
|
32
|
+
params[value.name] = value.value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
params
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,146 @@
|
|
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
|
+
xml = options[:builder] || Builder::XmlMarkup.new(:indent => 2)
|
17
|
+
xml.instruct! unless options[:instruct].is_a?(FalseClass)
|
18
|
+
|
19
|
+
xml.tag!(*root_element(resource)) do
|
20
|
+
add_link_to(resource, xml, :self => true)
|
21
|
+
|
22
|
+
resource.values.each do |value|
|
23
|
+
|
24
|
+
if value.type == :collection # serialize the stuffs
|
25
|
+
resources = value.value
|
26
|
+
if first_resource = resources.first
|
27
|
+
xml.tag!(first_resource.name.pluralize, collections_decorations) do
|
28
|
+
resources.each do |resource|
|
29
|
+
serialize(resource, { :instruct => false, :builder => xml })
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
elsif value.type == :link
|
35
|
+
add_link_to(value, xml)
|
36
|
+
elsif value.type == :resource
|
37
|
+
serialize(value, {:instruct => false, :builder => xml})
|
38
|
+
else # plain ole
|
39
|
+
add_tag(xml, value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# returns a resource, or collection of resources.
|
46
|
+
def deserialize(xml, options = {})
|
47
|
+
build_resource(REXML::Document.new(xml).root)
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def add_link_to(resource, builder, options = {})
|
53
|
+
is_self = !!options[:self]
|
54
|
+
|
55
|
+
attributes = {:type => "link"}
|
56
|
+
attributes.merge!(:nil => "true") if resource.full_url.blank?
|
57
|
+
builder.tag!((is_self ? "restful-url" : transform_link_name(resource.name)), resource.full_url, attributes)
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_tag(builder, value)
|
61
|
+
string_value = case value.extended_type
|
62
|
+
when :datetime
|
63
|
+
value.value.xmlschema
|
64
|
+
else
|
65
|
+
value.value.to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
builder.tag!(
|
69
|
+
value.name.to_s.dasherize,
|
70
|
+
string_value,
|
71
|
+
decorations(value)
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def decorations(value)
|
76
|
+
decorations = {}
|
77
|
+
|
78
|
+
if value.extended_type == :binary
|
79
|
+
decorations[:encoding] = 'base64'
|
80
|
+
end
|
81
|
+
|
82
|
+
if value.extended_type != :string and value.extended_type != :notype
|
83
|
+
decorations[:type] = value.extended_type
|
84
|
+
end
|
85
|
+
|
86
|
+
if value.extended_type == :datetime
|
87
|
+
decorations[:type] = :datetime
|
88
|
+
end
|
89
|
+
|
90
|
+
if value.value.nil?
|
91
|
+
decorations[:nil] = true
|
92
|
+
end
|
93
|
+
|
94
|
+
decorations
|
95
|
+
end
|
96
|
+
|
97
|
+
def collections_decorations
|
98
|
+
{ :type => "array" }
|
99
|
+
end
|
100
|
+
|
101
|
+
def root_element(resource, options = {})
|
102
|
+
[resource.name]
|
103
|
+
end
|
104
|
+
|
105
|
+
# turns a rexml node into a Resource
|
106
|
+
def build_resource(node)
|
107
|
+
resource = root_resource(node)
|
108
|
+
|
109
|
+
node.elements.each do |el|
|
110
|
+
type = calculate_node_type(el)
|
111
|
+
resource.values << case type
|
112
|
+
|
113
|
+
when :link : build_link(el, type)
|
114
|
+
when :datetime
|
115
|
+
Restful.attr(el.name, DateTime.parse(el.text), type)
|
116
|
+
when :resource
|
117
|
+
build_resource(el)
|
118
|
+
when :array
|
119
|
+
Restful.collection(el.name, el.elements.map { |child| build_resource(child) }, type)
|
120
|
+
else
|
121
|
+
Restful.attr(el.name, el.text, type)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
resource
|
126
|
+
end
|
127
|
+
|
128
|
+
def calculate_node_type(el)
|
129
|
+
if el.children.size > 1 && el.attributes["type"].blank?
|
130
|
+
return :resource
|
131
|
+
else
|
132
|
+
(el.attributes["type"] || "string").to_sym
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def build_link(el, type)
|
137
|
+
Restful.link(revert_link_name(el.name), nil, el.text, type)
|
138
|
+
end
|
139
|
+
|
140
|
+
def root_resource(node)
|
141
|
+
url = node.delete_element("restful-url").try(:text)
|
142
|
+
Restful.resource(node.name, :url => url)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
data/lib/restful.rb
ADDED
@@ -0,0 +1,64 @@
|
|
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/resource'
|
7
|
+
require 'restful/apimodel/attribute'
|
8
|
+
require 'restful/apimodel/collection'
|
9
|
+
require 'restful/apimodel/link'
|
10
|
+
require 'restful/serializers/xml_serializer'
|
11
|
+
require 'restful/serializers/json_serializer'
|
12
|
+
require 'restful/serializers/atom_like_serializer'
|
13
|
+
require 'restful/serializers/params_serializer'
|
14
|
+
require 'restful/serializers/hash_serializer'
|
15
|
+
|
16
|
+
module Restful
|
17
|
+
|
18
|
+
MAJOR = 0
|
19
|
+
MINOR = 1
|
20
|
+
REVISION = 2
|
21
|
+
VERSION = [MAJOR, MINOR, REVISION].join(".")
|
22
|
+
|
23
|
+
#
|
24
|
+
# Restful.from_xml, #from_atom_like. Methods correspond with
|
25
|
+
# resgistered serializers.
|
26
|
+
#
|
27
|
+
def self.method_missing(method, *args, &block)
|
28
|
+
if method.to_s.match(/^from_(.*)$/)
|
29
|
+
if serializer_clazz = Restful::Serializers::Base.serializers[type = $1.to_sym]
|
30
|
+
s = serializer_clazz.new
|
31
|
+
s.deserialize(args.first)
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
35
|
+
else
|
36
|
+
super
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Shortcuts past the namespaces
|
42
|
+
#
|
43
|
+
|
44
|
+
def self.cfg(*options)
|
45
|
+
Restful::Rails::ActiveRecord::Configuration::Config.new(*options)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.attr(*options)
|
49
|
+
Restful::ApiModel::Attribute.new(*options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.link(*options)
|
53
|
+
Restful::ApiModel::Link.new(*options)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.collection(*options)
|
57
|
+
Restful::ApiModel::Collection.new(*options)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.resource(*options)
|
61
|
+
Restful::ApiModel::Resource.new(*options)
|
62
|
+
end
|
63
|
+
|
64
|
+
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.1"
|
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{ init.rb lib/restful/apimodel/attribute.rb lib/restful/apimodel/collection.rb lib/restful/apimodel/link.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/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.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,108 @@
|
|
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")
|
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 return link attributes from a model" do
|
21
|
+
@pet.to_restful.links.map { |node| node.name }.sort.should.equal [:person_id]
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "should convert a NULL inner association such as person.wallet to a link with a null value" do
|
25
|
+
@person.wallet = nil
|
26
|
+
|
27
|
+
wallet = @person.to_restful(:restful_options => { :expansion => :collapsed }).links.select { |link| link.name == "wallet-restful-url" }.first
|
28
|
+
wallet.should.not.== nil
|
29
|
+
wallet.value.should.== nil
|
30
|
+
end
|
31
|
+
|
32
|
+
specify "should return plain attributes from a model" do
|
33
|
+
@pet.to_restful.simple_attributes.map { |node| node.name }.should.equal [:name]
|
34
|
+
end
|
35
|
+
|
36
|
+
specify "should return collections attributes from a model" do
|
37
|
+
restful = @person.to_restful
|
38
|
+
restful.collections.map { |node| node.name }.sort.should.equal [:pets]
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "should be able to convert themselves to an apimodel containing all and only the attributes exposed by Model.publish_api" do
|
42
|
+
resource = @person.to_restful
|
43
|
+
|
44
|
+
resource.simple_attributes.select { |node| node.name == :name }.should.not.blank
|
45
|
+
resource.simple_attributes.select { |node| node.name == :biography }.should.blank
|
46
|
+
|
47
|
+
mietze = @person.to_restful.collections .select { |node| node.name == :pets }.first.value.first
|
48
|
+
mietze.simple_attributes.size.should.== 2
|
49
|
+
mietze.simple_attributes.select { |node| node.name == :name }.should.not.blank
|
50
|
+
mietze.simple_attributes.select { |node| node.name == :species }.should.not.blank
|
51
|
+
end
|
52
|
+
|
53
|
+
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
|
54
|
+
resource = @person.to_restful(:restful_options => { :nested => false })
|
55
|
+
resource.simple_attributes.select { |node| node.name == :name }.should.not.blank
|
56
|
+
resource.simple_attributes.select { |node| node.name == :biography }.should.blank
|
57
|
+
|
58
|
+
mietze = resource.collections .select { |node| node.name == :pets }.first.value.first
|
59
|
+
mietze.simple_attributes.size.should.== 2
|
60
|
+
mietze.simple_attributes.select { |node| node.name == :name }.should.not.blank
|
61
|
+
mietze.simple_attributes.select { |node| node.name == :species }.should.not.blank
|
62
|
+
end
|
63
|
+
|
64
|
+
specify "should be able to override to_restful published fields by passing them into the method" do
|
65
|
+
api = @person.to_restful(:pets)
|
66
|
+
|
67
|
+
api.simple_attributes.should.blank?
|
68
|
+
api.collections.map { |node| node.name }.sort.should.equal [:pets]
|
69
|
+
end
|
70
|
+
|
71
|
+
specify "should be able to handle relations that are nil/null" do
|
72
|
+
@person.wallet = nil
|
73
|
+
@person.save!
|
74
|
+
@person.reload
|
75
|
+
|
76
|
+
assert_nothing_raised do
|
77
|
+
@person.to_restful
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
specify "should be able to expand a :belongs_to relationship" do
|
82
|
+
xml_should_eql_fixture(@pet.to_restful_xml(:owner), "pets", :nameless_pet)
|
83
|
+
end
|
84
|
+
|
85
|
+
specify "should return collapsed resources by default when :expansion => :collapsed is passed" do
|
86
|
+
Person.restful_publish(:name, :wallet, :restful_options => { :expansion => :collapsed })
|
87
|
+
xml_should_eql_fixture(@person.to_restful_xml, "people", :joe_bloggs)
|
88
|
+
end
|
89
|
+
|
90
|
+
specify "should be able to export content generated by methods that return strings" do
|
91
|
+
xml_should_eql_fixture(@person.to_restful_xml(:location_sentence), "people", :no_wallet)
|
92
|
+
end
|
93
|
+
|
94
|
+
specify "should be able to export content generated by methods (not attributes) and compute the correct style" do
|
95
|
+
xml_should_eql_fixture(@person.to_restful_xml(:oldest_pet), "people", :with_oldest_pet)
|
96
|
+
end
|
97
|
+
|
98
|
+
specify "should be able to export content generated by methods (not attributes) while filtering with a nested configuration" do
|
99
|
+
xml_should_eql_fixture(@person.to_restful_xml(:oldest_pet => [:species]), "people", :with_oldest_pet_species)
|
100
|
+
end
|
101
|
+
|
102
|
+
specify "should create element with nil='true' attribute if no relation is set" do
|
103
|
+
@person.wallet = nil
|
104
|
+
@person.save
|
105
|
+
|
106
|
+
xml_should_eql_fixture(@person.to_restful_xml(:wallet), "people", :joe_with_zwiebelleder)
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,17 @@
|
|
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
|
+
apiable
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
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
|
+
}
|