apipie-rails 0.5.20 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +12 -21
  3. data/.github/workflows/rubocop-challenger.yml +28 -0
  4. data/.github/workflows/rubocop.yml +18 -0
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +128 -0
  7. data/.rubocop_todo.yml +2062 -0
  8. data/.vscode/settings.json +3 -0
  9. data/CHANGELOG.md +144 -0
  10. data/Gemfile +20 -0
  11. data/README.rst +106 -15
  12. data/Rakefile +0 -5
  13. data/apipie-rails.gemspec +18 -9
  14. data/app/controllers/apipie/apipies_controller.rb +14 -29
  15. data/app/helpers/apipie_helper.rb +1 -1
  16. data/app/public/apipie/javascripts/bundled/bootstrap-collapse.js +70 -41
  17. data/app/public/apipie/javascripts/bundled/bootstrap.js +1033 -479
  18. data/app/public/apipie/javascripts/bundled/jquery.js +5 -5
  19. data/app/public/apipie/stylesheets/bundled/bootstrap-responsive.min.css +9 -12
  20. data/app/public/apipie/stylesheets/bundled/bootstrap.min.css +9 -689
  21. data/app/views/apipie/apipies/_deprecation.html.erb +16 -0
  22. data/app/views/apipie/apipies/_params.html.erb +7 -1
  23. data/config/locales/en.yml +8 -0
  24. data/config/locales/ko.yml +31 -0
  25. data/gemfiles/Gemfile.tools +9 -0
  26. data/lib/apipie/apipie_module.rb +7 -7
  27. data/lib/apipie/application.rb +132 -97
  28. data/lib/apipie/configuration.rb +43 -33
  29. data/lib/apipie/dsl_definition.rb +39 -27
  30. data/lib/apipie/error_description.rb +3 -3
  31. data/lib/apipie/errors.rb +16 -16
  32. data/lib/apipie/extractor/collector.rb +4 -5
  33. data/lib/apipie/extractor/recorder.rb +33 -6
  34. data/lib/apipie/extractor/writer.rb +14 -14
  35. data/lib/apipie/extractor.rb +6 -9
  36. data/lib/apipie/generator/config.rb +12 -0
  37. data/lib/apipie/generator/generator.rb +2 -0
  38. data/lib/apipie/generator/swagger/computed_interface_id.rb +23 -0
  39. data/lib/apipie/generator/swagger/config.rb +80 -0
  40. data/lib/apipie/generator/swagger/context.rb +38 -0
  41. data/lib/apipie/generator/swagger/method_description/api_decorator.rb +20 -0
  42. data/lib/apipie/generator/swagger/method_description/api_schema_service.rb +89 -0
  43. data/lib/apipie/generator/swagger/method_description/decorator.rb +22 -0
  44. data/lib/apipie/generator/swagger/method_description/parameters_service.rb +139 -0
  45. data/lib/apipie/generator/swagger/method_description/response_schema_service.rb +46 -0
  46. data/lib/apipie/generator/swagger/method_description/response_service.rb +58 -0
  47. data/lib/apipie/generator/swagger/method_description.rb +2 -0
  48. data/lib/apipie/generator/swagger/operation_id.rb +51 -0
  49. data/lib/apipie/generator/swagger/param_description/builder.rb +105 -0
  50. data/lib/apipie/generator/swagger/param_description/composite.rb +119 -0
  51. data/lib/apipie/generator/swagger/param_description/description.rb +15 -0
  52. data/lib/apipie/generator/swagger/param_description/in.rb +37 -0
  53. data/lib/apipie/generator/swagger/param_description/name.rb +18 -0
  54. data/lib/apipie/generator/swagger/param_description/path_params_composite.rb +61 -0
  55. data/lib/apipie/generator/swagger/param_description/referenced_composite.rb +36 -0
  56. data/lib/apipie/generator/swagger/param_description/type.rb +115 -0
  57. data/lib/apipie/generator/swagger/param_description.rb +18 -0
  58. data/lib/apipie/generator/swagger/path_decorator.rb +36 -0
  59. data/lib/apipie/generator/swagger/referenced_definitions.rb +17 -0
  60. data/lib/apipie/generator/swagger/resource_description_collection.rb +30 -0
  61. data/lib/apipie/generator/swagger/resource_description_composite.rb +56 -0
  62. data/lib/apipie/generator/swagger/schema.rb +63 -0
  63. data/lib/apipie/generator/swagger/swagger.rb +2 -0
  64. data/lib/apipie/generator/swagger/type.rb +16 -0
  65. data/lib/apipie/generator/swagger/type_extractor.rb +51 -0
  66. data/lib/apipie/generator/swagger/warning.rb +74 -0
  67. data/lib/apipie/generator/swagger/warning_writer.rb +54 -0
  68. data/lib/apipie/helpers.rb +3 -3
  69. data/lib/apipie/markup.rb +9 -8
  70. data/lib/apipie/method_description/api.rb +12 -0
  71. data/lib/apipie/method_description/apis_service.rb +82 -0
  72. data/lib/apipie/method_description.rb +12 -56
  73. data/lib/apipie/param_description/deprecation.rb +24 -0
  74. data/lib/apipie/param_description.rb +57 -24
  75. data/lib/apipie/resource_description.rb +42 -14
  76. data/lib/apipie/response_description.rb +3 -3
  77. data/lib/apipie/response_description_adapter.rb +10 -8
  78. data/lib/apipie/routing.rb +1 -1
  79. data/lib/apipie/rspec/response_validation_helper.rb +3 -3
  80. data/lib/apipie/static_dispatcher.rb +3 -1
  81. data/lib/apipie/swagger_generator.rb +28 -691
  82. data/lib/apipie/validator.rb +40 -10
  83. data/lib/apipie/version.rb +1 -1
  84. data/lib/apipie-rails.rb +36 -5
  85. data/lib/generators/apipie/install/install_generator.rb +1 -1
  86. data/lib/generators/apipie/views_generator.rb +1 -1
  87. data/lib/tasks/apipie.rake +35 -30
  88. data/spec/controllers/api/v2/architectures_controller_spec.rb +10 -3
  89. data/spec/controllers/api/v2/empty_middle_controller_spec.rb +23 -0
  90. data/spec/controllers/api/v2/nested/resources_controller_spec.rb +18 -2
  91. data/spec/controllers/api/v2/sub/footguns_controller_spec.rb +19 -0
  92. data/spec/controllers/included_param_group_controller_spec.rb +13 -0
  93. data/spec/{lib/swagger/response_validation_spec.rb → controllers/pets_controller_spec.rb} +26 -32
  94. data/spec/controllers/users_controller_spec.rb +47 -6
  95. data/spec/dummy/Rakefile +1 -1
  96. data/spec/dummy/app/controllers/api/v2/architectures_controller.rb +2 -1
  97. data/spec/dummy/app/controllers/api/v2/base_controller.rb +6 -0
  98. data/spec/dummy/app/controllers/api/v2/empty_middle_controller.rb +14 -0
  99. data/spec/dummy/app/controllers/api/v2/nested/resources_controller.rb +2 -2
  100. data/spec/dummy/app/controllers/api/v2/sub/footguns_controller.rb +30 -0
  101. data/spec/dummy/app/controllers/concerns_controller.rb +1 -1
  102. data/spec/dummy/app/controllers/{concerns/extending_concern.rb → extending_concern.rb} +0 -2
  103. data/spec/dummy/app/controllers/included_param_group_controller.rb +19 -0
  104. data/spec/dummy/app/controllers/overridden_concerns_controller.rb +2 -2
  105. data/spec/dummy/app/controllers/pets_controller.rb +4 -4
  106. data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +2 -2
  107. data/spec/dummy/app/controllers/{concerns/sample_controller.rb → sample_controller.rb} +0 -2
  108. data/spec/dummy/app/controllers/twitter_example_controller.rb +2 -2
  109. data/spec/dummy/app/controllers/users_controller.rb +17 -5
  110. data/spec/dummy/app/helpers/random_param_group.rb +8 -0
  111. data/spec/dummy/components/test_engine/test_engine.gemspec +1 -1
  112. data/spec/dummy/config/application.rb +2 -5
  113. data/spec/dummy/config/boot.rb +2 -2
  114. data/spec/dummy/config/environment.rb +1 -1
  115. data/spec/dummy/config/environments/development.rb +0 -3
  116. data/spec/dummy/config/environments/production.rb +0 -3
  117. data/spec/dummy/config/environments/test.rb +0 -5
  118. data/spec/dummy/config/initializers/apipie.rb +2 -2
  119. data/spec/dummy/config/routes.rb +8 -0
  120. data/spec/dummy/config.ru +1 -1
  121. data/spec/dummy/script/rails +2 -2
  122. data/spec/{controllers → lib/apipie}/apipies_controller_spec.rb +95 -23
  123. data/spec/lib/apipie/application_spec.rb +62 -0
  124. data/spec/lib/apipie/configuration_spec.rb +38 -0
  125. data/spec/lib/apipie/extractor/collector_spec.rb +57 -0
  126. data/spec/lib/apipie/extractor/recorder_spec.rb +77 -0
  127. data/spec/lib/{extractor → apipie/extractor}/writer_spec.rb +8 -6
  128. data/spec/lib/{file_handler_spec.rb → apipie/file_handler_spec.rb} +7 -0
  129. data/spec/lib/apipie/generator/swagger/config_spec.rb +19 -0
  130. data/spec/lib/apipie/generator/swagger/context_spec.rb +56 -0
  131. data/spec/lib/apipie/generator/swagger/method_description/api_schema_service_spec.rb +119 -0
  132. data/spec/lib/apipie/generator/swagger/method_description/response_schema_service_spec.rb +105 -0
  133. data/spec/lib/apipie/generator/swagger/operation_id_spec.rb +63 -0
  134. data/spec/lib/apipie/generator/swagger/param_description/builder_spec.rb +203 -0
  135. data/spec/lib/apipie/generator/swagger/param_description/composite_spec.rb +95 -0
  136. data/spec/lib/apipie/generator/swagger/param_description/description_spec.rb +79 -0
  137. data/spec/lib/apipie/generator/swagger/param_description/in_spec.rb +86 -0
  138. data/spec/lib/apipie/generator/swagger/param_description/name_spec.rb +81 -0
  139. data/spec/lib/apipie/generator/swagger/param_description/type_spec.rb +178 -0
  140. data/spec/lib/apipie/generator/swagger/param_description_spec.rb +28 -0
  141. data/spec/lib/apipie/generator/swagger/path_decorator_spec.rb +57 -0
  142. data/spec/lib/apipie/generator/swagger/referenced_definitions_spec.rb +35 -0
  143. data/spec/lib/apipie/generator/swagger/resource_description_composite_spec.rb +37 -0
  144. data/spec/lib/apipie/generator/swagger/resource_descriptions_collection_spec.rb +57 -0
  145. data/spec/lib/apipie/generator/swagger/schema_spec.rb +89 -0
  146. data/spec/lib/apipie/generator/swagger/type_extractor_spec.rb +38 -0
  147. data/spec/lib/apipie/generator/swagger/warning_spec.rb +51 -0
  148. data/spec/lib/apipie/generator/swagger/warning_writer_spec.rb +71 -0
  149. data/spec/lib/apipie/method_description/apis_service_spec.rb +60 -0
  150. data/spec/lib/apipie/method_description_spec.rb +133 -0
  151. data/spec/lib/apipie/no_documented_method_spec.rb +17 -0
  152. data/spec/lib/apipie/param_description/deprecation_spec.rb +31 -0
  153. data/spec/lib/{param_description_spec.rb → apipie/param_description_spec.rb} +332 -6
  154. data/spec/lib/{param_group_spec.rb → apipie/param_group_spec.rb} +6 -5
  155. data/spec/lib/apipie/resource_description_spec.rb +91 -0
  156. data/spec/lib/apipie/response_does_not_match_swagger_schema_spec.rb +35 -0
  157. data/spec/lib/apipie/swagger_generator_spec.rb +94 -0
  158. data/spec/lib/{validator_spec.rb → apipie/validator_spec.rb} +48 -12
  159. data/spec/lib/rake_spec.rb +3 -5
  160. data/spec/lib/swagger/openapi_2_0_schema.json +8 -1
  161. data/spec/lib/swagger/rake_swagger_spec.rb +24 -9
  162. data/spec/lib/swagger/swagger_dsl_spec.rb +18 -12
  163. data/spec/lib/validators/array_validator_spec.rb +1 -1
  164. data/spec/spec_helper.rb +10 -32
  165. data/spec/support/custom_bool_validator.rb +17 -0
  166. data/spec/{controllers → test_engine}/memes_controller_spec.rb +1 -1
  167. metadata +169 -122
  168. data/Gemfile +0 -1
  169. data/gemfiles/Gemfile.rails42 +0 -14
  170. data/gemfiles/Gemfile.rails42.lock +0 -160
  171. data/gemfiles/Gemfile.rails52 +0 -9
  172. data/gemfiles/Gemfile.rails60 +0 -10
  173. data/gemfiles/Gemfile.rails61 +0 -10
  174. data/spec/lib/application_spec.rb +0 -49
  175. data/spec/lib/method_description_spec.rb +0 -98
  176. data/spec/lib/resource_description_spec.rb +0 -48
  177. data/spec/support/rails-42-ruby-26.rb +0 -15
  178. /data/spec/lib/{extractor → apipie/extractor/recorder}/middleware_spec.rb +0 -0
  179. /data/spec/lib/{extractor → apipie}/extractor_spec.rb +0 -0
@@ -0,0 +1,16 @@
1
+ <% if deprecation.present? %>
2
+ <strong><%= t('apipie.deprecation_details') %></strong>
3
+ <ul>
4
+ <% if deprecation[:deprecated_in].present? %>
5
+ <li><%= t('apipie.deprecation.attributes.deprecated_in') %>: <%= deprecation[:deprecated_in] %></li>
6
+ <% end %>
7
+
8
+ <% if deprecation[:sunset_at].present? %>
9
+ <li><%= t('apipie.deprecation.attributes.sunset_at') %>: <%= deprecation[:sunset_at] %></li>
10
+ <% end %>
11
+
12
+ <% if deprecation[:info].present? %>
13
+ <li><%= t('apipie.deprecation.attributes.info') %>: <%= deprecation[:info] %></li>
14
+ <% end %>
15
+ </ul>
16
+ <% end %>
@@ -7,7 +7,11 @@
7
7
  <% end %>
8
8
  <tr style='background-color:rgb(<%= "#{col},#{col},#{col}" %>);'>
9
9
  <td>
10
- <strong><%= param[:full_name] %> </strong><br>
10
+ <strong><%= param[:full_name] %></strong>
11
+ <% if param[:deprecated].present? %>
12
+ <code><%= t('apipie.deprecated').upcase %></code>
13
+ <% end %>
14
+ <br>
11
15
  <small>
12
16
  <%= param[:required] ? t('apipie.required') : t('apipie.optional') %>
13
17
  <%= param[:allow_nil] ? ', '+t('apipie.nil_allowed') : '' %>
@@ -29,6 +33,8 @@
29
33
  </ul>
30
34
  <%- end %>
31
35
 
36
+ <%= render partial: 'deprecation', locals: { deprecation: param[:deprecation] } %>
37
+
32
38
  <% unless param[:metadata].blank? %>
33
39
  <br>
34
40
  Metadata:
@@ -30,3 +30,11 @@ en:
30
30
  headers: Headers
31
31
  header_name: Header name
32
32
  code: Code
33
+ returns: Returns
34
+ deprecated: Deprecated
35
+ deprecation_details: Deprecation details
36
+ deprecation:
37
+ attributes:
38
+ deprecated_in: Deprecated in
39
+ sunset_at: Sunset at
40
+ info: Info
@@ -0,0 +1,31 @@
1
+ ko:
2
+ apipie:
3
+ resources: 리소스
4
+ resource: 리소스
5
+ description: 설명
6
+ no_docs_found: 문서를 찾을 수 없습니다.
7
+ no_docs_found_descr: 해당 API에 대한 문서를 찾을 수 없습니다.
8
+ follow_instructions_html: 해당 컨트롤러의 설명을 %{href}를 따르세요.
9
+ follow_instructions_href: 자세한 설명
10
+ oops: 이런!!
11
+ resource_not_found_html: "%{resource} 리소스를 찾을 수 없습니다."
12
+ method_not_found_html: "%{resource} 리소스에 대한 %{method} 메소드를 찾을 수 없습니다."
13
+ goto_homepage_html: "%{href}로 시도해보세요."
14
+ goto_homepage_href: "%{app_name} API 문서 페이지"
15
+ required: 필수
16
+ optional: 옵션
17
+ nil_allowed: nil 허용
18
+ param_name: Param 이름
19
+ params: Params
20
+ examples: 예시
21
+ metadata: Metadata
22
+ errors: 에러
23
+ error_code: 코드
24
+ error_description: 설명
25
+ error_metadata: Metadata
26
+ supported_formats: 지원 포멧
27
+ enable_javascript_html: "%{comments_href}를 보기 위해서 JavaScript를 허용해주세요."
28
+ comments_powered_by_disqus: comments powered by %{disqus}
29
+ api_documentation: API 문서
30
+ headers: 헤더
31
+ header_name: 헤더 이름
@@ -0,0 +1,9 @@
1
+ # This Gemfile is used for IDEs like VS Code that need specific gems installed
2
+ # for their tools to work properly. It is not used for the application itself.
3
+
4
+ source 'https://rubygems.org'
5
+
6
+ gem 'rubocop-rails'
7
+ gem 'rubocop-rspec'
8
+ gem 'rubocop-performance'
9
+ gem 'ruby-lsp', '~> 0.5.1'
@@ -8,14 +8,14 @@ module Apipie
8
8
  @application ||= Apipie::Application.new
9
9
  end
10
10
 
11
- def self.to_json(version = nil, resource_name = nil, method_name = nil, lang = nil)
11
+ def self.to_json(version = nil, resource_id = nil, method_name = nil, lang = nil)
12
12
  version ||= Apipie.configuration.default_version
13
- app.to_json(version, resource_name, method_name, lang)
13
+ app.to_json(version, resource_id, method_name, lang)
14
14
  end
15
15
 
16
- def self.to_swagger_json(version = nil, resource_name = nil, method_name = nil, lang = nil, clear_warnings=true)
16
+ def self.to_swagger_json(version = nil, resource_id = nil, method_name = nil, lang = nil, clear_warnings = true)
17
17
  version ||= Apipie.configuration.default_version
18
- app.to_swagger_json(version, resource_name, method_name, lang, clear_warnings)
18
+ app.to_swagger_json(version, resource_id, method_name, lang, clear_warnings)
19
19
  end
20
20
 
21
21
  def self.json_schema_for_method_response(controller_name, method_name, return_code, allow_nulls)
@@ -24,7 +24,7 @@ module Apipie
24
24
  app.json_schema_for_method_response(version, controller_name, method_name, return_code, allow_nulls)
25
25
  end
26
26
 
27
- def self.json_schema_for_self_describing_class(cls, allow_nulls=true)
27
+ def self.json_schema_for_self_describing_class(cls, allow_nulls = true)
28
28
  app.json_schema_for_self_describing_class(cls, allow_nulls)
29
29
  end
30
30
 
@@ -70,11 +70,11 @@ module Apipie
70
70
  end
71
71
 
72
72
  def self.app_info_version_valid?(version)
73
- version && self.configuration.app_info.has_key?(version)
73
+ version && self.configuration.app_info.key?(version)
74
74
  end
75
75
 
76
76
  def self.api_base_url_version_valid?(version)
77
- version && self.configuration.api_base_url.has_key?(version)
77
+ version && self.configuration.api_base_url.key?(version)
78
78
  end
79
79
 
80
80
  def self.record(record)
@@ -25,49 +25,46 @@ module Apipie
25
25
  @resource_descriptions.keys.sort
26
26
  end
27
27
 
28
- def set_resource_id(controller, resource_id)
29
- @controller_to_resource_id[controller] = resource_id
30
- end
31
-
32
28
  def rails_routes(route_set = nil, base_url = "")
33
- if route_set.nil? && @rails_routes
34
- return @rails_routes
35
- end
29
+ return @_rails_routes if route_set.nil? && @_rails_routes
30
+
36
31
  route_set ||= Rails.application.routes
37
32
  # ensure routes are loaded
38
33
  Rails.application.reload_routes! unless Rails.application.routes.routes.any?
39
34
 
40
- flatten_routes = []
35
+ flattened_routes = []
41
36
 
42
37
  route_set.routes.each do |route|
43
- # This is a hack to workaround a bug in apipie with Rails 4.2.5.1 or newer. See https://github.com/Apipie/apipie-rails/issues/415
44
- route_app = Rails::VERSION::STRING.to_f >= 4.2 ? route.app.app : route.app
38
+ # route is_a ActionDispatch::Journey::Route
39
+ # route.app is_a ActionDispatch::Routing::Mapper::Constraints
40
+ # route.app.app is_a TestEngine::Engine
41
+ route_app = route.app.app
45
42
  if route_app.respond_to?(:routes) && route_app.routes.is_a?(ActionDispatch::Routing::RouteSet)
46
43
  # recursively go though the mounted engines
47
- flatten_routes.concat(rails_routes(route_app.routes, File.join(base_url, route.path.spec.to_s)))
44
+ flattened_routes.concat(rails_routes(route_app.routes, File.join(base_url, route.path.spec.to_s)))
48
45
  else
49
46
  route.base_url = base_url
50
- flatten_routes << route
47
+ flattened_routes << route
51
48
  end
52
49
  end
53
50
 
54
- @rails_routes = flatten_routes
51
+ @_rails_routes = flattened_routes
55
52
  end
56
53
 
57
- # the app might be nested when using contraints, namespaces etc.
58
- # this method does in depth search for the route controller
59
- def route_app_controller(app, route, visited_apps = [])
60
- if route.defaults[:controller]
61
- controller_name = "#{route.defaults[:controller]}_controller".camelize
62
- controller_name.safe_constantize
54
+ def rails_routes_by_controller_and_action
55
+ @_rails_routes_by_controller_and_action = rails_routes.group_by do |route|
56
+ requirements = route.requirements
57
+ [requirements[:controller], requirements[:action]]
63
58
  end
64
59
  end
65
60
 
61
+ def clear_cached_routes!
62
+ @_rails_routes = nil
63
+ @_rails_routes_by_controller_and_action = nil
64
+ end
65
+
66
66
  def routes_for_action(controller, method, args)
67
- routes = rails_routes.select do |route|
68
- controller == route_app_controller(route.app, route) &&
69
- method.to_s == route.defaults[:action]
70
- end
67
+ routes = rails_routes_by_controller_and_action[[controller.name.underscore.chomp('_controller'), method.to_s]] || []
71
68
 
72
69
  Apipie.configuration.routes_formatter.format_routes(routes, args)
73
70
  end
@@ -81,8 +78,8 @@ module Apipie
81
78
  versions = controller_versions(controller) if versions.empty?
82
79
 
83
80
  versions.each do |version|
84
- resource_name_with_version = "#{version}##{get_resource_name(controller)}"
85
- resource_description = get_resource_description(resource_name_with_version)
81
+ resource_id_with_version = "#{version}##{get_resource_id(controller)}"
82
+ resource_description = get_resource_description(resource_id_with_version)
86
83
 
87
84
  if resource_description.nil?
88
85
  resource_description = define_resource_description(controller, version)
@@ -98,24 +95,24 @@ module Apipie
98
95
  resource_description.add_method_description(method_description)
99
96
  end
100
97
 
101
- return ret_method_description
98
+ ret_method_description
102
99
  end
103
100
 
104
101
  # create new resource api description
105
102
  def define_resource_description(controller, version, dsl_data = nil)
106
103
  return if ignored?(controller)
107
104
 
108
- resource_name = get_resource_name(controller)
109
- resource_description = @resource_descriptions[version][resource_name]
105
+ resource_id = get_resource_id(controller)
106
+ resource_description = @resource_descriptions[version][resource_id]
110
107
  if resource_description
111
108
  # we already defined the description somewhere (probably in
112
109
  # some method. Updating just meta data from dsl
113
110
  resource_description.update_from_dsl_data(dsl_data) if dsl_data
114
111
  else
115
- resource_description = Apipie::ResourceDescription.new(controller, resource_name, dsl_data, version)
112
+ resource_description = Apipie::ResourceDescription.new(controller, resource_id, dsl_data, version)
116
113
 
117
- Apipie.debug("@resource_descriptions[#{version}][#{resource_name}] = #{resource_description}")
118
- @resource_descriptions[version][resource_name] ||= resource_description
114
+ Apipie.debug("@resource_descriptions[#{version}][#{resource_id}] = #{resource_description}")
115
+ @resource_descriptions[version][resource_id] ||= resource_description
119
116
  end
120
117
 
121
118
  return resource_description
@@ -125,15 +122,26 @@ module Apipie
125
122
  # resource_description? It's used to derivate the default value of
126
123
  # versions for methods.
127
124
  def controller_versions(controller)
128
- ret = @controller_versions[controller.to_s]
129
- return ret unless ret.empty?
130
- if controller == ActionController::Base || controller.nil?
131
- return [Apipie.configuration.default_version]
132
- else
133
- return controller_versions(controller.to_s.constantize.superclass)
125
+ value_from_parents(controller, default: [Apipie.configuration.default_version]) do |c|
126
+ ret = @controller_versions[c.to_s]
127
+ ret unless ret.empty?
134
128
  end
135
129
  end
136
130
 
131
+ # Recursively walks up the controller hierarchy looking for a value
132
+ # from the block.
133
+ # Stops at ActionController::Base.
134
+ # @param [Class] controller controller to start from
135
+ # @param [Array] args arguments passed to the block
136
+ # @param [Object] default default value to return if no value is found
137
+ # @param [Proc] block block to call with controller and args
138
+ def value_from_parents(controller, *args, default: nil, &block)
139
+ return default if controller == ActionController::Base || controller == AbstractController::Base || controller.nil?
140
+
141
+ thing = yield(controller, *args)
142
+ thing || value_from_parents(controller.superclass, *args, default: default, &block)
143
+ end
144
+
137
145
  def set_controller_versions(controller, versions)
138
146
  @controller_versions[controller.to_s] = versions
139
147
  end
@@ -145,7 +153,7 @@ module Apipie
145
153
 
146
154
  def get_param_group(controller, name)
147
155
  key = "#{controller.name}##{name}"
148
- if @param_groups.has_key?(key)
156
+ if @param_groups.key?(key)
149
157
  return @param_groups[key]
150
158
  else
151
159
  raise "param group #{key} not defined"
@@ -156,34 +164,32 @@ module Apipie
156
164
  #
157
165
  # There are two ways how this method can be used:
158
166
  # 1) Specify both parameters
159
- # resource_name:
167
+ # resource_id:
160
168
  # controller class - UsersController
161
169
  # string with resource name (plural) and version - "v1#users"
162
170
  # method_name: name of the method (string or symbol)
163
171
  #
164
172
  # 2) Specify only first parameter:
165
- # resource_name: string containing both resource and method name joined
173
+ # resource_id: string containing both resource and method name joined
166
174
  # with '#' symbol.
167
175
  # - "users#create" get default version
168
176
  # - "v2#users#create" get specific version
169
- def get_method_description(resource_name, method_name = nil)
170
- if resource_name.is_a?(String)
171
- crumbs = resource_name.split('#')
177
+ def get_method_description(resource_id, method_name = nil)
178
+ if resource_id.is_a?(String)
179
+ crumbs = resource_id.split('#')
172
180
  if method_name.nil?
173
181
  method_name = crumbs.pop
174
182
  end
175
- resource_name = crumbs.join("#")
176
- resource_description = get_resource_description(resource_name)
177
- elsif resource_name.respond_to? :apipie_resource_descriptions
178
- resource_description = get_resource_description(resource_name)
183
+ resource_id = crumbs.join("#")
184
+ resource_description = get_resource_description(resource_id)
185
+ elsif resource_id.respond_to? :apipie_resource_descriptions
186
+ resource_description = get_resource_description(resource_id)
179
187
  else
180
- raise ArgumentError.new("Resource #{resource_name} does not exists.")
181
- end
182
- unless resource_description.nil?
183
- resource_description.method_description(method_name.to_sym)
188
+ raise ArgumentError.new("Resource #{resource_id} does not exists.")
184
189
  end
190
+ resource_description&.method_description(method_name.to_sym)
185
191
  end
186
- alias :[] :get_method_description
192
+ alias [] get_method_description
187
193
 
188
194
  # options:
189
195
  # => "users"
@@ -196,19 +202,19 @@ module Apipie
196
202
  version = crumbs.first
197
203
  end
198
204
  version ||= Apipie.configuration.default_version
199
- if @resource_descriptions.has_key?(version)
205
+ if @resource_descriptions.key?(version)
200
206
  return @resource_descriptions[version][crumbs.last]
201
207
  end
202
208
  else
203
- resource_name = get_resource_name(resource)
209
+ resource_id = get_resource_id(resource)
204
210
  if version
205
- resource_name = "#{version}##{resource_name}"
211
+ resource_id = "#{version}##{resource_id}"
206
212
  end
207
213
 
208
- if resource_name.nil?
214
+ if resource_id.nil?
209
215
  return nil
210
216
  end
211
- resource_description = get_resource_description(resource_name)
217
+ resource_description = get_resource_description(resource_id)
212
218
  if resource_description && resource_description.controller.to_s == resource.to_s
213
219
  return resource_description
214
220
  end
@@ -231,7 +237,7 @@ module Apipie
231
237
 
232
238
  def remove_method_description(resource, versions, method_name)
233
239
  versions.each do |version|
234
- resource = get_resource_name(resource)
240
+ resource = get_resource_id(resource)
235
241
  if resource_description = get_resource_description("#{version}##{resource}")
236
242
  resource_description.remove_method_description(method_name)
237
243
  end
@@ -240,13 +246,12 @@ module Apipie
240
246
 
241
247
  # initialize variables for gathering dsl data
242
248
  def init_env
243
- @resource_descriptions ||= HashWithIndifferentAccess.new { |h, version| h[version] = {} }
244
- @controller_to_resource_id ||= {}
245
- @param_groups ||= {}
246
- @swagger_generator = Apipie::SwaggerGenerator.new(self)
249
+ @resource_descriptions = ActiveSupport::HashWithIndifferentAccess.new { |h, version| h[version] = {} }
250
+ @controller_to_resource_id = {}
251
+ @param_groups = {}
247
252
 
248
253
  # what versions does the controller belong in (specified by resource_description)?
249
- @controller_versions ||= Hash.new { |h, controller| h[controller.to_s] = [] }
254
+ @controller_versions = Hash.new { |h, controller| h[controller.to_s] = [] }
250
255
  end
251
256
 
252
257
  def recorded_examples
@@ -261,36 +266,41 @@ module Apipie
261
266
  def json_schema_for_method_response(version, controller_name, method_name, return_code, allow_nulls)
262
267
  method = @resource_descriptions[version][controller_name].method_description(method_name)
263
268
  raise NoDocumentedMethod.new(controller_name, method_name) if method.nil?
264
- @swagger_generator.json_schema_for_method_response(method, return_code, allow_nulls)
269
+
270
+ Apipie::SwaggerGenerator
271
+ .json_schema_for_method_response(method, return_code, allow_nulls)
265
272
  end
266
273
 
267
274
  def json_schema_for_self_describing_class(cls, allow_nulls)
268
- @swagger_generator.json_schema_for_self_describing_class(cls, allow_nulls)
275
+ Apipie::SwaggerGenerator
276
+ .json_schema_for_self_describing_class(cls, allow_nulls)
269
277
  end
270
278
 
271
- def to_swagger_json(version, resource_name, method_name, lang, clear_warnings=false)
272
- return unless valid_search_args?(version, resource_name, method_name)
279
+ def to_swagger_json(version, resource_id, method_name, language, clear_warnings = false)
280
+ return unless valid_search_args?(version, resource_id, method_name)
273
281
 
274
- # if resource_name is blank, take just resources which have some methods because
275
- # we dont want to show eg ApplicationController as resource
276
- # otherwise, take only the specified resource
277
- _resources = resource_descriptions[version].inject({}) do |result, (k,v)|
278
- if resource_name.blank?
279
- result[k] = v unless v._methods.blank?
280
- else
281
- result[k] = v if k == resource_name
282
- end
283
- result
284
- end
282
+ resources =
283
+ Apipie::Generator::Swagger::ResourceDescriptionsCollection
284
+ .new(resource_descriptions)
285
+ .filter(
286
+ resource_id: resource_id,
287
+ method_name: method_name,
288
+ version: version
289
+ )
285
290
 
286
- @swagger_generator.generate_from_resources(version,_resources, method_name, lang, clear_warnings)
291
+ Apipie::SwaggerGenerator.generate_from_resources(
292
+ resources,
293
+ version: version,
294
+ language: language,
295
+ clear_warnings: clear_warnings
296
+ )
287
297
  end
288
298
 
289
- def to_json(version, resource_name, method_name, lang)
299
+ def to_json(version, resource_id, method_name, lang)
290
300
 
291
- return unless valid_search_args?(version, resource_name, method_name)
301
+ return unless valid_search_args?(version, resource_id, method_name)
292
302
 
293
- _resources = if resource_name.blank?
303
+ _resources = if resource_id.blank?
294
304
  # take just resources which have some methods because
295
305
  # we dont want to show eg ApplicationController as resource
296
306
  resource_descriptions[version].inject({}) do |result, (k,v)|
@@ -298,7 +308,7 @@ module Apipie
298
308
  result
299
309
  end
300
310
  else
301
- [@resource_descriptions[version][resource_name].to_json(method_name, lang)]
311
+ [@resource_descriptions[version][resource_id].to_json(method_name, lang)]
302
312
  end
303
313
 
304
314
  url_args = Apipie.configuration.version_in_url ? version : ''
@@ -368,15 +378,39 @@ module Apipie
368
378
  Apipie.configuration.validate? || ! Apipie.configuration.use_cache? || Apipie.configuration.force_dsl?
369
379
  end
370
380
 
381
+ # @deprecated Use {#get_resource_id} instead
371
382
  def get_resource_name(klass)
383
+ ActiveSupport::Deprecation.warn(
384
+ <<~HEREDOC
385
+ Apipie::Application.get_resource_name is deprecated.
386
+ Use `Apipie::Application.get_resource_id instead.
387
+ HEREDOC
388
+ )
389
+
390
+ get_resource_id(klass)
391
+ end
392
+
393
+ def set_resource_id(controller, resource_id)
394
+ @controller_to_resource_id[controller] = resource_id
395
+ end
396
+
397
+ def get_resource_id(klass)
372
398
  if klass.class == String
373
399
  klass
374
- elsif @controller_to_resource_id.has_key?(klass)
400
+ elsif @controller_to_resource_id.key?(klass)
375
401
  @controller_to_resource_id[klass]
376
402
  elsif Apipie.configuration.namespaced_resources? && klass.respond_to?(:controller_path)
377
403
  return nil if klass == ActionController::Base
404
+
405
+ version_prefix = version_prefix(klass)
378
406
  path = klass.controller_path
379
- path.gsub(version_prefix(klass), "").gsub("/", "-")
407
+
408
+ unless version_prefix == '/'
409
+ path =
410
+ path.gsub(version_prefix, '')
411
+ end
412
+
413
+ path.gsub('/', '-')
380
414
  elsif klass.respond_to?(:controller_name)
381
415
  return nil if klass == ActionController::Base
382
416
  klass.controller_name
@@ -386,11 +420,11 @@ module Apipie
386
420
  end
387
421
 
388
422
  def locale
389
- Apipie.configuration.locale.call(nil) if Apipie.configuration.locale
423
+ Apipie.configuration.locale&.call(nil)
390
424
  end
391
425
 
392
426
  def locale=(locale)
393
- Apipie.configuration.locale.call(locale) if Apipie.configuration.locale
427
+ Apipie.configuration.locale&.call(locale)
394
428
  end
395
429
 
396
430
  def translate(str, locale)
@@ -403,14 +437,14 @@ module Apipie
403
437
 
404
438
  private
405
439
 
406
- # Make sure that the version/resource_name/method_name are valid combination
407
- # resource_name and method_name can be nil
408
- def valid_search_args?(version, resource_name, method_name)
409
- return false unless self.resource_descriptions.has_key?(version)
410
- if resource_name
411
- return false unless self.resource_descriptions[version].has_key?(resource_name)
440
+ # Make sure that the version/resource_id/method_name are valid combination
441
+ # resource_id and method_name can be nil
442
+ def valid_search_args?(version, resource_id, method_name)
443
+ return false unless self.resource_descriptions.key?(version)
444
+ if resource_id
445
+ return false unless self.resource_descriptions[version].key?(resource_id)
412
446
  if method_name
413
- resource_description = self.resource_descriptions[version][resource_name]
447
+ resource_description = self.resource_descriptions[version][resource_id]
414
448
  return false unless resource_description.valid_method_name?(method_name)
415
449
  end
416
450
  end
@@ -418,7 +452,7 @@ module Apipie
418
452
  end
419
453
 
420
454
  def version_prefix(klass)
421
- version = controller_versions(klass.to_s).first
455
+ version = controller_versions(klass).first
422
456
  base_url = get_base_url(version)
423
457
  return "/" if base_url.blank?
424
458
  base_url[1..-1] + "/"
@@ -456,10 +490,11 @@ module Apipie
456
490
  # as this would break loading of the controllers.
457
491
  def rails_mark_classes_for_reload
458
492
  unless Rails.application.config.cache_classes
459
- Rails::VERSION::MAJOR == 4 ? ActionDispatch::Reloader.cleanup! : Rails.application.reloader.reload!
493
+ clear_cached_routes!
494
+ Rails.application.reloader.reload!
460
495
  init_env
461
496
  reload_examples
462
- Rails::VERSION::MAJOR == 4 ? ActionDispatch::Reloader.prepare! : Rails.application.reloader.prepare!
497
+ Rails.application.reloader.prepare!
463
498
  end
464
499
  end
465
500