restful_objects 0.0.1 → 0.0.2
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.
- checksums.yaml +8 -8
- data/LICENSE +191 -0
- data/README.md +83 -0
- data/bin/restful_server.rb +12 -0
- data/lib/restful_objects/{model.rb → domain_model.rb} +0 -0
- data/lib/restful_objects/object.rb +2 -114
- data/lib/restful_objects/object_base.rb +116 -0
- data/lib/restful_objects/property_description.rb +68 -0
- data/lib/restful_objects/service.rb +21 -0
- data/lib/restful_objects/version.rb +1 -1
- data/lib/restful_objects.rb +34 -0
- data/spec/integration/domain-types_actions_spec.rb +43 -0
- data/spec/integration/domain-types_collections_spec.rb +45 -0
- data/spec/integration/domain-types_properties_spec.rb +41 -0
- data/spec/integration/server-root_spec.rb +98 -0
- data/spec/spec_helper.rb +52 -0
- data/spec/unit/object_actions_spec.rb +380 -0
- data/spec/unit/object_collections_spec.rb +190 -0
- data/spec/unit/object_properties_spec.rb +206 -0
- data/spec/unit/object_spec.rb +228 -0
- data/spec/unit/service_spec.rb +125 -0
- data/spec/unit/type_list_spec.rb +37 -0
- metadata +49 -20
@@ -0,0 +1,190 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require_relative '../spec_helper'
|
3
|
+
|
4
|
+
describe RestfulObjects::ObjectActions do
|
5
|
+
before :all do
|
6
|
+
RestfulObjects::DomainModel.current.reset
|
7
|
+
|
8
|
+
class Address
|
9
|
+
include RestfulObjects::Object
|
10
|
+
|
11
|
+
property :street, :string
|
12
|
+
property :number, :int
|
13
|
+
end
|
14
|
+
|
15
|
+
class CollectionsTest
|
16
|
+
include RestfulObjects::Object
|
17
|
+
|
18
|
+
collection :addresses, Address
|
19
|
+
collection :collection_full_metadata, Address
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
before :each do
|
24
|
+
@object = CollectionsTest.new
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should create a collection' do
|
28
|
+
@object.addresses.is_a?(Enumerable).should be_true
|
29
|
+
@object.addresses.empty?.should be_true
|
30
|
+
|
31
|
+
a = Address.new
|
32
|
+
a.street = 'Evergreen'
|
33
|
+
a.number = 1234
|
34
|
+
|
35
|
+
@object.addresses.push(a)
|
36
|
+
@object.addresses.empty?.should be_false
|
37
|
+
@object.addresses.count.should eq(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should generate json for the collection' do
|
41
|
+
a1 = Address.new
|
42
|
+
@object.addresses.push a1
|
43
|
+
a2 = Address.new
|
44
|
+
@object.addresses.push a2
|
45
|
+
a3 = Address.new
|
46
|
+
@object.addresses.push a3
|
47
|
+
|
48
|
+
expected = { 'id' => 'addresses',
|
49
|
+
'value' => [
|
50
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/value;collection="addresses"',
|
51
|
+
'href' => "http://localhost/objects/Address/#{a1.object_id}",
|
52
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object"',
|
53
|
+
'method' => 'GET' },
|
54
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/value;collection="addresses"',
|
55
|
+
'href' => "http://localhost/objects/Address/#{a2.object_id}",
|
56
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object"',
|
57
|
+
'method' => 'GET' },
|
58
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/value;collection="addresses"',
|
59
|
+
'href' => "http://localhost/objects/Address/#{a3.object_id}",
|
60
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object"',
|
61
|
+
'method' => 'GET' }
|
62
|
+
],
|
63
|
+
'links' => [
|
64
|
+
{ 'rel' => 'self',
|
65
|
+
'href' => "http://localhost/objects/CollectionsTest/#{@object.object_id}/collections/addresses",
|
66
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-collection"',
|
67
|
+
'method' => 'GET' },
|
68
|
+
{ 'rel' => 'up',
|
69
|
+
'href' => "http://localhost/objects/CollectionsTest/#{@object.object_id}",
|
70
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object"',
|
71
|
+
'method' => 'GET' },
|
72
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/add-to;collection="addresses"',
|
73
|
+
'href' => "http://localhost/objects/CollectionsTest/#{@object.object_id}/collections/addresses",
|
74
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-collection"',
|
75
|
+
'method' => 'PUT',
|
76
|
+
'arguments' => { 'value' => nil } },
|
77
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/remove-from;collection="addresses"',
|
78
|
+
'href' => "http://localhost/objects/CollectionsTest/#{@object.object_id}/collections/addresses",
|
79
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-collection"',
|
80
|
+
'method' => 'DELETE',
|
81
|
+
'arguments' => { 'value' => nil } },
|
82
|
+
]
|
83
|
+
}
|
84
|
+
|
85
|
+
get "/objects/CollectionsTest/#{@object.object_id}/collections/addresses"
|
86
|
+
|
87
|
+
last_response.body.should match_json_expression expected
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should add an object to a collection' do
|
91
|
+
address = Address.new
|
92
|
+
|
93
|
+
json = { 'value' => { 'href' => "http://localhost/objects/Address/#{address.object_id}" } }.to_json
|
94
|
+
|
95
|
+
put "/objects/CollectionsTest/#{@object.object_id}/collections/addresses", {}, { input: json }
|
96
|
+
|
97
|
+
@object.addresses.include?(address).should be_true
|
98
|
+
|
99
|
+
expected = { 'id' => 'addresses',
|
100
|
+
'value' => [
|
101
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/value;collection="addresses"',
|
102
|
+
'href' => "http://localhost/objects/Address/#{address.object_id}",
|
103
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object"',
|
104
|
+
'method' => 'GET' } ],
|
105
|
+
'links' => [
|
106
|
+
{ 'rel' => 'self',
|
107
|
+
'href' => "http://localhost/objects/CollectionsTest/#{@object.object_id}/collections/addresses",
|
108
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-collection"',
|
109
|
+
'method' => 'GET' },
|
110
|
+
{ 'rel' => 'up',
|
111
|
+
'href' => "http://localhost/objects/CollectionsTest/#{@object.object_id}",
|
112
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object"',
|
113
|
+
'method' => 'GET' },
|
114
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/add-to;collection="addresses"',
|
115
|
+
'href' => "http://localhost/objects/CollectionsTest/#{@object.object_id}/collections/addresses",
|
116
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-collection"',
|
117
|
+
'method' => 'PUT',
|
118
|
+
'arguments' => { 'value' => nil } },
|
119
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/remove-from;collection="addresses"',
|
120
|
+
'href' => "http://localhost/objects/CollectionsTest/#{@object.object_id}/collections/addresses",
|
121
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-collection"',
|
122
|
+
'method' => 'DELETE',
|
123
|
+
'arguments' => { 'value' => nil } },
|
124
|
+
]
|
125
|
+
}
|
126
|
+
|
127
|
+
last_response.body.should match_json_expression expected
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should remove an object from a collection' do
|
131
|
+
address = Address.new
|
132
|
+
|
133
|
+
@object.addresses.push(address)
|
134
|
+
|
135
|
+
json = { 'value' => { 'href' => "http://localhost/objects/Address/#{address.object_id}" } }.to_json
|
136
|
+
|
137
|
+
delete "/objects/CollectionsTest/#{@object.object_id}/collections/addresses", {}, { input: json }
|
138
|
+
|
139
|
+
@object.addresses.include?(address).should be_false
|
140
|
+
|
141
|
+
expected = { 'id' => 'addresses',
|
142
|
+
'value' => [],
|
143
|
+
'links' => [
|
144
|
+
{ 'rel' => 'self',
|
145
|
+
'href' => "http://localhost/objects/CollectionsTest/#{@object.object_id}/collections/addresses",
|
146
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-collection"',
|
147
|
+
'method' => 'GET' },
|
148
|
+
{ 'rel' => 'up',
|
149
|
+
'href' => "http://localhost/objects/CollectionsTest/#{@object.object_id}",
|
150
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object"',
|
151
|
+
'method' => 'GET' },
|
152
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/add-to;collection="addresses"',
|
153
|
+
'href' => "http://localhost/objects/CollectionsTest/#{@object.object_id}/collections/addresses",
|
154
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-collection"',
|
155
|
+
'method' => 'PUT',
|
156
|
+
'arguments' => { 'value' => nil } },
|
157
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/remove-from;collection="addresses"',
|
158
|
+
'href' => "http://localhost/objects/CollectionsTest/#{@object.object_id}/collections/addresses",
|
159
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-collection"',
|
160
|
+
'method' => 'DELETE',
|
161
|
+
'arguments' => { 'value' => nil } },
|
162
|
+
]
|
163
|
+
}
|
164
|
+
|
165
|
+
last_response.body.should match_json_expression expected
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'should generate metadata in extensions' do
|
169
|
+
collection = @object.rs_type.collections['collection_full_metadata']
|
170
|
+
collection.friendly_name = 'Friendly Collection'
|
171
|
+
collection.description = 'Collection Description'
|
172
|
+
collection.plural_form = 'Collections'
|
173
|
+
expected = {
|
174
|
+
'id' => 'collection_full_metadata',
|
175
|
+
'extensions' => {
|
176
|
+
'friendlyName' => 'Friendly Collection',
|
177
|
+
'description' => 'Collection Description',
|
178
|
+
'returnType' => 'list',
|
179
|
+
'elementType' => 'Address',
|
180
|
+
'pluralForm' => 'Collections',
|
181
|
+
'memberOrder' => Fixnum
|
182
|
+
}.strict!
|
183
|
+
}
|
184
|
+
|
185
|
+
get "/objects/ActionsTest/#{@object.object_id}/collections/collection_full_metadata"
|
186
|
+
|
187
|
+
last_response.body.should match_json_expression expected
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe RestfulObjects::ObjectProperties do
|
4
|
+
before :all do
|
5
|
+
RestfulObjects::DomainModel.current.reset
|
6
|
+
|
7
|
+
class PropertiesTest
|
8
|
+
include RestfulObjects::Object
|
9
|
+
|
10
|
+
property :id, :int, read_only: true
|
11
|
+
property :name, :string, max_length: 10
|
12
|
+
property :string_prop, :string
|
13
|
+
property :int_prop, :int
|
14
|
+
property :decimal_prop, :decimal
|
15
|
+
property :date_prop, :date
|
16
|
+
property :blob_prop, :blob
|
17
|
+
|
18
|
+
property :prop_full_metadata, :string, friendly_name: 'Meta Prop', description: 'To Test Metadata', max_length: 30,
|
19
|
+
pattern: '.*abc.*', optional: false
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
super
|
23
|
+
@id = 99
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
before :each do
|
29
|
+
@object = PropertiesTest.new
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should respond to properties' do
|
33
|
+
@object.respond_to?(:string_prop).should be_true
|
34
|
+
@object.respond_to?(:string_prop=).should be_true
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should not generate writer for read-only property' do
|
38
|
+
@object.respond_to?(:id).should be_true
|
39
|
+
@object.respond_to?(:id=).should be_false
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should generate json for a read-only property' do
|
43
|
+
expected = { 'id' =>
|
44
|
+
{ 'value' => 99,
|
45
|
+
'links' => [
|
46
|
+
{ 'rel' => 'self',
|
47
|
+
'href' => "http://localhost/objects/PropertiesTest/#{@object.object_id}/properties/id",
|
48
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-property"',
|
49
|
+
'method' => 'GET'},
|
50
|
+
{ 'rel' => 'up',
|
51
|
+
'href' => "http://localhost/objects/PropertiesTest/#{@object.object_id}",
|
52
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object"',
|
53
|
+
'method' => 'GET'}
|
54
|
+
],
|
55
|
+
'disabledReason' => 'read-only property'
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
get "/objects/PropertiesTest/#{@object.object_id}/properties/id"
|
60
|
+
|
61
|
+
last_response.body.should match_json_expression expected
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should generate json for a writable property' do
|
65
|
+
@object.name = 'Mr. John'
|
66
|
+
|
67
|
+
expected = { 'name' =>
|
68
|
+
{ 'value' => 'Mr. John',
|
69
|
+
'links' => [
|
70
|
+
{ 'rel' => 'self',
|
71
|
+
'href' => "http://localhost/objects/PropertiesTest/#{@object.object_id}/properties/name",
|
72
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-property"',
|
73
|
+
'method' => 'GET' },
|
74
|
+
{ 'rel' => 'up',
|
75
|
+
'href' => "http://localhost/objects/PropertiesTest/#{@object.object_id}",
|
76
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object"',
|
77
|
+
'method' => 'GET' },
|
78
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/modify;property="name"',
|
79
|
+
'href' => "http://localhost/objects/PropertiesTest/#{@object.object_id}/properties/name",
|
80
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-property"',
|
81
|
+
'method' => 'PUT',
|
82
|
+
'arguments' => { 'value' => nil } },
|
83
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/clear;property="name"',
|
84
|
+
'href' => "http://localhost/objects/PropertiesTest/#{@object.object_id}/properties/name",
|
85
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-property"',
|
86
|
+
'method' => 'DELETE' }
|
87
|
+
]
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
get "/objects/PropertiesTest/#{@object.object_id}/properties/name"
|
92
|
+
|
93
|
+
last_response.body.should match_json_expression expected
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should enforce string property max_length' do
|
97
|
+
@object.name = 'x' * 10
|
98
|
+
@object.name.should eq('x' * 10)
|
99
|
+
expect { @object.name = 'x' * 11 }.to raise_error
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should process different property types get' do
|
103
|
+
@object.string_prop = 'A string'
|
104
|
+
@object.int_prop = 1234
|
105
|
+
@object.decimal_prop = 333.33
|
106
|
+
@object.date_prop = Date.new(2012, 2, 29)
|
107
|
+
@object.blob_prop = "\xE5\xA5\xB4\x30\xF2\x8C\x71\xD9"
|
108
|
+
|
109
|
+
expected = {
|
110
|
+
'string_prop' => 'A string',
|
111
|
+
'int_prop' => 1234,
|
112
|
+
'decimal_prop' => 333.33,
|
113
|
+
'date_prop' => '2012-02-29',
|
114
|
+
'blob_prop' => '5aW0MPKMcdk=' }
|
115
|
+
|
116
|
+
expected.each do |name, value|
|
117
|
+
get "/objects/PropertiesTest/#{@object.object_id}/properties/#{name}"
|
118
|
+
JSON.parse(last_response.body)[name]['value'].should eq value
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should process different property types set' do
|
123
|
+
values = {
|
124
|
+
'string_prop' => 'A string',
|
125
|
+
'int_prop' => 1234,
|
126
|
+
'decimal_prop' => 333.33,
|
127
|
+
'date_prop' => '2012-02-29',
|
128
|
+
'blob_prop' => '5aW0MPKMcdk=' }
|
129
|
+
|
130
|
+
values.each do |name, value|
|
131
|
+
put "/objects/PropertiesTest/#{@object.object_id}/properties/#{name}", { 'value' => value }.to_json
|
132
|
+
end
|
133
|
+
|
134
|
+
@object.string_prop.should eq 'A string'
|
135
|
+
@object.int_prop.should eq 1234
|
136
|
+
@object.decimal_prop.should eq 333.33
|
137
|
+
@object.date_prop.should eq Date.new(2012, 2, 29)
|
138
|
+
@object.blob_prop.should eq "\xE5\xA5\xB4\x30\xF2\x8C\x71\xD9"
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should process a property put with json' do
|
142
|
+
json = { 'value' => 'masterkey' }.to_json
|
143
|
+
|
144
|
+
expected = { 'name' =>
|
145
|
+
{ 'value' => 'masterkey',
|
146
|
+
'links' => [
|
147
|
+
{ 'rel' => 'self',
|
148
|
+
'href' => "http://localhost/objects/PropertiesTest/#{@object.object_id}/properties/name",
|
149
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-property"',
|
150
|
+
'method' => 'GET' },
|
151
|
+
{ 'rel' => 'up',
|
152
|
+
'href' => "http://localhost/objects/PropertiesTest/#{@object.object_id}",
|
153
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object"',
|
154
|
+
'method' => 'GET' },
|
155
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/modify;property="name"',
|
156
|
+
'href' => "http://localhost/objects/PropertiesTest/#{@object.object_id}/properties/name",
|
157
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-property"',
|
158
|
+
'method' => 'PUT',
|
159
|
+
'arguments' => { 'value' => nil } },
|
160
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/clear;property="name"',
|
161
|
+
'href' => "http://localhost/objects/PropertiesTest/#{@object.object_id}/properties/name",
|
162
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-property"',
|
163
|
+
'method' => 'DELETE' }
|
164
|
+
]
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
put "/objects/PropertiesTest/#{@object.object_id}/properties/name", json
|
169
|
+
|
170
|
+
last_response.body.should match_json_expression expected
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'should process a property delete' do
|
174
|
+
@object.name = 'irrelevant'
|
175
|
+
|
176
|
+
delete "/objects/PropertiesTest/#{@object.object_id}/properties/name"
|
177
|
+
|
178
|
+
@object.name.should be_nil
|
179
|
+
|
180
|
+
expected = { 'name' => { 'value' => nil } }
|
181
|
+
|
182
|
+
last_response.body.should match_json_expression expected
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'should generate metadata in extensions' do
|
186
|
+
expected = {
|
187
|
+
'prop_full_metadata' => {
|
188
|
+
'extensions' => {
|
189
|
+
'friendlyName' => 'Meta Prop',
|
190
|
+
'description' => 'To Test Metadata',
|
191
|
+
'returnType' => 'string',
|
192
|
+
'format' => 'string',
|
193
|
+
'optional' => false,
|
194
|
+
'maxLength' => 30,
|
195
|
+
'pattern' => '.*abc.*',
|
196
|
+
'memberOrder' => Fixnum
|
197
|
+
}.strict!
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
get "/objects/PropertiesTest/#{@object.object_id}/properties/prop_full_metadata"
|
202
|
+
|
203
|
+
last_response.body.should match_json_expression expected
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
@@ -0,0 +1,228 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require_relative '../spec_helper'
|
3
|
+
|
4
|
+
describe RestfulObjects::Object do
|
5
|
+
before :all do
|
6
|
+
RestfulObjects::DomainModel.current.reset
|
7
|
+
|
8
|
+
class Address
|
9
|
+
include RestfulObjects::Object
|
10
|
+
|
11
|
+
property :street, :string
|
12
|
+
property :number, :int
|
13
|
+
end
|
14
|
+
|
15
|
+
class ObjectTest
|
16
|
+
include RestfulObjects::Object
|
17
|
+
|
18
|
+
property :id, :int, read_only: true
|
19
|
+
property :password, :string, max_length: 10
|
20
|
+
|
21
|
+
action :hash_password, :string
|
22
|
+
|
23
|
+
collection :addresses, Address
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@id = 99
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
before(:each) do
|
33
|
+
@object = ObjectTest.new
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'module should add class macros functionality' do
|
37
|
+
@object.class.respond_to?(:property).should be_true
|
38
|
+
@object.class.respond_to?(:action).should be_true
|
39
|
+
@object.class.respond_to?(:collection).should be_true
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should add the type information to the model' do
|
43
|
+
model.types.include?('ObjectTest').should be_true
|
44
|
+
|
45
|
+
domain_type = model.types['ObjectTest']
|
46
|
+
|
47
|
+
domain_type.properties.include?('id').should be_true
|
48
|
+
domain_type.properties['id'].return_type.should eq(:int)
|
49
|
+
domain_type.properties['id'].read_only.should be_true
|
50
|
+
domain_type.properties['id'].max_length.should be_nil
|
51
|
+
|
52
|
+
domain_type.properties.include?('password').should be_true
|
53
|
+
domain_type.properties['password'].return_type.should eq(:string)
|
54
|
+
domain_type.properties['password'].read_only.should be_false
|
55
|
+
domain_type.properties['password'].max_length.should eq(10)
|
56
|
+
|
57
|
+
domain_type.actions.include?('hash_password').should be_true
|
58
|
+
domain_type.actions['hash_password'].parameters.count.should eq(0)
|
59
|
+
domain_type.actions['hash_password'].result_type.should eq(:string)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should generate json for the object' do
|
63
|
+
@object.password = 'secret_key'
|
64
|
+
address = Address.new
|
65
|
+
@object.addresses.push(address)
|
66
|
+
|
67
|
+
expected = {
|
68
|
+
'instanceId' => @object.object_id.to_s,
|
69
|
+
'title' => "ObjectTest (#{@object.object_id})",
|
70
|
+
'members' => {
|
71
|
+
'id' =>
|
72
|
+
{ 'memberType' => 'property',
|
73
|
+
'value' => 99,
|
74
|
+
'disabledReason' => 'read-only property',
|
75
|
+
'links' => [
|
76
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/details;property="id"',
|
77
|
+
'href' => "http://localhost/objects/ObjectTest/#{@object.object_id}/properties/id",
|
78
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-property"',
|
79
|
+
'method' => 'GET' }
|
80
|
+
],
|
81
|
+
'extensions' => { }
|
82
|
+
},
|
83
|
+
'password' => {
|
84
|
+
'memberType' => 'property',
|
85
|
+
'value' => 'secret_key',
|
86
|
+
'links' => [
|
87
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/details;property="password"',
|
88
|
+
'href' => "http://localhost/objects/ObjectTest/#{@object.object_id}/properties/password",
|
89
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-property"',
|
90
|
+
'method' => 'GET' }
|
91
|
+
],
|
92
|
+
'extensions' => { }
|
93
|
+
},
|
94
|
+
'addresses' => {
|
95
|
+
'memberType' => 'collection',
|
96
|
+
'size' => 1,
|
97
|
+
'links' => [
|
98
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/details;collection="addresses"',
|
99
|
+
'href' => "http://localhost/objects/ObjectTest/#{@object.object_id}/collections/addresses",
|
100
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-collection"',
|
101
|
+
'method' => 'GET' }
|
102
|
+
],
|
103
|
+
'extensions' => { }
|
104
|
+
},
|
105
|
+
'hash_password' => {
|
106
|
+
'memberType' => 'action',
|
107
|
+
'links' => [
|
108
|
+
{ 'rel' => 'urn:org.restfulobjects:rels/details;action="hash_password"',
|
109
|
+
'href' => "http://localhost/objects/ObjectTest/#{@object.object_id}/actions/hash_password",
|
110
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object-action"',
|
111
|
+
'method' => 'GET' }
|
112
|
+
],
|
113
|
+
'extensions' => { }
|
114
|
+
}
|
115
|
+
},
|
116
|
+
'links' => [
|
117
|
+
{ 'rel' => 'self',
|
118
|
+
'href' => "http://localhost/objects/ObjectTest/#{@object.object_id}",
|
119
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/object"',
|
120
|
+
'method' => 'GET' },
|
121
|
+
{ 'rel' => 'describedby',
|
122
|
+
'href' => "http://localhost/domain-types/ObjectTest",
|
123
|
+
'type' => 'application/json;profile="urn:org.restfulobjects:repr-types/domain-type"',
|
124
|
+
'method' => 'GET' }
|
125
|
+
],
|
126
|
+
'extensions' => wildcard_matcher
|
127
|
+
}
|
128
|
+
|
129
|
+
get "/objects/ObjectTest/#{@object.object_id}"
|
130
|
+
|
131
|
+
last_response.body.should match_json_expression expected
|
132
|
+
last_response.content_type.should eq 'application/json;profile="urn:org.restfulobjects:repr-types/object";x-ro-domain-type="ObjectTest"'
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should generate metadata in extensions' do
|
136
|
+
@object.rs_type.plural_name = 'Test Objects'
|
137
|
+
@object.rs_type.friendly_name = 'Test Object Friendly'
|
138
|
+
@object.rs_type.description = 'An object to test'
|
139
|
+
|
140
|
+
expected = {
|
141
|
+
'instanceId' => @object.object_id.to_s,
|
142
|
+
'extensions' => {
|
143
|
+
'domainType' => 'ObjectTest',
|
144
|
+
'pluralName' => 'Test Objects',
|
145
|
+
'friendlyName' => 'Test Object Friendly',
|
146
|
+
'description' => 'An object to test',
|
147
|
+
'isService' => false
|
148
|
+
}.strict!
|
149
|
+
}
|
150
|
+
|
151
|
+
get "/objects/ObjectTest/#{@object.object_id}"
|
152
|
+
|
153
|
+
last_response.body.should match_json_expression expected
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'should call initialize on object' do
|
157
|
+
class InitializedObject
|
158
|
+
include RestfulObjects::Object
|
159
|
+
attr_reader :init_called
|
160
|
+
def initialize
|
161
|
+
super
|
162
|
+
@init_called = true
|
163
|
+
@title = 'A title'
|
164
|
+
end
|
165
|
+
end
|
166
|
+
obj = InitializedObject.new
|
167
|
+
obj.init_called.should be_true
|
168
|
+
obj.title.should eq 'A title'
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should send on_after_create callback when object is created' do
|
172
|
+
class CreatedObject
|
173
|
+
include RestfulObjects::Object
|
174
|
+
attr_reader :called
|
175
|
+
def on_after_create
|
176
|
+
@called = true
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
CreatedObject.new.called.should be_true
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'should send on_after_update callback when object property is updated or deleted' do
|
184
|
+
class UpdatableObject
|
185
|
+
include RestfulObjects::Object
|
186
|
+
attr_accessor :prop_updated
|
187
|
+
property :data, :string
|
188
|
+
def on_after_update
|
189
|
+
@prop_updated = true
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
obj = UpdatableObject.new
|
194
|
+
|
195
|
+
obj.prop_updated.should_not be_true
|
196
|
+
|
197
|
+
put "/objects/UpdatableObject/#{obj.object_id}/properties/data", {}, { input: { 'value' => 'irrelevant' }.to_json }
|
198
|
+
|
199
|
+
obj.prop_updated.should be_true
|
200
|
+
|
201
|
+
obj.prop_updated = false
|
202
|
+
|
203
|
+
delete "/objects/UpdatableObject/#{obj.object_id}/properties/data"
|
204
|
+
|
205
|
+
obj.prop_updated.should be_true
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'should send on_after_delete callback when object is deleted' do
|
209
|
+
class DeletedObject
|
210
|
+
include RestfulObjects::Object
|
211
|
+
attr_reader :destroyed
|
212
|
+
def on_after_delete
|
213
|
+
@destroyed = true
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
obj = DeletedObject.new
|
218
|
+
|
219
|
+
obj.deleted?.should_not be_true
|
220
|
+
obj.destroyed.should_not be_true
|
221
|
+
|
222
|
+
delete "/objects/DeletedObject/#{obj.object_id}"
|
223
|
+
|
224
|
+
obj.deleted?.should be_true
|
225
|
+
obj.destroyed.should be_true
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|