restful_objects 0.0.2 → 0.0.3
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/README.md +3 -2
- data/bin/restful_server.rb +0 -0
- data/lib/restful_objects/action_description.rb +96 -82
- data/lib/restful_objects/action_list.rb +17 -17
- data/lib/restful_objects/collection_description.rb +47 -47
- data/lib/restful_objects/collection_list.rb +17 -17
- data/lib/restful_objects/domain_model.rb +83 -79
- data/lib/restful_objects/http_response.rb +11 -11
- data/lib/restful_objects/link_generator.rb +104 -104
- data/lib/restful_objects/object.rb +20 -20
- data/lib/restful_objects/object_actions.rb +134 -134
- data/lib/restful_objects/object_base.rb +10 -0
- data/lib/restful_objects/object_collections.rb +84 -84
- data/lib/restful_objects/object_list.rb +16 -16
- data/lib/restful_objects/object_macros.rb +35 -35
- data/lib/restful_objects/object_properties.rb +78 -78
- data/lib/restful_objects/parameter_description.rb +60 -60
- data/lib/restful_objects/parameter_description_list.rb +15 -15
- data/lib/restful_objects/property_description.rb +68 -68
- data/lib/restful_objects/property_list.rb +17 -17
- data/lib/restful_objects/service.rb +21 -21
- data/lib/restful_objects/service_list.rb +55 -55
- data/lib/restful_objects/type.rb +110 -110
- data/lib/restful_objects/type_list.rb +30 -30
- data/lib/restful_objects/user.rb +30 -30
- data/lib/restful_objects/version.rb +1 -1
- data/spec/integration/domain-types_actions_spec.rb +43 -43
- data/spec/integration/domain-types_collections_spec.rb +45 -45
- data/spec/integration/domain-types_properties_spec.rb +41 -41
- data/spec/integration/server-root_spec.rb +98 -98
- data/spec/spec_helper.rb +52 -52
- data/spec/unit/object_actions_spec.rb +380 -380
- data/spec/unit/object_collections_spec.rb +190 -190
- data/spec/unit/object_properties_spec.rb +215 -206
- data/spec/unit/object_spec.rb +228 -228
- data/spec/unit/service_spec.rb +125 -125
- data/spec/unit/type_list_spec.rb +37 -37
- metadata +2 -2
data/spec/unit/object_spec.rb
CHANGED
@@ -1,228 +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
|
38
|
-
@object.class.respond_to?(:action).should
|
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
|
-
|
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, return_type: :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
|
+
|