grape-swagger 0.20.3 → 0.21.0

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +10 -10
  3. data/.travis.yml +8 -3
  4. data/CHANGELOG.md +27 -0
  5. data/Gemfile +2 -0
  6. data/README.md +111 -12
  7. data/UPGRADING.md +9 -0
  8. data/grape-swagger.gemspec +1 -3
  9. data/lib/grape-swagger.rb +8 -1
  10. data/lib/grape-swagger/doc_methods/optional_object.rb +14 -2
  11. data/lib/grape-swagger/doc_methods/parse_params.rb +3 -4
  12. data/lib/grape-swagger/doc_methods/path_string.rb +4 -3
  13. data/lib/grape-swagger/endpoint.rb +25 -55
  14. data/lib/grape-swagger/errors.rb +3 -0
  15. data/lib/grape-swagger/grape/route.rb +2 -1
  16. data/lib/grape-swagger/model_parsers.rb +33 -0
  17. data/lib/grape-swagger/version.rb +1 -1
  18. data/spec/issues/403_versions_spec.rb +20 -4
  19. data/spec/lib/model_parsers_spec.rb +102 -0
  20. data/spec/lib/optional_object_spec.rb +15 -11
  21. data/spec/lib/path_string_spec.rb +72 -18
  22. data/spec/lib/produces_consumes_spec.rb +10 -5
  23. data/spec/spec_helper.rb +4 -2
  24. data/spec/support/empty_model_parser.rb +20 -0
  25. data/spec/support/mock_parser.rb +22 -0
  26. data/spec/support/model_parsers/entity_parser.rb +325 -0
  27. data/spec/support/{api_swagger_v2_result.rb → model_parsers/mock_parser.rb} +186 -60
  28. data/spec/support/model_parsers/representable_parser.rb +394 -0
  29. data/spec/support/the_paths_definitions.rb +7 -3
  30. data/spec/swagger_v2/api_swagger_v2_definitions-models_spec.rb +5 -4
  31. data/spec/swagger_v2/api_swagger_v2_detail_spec.rb +3 -3
  32. data/spec/swagger_v2/api_swagger_v2_extensions_spec.rb +1 -1
  33. data/spec/swagger_v2/api_swagger_v2_format-content_type_spec.rb +1 -1
  34. data/spec/swagger_v2/api_swagger_v2_headers_spec.rb +5 -3
  35. data/spec/swagger_v2/api_swagger_v2_hide_documentation_path_spec.rb +1 -1
  36. data/spec/swagger_v2/api_swagger_v2_mounted_spec.rb +1 -1
  37. data/spec/swagger_v2/api_swagger_v2_param_type_body_nested_spec.rb +25 -14
  38. data/spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb +22 -12
  39. data/spec/swagger_v2/api_swagger_v2_param_type_spec.rb +30 -18
  40. data/spec/swagger_v2/api_swagger_v2_request_params_fix_spec.rb +6 -3
  41. data/spec/swagger_v2/api_swagger_v2_response_spec.rb +13 -40
  42. data/spec/swagger_v2/api_swagger_v2_spec.rb +4 -2
  43. data/spec/swagger_v2/api_swagger_v2_type-format_spec.rb +6 -36
  44. data/spec/swagger_v2/default_api_spec.rb +10 -2
  45. data/spec/swagger_v2/endpoint_versioned_path_spec.rb +30 -0
  46. data/spec/swagger_v2/errors_spec.rb +75 -0
  47. data/spec/swagger_v2/hide_api_spec.rb +22 -4
  48. data/spec/swagger_v2/mounted_target_class_spec.rb +6 -2
  49. data/spec/swagger_v2/namespace_tags_prefix_spec.rb +6 -3
  50. data/spec/swagger_v2/namespace_tags_spec.rb +6 -3
  51. data/spec/swagger_v2/params_array_spec.rb +4 -2
  52. data/spec/swagger_v2/params_hash_spec.rb +4 -2
  53. data/spec/swagger_v2/params_nested_spec.rb +4 -2
  54. data/spec/swagger_v2/simple_mounted_api_spec.rb +66 -24
  55. metadata +23 -40
  56. data/spec/support/the_api_entities.rb +0 -50
  57. data/spec/swagger_v2/response_model_spec.rb +0 -208
@@ -24,8 +24,8 @@ module Grape
24
24
  swagger: '2.0',
25
25
  produces: content_types_for(target_class),
26
26
  authorizations: options[:authorizations],
27
- host: GrapeSwagger::DocMethods::OptionalObject.build(:host, options, request.host_with_port),
28
- basePath: GrapeSwagger::DocMethods::OptionalObject.build(:base_path, options, request.env['SCRIPT_NAME']),
27
+ host: GrapeSwagger::DocMethods::OptionalObject.build(:host, options, request),
28
+ basePath: GrapeSwagger::DocMethods::OptionalObject.build(:base_path, options, request),
29
29
  tags: GrapeSwagger::DocMethods::TagNameDescription.build(options),
30
30
  schemes: options[:schemes].is_a?(String) ? [options[:schemes]] : options[:schemes]
31
31
  }.delete_if { |_, value| value.blank? }
@@ -86,7 +86,7 @@ module Grape
86
86
  routes.each do |route|
87
87
  next if hidden?(route)
88
88
 
89
- @item, path = GrapeSwagger::DocMethods::PathString.build(route.path, options)
89
+ @item, path = GrapeSwagger::DocMethods::PathString.build(route, options)
90
90
  @entity = route.entity || route.options[:success]
91
91
 
92
92
  verb, method_object = method_object(route, options, path)
@@ -103,6 +103,7 @@ module Grape
103
103
 
104
104
  def method_object(route, options, path)
105
105
  method = {}
106
+ method[:summary] = summary_object(route)
106
107
  method[:description] = description_object(route, options[:markdown])
107
108
  method[:produces] = produces_object(route, options[:produces] || options[:format])
108
109
  method[:consumes] = consumes_object(route, options[:format])
@@ -115,6 +116,14 @@ module Grape
115
116
  [route.request_method.downcase.to_sym, method]
116
117
  end
117
118
 
119
+ def summary_object(route)
120
+ summary = route.options[:desc] if route.options.key?(:desc)
121
+ summary = route.description if route.description.present?
122
+ summary = route.options[:summary] if route.options.key?(:summary)
123
+
124
+ summary
125
+ end
126
+
118
127
  def description_object(route, markdown)
119
128
  description = route.options[:desc] if route.options.key?(:desc)
120
129
  description = route.description if route.description.present?
@@ -226,53 +235,25 @@ module Grape
226
235
  end
227
236
  end
228
237
 
229
- def parse_response_params(params)
230
- return if params.nil?
238
+ def expose_params_from_model(model)
239
+ model_name = model_name(model)
231
240
 
232
- params.each_with_object({}) do |x, memo|
233
- next if x[1].fetch(:documentation, {}).fetch(:in, nil).to_s == 'header'
234
- x[0] = x.last[:as] if x.last[:as]
241
+ return model_name if @definitions.key?(model_name)
242
+ @definitions[model_name] = nil
235
243
 
236
- model = x.last[:using] if x.last[:using].present?
237
- model ||= x.last[:documentation][:type] if x.last[:documentation] && could_it_be_a_model?(x.last[:documentation])
244
+ properties = nil
245
+ parser = nil
238
246
 
239
- if model
240
- name = expose_params_from_model(model)
241
- memo[x.first] = if x.last[:documentation] && x.last[:documentation][:is_array]
242
- { 'type' => 'array', 'items' => { '$ref' => "#/definitions/#{name}" } }
243
- else
244
- { '$ref' => "#/definitions/#{name}" }
245
- end
246
- else
247
- documented_type = x.last[:type]
248
- documented_type ||= x.last[:documentation][:type] if x.last[:documentation]
249
- data_type = GrapeSwagger::DocMethods::DataType.call(documented_type)
250
-
251
- if GrapeSwagger::DocMethods::DataType.primitive?(data_type)
252
- data = GrapeSwagger::DocMethods::DataType.mapping(data_type)
253
- memo[x.first] = { type: data.first, format: data.last }
254
- else
255
- memo[x.first] = { type: data_type }
256
- end
257
-
258
- memo[x.first][:enum] = x.last[:values] if x.last[:values] && x.last[:values].is_a?(Array)
259
- end
260
- memo[x.first][:description] = x.last[:documentation][:desc] if x.last[:documentation] && x.last[:documentation][:desc]
247
+ GrapeSwagger.model_parsers.each do |klass, ancestor|
248
+ next unless model.ancestors.map(&:to_s).include?(ancestor)
249
+ parser = klass.new(model, self)
250
+ break
261
251
  end
262
- end
263
252
 
264
- def expose_params_from_model(model)
265
- model_name = model_name(model)
253
+ properties = parser.call unless parser.nil?
266
254
 
267
- # TODO: this should only be a temporary hack ;)
268
- if GrapeEntity::VERSION =~ /0\.4\.\d/
269
- parameters = model.exposures ? model.exposures : model.documentation
270
- elsif GrapeEntity::VERSION =~ /0\.5\.\d/
271
- parameters = model.root_exposures.each_with_object({}) do |value, memo|
272
- memo[value.attribute] = value.send(:options)
273
- end
274
- end
275
- properties = parse_response_params(parameters)
255
+ raise GrapeSwagger::Errors::UnregisteredParser, "No parser registered for #{model_name}." unless parser
256
+ raise GrapeSwagger::Errors::SwaggerSpec, "Empty model #{model_name}, swagger 2.0 doesn't support empty definitions." unless properties && properties.any?
276
257
 
277
258
  @definitions[model_name] = { type: 'object', properties: properties }
278
259
 
@@ -283,17 +264,6 @@ module Grape
283
264
  name.respond_to?(:name) ? name.name.demodulize.camelize : name.split('::').last
284
265
  end
285
266
 
286
- def could_it_be_a_model?(value)
287
- (
288
- value[:type].to_s.include?('Entity') || value[:type].to_s.include?('Entities')
289
- ) || (
290
- value[:type] &&
291
- value[:type].is_a?(Class) &&
292
- !GrapeSwagger::DocMethods::DataType.primitive?(value[:type].name.downcase) &&
293
- !value[:type] == Array
294
- )
295
- end
296
-
297
267
  def hidden?(route)
298
268
  route_hidden = route.options[:hidden]
299
269
  route_hidden = route_hidden.call if route_hidden.is_a?(Proc)
@@ -5,5 +5,8 @@ module GrapeSwagger
5
5
  super("Missing required dependency: #{missing_gem}")
6
6
  end
7
7
  end
8
+
9
+ class UnregisteredParser < StandardError; end
10
+ class SwaggerSpec < StandardError; end
8
11
  end
9
12
  end
@@ -1,7 +1,8 @@
1
1
  # backwards compatibility for Grape < 0.16.0
2
2
  module Grape
3
3
  class Route
4
- [:path, :prefix, :entity, :description, :settings, :params, :headers, :http_codes].each do |m|
4
+ [:path, :prefix, :entity, :description, :settings, :params, :headers, :http_codes, :version]
5
+ .each do |m|
5
6
  define_method m do
6
7
  send "route_#{m}"
7
8
  end
@@ -0,0 +1,33 @@
1
+ module GrapeSwagger
2
+ class ModelParsers
3
+ include Enumerable
4
+
5
+ def initialize
6
+ @parsers = {}
7
+ end
8
+
9
+ def register(klass, ancestor)
10
+ @parsers[klass] = ancestor.to_s
11
+ end
12
+
13
+ def insert_before(before_klass, klass, ancestor)
14
+ subhash = @parsers.except(klass).to_a
15
+ insert_at = subhash.index(subhash.assoc(before_klass))
16
+ insert_at = subhash.length - 1 if insert_at.nil?
17
+ @parsers = Hash[subhash.insert(insert_at, [klass, ancestor])]
18
+ end
19
+
20
+ def insert_after(after_klass, klass, ancestor)
21
+ subhash = @parsers.except(klass).to_a
22
+ insert_at = subhash.index(subhash.assoc(after_klass))
23
+ insert_at = subhash.length - 1 if insert_at.nil?
24
+ @parsers = Hash[subhash.insert(insert_at + 1, [klass, ancestor])]
25
+ end
26
+
27
+ def each
28
+ @parsers.each_pair do |klass, ancestor|
29
+ yield klass, ancestor
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,3 +1,3 @@
1
1
  module GrapeSwagger
2
- VERSION = '0.20.3'.freeze
2
+ VERSION = '0.21.0'.freeze
3
3
  end
@@ -29,6 +29,7 @@ describe 'describing versions' do
29
29
  paths: {
30
30
  :'/nothings' => {
31
31
  get: {
32
+ summary: 'no versions given',
32
33
  description: 'no versions given',
33
34
  produces: ['application/json'],
34
35
  responses: {
@@ -36,7 +37,10 @@ describe 'describing versions' do
36
37
  },
37
38
  tags: ['nothings'],
38
39
  operationId: 'getNothings'
39
- } } })
40
+ }
41
+ }
42
+ }
43
+ )
40
44
  end
41
45
  end
42
46
 
@@ -68,6 +72,7 @@ describe 'describing versions' do
68
72
  paths: {
69
73
  :'/v2/api_version' => {
70
74
  get: {
75
+ summary: 'api versions given',
71
76
  description: 'api versions given',
72
77
  produces: ['application/json'],
73
78
  responses: {
@@ -75,7 +80,10 @@ describe 'describing versions' do
75
80
  },
76
81
  tags: ['api_version'],
77
82
  operationId: 'getV2ApiVersion'
78
- } } })
83
+ }
84
+ }
85
+ }
86
+ )
79
87
  end
80
88
  end
81
89
 
@@ -106,6 +114,7 @@ describe 'describing versions' do
106
114
  paths: {
107
115
  :'/doc_version' => {
108
116
  get: {
117
+ summary: 'doc versions given',
109
118
  description: 'doc versions given',
110
119
  produces: ['application/json'],
111
120
  responses: {
@@ -113,7 +122,10 @@ describe 'describing versions' do
113
122
  },
114
123
  tags: ['doc_version'],
115
124
  operationId: 'getDocVersion'
116
- } } })
125
+ }
126
+ }
127
+ }
128
+ )
117
129
  end
118
130
  end
119
131
 
@@ -145,6 +157,7 @@ describe 'describing versions' do
145
157
  paths: {
146
158
  :'/v2/both_versions' => {
147
159
  get: {
160
+ summary: 'both versions given',
148
161
  description: 'both versions given',
149
162
  produces: ['application/json'],
150
163
  responses: {
@@ -152,7 +165,10 @@ describe 'describing versions' do
152
165
  },
153
166
  tags: ['both_versions'],
154
167
  operationId: 'getV2BothVersions'
155
- } } })
168
+ }
169
+ }
170
+ }
171
+ )
156
172
  end
157
173
  end
158
174
  end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ describe GrapeSwagger::ModelParsers do
4
+ let(:model_parsers) { described_class.new }
5
+ let(:parser) { Class.new }
6
+ let(:parser2) { Class.new }
7
+ let(:parser3) { Class.new }
8
+
9
+ describe '#register' do
10
+ describe 'successfully register new parser' do
11
+ before do
12
+ model_parsers.register(parser, Class)
13
+ end
14
+
15
+ specify do
16
+ expect(model_parsers.to_a).to eq([[parser, 'Class']])
17
+ end
18
+ end
19
+
20
+ describe 'should be empty if no registered parsers' do
21
+ specify do
22
+ expect(model_parsers.to_a).to be_empty
23
+ end
24
+ end
25
+ end
26
+
27
+ describe '#insert_before' do
28
+ describe 'SomeModelParser2 should be first parser' do
29
+ before do
30
+ model_parsers.register(parser, Class)
31
+ model_parsers.register(parser3, Class)
32
+ model_parsers.insert_before(parser, parser2, Class)
33
+ end
34
+
35
+ specify do
36
+ expect(model_parsers.count).to eq(3)
37
+ expect(model_parsers.to_a.first).to eq([parser2, Class])
38
+ end
39
+ end
40
+
41
+ describe 'SomeModelParser2 should be inserted anyway if SomeModelParser not registered' do
42
+ before do
43
+ model_parsers.register(parser3, Class)
44
+ model_parsers.insert_before(parser, parser2, Class)
45
+ end
46
+
47
+ specify do
48
+ expect(model_parsers.count).to eq(2)
49
+ expect(model_parsers.to_a).to include([parser2, Class])
50
+ end
51
+ end
52
+
53
+ describe 'SomeModelParser2 should be inserted anyway if model parsers is empty' do
54
+ before do
55
+ model_parsers.insert_before(parser, parser2, Class)
56
+ end
57
+
58
+ specify do
59
+ expect(model_parsers.count).to eq(1)
60
+ expect(model_parsers.to_a).to include([parser2, Class])
61
+ end
62
+ end
63
+ end
64
+
65
+ describe '#insert_after' do
66
+ describe 'SomeModelParser2 should be second parser' do
67
+ before do
68
+ model_parsers.register(parser, Class)
69
+ model_parsers.register(parser3, Class)
70
+ model_parsers.insert_after(parser, parser2, Class)
71
+ end
72
+
73
+ specify do
74
+ expect(model_parsers.count).to eq(3)
75
+ expect(model_parsers.to_a[1]).to eq([parser2, Class])
76
+ end
77
+ end
78
+
79
+ describe 'SomeModelParser2 should be inserted anyway if SomeModelParser not registered' do
80
+ before do
81
+ model_parsers.register(parser3, Class)
82
+ model_parsers.insert_after(parser, parser2, Class)
83
+ end
84
+
85
+ specify do
86
+ expect(model_parsers.count).to eq(2)
87
+ expect(model_parsers.to_a).to include([parser2, Class])
88
+ end
89
+ end
90
+
91
+ describe 'SomeModelParser2 should be inserted anyway if model parsers is empty' do
92
+ before do
93
+ model_parsers.insert_after(parser, parser2, Class)
94
+ end
95
+
96
+ specify do
97
+ expect(model_parsers.count).to eq(1)
98
+ expect(model_parsers.to_a).to include([parser2, Class])
99
+ end
100
+ end
101
+ end
102
+ end
@@ -7,33 +7,37 @@ describe GrapeSwagger::DocMethods::OptionalObject do
7
7
  specify { expect(subject).to respond_to :build }
8
8
 
9
9
  describe 'build' do
10
- let(:key) { :bar }
11
- let(:request) { 'somes/request/string' }
10
+ let(:key) { :host }
11
+ let!(:request) { Rack::Request.new(Rack::MockRequest.env_for('http://example.com:8080/')) }
12
12
 
13
- describe 'no option given for key' do
13
+ describe 'no option given for host, take from request' do
14
14
  let(:options) { { foo: 'foo' } }
15
15
  specify do
16
- expect(subject.build(key, options)).to be_nil
17
- expect(subject.build(key, options, request)).to eql request
16
+ expect(subject.build(key, options, request)).to eql request.host_with_port
18
17
  end
19
18
  end
20
19
 
21
- let(:value) { 'some optional value' }
20
+ let(:value) { 'grape-swagger.example.com' }
22
21
 
23
22
  describe 'option is a string' do
24
- let(:options) { { bar: value } }
23
+ let(:options) { { host: value } }
25
24
  specify do
26
- expect(subject.build(key, options)).to eql value
27
25
  expect(subject.build(key, options, request)).to eql value
28
26
  end
29
27
  end
30
28
 
31
- describe 'option is a proc' do
32
- let(:options) { { bar: -> { value } } }
29
+ describe 'option is a lambda' do
30
+ let(:options) { { host: -> { value } } }
33
31
  specify do
34
- expect(subject.build(key, options)).to eql value
35
32
  expect(subject.build(key, options, request)).to eql value
36
33
  end
37
34
  end
35
+
36
+ describe 'option is a proc' do
37
+ let(:options) { { host: proc { |request| request.host =~ /^example/ ? '/api-example' : '/api' } } }
38
+ specify do
39
+ expect(subject.build(key, options, request)).to eql '/api-example'
40
+ end
41
+ end
38
42
  end
39
43
  end
@@ -8,29 +8,83 @@ describe GrapeSwagger::DocMethods::PathString do
8
8
 
9
9
  describe 'operation_id_object' do
10
10
  describe 'version' do
11
- describe 'defaults: not given, false' do
11
+ describe 'defaults: given, true' do
12
+ let(:options) { { add_version: true } }
13
+ let(:route) { Struct.new(:version, :path).new('v1') }
14
+
15
+ specify 'The returned path includes version' do
16
+ route.path = '/{version}/thing(.json)'
17
+ expect(subject.build(route, options)).to eql ['Thing', '/v1/thing']
18
+ route.path = '/{version}/thing/foo(.json)'
19
+ expect(subject.build(route, options)).to eql ['Foo', '/v1/thing/foo']
20
+ route.path = '/{version}/thing(.:format)'
21
+ expect(subject.build(route, options)).to eql ['Thing', '/v1/thing']
22
+ route.path = '/{version}/thing/foo(.:format)'
23
+ expect(subject.build(route, options)).to eql ['Foo', '/v1/thing/foo']
24
+ route.path = '/{version}/thing/:id'
25
+ expect(subject.build(route, options)).to eql ['Thing', '/v1/thing/{id}']
26
+ route.path = '/{version}/thing/foo/:id'
27
+ expect(subject.build(route, options)).to eql ['Foo', '/v1/thing/foo/{id}']
28
+ end
29
+ end
30
+
31
+ describe 'defaults: not given, both false' do
12
32
  let(:options) { { add_version: false } }
33
+ let(:route) { Struct.new(:version, :path).new }
13
34
 
14
- specify do
15
- expect(subject.build('/thing(.json)', options)).to eql ['Thing', '/thing']
16
- expect(subject.build('/thing/foo(.json)', options)).to eql ['Foo', '/thing/foo']
17
- expect(subject.build('/thing(.:format)', options)).to eql ['Thing', '/thing']
18
- expect(subject.build('/thing/foo(.:format)', options)).to eql ['Foo', '/thing/foo']
19
- expect(subject.build('/thing/:id', options)).to eql ['Thing', '/thing/{id}']
20
- expect(subject.build('/thing/foo/:id', options)).to eql ['Foo', '/thing/foo/{id}']
35
+ specify 'The returned path does not include version' do
36
+ route.path = '/{version}/thing(.json)'
37
+ expect(subject.build(route, options)).to eql ['Thing', '/thing']
38
+ route.path = '/{version}/thing/foo(.json)'
39
+ expect(subject.build(route, options)).to eql ['Foo', '/thing/foo']
40
+ route.path = '/{version}/thing(.:format)'
41
+ expect(subject.build(route, options)).to eql ['Thing', '/thing']
42
+ route.path = '/{version}/thing/foo(.:format)'
43
+ expect(subject.build(route, options)).to eql ['Foo', '/thing/foo']
44
+ route.path = '/{version}/thing/:id'
45
+ expect(subject.build(route, options)).to eql ['Thing', '/thing/{id}']
46
+ route.path = '/{version}/thing/foo/:id'
47
+ expect(subject.build(route, options)).to eql ['Foo', '/thing/foo/{id}']
21
48
  end
22
49
  end
23
50
 
24
- describe 'defaults: given, true' do
25
- let(:options) { { version: 'v1', add_version: true } }
26
-
27
- specify do
28
- expect(subject.build('/{version}/thing(.json)', options)).to eql ['Thing', '/v1/thing']
29
- expect(subject.build('/{version}/thing/foo(.json)', options)).to eql ['Foo', '/v1/thing/foo']
30
- expect(subject.build('/{version}/thing(.:format)', options)).to eql ['Thing', '/v1/thing']
31
- expect(subject.build('/{version}/thing/foo(.:format)', options)).to eql ['Foo', '/v1/thing/foo']
32
- expect(subject.build('/{version}/thing/:id', options)).to eql ['Thing', '/v1/thing/{id}']
33
- expect(subject.build('/{version}/thing/foo/:id', options)).to eql ['Foo', '/v1/thing/foo/{id}']
51
+ describe 'defaults: add_version false' do
52
+ let(:options) { { add_version: false } }
53
+ let(:route) { Struct.new(:version, :path).new('v1') }
54
+
55
+ specify 'The returned path does not include version' do
56
+ route.path = '/{version}/thing(.json)'
57
+ expect(subject.build(route, options)).to eql ['Thing', '/thing']
58
+ route.path = '/{version}/thing/foo(.json)'
59
+ expect(subject.build(route, options)).to eql ['Foo', '/thing/foo']
60
+ route.path = '/{version}/thing(.:format)'
61
+ expect(subject.build(route, options)).to eql ['Thing', '/thing']
62
+ route.path = '/{version}/thing/foo(.:format)'
63
+ expect(subject.build(route, options)).to eql ['Foo', '/thing/foo']
64
+ route.path = '/{version}/thing/:id'
65
+ expect(subject.build(route, options)).to eql ['Thing', '/thing/{id}']
66
+ route.path = '/{version}/thing/foo/:id'
67
+ expect(subject.build(route, options)).to eql ['Foo', '/thing/foo/{id}']
68
+ end
69
+ end
70
+
71
+ describe 'defaults: root_version nil' do
72
+ let(:options) { { add_version: true } }
73
+ let(:route) { Struct.new(:version, :path).new }
74
+
75
+ specify 'The returned path does not include version' do
76
+ route.path = '/{version}/thing(.json)'
77
+ expect(subject.build(route, options)).to eql ['Thing', '/thing']
78
+ route.path = '/{version}/thing/foo(.json)'
79
+ expect(subject.build(route, options)).to eql ['Foo', '/thing/foo']
80
+ route.path = '/{version}/thing(.:format)'
81
+ expect(subject.build(route, options)).to eql ['Thing', '/thing']
82
+ route.path = '/{version}/thing/foo(.:format)'
83
+ expect(subject.build(route, options)).to eql ['Foo', '/thing/foo']
84
+ route.path = '/{version}/thing/:id'
85
+ expect(subject.build(route, options)).to eql ['Thing', '/thing/{id}']
86
+ route.path = '/{version}/thing/foo/:id'
87
+ expect(subject.build(route, options)).to eql ['Foo', '/thing/foo/{id}']
34
88
  end
35
89
  end
36
90
  end