raml_ruby 0.1.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.
Files changed (88) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +71 -0
  7. data/Rakefile +1 -0
  8. data/fixtures/include_1.raml +7 -0
  9. data/fixtures/schemas/canonicalSchemas.raml +3 -0
  10. data/fixtures/schemas/filesystem/file.json +1 -0
  11. data/fixtures/schemas/filesystem/files.json +1 -0
  12. data/fixtures/schemas/filesystem/fileupdate.json +1 -0
  13. data/fixtures/schemas/filesystem/relative/test.json +1 -0
  14. data/lib/raml.rb +104 -0
  15. data/lib/raml/exceptions.rb +27 -0
  16. data/lib/raml/mixin/bodies.rb +32 -0
  17. data/lib/raml/mixin/documentable.rb +32 -0
  18. data/lib/raml/mixin/global.rb +20 -0
  19. data/lib/raml/mixin/headers.rb +22 -0
  20. data/lib/raml/mixin/merge.rb +24 -0
  21. data/lib/raml/mixin/parent.rb +54 -0
  22. data/lib/raml/mixin/validation.rb +49 -0
  23. data/lib/raml/node.rb +219 -0
  24. data/lib/raml/node/abstract_method.rb +61 -0
  25. data/lib/raml/node/abstract_resource.rb +165 -0
  26. data/lib/raml/node/abstract_resource_circular.rb +5 -0
  27. data/lib/raml/node/body.rb +94 -0
  28. data/lib/raml/node/documentation.rb +28 -0
  29. data/lib/raml/node/header.rb +4 -0
  30. data/lib/raml/node/method.rb +106 -0
  31. data/lib/raml/node/parameter/abstract_parameter.rb +251 -0
  32. data/lib/raml/node/parameter/base_uri_parameter.rb +6 -0
  33. data/lib/raml/node/parameter/form_parameter.rb +6 -0
  34. data/lib/raml/node/parameter/query_parameter.rb +6 -0
  35. data/lib/raml/node/parameter/uri_parameter.rb +7 -0
  36. data/lib/raml/node/parametized_reference.rb +15 -0
  37. data/lib/raml/node/reference.rb +4 -0
  38. data/lib/raml/node/resource.rb +26 -0
  39. data/lib/raml/node/resource_type.rb +20 -0
  40. data/lib/raml/node/resource_type_reference.rb +5 -0
  41. data/lib/raml/node/response.rb +32 -0
  42. data/lib/raml/node/root.rb +246 -0
  43. data/lib/raml/node/schema.rb +41 -0
  44. data/lib/raml/node/schema_reference.rb +5 -0
  45. data/lib/raml/node/template.rb +55 -0
  46. data/lib/raml/node/trait.rb +18 -0
  47. data/lib/raml/node/trait_reference.rb +5 -0
  48. data/lib/raml/parser.rb +57 -0
  49. data/lib/raml/parser/include.rb +25 -0
  50. data/lib/raml/patch/hash.rb +6 -0
  51. data/lib/raml/patch/module.rb +12 -0
  52. data/lib/raml/version.rb +3 -0
  53. data/raml_ruby.gemspec +35 -0
  54. data/raml_spec_reqs.md +276 -0
  55. data/templates/abstract_parameter.slim +68 -0
  56. data/templates/body.slim +15 -0
  57. data/templates/collapse.slim +10 -0
  58. data/templates/documentation.slim +2 -0
  59. data/templates/method.slim +38 -0
  60. data/templates/resource.slim +33 -0
  61. data/templates/response.slim +13 -0
  62. data/templates/root.slim +39 -0
  63. data/templates/style.sass +119 -0
  64. data/test/apis/box-api.raml +4224 -0
  65. data/test/apis/instagram-api.raml +3378 -0
  66. data/test/apis/stripe-api.raml +12227 -0
  67. data/test/apis/twilio-rest-api.raml +6618 -0
  68. data/test/apis/twitter-rest-api.raml +34284 -0
  69. data/test/raml/body_spec.rb +268 -0
  70. data/test/raml/documentation_spec.rb +49 -0
  71. data/test/raml/header_spec.rb +17 -0
  72. data/test/raml/include_spec.rb +40 -0
  73. data/test/raml/method_spec.rb +701 -0
  74. data/test/raml/parameter/abstract_parameter_spec.rb +564 -0
  75. data/test/raml/parameter/form_parameter_spec.rb +17 -0
  76. data/test/raml/parameter/query_parameter_spec.rb +33 -0
  77. data/test/raml/parameter/uri_parameter_spec.rb +44 -0
  78. data/test/raml/parser_spec.rb +53 -0
  79. data/test/raml/raml_spec.rb +32 -0
  80. data/test/raml/resource_spec.rb +440 -0
  81. data/test/raml/resource_type_spec.rb +51 -0
  82. data/test/raml/response_spec.rb +251 -0
  83. data/test/raml/root_spec.rb +655 -0
  84. data/test/raml/schema_spec.rb +110 -0
  85. data/test/raml/spec_helper.rb +11 -0
  86. data/test/raml/template_spec.rb +98 -0
  87. data/test/raml/trait_spec.rb +31 -0
  88. metadata +337 -0
@@ -0,0 +1,17 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Raml::Parameter::FormParameter do
4
+ let(:root_data) { {'title' => 'x', 'baseUri' => 'http://foo.com'} }
5
+ let(:root) { Raml::Root.new root_data }
6
+ let(:name) { 'AWSAccessKeyId' }
7
+ let (:data) {
8
+ YAML.load(%q(
9
+ description: The AWS Access Key ID of the owner of the bucket who grants ...
10
+ type: string
11
+ ))
12
+ }
13
+
14
+ it "should instanciate Form parameter" do
15
+ Raml::Parameter::FormParameter.new(name, data, root)
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Raml::Parameter::QueryParameter do
4
+ let(:root_data) { {'title' => 'x', 'baseUri' => 'http://foo.com'} }
5
+ let(:root) { Raml::Root.new root_data }
6
+ let(:name) { 'page' }
7
+ let(:data) {
8
+ YAML.load(%q(
9
+ type: integer
10
+ ))
11
+ }
12
+
13
+ subject { Raml::Parameter::QueryParameter.new(name, data, root) }
14
+
15
+ it "should instanciate Query parameter" do
16
+ Raml::Parameter::QueryParameter.new(name, data, root)
17
+ end
18
+
19
+ describe "#document" do
20
+ let(:data) {
21
+ YAML.load(%q(
22
+ description: Specify the page that you want to retrieve
23
+ type: integer
24
+ required: true
25
+ example: 1
26
+ ))
27
+ }
28
+
29
+ it "prints out documentation" do
30
+ subject.document
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,44 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Raml::Parameter::UriParameter do
4
+ let(:root_data) { {'title' => 'x', 'baseUri' => 'http://foo.com'} }
5
+ let(:root) { Raml::Root.new root_data }
6
+ let(:name) { 'AccountSid' }
7
+ let(:data) {
8
+ YAML.load(%q(
9
+ description: |
10
+ An Account instance resource represents a single Twilio account.
11
+ type: string
12
+ ))
13
+ }
14
+
15
+ subject { Raml::Parameter::UriParameter.new(name, data, root) }
16
+
17
+ describe '#new' do
18
+ it "should instanciate Uri parameter" do
19
+ Raml::Parameter::UriParameter.new(name, data, root)
20
+ end
21
+
22
+ context 'when no required attribute is given' do
23
+ let(:data) { { } }
24
+ it 'defaults to true' do
25
+ subject.required.should == true
26
+ end
27
+ end
28
+ end
29
+
30
+ describe "#document" do
31
+ let(:data) {
32
+ YAML.load(%q(
33
+ description: Specify the page that you want to retrieve
34
+ type: integer
35
+ required: true
36
+ example: 1
37
+ ))
38
+ }
39
+
40
+ it "prints out documentation" do
41
+ subject.document
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,53 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Raml::Parser do
4
+ let (:data) {
5
+ %q(
6
+ #%RAML 0.8
7
+ baseUri: https://api.example.com
8
+ title: Filesystem API
9
+ version: 0.1
10
+ /files:
11
+ get:
12
+ responses:
13
+ 200:
14
+ body:
15
+ application/xml:
16
+ schema: Files
17
+ )
18
+ }
19
+
20
+ describe '.parse' do
21
+ it "should parse the data" do
22
+ root = Raml::Parser.parse(data)
23
+ root.should be_a Raml::Root
24
+ root.title.should eq 'Filesystem API'
25
+ end
26
+
27
+ context 'when the RAML file has !include directives' do
28
+ it 'inserts the data into the right location and parses RAML included files' do
29
+ file = File.new 'fixtures/include_1.raml'
30
+ root = Raml::Parser.parse file.read, 'fixtures'
31
+ root.schemas.should be_a Hash
32
+ root.schemas.size.should be 4
33
+ root.schemas.keys.should contain_exactly('FileUpdate', 'Files', 'Test', 'File')
34
+ root.schemas['FileUpdate'].value.should eq 'file_update_schema'
35
+ root.schemas['Files' ].value.should eq 'files_schema'
36
+ root.schemas['Test' ].value.should eq 'test_schema'
37
+ root.schemas['File' ].value.should eq 'file_schema'
38
+ end
39
+
40
+ context 'when the included file is not redable' do
41
+ it do
42
+ expect { Raml::Parser.parse('- !include does_not_exit') }.to raise_error Raml::CantIncludeFile
43
+ end
44
+ end
45
+
46
+ context 'when the !include directive is not given a file path' do
47
+ it do
48
+ expect { Raml::Parser.parse('- !include') }.to raise_error Raml::CantIncludeFile
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,32 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Raml do
4
+ describe '#parse_file' do
5
+ let(:rest_of_doc) { "title: Some API\nbaseUri: https://app.zencoder.com/api" }
6
+ before do
7
+ stub(File).new('file.raml').stub! do |stub|
8
+ stub.readline { comment }
9
+ stub.read { rest_of_doc }
10
+ end
11
+ end
12
+ context 'when given a valid RAML 0.8 file with a valid version comment' do
13
+ let(:comment ) { '#%RAML 0.8' }
14
+ it do
15
+ expect { Raml.parse_file 'file.raml' }.to_not raise_error
16
+ end
17
+ end
18
+ context 'when given a valid RAML 0.8 file with an invalid version comment' do
19
+ let(:comment ) { '#%RAML 0.7' }
20
+ it do
21
+ expect { Raml.parse_file 'file.raml' }.to raise_error Raml::UnsupportedRamlVersion
22
+ end
23
+ end
24
+ context 'when given a valid RAML 0.8 file with no version comment' do
25
+ let(:comment ) { 'title: Some API' }
26
+ let(:rest_of_doc) { 'version: v2' }
27
+ it do
28
+ expect { Raml.parse_file 'file.raml' }.to raise_error Raml::UnsupportedRamlVersion
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,440 @@
1
+ # encoding: UTF-8
2
+ require_relative 'spec_helper'
3
+
4
+ describe Raml::Resource do
5
+ let(:name) { '/{id}' }
6
+ let(:data) {
7
+ YAML.load(%q(
8
+ uriParameters:
9
+ id:
10
+ type: integer
11
+ required: true
12
+ example: 277102
13
+ /processing_status:
14
+ get:
15
+ displayName: Processing status
16
+ description: Получить статус загрузки
17
+ responses:
18
+ 200:
19
+ body:
20
+ application/json:
21
+ example: |
22
+ {
23
+ "percent": 0,
24
+ "type": "download",
25
+ "status":"initial"
26
+ }
27
+ ))
28
+ }
29
+ let(:root_data) { {'title' => 'x', 'baseUri' => 'http://foo.com'} }
30
+ let(:root) { Raml::Root.new root_data }
31
+
32
+ subject { Raml::Resource.new(name, data, root) }
33
+
34
+ describe '#new' do
35
+ it "should instanciate Resource" do
36
+ subject
37
+ end
38
+
39
+ context 'when displayName is given' do
40
+ let(:data) { { 'displayName' => 'My Name', 'description' => 'foo' } }
41
+ it { expect { subject }.to_not raise_error }
42
+ it 'should store the value' do
43
+ subject.display_name.should eq data['displayName']
44
+ end
45
+ it 'uses the displayName in the documentation' do
46
+ subject.document.should include data['displayName']
47
+ end
48
+ end
49
+
50
+ context 'when description is not given' do
51
+ let(:data) { {} }
52
+ it { expect { subject }.to_not raise_error }
53
+ end
54
+ context 'when description is given' do
55
+ context 'when the description property is not a string' do
56
+ let(:data) { { 'description' => 1 } }
57
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /description/ }
58
+ end
59
+ context 'when the description property is a string' do
60
+ let(:data) { { 'description' => 'My Description'} }
61
+ it { expect { subject }.to_not raise_error }
62
+ it 'should store the value' do
63
+ subject.description.should eq data['description']
64
+ end
65
+ it 'uses the description in the documentation' do
66
+ subject.document.should include data['description']
67
+ end
68
+ end
69
+ end
70
+
71
+ context 'when the uriParameters parameter is given with valid parameters' do
72
+ context 'when the uriParameters property is well formed' do
73
+ it { expect { subject }.to_not raise_error }
74
+ it 'stores all as Raml::Parameter::UriParameter instances' do
75
+ expect( subject.uri_parameters.values ).to all( be_a Raml::Parameter::UriParameter )
76
+ end
77
+ end
78
+ context 'when the uriParameters property is not a map' do
79
+ let(:data) { { 'uriParameters' => 1 } }
80
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /uriParameters/ }
81
+ end
82
+ context 'when the uriParameters property is not a map with non-string keys' do
83
+ let(:data) { { 'uriParameters' => { 1 => {}} } }
84
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /uriParameters/ }
85
+ end
86
+ context 'when the uriParameters property is not a map with non-string keys' do
87
+ let(:data) { { 'uriParameters' => { '1' => 'x'} } }
88
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /uriParameters/ }
89
+ end
90
+ end
91
+
92
+ context 'when nested resources are defined' do
93
+ let(:name) { '/{userId}' }
94
+ let(:data) {
95
+ YAML.load(
96
+ %q(
97
+ uriParameters:
98
+ userId:
99
+ type: integer
100
+ /followers:
101
+ displayName: Followers
102
+ /following:
103
+ displayName: Following
104
+ /keys:
105
+ /{keyId}:
106
+ uriParameters:
107
+ keyId:
108
+ type: integer
109
+ )
110
+ )
111
+ }
112
+ it { expect { subject }.to_not raise_error }
113
+ it 'stores all as Raml::Resource instances' do
114
+ expect( subject.resources.values ).to all( be_a Raml::Resource )
115
+ expect( subject.resources.keys ).to contain_exactly('/followers','/following', '/keys')
116
+ end
117
+ end
118
+
119
+ context 'when a baseUriParameters property is given' do
120
+ context 'when the baseUriParameters property is well formed' do
121
+ let(:name) { '/files' }
122
+ let(:data) {
123
+ YAML.load(
124
+ %q(
125
+ displayName: Download files
126
+ baseUriParameters:
127
+ apiDomain:
128
+ enum: [ "api-content" ]
129
+ )
130
+ )
131
+ }
132
+
133
+ it { expect { subject }.to_not raise_error }
134
+ it 'stores all as Raml::Parameter::UriParameter instances' do
135
+ expect( subject.base_uri_parameters.values ).to all( be_a Raml::Parameter::BaseUriParameter )
136
+ subject.base_uri_parameters.keys.should contain_exactly('apiDomain')
137
+ end
138
+ end
139
+ context 'when the baseUriParameters property is not a map' do
140
+ before { data['baseUriParameters'] = 1 }
141
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /baseUriParameters/ }
142
+ end
143
+ context 'when the baseUriParameters property is not a map with non-string keys' do
144
+ before { data['baseUriParameters'] = { 1 => {}} }
145
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /baseUriParameters/ }
146
+ end
147
+ context 'when the baseUriParameters property is not a map with non-string keys' do
148
+ before { data['baseUriParameters'] = { '1' => 'x'} }
149
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /baseUriParameters/ }
150
+ end
151
+ context 'when the baseUriParameters property has a key for the reserved "version" parameter' do
152
+ before { data['baseUriParameters'] = { 'version' => {}} }
153
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /baseUriParameters/ }
154
+ end
155
+ end
156
+
157
+ context 'when an type property is given' do
158
+ let(:root) {
159
+ Raml::Root.new 'title' => 'x', 'baseUri' => 'http://foo.com', 'resourceTypes' => [
160
+ { 'collection' => {} },
161
+ { 'member' => {} },
162
+ { 'auditableResource' => {} }
163
+ ]
164
+ }
165
+ context 'when the property is valid' do
166
+ context 'when the property is a resource type reference' do
167
+ before { data['type'] = 'collection' }
168
+ it { expect { subject }.to_not raise_error }
169
+ it 'should store the resource type reference' do
170
+ subject.type.should be_a Raml::ResourceTypeReference
171
+ subject.type.name.should == 'collection'
172
+ end
173
+ end
174
+ context 'when the property is a resource type reference with parameters' do
175
+ before { data['type'] = {'collection' => {'maxSize' => 10}} }
176
+ it { expect { subject }.to_not raise_error }
177
+ it 'should store the resource type reference' do
178
+ subject.type.should be_a Raml::ResourceTypeReference
179
+ subject.type.name.should == 'collection'
180
+ end
181
+ end
182
+ context 'when the property is a resource type definitions' do
183
+ let(:definition) {
184
+ YAML.load(%q(
185
+ usage: This resourceType should be used for any collection of items
186
+ description: The collection of <<resourcePathName>>
187
+ get:
188
+ description: Get all <<resourcePathName>>, optionally filtered
189
+ ))
190
+ }
191
+ before { data['type'] = definition }
192
+
193
+ it { expect { subject }.to_not raise_error }
194
+ it 'should store the resource type' do
195
+ subject.type.should be_a Raml::ResourceType
196
+ subject.send(:instantiate_resource_type).usage.should == definition['usage']
197
+ end
198
+ end
199
+ end
200
+ context 'when the property is invalid' do
201
+ context 'when the type property is not a string or a map' do
202
+ before { data['type'] = 1 }
203
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /type/ }
204
+ end
205
+ context 'when the property is a resource type name with parameters, but the params are not a map' do
206
+ before { data['type'] = { 'collection' => 1 } }
207
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /type/ }
208
+ end
209
+ end
210
+ end
211
+
212
+ context 'when an is property is given' do
213
+ let(:root) {
214
+ Raml::Root.new 'title' => 'x', 'baseUri' => 'http://foo.com', 'traits' => [
215
+ { 'secured' => {} },
216
+ { 'paged' => {} },
217
+ { 'rateLimited' => {} }
218
+ ]
219
+ }
220
+ context 'when the property is valid' do
221
+ context 'when the property is an array of trait references' do
222
+ let(:data) { { 'is' => [ 'secured', 'paged' ] } }
223
+ it { expect { subject }.to_not raise_error }
224
+ it 'should store the trait references' do
225
+ subject.traits.should all( be_a Raml::TraitReference )
226
+ subject.traits.map(&:name).should contain_exactly('secured', 'paged')
227
+ end
228
+ end
229
+ context 'when the property is an array of trait references with parameters' do
230
+ let(:data) { {
231
+ 'is' => [
232
+ {'secured' => {'tokenName' => 'access_token'}},
233
+ {'paged' => {'maxPages' => 10 }}
234
+ ]
235
+ } }
236
+ it { expect { subject }.to_not raise_error }
237
+ it 'should store the trait references' do
238
+ subject.traits.should all( be_a Raml::TraitReference )
239
+ subject.traits.map(&:name).should contain_exactly('secured', 'paged')
240
+ end
241
+ end
242
+ context 'when the property is an array of trait definitions' do
243
+ let(:data) { {
244
+ 'is' => [
245
+ {'queryParameters' => {'tokenName' => {'description'=>'foo'}}},
246
+ {'queryParameters' => {'numPages' => {'description'=>'bar'}}}
247
+ ]
248
+ } }
249
+ it { expect { subject }.to_not raise_error }
250
+ it 'should store the traits' do
251
+ subject.traits.should all( be_a Raml::Trait )
252
+ subject.traits[0].value.should eq ({'queryParameters' => {'tokenName' => {'description'=>'foo'}}})
253
+ subject.traits[1].value.should eq ({'queryParameters' => {'numPages' => {'description'=>'bar'}}})
254
+ end
255
+ end
256
+ context 'when the property is an array of mixed trait refrences, trait refrences with parameters, and trait definitions' do
257
+ let(:data) { {
258
+ 'is' => [
259
+ {'secured' => {'tokenName' => 'access_token'}},
260
+ {'queryParameters' => {'numPages' => {'description'=>'bar'}}},
261
+ 'rateLimited'
262
+ ]
263
+ } }
264
+ it { expect { subject }.to_not raise_error }
265
+ it 'should store the traits' do
266
+ subject.traits.select {|t| t.is_a? Raml::TraitReference }.map(&:name).should contain_exactly('secured', 'rateLimited')
267
+ subject.traits.select {|t| t.is_a? Raml::Trait }[0].value.should eq ({'queryParameters' => {'numPages' => {'description'=>'bar'}}})
268
+ end
269
+ end
270
+ end
271
+ context 'when the property is invalid' do
272
+ context 'when the property is not an array' do
273
+ let(:data) { { 'is' => 1 } }
274
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /is/ }
275
+ end
276
+ context 'when the property is an array with elements other than a string or map' do
277
+ let(:data) { { 'is' => [1] } }
278
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /is/ }
279
+ end
280
+ context 'when the property is an array an element that appears to be a trait name with parameters, but the params are not a map' do
281
+ let(:data) { { 'is' => [ { 'secured' => 1 } ] } }
282
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /is/ }
283
+ end
284
+ end
285
+ end
286
+
287
+ context 'when the syntax tree contains optional properties' do
288
+ let(:data) {
289
+ YAML.load(%q(
290
+ uriParameters:
291
+ id:
292
+ type: integer
293
+ required: true
294
+ example: 277102
295
+ /processing_status:
296
+ get:
297
+ displayName: Processing status
298
+ description: Получить статус загрузки
299
+ responses:
300
+ 200?:
301
+ body:
302
+ application/json:
303
+ example: |
304
+ {
305
+ "percent": 0,
306
+ "type": "download",
307
+ "status":"initial"
308
+ }
309
+ ))
310
+ }
311
+ it { expect { subject }.to raise_error Raml::InvalidProperty, /Optional properties/ }
312
+ end
313
+ end
314
+
315
+ describe '#apply_resource_type' do
316
+ let(:resource_data) { {
317
+ 'type' => {
318
+ 'get' => { 'description' => 'resource type description', 'displayName' => 'resource type displayName' }
319
+ },
320
+ 'get' => {'description' => 'method description'},
321
+ 'post' => {},
322
+ '/foo' => {},
323
+ '/bar' => {}
324
+ } }
325
+ let(:resource) { Raml::Resource.new('/foo', resource_data, root) }
326
+ context 'when it has a resource type' do
327
+ it 'merges the resource type to the resource' do
328
+ resource.type.should be_a Raml::ResourceType
329
+ mock.proxy(resource).instantiate_resource_type { |instantiated_type|
330
+ mock(resource).merge(instantiated_type)
331
+ mock(resource).merge(is_a(Raml::Resource))
332
+ instantiated_type
333
+ }
334
+ resource.apply_resource_type
335
+ end
336
+ it 'applies the resource type correctly' do
337
+ resource.apply_resource_type
338
+ resource.methods['get'].description.should eq 'method description'
339
+ resource.methods['get'].display_name.should eq 'resource type displayName'
340
+ end
341
+ end
342
+ context 'when it has nested resources' do
343
+ it 'calls #apply_resource_type on the nested resources' do
344
+ resource.resources.size.should eq 2
345
+ resource.resources.values.each { |resource| mock(resource).apply_resource_type {} }
346
+ resource.apply_resource_type
347
+ end
348
+ end
349
+ end
350
+
351
+ describe '#apply_traits' do
352
+ let(:resource_data) { {
353
+ 'is' => [
354
+ { 'description' => 'trait1 description' },
355
+ { 'description' => 'trait2 description' }
356
+ ],
357
+ 'get' => {},
358
+ 'post' => {},
359
+ '/foo' => {},
360
+ '/bar' => {}
361
+ } }
362
+ let(:resource) { Raml::Resource.new('/foo', resource_data, root) }
363
+ it 'calls apply_traits on all its methods' do
364
+ resource.traits.size.should eq 2
365
+ resource.methods.size.should eq 2
366
+ resource.methods.values.each { |method| mock(method).apply_traits {} }
367
+ resource.apply_traits
368
+ end
369
+ it 'should call apply_trait on child resources without the resource traits' do
370
+ resource.traits.size.should eq 2
371
+ resource.resources.size.should eq 2
372
+ resource.resources.values.each { |resource| mock(resource).apply_traits {} }
373
+ resource.apply_traits
374
+ end
375
+ end
376
+
377
+ describe '#merge' do
378
+ let(:resource) { Raml::Resource.new('/foo', resource_data, root) }
379
+ context 'when called with something other than a ResourceType' do
380
+ let(:resource_data) { {} }
381
+ it do
382
+ expect { resource.merge(Raml::ResourceTypeReference.new('bar', root)) }.to raise_error Raml::MergeError
383
+ end
384
+ end
385
+ context 'when called with a ResourceType::Instance' do
386
+ let(:root_data) { {
387
+ 'title' => 'x',
388
+ 'baseUri' => 'http://foo.com',
389
+ 'traits' => [ {
390
+ 'secured' => { 'usage' => 'requires authentication' },
391
+ 'paged' => { 'usage' => 'allows for paging' }
392
+ } ]
393
+ } }
394
+ let(:resource_type) { Raml::ResourceType.new('bar', resource_type_data, root).instantiate({}) }
395
+ let(:resource_data) { {
396
+ 'is' => [ 'secured' ],
397
+ 'baseUriParameters' => { 'apiDomain' => { 'enum' => ['api'] } },
398
+ 'uriParameters' => { 'userId' => { 'type' => 'integer' } },
399
+ 'get' => {
400
+ 'queryParameters' => { 'id' => { 'type' => 'integer' } }
401
+ }
402
+ } }
403
+ let(:resource_type_data) { {
404
+ 'usage' => 'resource usage',
405
+ 'is' => [ 'paged' ],
406
+ 'baseUriParameters' => { 'apiDomain' => { 'enum' => ['static'] } },
407
+ 'uriParameters' => { 'language' => { 'default' => 'en' } },
408
+ 'get' => {
409
+ 'queryParameters' => { 'query' => { 'maxLength' => 100 } }
410
+ },
411
+ 'post' => {
412
+ 'description' => 'create a new one'
413
+ }
414
+ } }
415
+ it 'merges the resource type into the resource' do
416
+ resource.merge resource_type
417
+ resource.traits.map { |trait_ref| trait_ref.name }.should eq [ 'paged', 'secured' ]
418
+ resource.base_uri_parameters.keys.should contain_exactly('apiDomain')
419
+ resource.base_uri_parameters['apiDomain'].enum.should eq ['static']
420
+ resource.uri_parameters.keys.should contain_exactly('userId', 'language')
421
+ resource.methods.keys.should contain_exactly('get', 'post')
422
+ resource.methods['get'].query_parameters.keys.should contain_exactly('id', 'query')
423
+ end
424
+ it 'does not add the usage property to the resource' do
425
+ resource.merge resource_type
426
+ expect { resource.usage }.to raise_error NoMethodError
427
+ end
428
+ end
429
+ end
430
+
431
+ describe '#document' do
432
+ it 'returns a String' do
433
+ subject.document.should be_a String
434
+ end
435
+ it 'should render the template' do
436
+ mock(Slim::Template).new(/templates\/resource.slim\z/, is_a(Hash)).mock!.render(is_a(Raml::Node)) { '' }
437
+ subject.document
438
+ end
439
+ end
440
+ end