apipierails3 0.0.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.
- checksums.yaml +17 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +27 -0
- data/APACHE-LICENSE-2.0 +202 -0
- data/CHANGELOG.md +469 -0
- data/Gemfile +1 -0
- data/Gemfile.rails32 +6 -0
- data/Gemfile.rails41 +6 -0
- data/Gemfile.rails42 +11 -0
- data/Gemfile.rails50 +6 -0
- data/Gemfile.rails51 +7 -0
- data/MIT-LICENSE +20 -0
- data/NOTICE +4 -0
- data/PROPOSAL_FOR_RESPONSE_DESCRIPTIONS.md +244 -0
- data/README.rst +1874 -0
- data/Rakefile +13 -0
- data/apipierails3.gemspec +27 -0
- data/app/controllers/apipie/apipies_controller.rb +199 -0
- data/app/helpers/apipie_helper.rb +10 -0
- data/app/public/apipie/javascripts/apipie.js +6 -0
- data/app/public/apipie/javascripts/bundled/bootstrap-collapse.js +138 -0
- data/app/public/apipie/javascripts/bundled/bootstrap.js +1726 -0
- data/app/public/apipie/javascripts/bundled/jquery.js +5 -0
- data/app/public/apipie/javascripts/bundled/prettify.js +28 -0
- data/app/public/apipie/stylesheets/application.css +7 -0
- data/app/public/apipie/stylesheets/bundled/bootstrap-responsive.min.css +12 -0
- data/app/public/apipie/stylesheets/bundled/bootstrap.min.css +689 -0
- data/app/public/apipie/stylesheets/bundled/prettify.css +30 -0
- data/app/views/apipie/apipies/_disqus.html.erb +13 -0
- data/app/views/apipie/apipies/_errors.html.erb +23 -0
- data/app/views/apipie/apipies/_headers.html.erb +26 -0
- data/app/views/apipie/apipies/_languages.erb +6 -0
- data/app/views/apipie/apipies/_metadata.erb +1 -0
- data/app/views/apipie/apipies/_method_detail.erb +61 -0
- data/app/views/apipie/apipies/_params.html.erb +42 -0
- data/app/views/apipie/apipies/_params_plain.html.erb +20 -0
- data/app/views/apipie/apipies/apipie_404.html.erb +17 -0
- data/app/views/apipie/apipies/apipie_checksum.json.erb +1 -0
- data/app/views/apipie/apipies/getting_started.html.erb +6 -0
- data/app/views/apipie/apipies/index.html.erb +56 -0
- data/app/views/apipie/apipies/method.html.erb +41 -0
- data/app/views/apipie/apipies/plain.html.erb +77 -0
- data/app/views/apipie/apipies/resource.html.erb +80 -0
- data/app/views/apipie/apipies/static.html.erb +103 -0
- data/app/views/layouts/apipie/apipie.html.erb +27 -0
- data/config/locales/de.yml +28 -0
- data/config/locales/en.yml +32 -0
- data/config/locales/es.yml +28 -0
- data/config/locales/fr.yml +31 -0
- data/config/locales/it.yml +31 -0
- data/config/locales/ja.yml +31 -0
- data/config/locales/pl.yml +28 -0
- data/config/locales/pt-BR.yml +28 -0
- data/config/locales/ru.yml +28 -0
- data/config/locales/tr.yml +28 -0
- data/config/locales/zh-CN.yml +28 -0
- data/config/locales/zh-TW.yml +28 -0
- data/images/screenshot-1.png +0 -0
- data/images/screenshot-2.png +0 -0
- data/lib/apipie/apipie_module.rb +83 -0
- data/lib/apipie/application.rb +462 -0
- data/lib/apipie/configuration.rb +186 -0
- data/lib/apipie/dsl_definition.rb +607 -0
- data/lib/apipie/error_description.rb +44 -0
- data/lib/apipie/errors.rb +86 -0
- data/lib/apipie/extractor.rb +177 -0
- data/lib/apipie/extractor/collector.rb +117 -0
- data/lib/apipie/extractor/recorder.rb +166 -0
- data/lib/apipie/extractor/writer.rb +454 -0
- data/lib/apipie/helpers.rb +73 -0
- data/lib/apipie/markup.rb +48 -0
- data/lib/apipie/method_description.rb +273 -0
- data/lib/apipie/middleware/checksum_in_headers.rb +35 -0
- data/lib/apipie/param_description.rb +280 -0
- data/lib/apipie/railtie.rb +9 -0
- data/lib/apipie/resource_description.rb +124 -0
- data/lib/apipie/response_description.rb +131 -0
- data/lib/apipie/response_description_adapter.rb +200 -0
- data/lib/apipie/routes_formatter.rb +33 -0
- data/lib/apipie/routing.rb +16 -0
- data/lib/apipie/rspec/response_validation_helper.rb +192 -0
- data/lib/apipie/see_description.rb +39 -0
- data/lib/apipie/static_dispatcher.rb +69 -0
- data/lib/apipie/swagger_generator.rb +707 -0
- data/lib/apipie/tag_list_description.rb +11 -0
- data/lib/apipie/validator.rb +526 -0
- data/lib/apipie/version.rb +3 -0
- data/lib/apipierails3.rb +25 -0
- data/lib/generators/apipie/install/README +6 -0
- data/lib/generators/apipie/install/install_generator.rb +25 -0
- data/lib/generators/apipie/install/templates/initializer.rb.erb +7 -0
- data/lib/generators/apipie/views_generator.rb +11 -0
- data/lib/tasks/apipie.rake +345 -0
- data/rel-eng/packages/.readme +3 -0
- data/rel-eng/packages/rubygem-apipie-rails +1 -0
- data/rel-eng/tito.props +5 -0
- data/spec/controllers/api/v1/architectures_controller_spec.rb +29 -0
- data/spec/controllers/api/v2/architectures_controller_spec.rb +12 -0
- data/spec/controllers/api/v2/nested/resources_controller_spec.rb +11 -0
- data/spec/controllers/apipies_controller_spec.rb +273 -0
- data/spec/controllers/concerns_controller_spec.rb +42 -0
- data/spec/controllers/extended_controller_spec.rb +11 -0
- data/spec/controllers/users_controller_spec.rb +740 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/api/base_controller.rb +4 -0
- data/spec/dummy/app/controllers/api/v1/architectures_controller.rb +43 -0
- data/spec/dummy/app/controllers/api/v1/base_controller.rb +11 -0
- data/spec/dummy/app/controllers/api/v2/architectures_controller.rb +30 -0
- data/spec/dummy/app/controllers/api/v2/base_controller.rb +11 -0
- data/spec/dummy/app/controllers/api/v2/nested/architectures_controller.rb +32 -0
- data/spec/dummy/app/controllers/api/v2/nested/resources_controller.rb +33 -0
- data/spec/dummy/app/controllers/application_controller.rb +18 -0
- data/spec/dummy/app/controllers/concerns/extending_concern.rb +11 -0
- data/spec/dummy/app/controllers/concerns/sample_controller.rb +41 -0
- data/spec/dummy/app/controllers/concerns_controller.rb +8 -0
- data/spec/dummy/app/controllers/extended_controller.rb +14 -0
- data/spec/dummy/app/controllers/files_controller.rb +5 -0
- data/spec/dummy/app/controllers/overridden_concerns_controller.rb +31 -0
- data/spec/dummy/app/controllers/pets_controller.rb +408 -0
- data/spec/dummy/app/controllers/pets_using_auto_views_controller.rb +73 -0
- data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +95 -0
- data/spec/dummy/app/controllers/tagged_cats_controller.rb +32 -0
- data/spec/dummy/app/controllers/tagged_dogs_controller.rb +15 -0
- data/spec/dummy/app/controllers/twitter_example_controller.rb +307 -0
- data/spec/dummy/app/controllers/users_controller.rb +297 -0
- data/spec/dummy/app/views/layouts/application.html.erb +21 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +49 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +21 -0
- data/spec/dummy/config/environment.rb +8 -0
- data/spec/dummy/config/environments/development.rb +28 -0
- data/spec/dummy/config/environments/production.rb +52 -0
- data/spec/dummy/config/environments/test.rb +38 -0
- data/spec/dummy/config/initializers/apipie.rb +110 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +8 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +51 -0
- data/spec/dummy/db/.gitkeep +0 -0
- data/spec/dummy/doc/apipie_examples.json +1 -0
- data/spec/dummy/doc/users/desc_from_file.md +1 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/stylesheets/.gitkeep +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/lib/application_spec.rb +49 -0
- data/spec/lib/extractor/extractor_spec.rb +9 -0
- data/spec/lib/extractor/middleware_spec.rb +44 -0
- data/spec/lib/extractor/writer_spec.rb +110 -0
- data/spec/lib/file_handler_spec.rb +18 -0
- data/spec/lib/method_description_spec.rb +98 -0
- data/spec/lib/param_description_spec.rb +345 -0
- data/spec/lib/param_group_spec.rb +60 -0
- data/spec/lib/rake_spec.rb +71 -0
- data/spec/lib/resource_description_spec.rb +48 -0
- data/spec/lib/swagger/openapi_2_0_schema.json +1607 -0
- data/spec/lib/swagger/rake_swagger_spec.rb +139 -0
- data/spec/lib/swagger/response_validation_spec.rb +104 -0
- data/spec/lib/swagger/swagger_dsl_spec.rb +658 -0
- data/spec/lib/validator_spec.rb +113 -0
- data/spec/lib/validators/array_validator_spec.rb +85 -0
- data/spec/spec_helper.rb +109 -0
- data/spec/support/rake.rb +21 -0
- metadata +415 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'zh-TW':
|
|
2
|
+
apipie:
|
|
3
|
+
resources: 資源
|
|
4
|
+
resource: 資源
|
|
5
|
+
description: 描述
|
|
6
|
+
no_docs_found: 沒有找到文檔
|
|
7
|
+
no_docs_found_descr: 沒有找到文檔。
|
|
8
|
+
follow_instructions_html: 點擊 %{href} 查看描述。
|
|
9
|
+
follow_instructions_href: 高級指導
|
|
10
|
+
oops: 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: 允許空值
|
|
18
|
+
param_name: 參數名字
|
|
19
|
+
params: 參數
|
|
20
|
+
examples: 示例
|
|
21
|
+
metadata: 元數據
|
|
22
|
+
errors: 錯誤
|
|
23
|
+
supported_formats: 支持格式
|
|
24
|
+
enable_javascript_html: 瀏覽 %{comments_href}前請允許執行 JavaScript 。
|
|
25
|
+
comments_powered_by_disqus: 評論技術支持 %{disqus}
|
|
26
|
+
api_documentation: API 文檔
|
|
27
|
+
headers: 頭部
|
|
28
|
+
header_name: 頭部名字
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require "apipie/helpers"
|
|
2
|
+
require "apipie/application"
|
|
3
|
+
|
|
4
|
+
module Apipie
|
|
5
|
+
extend Apipie::Helpers
|
|
6
|
+
|
|
7
|
+
def self.app
|
|
8
|
+
@application ||= Apipie::Application.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.to_json(version = nil, resource_name = nil, method_name = nil, lang = nil)
|
|
12
|
+
version ||= Apipie.configuration.default_version
|
|
13
|
+
app.to_json(version, resource_name, method_name, lang)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.to_swagger_json(version = nil, resource_name = nil, method_name = nil, lang = nil, clear_warnings=true)
|
|
17
|
+
version ||= Apipie.configuration.default_version
|
|
18
|
+
app.to_swagger_json(version, resource_name, method_name, lang, clear_warnings)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.json_schema_for_method_response(controller_name, method_name, return_code, allow_nulls)
|
|
22
|
+
# note: this does not support versions (only the default version is queried)!
|
|
23
|
+
version ||= Apipie.configuration.default_version
|
|
24
|
+
app.json_schema_for_method_response(version, controller_name, method_name, return_code, allow_nulls)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.json_schema_for_self_describing_class(cls, allow_nulls=true)
|
|
28
|
+
app.json_schema_for_self_describing_class(cls, allow_nulls)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# all calls delegated to Apipie::Application instance
|
|
33
|
+
def self.method_missing(method, *args, &block)
|
|
34
|
+
app.respond_to?(method) ? app.send(method, *args, &block) : super
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.configure
|
|
38
|
+
yield configuration
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.configuration
|
|
42
|
+
@configuration ||= Configuration.new
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.debug(message)
|
|
46
|
+
puts message if Apipie.configuration.debug
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# get application description for given or default version
|
|
50
|
+
def self.app_info(version = nil, lang = nil)
|
|
51
|
+
info = if app_info_version_valid? version
|
|
52
|
+
translate(self.configuration.app_info[version], lang)
|
|
53
|
+
elsif app_info_version_valid? Apipie.configuration.default_version
|
|
54
|
+
translate(self.configuration.app_info[Apipie.configuration.default_version], lang)
|
|
55
|
+
else
|
|
56
|
+
"Another API description"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
Apipie.markup_to_html info
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.api_base_url(version = nil)
|
|
63
|
+
if api_base_url_version_valid? version
|
|
64
|
+
self.configuration.api_base_url[version]
|
|
65
|
+
elsif api_base_url_version_valid? Apipie.configuration.default_version
|
|
66
|
+
self.configuration.api_base_url[Apipie.configuration.default_version]
|
|
67
|
+
else
|
|
68
|
+
"/api"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self.app_info_version_valid?(version)
|
|
73
|
+
version && self.configuration.app_info.has_key?(version)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.api_base_url_version_valid?(version)
|
|
77
|
+
version && self.configuration.api_base_url.has_key?(version)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def self.record(record)
|
|
81
|
+
Apipie::Extractor.start record
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
require 'apipie/static_dispatcher'
|
|
2
|
+
require 'apipie/routes_formatter'
|
|
3
|
+
require 'yaml'
|
|
4
|
+
require 'digest/sha1'
|
|
5
|
+
require 'json'
|
|
6
|
+
|
|
7
|
+
module Apipie
|
|
8
|
+
|
|
9
|
+
class Application
|
|
10
|
+
# we need engine just for serving static assets
|
|
11
|
+
class Engine < Rails::Engine
|
|
12
|
+
initializer "static assets", :before => :build_middleware_stack do |app|
|
|
13
|
+
app.middleware.use ::Apipie::StaticDispatcher, "#{root}/app/public"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
attr_reader :resource_descriptions
|
|
18
|
+
|
|
19
|
+
def initialize
|
|
20
|
+
super
|
|
21
|
+
init_env
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def available_versions
|
|
25
|
+
@resource_descriptions.keys.sort
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def set_resource_id(controller, resource_id)
|
|
29
|
+
@controller_to_resource_id[controller] = resource_id
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def rails_routes(route_set = nil)
|
|
33
|
+
if route_set.nil? && @rails_routes
|
|
34
|
+
return @rails_routes
|
|
35
|
+
end
|
|
36
|
+
route_set ||= Rails.application.routes
|
|
37
|
+
# ensure routes are loaded
|
|
38
|
+
Rails.application.reload_routes! unless Rails.application.routes.routes.any?
|
|
39
|
+
|
|
40
|
+
flatten_routes = []
|
|
41
|
+
|
|
42
|
+
route_set.routes.each do |route|
|
|
43
|
+
if route.app.respond_to?(:routes) && route.app.routes.is_a?(ActionDispatch::Routing::RouteSet)
|
|
44
|
+
# recursively go though the moutned engines
|
|
45
|
+
flatten_routes.concat(rails_routes(route.app.routes))
|
|
46
|
+
else
|
|
47
|
+
flatten_routes << route
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
@rails_routes = flatten_routes
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# the app might be nested when using contraints, namespaces etc.
|
|
55
|
+
# this method does in depth search for the route controller
|
|
56
|
+
def route_app_controller(app, route, visited_apps = [])
|
|
57
|
+
if route.defaults[:controller]
|
|
58
|
+
controller_name = "#{route.defaults[:controller]}_controller".camelize
|
|
59
|
+
controller_name.safe_constantize
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def routes_for_action(controller, method, args)
|
|
64
|
+
routes = rails_routes.select do |route|
|
|
65
|
+
controller == route_app_controller(route.app, route) &&
|
|
66
|
+
method.to_s == route.defaults[:action]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
Apipie.configuration.routes_formatter.format_routes(routes, args)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# create new method api description
|
|
73
|
+
def define_method_description(controller, method_name, dsl_data)
|
|
74
|
+
return if ignored?(controller, method_name)
|
|
75
|
+
ret_method_description = nil
|
|
76
|
+
|
|
77
|
+
versions = dsl_data[:api_versions] || []
|
|
78
|
+
versions = controller_versions(controller) if versions.empty?
|
|
79
|
+
|
|
80
|
+
versions.each do |version|
|
|
81
|
+
resource_name_with_version = "#{version}##{get_resource_name(controller)}"
|
|
82
|
+
resource_description = get_resource_description(resource_name_with_version)
|
|
83
|
+
|
|
84
|
+
if resource_description.nil?
|
|
85
|
+
resource_description = define_resource_description(controller, version)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
method_description = Apipie::MethodDescription.new(method_name, resource_description, dsl_data)
|
|
89
|
+
|
|
90
|
+
# we create separate method description for each version in
|
|
91
|
+
# case the method belongs to more versions. We return just one
|
|
92
|
+
# becuase the version doesn't matter for the purpose it's used
|
|
93
|
+
# (to wrap the original version with validators)
|
|
94
|
+
ret_method_description ||= method_description
|
|
95
|
+
resource_description.add_method_description(method_description)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
return ret_method_description
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# create new resource api description
|
|
102
|
+
def define_resource_description(controller, version, dsl_data = nil)
|
|
103
|
+
return if ignored?(controller)
|
|
104
|
+
|
|
105
|
+
resource_name = get_resource_name(controller)
|
|
106
|
+
resource_description = @resource_descriptions[version][resource_name]
|
|
107
|
+
if resource_description
|
|
108
|
+
# we already defined the description somewhere (probably in
|
|
109
|
+
# some method. Updating just meta data from dsl
|
|
110
|
+
resource_description.update_from_dsl_data(dsl_data) if dsl_data
|
|
111
|
+
else
|
|
112
|
+
resource_description = Apipie::ResourceDescription.new(controller, resource_name, dsl_data, version)
|
|
113
|
+
|
|
114
|
+
Apipie.debug("@resource_descriptions[#{version}][#{resource_name}] = #{resource_description}")
|
|
115
|
+
@resource_descriptions[version][resource_name] ||= resource_description
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
return resource_description
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# recursively searches what versions has the controller specified in
|
|
122
|
+
# resource_description? It's used to derivate the default value of
|
|
123
|
+
# versions for methods.
|
|
124
|
+
def controller_versions(controller)
|
|
125
|
+
ret = @controller_versions[controller.to_s]
|
|
126
|
+
return ret unless ret.empty?
|
|
127
|
+
if controller == ActionController::Base || controller.nil?
|
|
128
|
+
return [Apipie.configuration.default_version]
|
|
129
|
+
else
|
|
130
|
+
return controller_versions(controller.to_s.constantize.superclass)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def set_controller_versions(controller, versions)
|
|
135
|
+
@controller_versions[controller.to_s] = versions
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def add_param_group(controller, name, &block)
|
|
139
|
+
key = "#{controller.name}##{name}"
|
|
140
|
+
@param_groups[key] = block
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def get_param_group(controller, name)
|
|
144
|
+
key = "#{controller.name}##{name}"
|
|
145
|
+
if @param_groups.has_key?(key)
|
|
146
|
+
return @param_groups[key]
|
|
147
|
+
else
|
|
148
|
+
raise "param group #{key} not defined"
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# get api for given method
|
|
153
|
+
#
|
|
154
|
+
# There are two ways how this method can be used:
|
|
155
|
+
# 1) Specify both parameters
|
|
156
|
+
# resource_name:
|
|
157
|
+
# controller class - UsersController
|
|
158
|
+
# string with resource name (plural) and version - "v1#users"
|
|
159
|
+
# method_name: name of the method (string or symbol)
|
|
160
|
+
#
|
|
161
|
+
# 2) Specify only first parameter:
|
|
162
|
+
# resource_name: string containing both resource and method name joined
|
|
163
|
+
# with '#' symbol.
|
|
164
|
+
# - "users#create" get default version
|
|
165
|
+
# - "v2#users#create" get specific version
|
|
166
|
+
def get_method_description(resource_name, method_name = nil)
|
|
167
|
+
if resource_name.is_a?(String)
|
|
168
|
+
crumbs = resource_name.split('#')
|
|
169
|
+
if method_name.nil?
|
|
170
|
+
method_name = crumbs.pop
|
|
171
|
+
end
|
|
172
|
+
resource_name = crumbs.join("#")
|
|
173
|
+
resource_description = get_resource_description(resource_name)
|
|
174
|
+
elsif resource_name.respond_to? :apipie_resource_descriptions
|
|
175
|
+
resource_description = get_resource_description(resource_name)
|
|
176
|
+
else
|
|
177
|
+
raise ArgumentError.new("Resource #{resource_name} does not exists.")
|
|
178
|
+
end
|
|
179
|
+
unless resource_description.nil?
|
|
180
|
+
resource_description.method_description(method_name.to_sym)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
alias :[] :get_method_description
|
|
184
|
+
|
|
185
|
+
# options:
|
|
186
|
+
# => "users"
|
|
187
|
+
# => "v2#users"
|
|
188
|
+
# => V2::UsersController
|
|
189
|
+
def get_resource_description(resource, version = nil)
|
|
190
|
+
if resource.is_a?(String)
|
|
191
|
+
crumbs = resource.split('#')
|
|
192
|
+
if crumbs.size == 2
|
|
193
|
+
version = crumbs.first
|
|
194
|
+
end
|
|
195
|
+
version ||= Apipie.configuration.default_version
|
|
196
|
+
if @resource_descriptions.has_key?(version)
|
|
197
|
+
return @resource_descriptions[version][crumbs.last]
|
|
198
|
+
end
|
|
199
|
+
else
|
|
200
|
+
resource_name = get_resource_name(resource)
|
|
201
|
+
if version
|
|
202
|
+
resource_name = "#{version}##{resource_name}"
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
if resource_name.nil?
|
|
206
|
+
return nil
|
|
207
|
+
end
|
|
208
|
+
resource_description = get_resource_description(resource_name)
|
|
209
|
+
if resource_description && resource_description.controller.to_s == resource.to_s
|
|
210
|
+
return resource_description
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# get all versions of resource description
|
|
216
|
+
def get_resource_descriptions(resource)
|
|
217
|
+
available_versions.map do |version|
|
|
218
|
+
get_resource_description(resource, version)
|
|
219
|
+
end.compact
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# get all versions of method description
|
|
223
|
+
def get_method_descriptions(resource, method)
|
|
224
|
+
get_resource_descriptions(resource).map do |resource_description|
|
|
225
|
+
resource_description.method_description(method.to_sym)
|
|
226
|
+
end.compact
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def remove_method_description(resource, versions, method_name)
|
|
230
|
+
versions.each do |version|
|
|
231
|
+
resource = get_resource_name(resource)
|
|
232
|
+
if resource_description = get_resource_description("#{version}##{resource}")
|
|
233
|
+
resource_description.remove_method_description(method_name)
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# initialize variables for gathering dsl data
|
|
239
|
+
def init_env
|
|
240
|
+
@resource_descriptions ||= HashWithIndifferentAccess.new { |h, version| h[version] = {} }
|
|
241
|
+
@controller_to_resource_id ||= {}
|
|
242
|
+
@param_groups ||= {}
|
|
243
|
+
@swagger_generator = Apipie::SwaggerGenerator.new(self)
|
|
244
|
+
|
|
245
|
+
# what versions does the controller belong in (specified by resource_description)?
|
|
246
|
+
@controller_versions ||= Hash.new { |h, controller| h[controller.to_s] = [] }
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def recorded_examples
|
|
250
|
+
return @recorded_examples if @recorded_examples
|
|
251
|
+
@recorded_examples = Apipie::Extractor::Writer.load_recorded_examples
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def reload_examples
|
|
255
|
+
@recorded_examples = nil
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def json_schema_for_method_response(version, controller_name, method_name, return_code, allow_nulls)
|
|
259
|
+
method = @resource_descriptions[version][controller_name].method_description(method_name)
|
|
260
|
+
raise NoDocumentedMethod.new(controller_name, method_name) if method.nil?
|
|
261
|
+
@swagger_generator.json_schema_for_method_response(method, return_code, allow_nulls)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def json_schema_for_self_describing_class(cls, allow_nulls)
|
|
265
|
+
@swagger_generator.json_schema_for_self_describing_class(cls, allow_nulls)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def to_swagger_json(version, resource_name, method_name, lang, clear_warnings=false)
|
|
269
|
+
return unless valid_search_args?(version, resource_name, method_name)
|
|
270
|
+
|
|
271
|
+
# if resource_name is blank, take just resources which have some methods because
|
|
272
|
+
# we dont want to show eg ApplicationController as resource
|
|
273
|
+
# otherwise, take only the specified resource
|
|
274
|
+
_resources = resource_descriptions[version].inject({}) do |result, (k,v)|
|
|
275
|
+
if resource_name.blank?
|
|
276
|
+
result[k] = v unless v._methods.blank?
|
|
277
|
+
else
|
|
278
|
+
result[k] = v if k == resource_name
|
|
279
|
+
end
|
|
280
|
+
result
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
@swagger_generator.generate_from_resources(version,_resources, method_name, lang, clear_warnings)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def to_json(version, resource_name, method_name, lang)
|
|
287
|
+
|
|
288
|
+
return unless valid_search_args?(version, resource_name, method_name)
|
|
289
|
+
|
|
290
|
+
_resources = if resource_name.blank?
|
|
291
|
+
# take just resources which have some methods because
|
|
292
|
+
# we dont want to show eg ApplicationController as resource
|
|
293
|
+
resource_descriptions[version].inject({}) do |result, (k,v)|
|
|
294
|
+
result[k] = v.to_json(nil, lang) unless v._methods.blank?
|
|
295
|
+
result
|
|
296
|
+
end
|
|
297
|
+
else
|
|
298
|
+
[@resource_descriptions[version][resource_name].to_json(method_name, lang)]
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
url_args = Apipie.configuration.version_in_url ? version : ''
|
|
302
|
+
|
|
303
|
+
{
|
|
304
|
+
:docs => {
|
|
305
|
+
:name => Apipie.configuration.app_name,
|
|
306
|
+
:info => Apipie.app_info(version, lang),
|
|
307
|
+
:copyright => Apipie.configuration.copyright,
|
|
308
|
+
:doc_url => Apipie.full_url(url_args),
|
|
309
|
+
:api_url => Apipie.api_base_url(version),
|
|
310
|
+
:resources => _resources
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def api_controllers_paths
|
|
316
|
+
Dir.glob(Apipie.configuration.api_controllers_matcher)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def reload_documentation
|
|
320
|
+
# don't load translated strings, we'll translate them later
|
|
321
|
+
old_locale = locale
|
|
322
|
+
locale = Apipie.configuration.default_locale
|
|
323
|
+
|
|
324
|
+
rails_mark_classes_for_reload
|
|
325
|
+
|
|
326
|
+
api_controllers_paths.each do |f|
|
|
327
|
+
load_controller_from_file f
|
|
328
|
+
end
|
|
329
|
+
@checksum = nil if Apipie.configuration.update_checksum
|
|
330
|
+
|
|
331
|
+
locale = old_locale
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def load_documentation
|
|
335
|
+
if !@documentation_loaded || Apipie.configuration.reload_controllers?
|
|
336
|
+
Apipie.reload_documentation
|
|
337
|
+
@documentation_loaded = true
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def compute_checksum
|
|
342
|
+
if Apipie.configuration.use_cache?
|
|
343
|
+
file_base = File.join(Apipie.configuration.cache_dir, Apipie.configuration.doc_base_url)
|
|
344
|
+
all_docs = {}
|
|
345
|
+
Dir.glob(file_base + '/*.json').sort.each do |f|
|
|
346
|
+
all_docs[File.basename(f, '.json')] = JSON.parse(File.read(f))
|
|
347
|
+
end
|
|
348
|
+
else
|
|
349
|
+
load_documentation if available_versions == []
|
|
350
|
+
all_docs = Apipie.available_versions.inject({}) do |all, version|
|
|
351
|
+
all.update(version => Apipie.to_json(version))
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
Digest::SHA1.hexdigest(JSON.dump(all_docs))
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def checksum
|
|
358
|
+
@checksum ||= compute_checksum
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
# Is there a reason to interpret the DSL for this run?
|
|
362
|
+
# with specific setting for some environment there is no reason the dsl
|
|
363
|
+
# should be interpreted (e.g. no validations and doc from cache)
|
|
364
|
+
def active_dsl?
|
|
365
|
+
Apipie.configuration.validate? || ! Apipie.configuration.use_cache? || Apipie.configuration.force_dsl?
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def get_resource_name(klass)
|
|
369
|
+
if klass.class == String
|
|
370
|
+
klass
|
|
371
|
+
elsif @controller_to_resource_id.has_key?(klass)
|
|
372
|
+
@controller_to_resource_id[klass]
|
|
373
|
+
elsif Apipie.configuration.namespaced_resources? && klass.respond_to?(:controller_path)
|
|
374
|
+
return nil if klass == ActionController::Base
|
|
375
|
+
path = klass.controller_path
|
|
376
|
+
path.gsub(version_prefix(klass), "").gsub("/", "-")
|
|
377
|
+
elsif klass.respond_to?(:controller_name)
|
|
378
|
+
return nil if klass == ActionController::Base
|
|
379
|
+
klass.controller_name
|
|
380
|
+
else
|
|
381
|
+
raise "Apipie: Can not resolve resource #{klass} name."
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def locale
|
|
386
|
+
Apipie.configuration.locale.call(nil) if Apipie.configuration.locale
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def locale=(locale)
|
|
390
|
+
Apipie.configuration.locale.call(locale) if Apipie.configuration.locale
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def translate(str, locale)
|
|
394
|
+
if Apipie.configuration.translate
|
|
395
|
+
Apipie.configuration.translate.call(str, locale)
|
|
396
|
+
else
|
|
397
|
+
str
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
private
|
|
402
|
+
|
|
403
|
+
# Make sure that the version/resource_name/method_name are valid combination
|
|
404
|
+
# resource_name and method_name can be nil
|
|
405
|
+
def valid_search_args?(version, resource_name, method_name)
|
|
406
|
+
return false unless self.resource_descriptions.has_key?(version)
|
|
407
|
+
if resource_name
|
|
408
|
+
return false unless self.resource_descriptions[version].has_key?(resource_name)
|
|
409
|
+
if method_name
|
|
410
|
+
resource_description = self.resource_descriptions[version][resource_name]
|
|
411
|
+
return false unless resource_description.valid_method_name?(method_name)
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
return true
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def version_prefix(klass)
|
|
418
|
+
version = controller_versions(klass.to_s).first
|
|
419
|
+
base_url = get_base_url(version)
|
|
420
|
+
return "/" if base_url.blank?
|
|
421
|
+
base_url[1..-1] + "/"
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
def get_base_url(version)
|
|
425
|
+
Apipie.configuration.api_base_url[version]
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
def get_resource_version(resource_description)
|
|
429
|
+
if resource_description.respond_to? :_version
|
|
430
|
+
resource_description._version
|
|
431
|
+
else
|
|
432
|
+
Apipie.configuration.default_version
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
def load_controller_from_file(controller_file)
|
|
437
|
+
controller_class_name = controller_file.gsub(/\A.*\/app\/controllers\//,"").gsub(/\.\w*\Z/,"").camelize
|
|
438
|
+
controller_class_name.constantize
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def ignored?(controller, method = nil)
|
|
442
|
+
ignored = Apipie.configuration.ignored
|
|
443
|
+
return true if ignored.include?(controller.name)
|
|
444
|
+
return true if ignored.include?("#{controller.name}##{method}")
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
# Since Rails 3.2, the classes are reloaded only on file change.
|
|
448
|
+
# We need to reload all the controller classes to rebuild the
|
|
449
|
+
# docs, therefore we just force to reload all the code. This
|
|
450
|
+
# happens only when reload_controllers is set to true and only
|
|
451
|
+
# when showing the documentation.
|
|
452
|
+
#
|
|
453
|
+
# If cache_classes is set to false, it does nothing,
|
|
454
|
+
# as this would break loading of the controllers.
|
|
455
|
+
def rails_mark_classes_for_reload
|
|
456
|
+
init_env
|
|
457
|
+
reload_examples
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
end
|
|
462
|
+
end
|