apipie-rails 0.9.4 → 1.0.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -14
  3. data/.rubocop_todo.yml +102 -213
  4. data/CHANGELOG.md +17 -6
  5. data/README.rst +12 -12
  6. data/app/controllers/apipie/apipies_controller.rb +4 -4
  7. data/lib/apipie/apipie_module.rb +4 -4
  8. data/lib/apipie/application.rb +70 -54
  9. data/lib/apipie/configuration.rb +19 -26
  10. data/lib/apipie/dsl_definition.rb +4 -5
  11. data/lib/apipie/extractor/collector.rb +2 -2
  12. data/lib/apipie/extractor.rb +1 -1
  13. data/lib/apipie/generator/config.rb +12 -0
  14. data/lib/apipie/generator/swagger/computed_interface_id.rb +23 -0
  15. data/lib/apipie/generator/swagger/config.rb +78 -0
  16. data/lib/apipie/generator/swagger/context.rb +12 -1
  17. data/lib/apipie/generator/swagger/method_description/api_decorator.rb +20 -0
  18. data/lib/apipie/generator/swagger/method_description/api_schema_service.rb +86 -0
  19. data/lib/apipie/generator/swagger/method_description/decorator.rb +22 -0
  20. data/lib/apipie/generator/swagger/method_description/parameters_service.rb +139 -0
  21. data/lib/apipie/generator/swagger/method_description/response_schema_service.rb +46 -0
  22. data/lib/apipie/generator/swagger/method_description/response_service.rb +58 -0
  23. data/lib/apipie/generator/swagger/method_description.rb +2 -0
  24. data/lib/apipie/generator/swagger/operation_id.rb +1 -1
  25. data/lib/apipie/generator/swagger/param_description/builder.rb +4 -4
  26. data/lib/apipie/generator/swagger/param_description/composite.rb +9 -1
  27. data/lib/apipie/generator/swagger/param_description/in.rb +1 -1
  28. data/lib/apipie/generator/swagger/param_description/path_params_composite.rb +61 -0
  29. data/lib/apipie/generator/swagger/param_description/referenced_composite.rb +36 -0
  30. data/lib/apipie/generator/swagger/param_description/type.rb +9 -2
  31. data/lib/apipie/generator/swagger/path_decorator.rb +36 -0
  32. data/lib/apipie/generator/swagger/referenced_definitions.rb +17 -0
  33. data/lib/apipie/generator/swagger/resource_description_collection.rb +30 -0
  34. data/lib/apipie/generator/swagger/resource_description_composite.rb +56 -0
  35. data/lib/apipie/generator/swagger/schema.rb +63 -0
  36. data/lib/apipie/generator/swagger/type_extractor.rb +0 -19
  37. data/lib/apipie/generator/swagger/warning.rb +3 -6
  38. data/lib/apipie/generator/swagger/warning_writer.rb +7 -1
  39. data/lib/apipie/method_description.rb +4 -2
  40. data/lib/apipie/param_description.rb +4 -2
  41. data/lib/apipie/resource_description.rb +1 -1
  42. data/lib/apipie/swagger_generator.rb +27 -551
  43. data/lib/apipie/validator.rb +7 -3
  44. data/lib/apipie/version.rb +1 -1
  45. data/lib/apipie-rails.rb +17 -0
  46. data/lib/tasks/apipie.rake +15 -10
  47. data/spec/controllers/api/v2/nested/resources_controller_spec.rb +2 -2
  48. data/spec/controllers/pets_controller_spec.rb +10 -16
  49. data/spec/controllers/users_controller_spec.rb +2 -2
  50. data/spec/dummy/app/controllers/pets_controller.rb +4 -4
  51. data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +2 -2
  52. data/spec/dummy/app/controllers/twitter_example_controller.rb +2 -2
  53. data/spec/dummy/app/controllers/users_controller.rb +5 -5
  54. data/spec/lib/apipie/application_spec.rb +16 -7
  55. data/spec/lib/apipie/configuration_spec.rb +15 -0
  56. data/spec/lib/apipie/generator/swagger/config_spec.rb +19 -0
  57. data/spec/lib/apipie/generator/swagger/context_spec.rb +22 -2
  58. data/spec/lib/apipie/generator/swagger/method_description/api_schema_service_spec.rb +106 -0
  59. data/spec/lib/apipie/generator/swagger/method_description/response_schema_service_spec.rb +105 -0
  60. data/spec/lib/apipie/generator/swagger/param_description/builder_spec.rb +1 -1
  61. data/spec/lib/apipie/generator/swagger/param_description/composite_spec.rb +2 -2
  62. data/spec/lib/apipie/generator/swagger/param_description/type_spec.rb +7 -7
  63. data/spec/lib/apipie/generator/swagger/path_decorator_spec.rb +57 -0
  64. data/spec/lib/apipie/generator/swagger/referenced_definitions_spec.rb +35 -0
  65. data/spec/lib/apipie/generator/swagger/resource_description_composite_spec.rb +37 -0
  66. data/spec/lib/apipie/generator/swagger/resource_descriptions_collection_spec.rb +57 -0
  67. data/spec/lib/apipie/generator/swagger/schema_spec.rb +89 -0
  68. data/spec/lib/apipie/generator/swagger/type_extractor_spec.rb +0 -43
  69. data/spec/lib/apipie/generator/swagger/warning_spec.rb +1 -1
  70. data/spec/lib/apipie/generator/swagger/warning_writer_spec.rb +19 -7
  71. data/spec/lib/apipie/method_description_spec.rb +101 -66
  72. data/spec/lib/apipie/param_description_spec.rb +209 -49
  73. data/spec/lib/apipie/param_group_spec.rb +1 -0
  74. data/spec/lib/apipie/resource_description_spec.rb +1 -1
  75. data/spec/lib/apipie/swagger_generator_spec.rb +94 -0
  76. data/spec/lib/apipie/validator_spec.rb +47 -11
  77. data/spec/lib/swagger/rake_swagger_spec.rb +4 -4
  78. data/spec/lib/swagger/swagger_dsl_spec.rb +7 -7
  79. data/spec/lib/validators/array_validator_spec.rb +1 -1
  80. metadata +28 -2
@@ -0,0 +1,36 @@
1
+ class Apipie::Generator::Swagger::PathDecorator < SimpleDelegator
2
+ def param_names
3
+ @param_names ||= scan(/:(\w+)/).map { |ar| ar[0].to_sym }
4
+ end
5
+
6
+ # @param [Symbol] param_name
7
+ def param?(param_name)
8
+ param_names.include?(param_name)
9
+ end
10
+
11
+ # @param [String] controller_method
12
+ #
13
+ # @return [Apipie::Generator::Swagger::PathDecorator]
14
+ def swagger_path(controller_method = nil)
15
+ current_path = gsub(/:(\w+)/, '{\1}').gsub(%r{/$}, '')
16
+
17
+ unless current_path.starts_with?('/')
18
+ warn_for_missing_slash(controller_method) if controller_method.present?
19
+
20
+ current_path = "/#{current_path}"
21
+ end
22
+
23
+ current_path
24
+ end
25
+
26
+ private
27
+
28
+ # @param [String] controller_method
29
+ def warn_for_missing_slash(controller_method)
30
+ Apipie::Generator::Swagger::Warning.for_code(
31
+ Apipie::Generator::Swagger::Warning::ADDED_MISSING_SLASH_CODE,
32
+ controller_method,
33
+ { path: self }
34
+ ).warn_through_writer
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ class Apipie::Generator::Swagger::ReferencedDefinitions
2
+ include Singleton
3
+
4
+ attr_reader :definitions
5
+
6
+ def initialize
7
+ @definitions = {}
8
+ end
9
+
10
+ def add!(param_type, schema)
11
+ @definitions[param_type] = schema
12
+ end
13
+
14
+ def added?(name)
15
+ @definitions.key?(name)
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ class Apipie::Generator::Swagger::ResourceDescriptionsCollection
2
+ # @param [Hash{String->Apipie::ResourceDescription}] resource_descriptions
3
+ def initialize(resource_descriptions)
4
+ @resource_descriptions = resource_descriptions
5
+ end
6
+
7
+ # @return [Array<Apipie::ResourceDescription>]
8
+ def filter(version:, resource_id:, method_name: nil)
9
+ resources = []
10
+
11
+ # If resource_id is blank, take just resources which have some methods because
12
+ # we dont want to show eg ApplicationController as resource
13
+ # otherwise, take only the specified resource
14
+ @resource_descriptions[version].each do |resource_description_id, resource_description|
15
+ if (resource_id.blank? && resource_description._methods.present?) || resource_description_id == resource_id
16
+ resources << resource_description
17
+ end
18
+ end
19
+
20
+ if method_name.present?
21
+ resources = resources.select do |resource_description|
22
+ resource_description._methods.select do |method_description_name, _|
23
+ method_description_name == method_name
24
+ end.present?
25
+ end
26
+ end
27
+
28
+ resources
29
+ end
30
+ end
@@ -0,0 +1,56 @@
1
+ class Apipie::Generator::Swagger::ResourceDescriptionComposite
2
+ # @param [Array<Apipie::ResourceDescription>] resource_descriptions
3
+ def initialize(resource_descriptions, language:)
4
+ @resource_descriptions = resource_descriptions
5
+ @language = language
6
+ end
7
+
8
+ # @return [Hash{Symbol->Array | Hash}]
9
+ def to_swagger
10
+ {
11
+ tags: tags,
12
+ paths: paths
13
+ }
14
+ end
15
+
16
+ # @return [Array]
17
+ def tags
18
+ results = []
19
+
20
+ @resource_descriptions.each do |resource_description|
21
+ next unless resource_description._full_description
22
+
23
+ results << {
24
+ name: resource_description._id,
25
+ description: Apipie.app.translate(
26
+ resource_description._full_description,
27
+ @language
28
+ )
29
+ }
30
+ end
31
+
32
+ results
33
+ end
34
+
35
+ # @return [Hash]
36
+ def paths
37
+ results = {}
38
+
39
+ @resource_descriptions.each do |resource_description|
40
+ resource_description._methods.each_value do |method_description|
41
+ next unless method_description.show
42
+
43
+ result = Apipie::Generator::Swagger::MethodDescription::ApiSchemaService
44
+ .new(
45
+ Apipie::Generator::Swagger::MethodDescription::Decorator.new(method_description),
46
+ language: @language
47
+ )
48
+ .call
49
+
50
+ results.deep_merge!(result)
51
+ end
52
+ end
53
+
54
+ results
55
+ end
56
+ end
@@ -0,0 +1,63 @@
1
+ class Apipie::Generator::Swagger::Schema
2
+ # @param [Array<Apipie::ResourceDescription>] resource_descriptions
3
+ def initialize(resource_descriptions, version:, language:, clear_warnings:)
4
+ @resource_descriptions = resource_descriptions
5
+ @language = language
6
+ @clear_warnings = clear_warnings
7
+ @swagger = {
8
+ swagger: '2.0',
9
+ info: {
10
+ title: Apipie.configuration.app_name.to_s,
11
+ description: "#{Apipie.app_info(version, @language)}#{Apipie.configuration.copyright}",
12
+ version: version.to_s,
13
+ 'x-copyright': Apipie.configuration.copyright
14
+ },
15
+ basePath: Apipie.api_base_url(version),
16
+ consumes: [],
17
+ paths: {},
18
+ definitions: {},
19
+ schemes: Apipie.configuration.generator.swagger.schemes,
20
+ tags: [],
21
+ securityDefinitions: Apipie.configuration.generator.swagger.security_definitions,
22
+ security: Apipie.configuration.generator.swagger.global_security
23
+ }
24
+ end
25
+
26
+ def generate
27
+ if Apipie.configuration.generator.swagger.api_host.present?
28
+ @swagger[:host] = Apipie.configuration.generator.swagger.api_host
29
+ end
30
+
31
+ if Apipie.configuration.generator.swagger.content_type_input == :json
32
+ @swagger[:consumes] = ['application/json']
33
+ @swagger[:info][:title] += ' (params in:body)'
34
+ else
35
+ @swagger[:consumes] = ['application/x-www-form-urlencoded', 'multipart/form-data']
36
+ @swagger[:info][:title] += ' (params in:formData)'
37
+ end
38
+
39
+ if @clear_warnings
40
+ Apipie::Generator::Swagger::WarningWriter.instance.clear!
41
+ end
42
+
43
+ @swagger.merge!(tags_and_paths)
44
+
45
+ if Apipie.configuration.generator.swagger.generate_x_computed_id_field?
46
+ @swagger[:info]['x-computed-id'] =
47
+ Apipie::Generator::Swagger::ComputedInterfaceId.instance.id
48
+ end
49
+
50
+ @swagger[:definitions] =
51
+ Apipie::Generator::Swagger::ReferencedDefinitions.instance.definitions
52
+
53
+ @swagger
54
+ end
55
+
56
+ private
57
+
58
+ def tags_and_paths
59
+ Apipie::Generator::Swagger::ResourceDescriptionComposite
60
+ .new(@resource_descriptions, language: @language)
61
+ .to_swagger
62
+ end
63
+ end
@@ -25,21 +25,10 @@ class Apipie::Generator::Swagger::TypeExtractor
25
25
  @validator = validator
26
26
  end
27
27
 
28
- # @param [Hash<Symbol, Apipie::Generator::Swagger::Warning>] warnings
29
- def extract_with_warnings(warnings = {})
30
- if boolean? && warnings[:boolean].present?
31
- Apipie::Generator::Swagger::WarningWriter.instance.warn(warnings[:boolean])
32
- end
33
-
34
- extract
35
- end
36
-
37
28
  def extract
38
29
  expected_type =
39
30
  if string?
40
31
  :string
41
- elsif boolean?
42
- :boolean
43
32
  elsif enum?
44
33
  :enum
45
34
  else
@@ -59,12 +48,4 @@ class Apipie::Generator::Swagger::TypeExtractor
59
48
  @validator.is_a?(Apipie::Validator::EnumValidator) ||
60
49
  (@validator.respond_to?(:is_enum?) && @validator.is_enum?)
61
50
  end
62
-
63
- def boolean?
64
- @_boolean ||= enum? && boolean_values?
65
- end
66
-
67
- def boolean_values?
68
- @validator.values.to_set == Set.new([true, false])
69
- end
70
51
  end
@@ -7,7 +7,6 @@ class Apipie::Generator::Swagger::Warning
7
7
  OPTIONAL_WITHOUT_DEFAULT_VALUE_CODE = 105
8
8
  PARAM_IGNORED_IN_FORM_DATA_CODE = 106
9
9
  PATH_PARAM_NOT_DESCRIBED_CODE = 107
10
- INFERRING_BOOLEAN_CODE = 108
11
10
 
12
11
  CODES = {
13
12
  missing_method_summary: MISSING_METHOD_SUMMARY_CODE,
@@ -17,8 +16,7 @@ class Apipie::Generator::Swagger::Warning
17
16
  optional_param_in_path: OPTIONAL_PARAM_IN_PATH_CODE,
18
17
  optional_without_default_value: OPTIONAL_WITHOUT_DEFAULT_VALUE_CODE,
19
18
  param_ignored_in_form_data: PARAM_IGNORED_IN_FORM_DATA_CODE,
20
- path_param_not_described_code: PATH_PARAM_NOT_DESCRIBED_CODE,
21
- inferring_boolean: INFERRING_BOOLEAN_CODE
19
+ path_param_not_described_code: PATH_PARAM_NOT_DESCRIBED_CODE
22
20
  }
23
21
 
24
22
  MESSAGES = {
@@ -29,8 +27,7 @@ class Apipie::Generator::Swagger::Warning
29
27
  OPTIONAL_PARAM_IN_PATH_CODE => "The parameter :%{parameter} is 'in-path'. Ignoring 'not required' in DSL",
30
28
  OPTIONAL_WITHOUT_DEFAULT_VALUE_CODE => "The parameter :%{parameter} is optional but default value is not specified (use :default_value => ...)",
31
29
  PARAM_IGNORED_IN_FORM_DATA_CODE => "Ignoring param :%{parameter} -- cannot include Hash without fields in a formData specification",
32
- PATH_PARAM_NOT_DESCRIBED_CODE => "The parameter :%{name} appears in the path %{path} but is not described",
33
- INFERRING_BOOLEAN_CODE => "The parameter [%{parameter}] is Enum with [true, false] values. Inferring 'boolean'"
30
+ PATH_PARAM_NOT_DESCRIBED_CODE => "The parameter :%{name} appears in the path %{path} but is not described"
34
31
  }
35
32
 
36
33
  attr_reader :code
@@ -46,7 +43,7 @@ class Apipie::Generator::Swagger::Warning
46
43
  end
47
44
 
48
45
  def warning_message
49
- "WARNING (#{@code}): [#{@method_id}] -- #{@info_message}"
46
+ "WARNING (#{@code}): [#{@method_id}] -- #{@info_message}\n"
50
47
  end
51
48
 
52
49
  def warn
@@ -18,6 +18,12 @@ class Apipie::Generator::Swagger::WarningWriter
18
18
  @issued_warnings.count > 0
19
19
  end
20
20
 
21
+ def clear!
22
+ @issued_warnings = []
23
+
24
+ self
25
+ end
26
+
21
27
  private
22
28
 
23
29
  # @param [Apipie::Generator::Swagger::Warning] warning
@@ -43,6 +49,6 @@ class Apipie::Generator::Swagger::WarningWriter
43
49
 
44
50
  # @return [FalseClass, TrueClass, Array]
45
51
  def suppress_warnings_config
46
- Apipie.configuration.swagger_suppress_warnings
52
+ Apipie.configuration.generator.swagger.suppress_warnings
47
53
  end
48
54
  end
@@ -1,5 +1,4 @@
1
1
  module Apipie
2
-
3
2
  class MethodDescription
4
3
  attr_reader :full_description, :method, :resource, :apis, :examples, :see, :formats, :headers, :show
5
4
  attr_accessor :metadata
@@ -182,6 +181,10 @@ module Apipie
182
181
  @from_concern
183
182
  end
184
183
 
184
+ def method_name
185
+ @method
186
+ end
187
+
185
188
  private
186
189
 
187
190
  def merge_params(params, new_params)
@@ -224,5 +227,4 @@ module Apipie
224
227
  example
225
228
  end
226
229
  end
227
-
228
230
  end
@@ -57,6 +57,10 @@ module Apipie
57
57
  @from_concern = @options[:param_group][:from_concern]
58
58
  end
59
59
 
60
+ if validator.is_a?(Hash)
61
+ @options.merge!(validator.select{|k,v| k != :array_of })
62
+ end
63
+
60
64
  @method_description = method_description
61
65
  @name = concern_subst(name)
62
66
  @as = options[:as] || @name
@@ -85,9 +89,7 @@ module Apipie
85
89
  if validator
86
90
  if (validator != Hash) && (validator.is_a? Hash) && (validator[:array_of])
87
91
  @is_array = true
88
- rest_of_options = validator
89
92
  validator = validator[:array_of]
90
- options.merge!(rest_of_options.select{|k,v| k != :array_of })
91
93
  raise "an ':array_of =>' validator is allowed exclusively on response-only fields" unless @response_only
92
94
  end
93
95
  @validator = Validator::BaseValidator.find(self, validator, @options, block)
@@ -65,7 +65,7 @@ module Apipie
65
65
  alias _name name
66
66
 
67
67
  def add_method_description(method_description)
68
- Apipie.debug "@resource_descriptions[#{self._version}][#{self._name}]._methods[#{method_description.method}] = #{method_description}"
68
+ Apipie.debug "@resource_descriptions[#{self._version}][#{self._id}]._methods[#{method_description.method}] = #{method_description}"
69
69
  @_methods[method_description.method.to_sym] = method_description
70
70
  end
71
71