restful 0.2.20
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/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.rb +65 -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 +160 -0
- data/lib/restful/rails.rb +22 -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/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 +160 -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 +106 -0
@@ -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
|
+
}
|
@@ -0,0 +1,117 @@
|
|
1
|
+
joe_bloggs:
|
2
|
+
|
|
3
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
4
|
+
<person>
|
5
|
+
<restful-url type="link">http://example.com:3000/people/<%= @person.id %></restful-url>
|
6
|
+
<name>Joe Bloggs</name>
|
7
|
+
<wallet-restful-url type="link">http://example.com:3000/wallets/<%= @wallet.id %></wallet-restful-url>
|
8
|
+
</person>
|
9
|
+
|
10
|
+
no_wallet:
|
11
|
+
|
|
12
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
13
|
+
<person>
|
14
|
+
<restful-url type="link">http://example.com:3000/people/<%= @person.id %></restful-url>
|
15
|
+
<location-sentence><%= @person.location_sentence %></location-sentence>
|
16
|
+
</person>
|
17
|
+
|
18
|
+
with_oldest_pet:
|
19
|
+
|
|
20
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
21
|
+
<person>
|
22
|
+
<restful-url type="link">http://example.com:3000/people/<%= @person.id %></restful-url>
|
23
|
+
<oldest-pet>
|
24
|
+
<restful-url type="link">http://example.com:3000/pets/<%= @person.oldest_pet.id %></restful-url>
|
25
|
+
<name><%= @person.oldest_pet.name %></name>
|
26
|
+
<person-restful-url type="link">http://example.com:3000/people/<%= @person.id %></person-restful-url>
|
27
|
+
</oldest-pet>
|
28
|
+
</person>
|
29
|
+
|
30
|
+
with_oldest_pet_species:
|
31
|
+
|
|
32
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
33
|
+
<person>
|
34
|
+
<restful-url type="link">http://example.com:3000/people/<%= @person.id %></restful-url>
|
35
|
+
<oldest-pet>
|
36
|
+
<restful-url type="link">http://example.com:3000/pets/<%= @person.oldest_pet.id %></restful-url>
|
37
|
+
<species type="integer"><%= @person.oldest_pet.species %></species>
|
38
|
+
</oldest-pet>
|
39
|
+
</person>
|
40
|
+
|
41
|
+
joe_with_birthday:
|
42
|
+
|
|
43
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
44
|
+
<person>
|
45
|
+
<restful-url type="link">http://example.com:3000/people/<%= @person.id %></restful-url>
|
46
|
+
<birthday type="date"><%= @person.birthday.to_s(:db) %></birthday>
|
47
|
+
</person>
|
48
|
+
|
49
|
+
joe_with_zwiebelleder:
|
50
|
+
|
|
51
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
52
|
+
<person>
|
53
|
+
<restful-url type="link">http://example.com:3000/people/<%= @person.id %></restful-url>
|
54
|
+
<wallet nil="true"></wallet>
|
55
|
+
</person>
|
56
|
+
|
57
|
+
atom_person:
|
58
|
+
|
|
59
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
60
|
+
<person xml:base="http://example.com:3000">
|
61
|
+
<created-at><%= @person.created_at.xmlschema %></created-at>
|
62
|
+
<link rel="self" href="/people/<%= @person.id %>"/>
|
63
|
+
<name>Joe Bloggs</name>
|
64
|
+
<current-location>Under a tree</current-location>
|
65
|
+
<pets>
|
66
|
+
<pet>
|
67
|
+
<link rel="self" href="/pets/<%= @pet.id %>"/>
|
68
|
+
<name>mietze</name>
|
69
|
+
</pet>
|
70
|
+
</pets>
|
71
|
+
<wallet>
|
72
|
+
<link rel="self" href="/wallets/<%= @wallet.id %>"/>
|
73
|
+
<contents>an old photo, 5 euros in coins</contents>
|
74
|
+
</wallet>
|
75
|
+
</person>
|
76
|
+
|
77
|
+
verbose_no_pets:
|
78
|
+
|
|
79
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
80
|
+
<person>
|
81
|
+
<restful-url type="link">http://example.com:3000/people/<%= @person.id %></restful-url>
|
82
|
+
<name>Joe Bloggs</name>
|
83
|
+
<created-at type="datetime"><%= @person.created_at.xmlschema %></created-at>
|
84
|
+
<current-location>Under a tree</current-location>
|
85
|
+
<wallet-restful-url type="link" nil="true"></wallet-restful-url>
|
86
|
+
</person>
|
87
|
+
|
88
|
+
with_pets_and_expanded_wallet:
|
89
|
+
|
|
90
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
91
|
+
<person>
|
92
|
+
<restful-url type="link">http://example.com:3000/people/<%= @person.id %></restful-url>
|
93
|
+
<name>Joe Bloggs</name>
|
94
|
+
<created-at type="datetime"><%= @person.created_at.xmlschema %></created-at>
|
95
|
+
<current-location>Under a tree</current-location>
|
96
|
+
<pets type="array">
|
97
|
+
<pet>
|
98
|
+
<restful-url type="link">http://example.com:3000/pets/<%= @pet.id %></restful-url>
|
99
|
+
<name>mietze</name>
|
100
|
+
</pet>
|
101
|
+
</pets>
|
102
|
+
<wallet>
|
103
|
+
<restful-url type="link">http://example.com:3000/wallets/<%= @wallet.id %></restful-url>
|
104
|
+
<contents>an old photo, 5 euros in coins</contents>
|
105
|
+
</wallet>
|
106
|
+
</person>
|
107
|
+
|
108
|
+
hashy_person:
|
109
|
+
|
|
110
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
111
|
+
<person>
|
112
|
+
<restful-url type="link">http://example.com:3000/people/<%= @person.id %></restful-url>
|
113
|
+
<pets-ages-hash>
|
114
|
+
<mietze>200</mietze>
|
115
|
+
<motze>100</motze>
|
116
|
+
</pets-ages-hash>
|
117
|
+
</person>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
pets_array:
|
2
|
+
|
|
3
|
+
[
|
4
|
+
{
|
5
|
+
"restful_url": "http://example.com:3000/pets/<%= @person.pets.first.to_param %>",
|
6
|
+
"name": "mietze"
|
7
|
+
}
|
8
|
+
]
|
9
|
+
|
10
|
+
pets_array_with_total_entries:
|
11
|
+
|
|
12
|
+
{
|
13
|
+
"total_entries": 1001,
|
14
|
+
"pets": [
|
15
|
+
{
|
16
|
+
"restful_url": "http://example.com:3000/pets/<%= @person.pets.first.to_param %>",
|
17
|
+
"name": "mietze"
|
18
|
+
}
|
19
|
+
]
|
20
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
nameless_pet:
|
2
|
+
|
|
3
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
4
|
+
<pet>
|
5
|
+
<restful-url type="link">http://example.com:3000/pets/<%= @pet.id %></restful-url>
|
6
|
+
<owner>
|
7
|
+
<restful-url type="link">http://example.com:3000/people/<%= @person.id %></restful-url>
|
8
|
+
<name>Joe Bloggs</name>
|
9
|
+
<current-location>Under a tree</current-location>
|
10
|
+
<wallet-restful-url type="link">http://example.com:3000/wallets/<%= @wallet.id %></wallet-restful-url>
|
11
|
+
</owner>
|
12
|
+
</pet>
|
13
|
+
|
14
|
+
gracie:
|
15
|
+
|
|
16
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
17
|
+
<pet>
|
18
|
+
<person-restful-url type="link">http://example.com:3000/people/<%= @person.id %></person-restful-url>
|
19
|
+
<species>123</species>
|
20
|
+
<name>Gracie</name>
|
21
|
+
</pet>
|
22
|
+
|
23
|
+
pets_array:
|
24
|
+
|
|
25
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
26
|
+
<pets>
|
27
|
+
<pet>
|
28
|
+
<restful-url type="link">http://example.com:3000/pets/<%= @pet.id %></restful-url>
|
29
|
+
<name>mietze</name>
|
30
|
+
</pet>
|
31
|
+
</pets>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper.rb'
|
2
|
+
|
3
|
+
context "active record metadata" do
|
4
|
+
setup do
|
5
|
+
Person.restful_publish(:name, :pets => [:name, :species])
|
6
|
+
Pet.restful_publish(:person_id, :name) # person_id gets converted to a link automagically.
|
7
|
+
|
8
|
+
@person = Person.create(:name => "Jimmy Jones", :current_location => "Under a tree")
|
9
|
+
@pet = @person.pets.create(:name => "Mietze", :species => "cat")
|
10
|
+
end
|
11
|
+
|
12
|
+
teardown do
|
13
|
+
reset_config
|
14
|
+
end
|
15
|
+
|
16
|
+
specify "should be able to convert a collection to an array of resources" do
|
17
|
+
resources = Restful::Rails.tools.convert_collection_to_resources(@person, :pets, Restful.cfg)
|
18
|
+
pet = resources.first
|
19
|
+
|
20
|
+
resources.size.should.equal 1
|
21
|
+
pet.url.should.equal @pet.to_restful.url
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper.rb'
|
2
|
+
|
3
|
+
context "Configuration" do
|
4
|
+
specify "should have an empty whitelist if only restful options are passed in" do
|
5
|
+
config = Restful.cfg
|
6
|
+
config.restful_options[:expansion] = :expanded
|
7
|
+
config.whitelisted.should.empty
|
8
|
+
end
|
9
|
+
|
10
|
+
specify "should return fields without restful_options via whitelisted" do
|
11
|
+
config = Restful.cfg([:one, :two])
|
12
|
+
config.restful_options[:expansion] = :expanded
|
13
|
+
config.whitelisted.should.not.include :restful_options
|
14
|
+
end
|
15
|
+
|
16
|
+
specify "should know if it has restful_options" do
|
17
|
+
config = Restful.cfg([:one, :two])
|
18
|
+
config.restful_options[:expansion] = :expanded
|
19
|
+
config.restful_options.should.not.empty
|
20
|
+
end
|
21
|
+
|
22
|
+
specify "should be able to handle nested whitelist attributes" do
|
23
|
+
config = Restful.cfg(:one, :two => [:a, :b])
|
24
|
+
config.nested(:two).whitelisted.should.== [:a,:b]
|
25
|
+
end
|
26
|
+
|
27
|
+
specify "should know which attributes are published" do
|
28
|
+
config = Restful.cfg(:one, :two => [:a, :b])
|
29
|
+
config.published?(:two).should.== true
|
30
|
+
config.published?(:one).should.== true
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "should know if it is nested" do
|
34
|
+
config = Restful.cfg(:one, :restful_options => {:nested => true})
|
35
|
+
config.nested?.should.== true
|
36
|
+
end
|
37
|
+
|
38
|
+
specify "should preserve :include when :restful_options are present" do
|
39
|
+
Person.restful_publish :pets
|
40
|
+
p = Person.create
|
41
|
+
p.pets.create
|
42
|
+
|
43
|
+
restful = p.to_restful :include => :pets, :restful_options => {}
|
44
|
+
restful.collections.size.should.== 1
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper.rb'
|
2
|
+
|
3
|
+
context "restful publish" do
|
4
|
+
teardown do
|
5
|
+
reset_config
|
6
|
+
end
|
7
|
+
|
8
|
+
specify "should result in a method .published?(:attr_key) return true for published attributes" do
|
9
|
+
Pet.restful_publish(:person_id, :name) # person_id gets converted to a link automagically.
|
10
|
+
|
11
|
+
Pet.restful_config.published?(:name).should.equal true
|
12
|
+
Pet.restful_config.published?(:pets).should.equal false
|
13
|
+
Pet.restful_config.published?(:species).should.equal false
|
14
|
+
end
|
15
|
+
|
16
|
+
specify "should have restful_options as an empty hash after calling restful_publish" do
|
17
|
+
Person.restful_publish(:name, :pets => [:name, :species])
|
18
|
+
Person.restful_config.restful_options.should.==({})
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "api publishing with nesting" do
|
23
|
+
|
24
|
+
teardown do
|
25
|
+
reset_config
|
26
|
+
end
|
27
|
+
|
28
|
+
specify "should result in a method .published?(:attr_key) return true for nested attributes" do
|
29
|
+
Person.restful_publish(:name, :pets => [:name, :species])
|
30
|
+
Person.restful_config.published?(:pets).should.equal true
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "should be invoke to_restful on the nested model with the specified nested attributes" do
|
34
|
+
Person.restful_publish(:name, :pets => [:name, :species])
|
35
|
+
@person = Person.create(:name => "Joe Bloggs", :current_location => "Under a tree")
|
36
|
+
@pet = @person.pets.create(:name => "Mietze", :species => "cat")
|
37
|
+
|
38
|
+
Pet.any_instance.expects(:to_restful).with { |arg| arg.whitelisted == [:name, :species] }
|
39
|
+
@person.to_restful
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "should pass config over to nested objects. " do
|
43
|
+
Pet.restful_publish :name
|
44
|
+
House.restful_publish :people
|
45
|
+
|
46
|
+
house = House.create
|
47
|
+
person = house.people.create :name => "johannes"
|
48
|
+
person.pets.create :name => "puenktchen"
|
49
|
+
|
50
|
+
restful = [house].to_restful(:include => :pets)
|
51
|
+
|
52
|
+
restful.value.first.collections.first.value.first.collections.size.should.== 1
|
53
|
+
end
|
54
|
+
end
|